niedziela, 4 kwietnia 2010

Intel IPP i OpenCV

Ostatnio mam potrzebę zastosowania innej wizyjnej biblioteki - Intel® Integrated Performance Primitives (w skrócie IPP). Jak nazwa wskazuje, podobnie jak OpenCV, powstała ona przy udziale firmy Intel. Jest to biblioteka o wysokiej optymalizacji dzięki czemu osiąga ona niskie czasy wykonania. Istnieje możliwość przyspieszenia OpenCV gdy wcześniej zainstalowano IPP. Obecnie ma to już marginalne znaczenie. Wspieranych jest jedynie kilka funkcji, m.in. klasyfikator Harra czy DFT. Więcej o bibliotece powinno pojawić się na blogu w przyszłości, teraz skupię się na jednym aspekcie.

Pomimo że w IPP zawarto pokaźną liczbę niskopoziomowych funkcji, brakuje w niej odpowiednika highgui z OpenCV. Powoduje to, że wszystkie dane musimy alokować samodzielnie, samodzielnie też przetwarzać odpowiednie formaty plików graficznych. Z pomocą może nam jednak przyjść OpenCV ;-). Możemy wykorzystać cvLoadImage i operować na IplImage. Spójrzmy na przykładowy kod wyznaczający laplasjan obrazu:
#include < highgui.h >
#include < ippi.h >

int main() {
const char * str = "{ścieżka do pliku}";
IplImage * wczytanyObraz = cvLoadImage(str,CV_LOAD_IMAGE_GRAYSCALE);

IppiSize size;
size.height = wczytanyObraz->height;
size.width = wczytanyObraz->width;
int step = 0;

Ipp8u *poFiltracji = ippiMalloc_8u_C1(size.width,size.height,&step);
ippiFilterLaplace_8u_C1R((Ipp8u*)wczytanyObraz->imageData,wczytanyObraz->widthStep,poFiltracji,step,size,ippMskSize5x5);
IplImage * doWyswietlenia = cvCreateImageHeader(cvGetSize(wczytanyObraz),8,1);
cvSetData(doWyswietlenia,(void*)poFiltracji,step);

cvShowImage("okno",doWyswietlenia);
while(true)
{
int key = cvWaitKey(100);
if(key == (int) ' ')
break;
}
ippiFree(poFiltracji);
cvReleaseImage(&wczytanyObraz);
return 0;
}


W linii 6. wczytujemy z dysku plik. Robimy to z użyciem HighGui. w liniach 8-11 przygotowujemy dane potrzebne w funkcji IPP obliczającej laplasjan. W linii 13. alokujemy pamięć na obraz wynikowy. Funkcja ta alokuje obraz 8-bitowy o jednym kanale na co wskazuje jej nazwa (8u i C1). Więcej o nazewnictwie IPP w przyszłości. W linii 14. obliczamy właściwy wynik. I tutaj najważniejsze: jako źródło (w tym przypadku wskaźnik na Ipp8u) używamy imageData z IplImage, z kolei jako przeznaczenie używamy naszego zaalokowanego Ipp8u. Druga ważna rzecz dzieje się w liniach 15-16. Zamiast tworzyć obraz tworzymy tylko jego nagłówek. Dane natomiast ustawiamy korzystając ze wskaźnika na Ipp8u. Można jeszcze zwrócić uwagę na linię 25., gdzie zwalniamy zaalokowaną przez IPP strukturę.

Powyżej pokazano jak mieszać OpenCV i IPP. Przyznam, że powyższy kod to efekt moich prób jak uzyskać płynne przejście między OpenCV i IPP bez kopiowania danych między strukturami. Metoda może więc nie być idealna, lub co gorzej, mieć jakieś ukryte błędy... Jak ktoś zna lepsze podejście to proszę o podzielenie się w komentarzach :)

Brak komentarzy: