czwartek, 18 czerwca 2009

Jak sobie poradzić ze szkieletyzacją w Pandore

0 komentarze
Przetwarzanie obrazów w celu wydobycia z nich interesujących nas danych nie musi być trudne. Wystarczy opanować pewien zestaw operacji podstawowych i wybrać wygodny analizator obrazu (ja polecam Pandore). Tym wpisem chciałbym zacząć serię mini poradników jak sobie poradzić z różnymi problemami związanymi z analizą obrazu i jak rozwiązać niektóre zadania. Wpisy te będą oznaczone tagiem rozwiązania. Nie planuje opisywać działania poszczególnych operacji, a jedynie uzasadniać dlaczego w danym algorytmie zostały użyte. Czytelnika natomiast zachęcam do samodzielnego zapoznania się z podstawami. Szczególnie pomocna może okazać się książka prof. Leszka Wojnara "Komputerowa Analiza Obrazu", do której sam czasami zaglądam. Dodatkowo do każdej użytej instrukcji będzie podany link do pomocy programu.

Na początek zostanie pokazane jak wykonać szkieletyzację obrazu binarnego. Niestety poza szkieletem często dostajemy dodatkowe artefakty, których najchętniej byśmy się pozbyli. Służy do tego operacja usuwania gałęzi, która w przypadku Pandore nie najlepiej sobie radzi. Zobaczymy w jaki sposób można ten problem rozwiązać.

Konwersja obrazu
Test będzie przeprowadzony dla sztucznego obrazu, który przedstawia bliżej nieokreśloną strukturę połączonych elementów z dodatkowymi wypustkami.
Najpierw konwertujemy obraz do formatu Pandore.
pbmp2pan input.bmp ex1_i1.pan



Szkieletyzacja
Następnie uruchamiamy szkieletyzację. Na poniższym obrazie widzimy jej efekty. Można zauważyć, że poza właściwym szkieletem dostaliśmy sporo dodatkowych gałęzi, które po części pokrywają się z wypustkami, a po części zlokalizowane są w przypadkowych miejscach - głównie tam gdzie struktura ma nieregularną krawędź.
pskeletonization ex1_i1.pan ex1_i2.pan



Cieniowanie
Stosujemy operację cieniowania, aby upewnić się, że szkielet będzie miał grubość jednego piksela.
ppostthinning ex1_i2.pan ex1_i3.pan



Usunięcie gałęzi
Ta operacja, jak sama nazwa wskazuje powinna usunąć wszystkie artefakty i pozostawić tylko linie łączące się ze sobą i z krawędzią. Jednakże jej działanie nie jest do końca takie jak byśmy sobie tego życzyli.
Spróbujemy rozwiązać problem w inny sposób.
pbarbremoval 2 1 ex1_i3.pan ex1_i4.pan



Negatyw
Wykonujemy negatyw. W tym momencie obraz nie przedstawia już linii, a obiekty, rozdzielone przez te linie (przypomnienie: w analizie obrazu na obrazie binarnym kolor biały oznacza obiekty do analizy, a kolor czarny tło).
pinverse ex1_i4.pan ex1_i5.pan



Indeksacja obiektów
Każdemu rozłącznemu obszarowi nadajemy inną wartość. Pozwoli nam to patrzeć na nie jak na zupełnie niezależne obiekty.
plabeling 4 ex1_i5.pan ex1_i6.pan



Dylatacja
Powiększamy każdy obszar pasem o wartości jednego piksela. Można zauważyć, że w ten sposób straciliśmy granice pomiędzy obiektami.
pdilatation 0 1 ex1_i6.pan ex1_i7.pan



Wyznaczenie krawędzi
Rozdzielamy obiekty wprowadzając między nimi linie graniczne.
pboundary 4 ex1_i7.pan ex1_i8.pan



Maska
Powstały w ten sposób obraz będzie maską dla wyznaczonego w kroku trzecim szkieletu.
pand ex1_i3.pan ex1_i8.pan ex1_i9.pan


Pomimo tego, że przedstawione rozwiązanie dotyczy problemów związanych z analizatorem Pandore, to warto się z nim zapoznać, aby zobaczyć alternatywne metody usuwania gałęzi.

sobota, 13 czerwca 2009

Pokazywanie wyników detekcji z wykorzystaniem ImageMagick

0 komentarze
Często po zakończonej detekcji potrzebujemy nanieść obiekt na obraz źródłowy, aby dokładnie zobaczyć czy dostaliśmy to o co nam chodziło. Jeśli sami piszemy program, np. w C++ możemy łatwo zmodyfikować odpowiednie piksele nadając im ustalony kolor i przeźroczystość. Pisałem jak to zrobić z wykorzystaniem CImg we wpisie Nanoszenie wyników detekcji na obraz źródłowy w CImg. Natomiast jeśli korzystamy z gotowego analizatora obrazu (np. Pandore) będziemy musieli poradzić sobie w inny sposób. Najlepszy w przypadku pracy w terminalu zapewne będzie ImageMagick. W Ubuntu instalujemy go poleceniem:
sudo apt-get install imagemagick

Najpierw na obrazie reprezentującym obiekt ustawiamy tło jako przeźroczyste, a resztę wypełniamy wybranym kolorem:
convert ConnectedThresholdWhiteTest.png -colorize "0,255,255" -transparent black ConnectedThresholdWhiteTest-mask.png




Następnie nanosimy przygotowany obraz na obraz źródłowy, zadając przeźroczystość na poziomie 30%:
composite ConnectedThresholdWhiteTest-mask.png BrainT1Slice.png -compose src-over -blend 30 BrainT1Slice-result1.png




Opcjonalnie na koniec możemy dodać informacje liczbowe dotyczące wyniku detekcji:
convert BrainT1Slice-result1.png -fill '#ff03' -draw 'rectangle 5,5,114,22' -fill white -annotate +10+18 'Statistics: xx' BrainT1Slice-result2.png




Zaprezentowane podejście świetnie się sprawdza dla dużej ilości obrazów oraz w przypadku, gdy tego typu operacje wykonywane są bardzo często. Odpowiednio przygotowany skrypt w Bashu wykona za nas wszystkie operacje.

piątek, 12 czerwca 2009

Rusz głową z Head First

0 komentarze
Na co dzień nie programuje w Javie i nie mam bogatego doświadczenia z pracy w tym języku, ale wiem, że warto go znać. Chociażby dlatego, że jest to obecnie najpopularniejszy język programowania - tak przynajmniej podają statystyki (m.in. ranking TIOBE). Nawet gdyby się myliły to i tak mówi się, że znacznie łatwiej znaleźć pracę znając Javę i np. Oracle, niż PHP i MySQL, lub technologie Microsoftu. Dodatkowo jest to język naprawdę wszechstronny. Można w nim pisać aplikacje okienkowe, strony internetowe, a nawet aplikacje na komórki. Osoby korzystające z Javy na co dzień, na pewno potrafią wymienić jeszcze sporo powodów dlaczego warto (lub nie;)) poznać ten język. Ja mogę tylko podpowiedzieć jak w miarę bezboleśnie się do tego zabrać.

W Internecie jest cała masa kursów i przykładów pokazujących różne możliwości Javy. Jednak znalezienie materiałów pisanych przystępnych językiem nie tylko o podstawach, ale również o technologiach bardziej zaawansowanych może być problematyczne. I tutaj pojawia się seria książek "Head first ...", która wypełnia tę lukę. Wszystkie książki z serii - a jest ich już kilkanaście - pisane są luźnym językiem, który łatwo trafia do odbiorcy. Spora liczba ilustracji dodatkowo ułatwia utrwalenie niuansów języka.

Na początek warto zacząć od "Head first Java". Po jej lekturze, programowanie obiektowe w Javie nie powinno sprawiać już żadnego problemu, a przygotowanie programu okienkowego w Swingu okaże się łatwiejsze niż przypuszczaliśmy. Następnie w zależności od tego co nas interesuje możemy lepiej poznać technologie sieciowe (HF Servlests and JSP, HF EJB), zaawansowane techniki programowania (HF Software Development, HF Design Patterns, HF Object-Oriented Analysis and Design) lub tworzenie stron WWW (HF JavaScript, HF HTML with CSS & XHTML).

Moja skromna biblioteczka w ostatnim czasie powiększyła się o 4 pozycje z serii Head First, co widać na poniższym zdjęciu. W tym momencie wiem, że była to dobra inwestycja.

piątek, 5 czerwca 2009

Ariane - interfejs graficzny dla Pandore

0 komentarze
Praca z analizatorem obrazu Pandore dla użytkowników przyzwyczajonych do aplikacji okienkowych może być uciążliwa. Wpisywanie kolejnych komend w okienku terminala nie wszystkim odpowiada i może szybko zniechęcić do używania tego narzędzia. Zdają sobie również z tego sprawę twórcy Pandore, dlatego przygotowali graficzną nakładkę Ariane wspomagającą konstruowanie algorytmów. Dzięki niej możemy łatwo projektować kolejne etapy przetwarzania obrazu łącząc ze sobą odpowiednie bloczki operacyjne. Z programem dodatkowo została zintegrowana pomoc, co dodatkowo upraszcza jego użytkowanie.



Program można pobrać ze strony: http://www.greyc.ensicaen.fr/~regis/Ariane/

czwartek, 4 czerwca 2009

Detekcja ruchu w KDE

0 komentarze
Ostatnio, zupełnie przypadkiem trafiłem na dwie wiadomości dotyczące wsparcia biblioteki OpenCV w KDE. Oczywiście celem prowadzonych prac ma być wykorzystanie detekcji ruchu przy interakcji użytkownika z systemem. We wpisie zamieszczonym na blogu DrIDk's dev autor proponuje wprowadzenie modnego ostatnio w konsolach sterowania za pomocą ruchu również do gier dostępnych w KDE. Druga wiadomość jest równie obiecująca i dotyczy interakcji z pulpitem. Na poniższym filmiku widać już pierwsze efekty:



Biorąc pod uwagę rosnącą ilość urządzeń korzystających z ekranów dotykowych (szczególnie w telefonach komórkowych) i coraz częściej montowane kamerki w laptopach, można się spodziewać, że w niedalekiej przyszłości klawiatura, a nawet myszka przestaną być wogóle używane.

środa, 3 czerwca 2009

Edycja video w CImg i ffmpeg

0 komentarze
Próba edycji pliku wideo z poziomu C++ może okazać się kłopotliwa jeśli nie korzystamy z dodatkowych bibliotek. Jak wiadomo standardów zapisu / kompresji multimediów jest naprawdę sporo i jeśli poradzilibyśmy sobie z jednym formatem to taką samą pracę należało by wykonać dla pozostałych. W Linuksie może nas w tym wyręczyć narzędzie ffmpeg i zbiór bibliotek, które są w nim zawarte (więcej można przeczytać na Wikipedii).

Aby napisać prosty przykład korzystający z ffmpeg trzeba poznać podstawy API bibliotek libavcodec oraz libavformat. Dla początkującego użytkownika może okazać się problematyczna analiza techniczna dokumentacji i niuansów związanych z kodekami video. Dlatego skorzystamy z innej biblioteki, która zawiera wsparcie dla ffmpeg, a mianowicie CImg (ta mała biblioteka nie przestaje mnie zaskakiwać swoimi możliwościami).

Na początek musimy się upewnić, że mamy zainstalowany pakiet ffmpeg. Możemy wydać polecenie instalacji i jeśli go nie będzie zostanie pobrany i zainstalowany:
sudo apt-get install ffmpeg

Oczywiście będzie również potrzebny testowy film, który będziemy modyfikować. Ja korzystałem z Pixar "Yeti Dance" (Pixar-Yeti_Dance.mpeg).

Następnie przygotowujemy kod programu:
#include <iostream>
#include <ostream>
#include "../CImg.h"

using namespace std;
using namespace cimg_library;

void process_frame(CImg<unsigned char> &frame)
{
  //negatyw obrazu
  cimg_forXYV(frame,x,y,v) { frame(x,y,v) = 255 - frame(x,y,v); }
}

int main()
{
  CImgList<unsigned char> film;
  film.load_ffmpeg("Pixar-Yeti_Dance.mpeg"); //odczyt z pliku

  CImgDisplay disp_film1, disp_film2;

  cimglist_for(film,index) {
    film[index].display(disp_film1);  //wyświetl oryginalną klatkę
    process_frame( film[index] );     //nakładanie filtru
    film[index].display(disp_film2);  //wyświetl zmodyfikowaną klatkę
  }
  while (!disp_film1.is_closed) disp_film1.wait();

  film.save_ffmpeg("Pixar-Yeti_Dance-invert.mpeg"); //zapis
  return 0;
}

Kompilacja za pomocą pomocą polecenia:
g++ -o ffmpeg_test ffmpeg_test.cpp -lX11 -lpthread

Po uruchomieniu programu zobaczymy na ekranie zarówno obraz oryginalny, jak i zmodyfikowany:

Omówiony przykład jest bardzo prosty i nie pokazuje pełnych możliwości ffmpeg. Jednak na etapie projektowania algorytmu wykorzystanie biblioteki CImg może znacznie ułatwić przygotowanie działającego prototypu.