2012-03-29 15 views
7

Niedawno otrzymałem książkę "Learning OpenCV" autorstwa O'Reilly'ego i od tamtej pory zajmowałem się konwersją kodu przykładowego, który widzę od OpenCV do JavaCV, zwykle za nim trochę z mojej własnej modyfikacji. Cały czas staram się trzymać kodu OpenCV (języka C) jak najwięcej i unikać Javy. Na przykład zaimplementowałem wszystkie elementy interfejsu bezpośrednio za pomocą pakietu OpenCV highgui w JavaCV, a nie za pomocą Java Swing. W ten sposób mam nadzieję zarówno nauczyć się biblioteki OpenCV, jak i niektórych C w stosunkowo krótkim czasie, jak również stworzyć bibliotekę przydatnych funkcji, które będę mógł łatwo przekonwertować na C, jeśli zdecyduję się później przejść na czysty OpenCV.Konwersja pętli w macierzy OpenCV do JavaCV

W każdym razie, mam niewielką wiedzę na temat C i czasami wpadam w kłopoty, gdy mamy do czynienia ze wskaźnikami. Książka zaleca następującą kodu jako optymalne środki, za pomocą których można iterację matrycy 3-channel:

float sum(const CvMat* mat) { 
    float s = 0.0f; 
    for(int row=0; row<mat->rows; row++) { 
     const float* ptr = (const float*)(mat->data.ptr + row * mat->step); 
     for(col=0; col<mat->cols; col++) { 
      s += *ptr++; 
     } 
    } 
    return(s); 
} 

jest tu włączone wyjaśnieniem tego kodu:

Przy obliczaniu wskaźnika do matrycy , pamiętaj, że dane elementu matrycy są złączami. Dlatego podczas usuwania odnośnika do tego wskaźnika należy wskazać poprawny element złącza, aby uzyskać prawidłowy typ wskaźnika. Aby ustawić wskaźnik, musisz użyć elementu step macierzy. Jak wspomniano wcześniej, element krokowy jest w bajtach. Aby być bezpiecznym, najlepiej jest wykonać arytmetykę wskaźnika w bajtach i> następnie rzutować na odpowiedni typ, w tym przypadku float. Chociaż struktura CVMat ma> koncepcję wysokości i szerokości dla kompatybilności ze starszą strukturą IplImage, zamiast tego używamy bardziej aktualnych wierszy i cols. Na koniec zauważmy, że przeliczamy ptr dla> każdego wiersza, a nie po prostu zaczynamy od początku, a następnie zwiększamy wskaźnik każdego odczytu. To może wydawać się przesadne, ale ponieważ wskaźnik danych CvMat może po prostu wskazywać na ROI w większej tablicy, nie ma gwarancji, że dane będą> ciągłe w wierszach.

Mam jednak problem z konwersją do JavaCV. Pole ptr (wskaźnik) wydaje się być floatem, co mnie wprawia w zakłopotanie. Zakładam, że w rzeczywistości nie jest to "wskaźnik", ale raczej wartość, do której dodawana jest wartość każdego piksela? Czy jest to właściwie wskaźnik, którego wartość wyszukuje całkowitą sumę dla wszystkich kolumn w danym wierszu?

W każdym razie, byłbym wdzięczny, gdyby ktoś wysłał mi kod JavaCV dla pętli equivelent. Wiem, że istnieją inne sposoby dostępu do każdego piksela w CvMacie, ale AFAIK są mniej wydajne lub niedokładne.

+0

Z tego, co widzę na przykładzie, macierz jest adresowana jako dwuwymiarowy, szary typ danych typu float. Wszystkie wartości pikseli są sumowane do s, które staną się skumulowaną jasnością. Ptr jest w rzeczywistości wskaźnikiem, który wskazuje na tablicę w dowolnym punkcie, a 'ptr [x]' jest równe '(const float *) (mat-> data.ptr + row * mat-> step) [x]; '. ptr jest inicjowane dla danego piksela i inkrementowane, więc '[x]' nie jest konieczne i jest po prostu dereferencyjne z '*', równe '[0]'. –

+0

@zom W jaki sposób wskaźnik jest inkrementowany? Z tego, co rozumiem w kodzie, wskaźnik ma przypisaną wartość piksela? Czy jest przypisana pozycja piksela? Jeśli w poprzednim przypadku, to kiedy pojawi się operacja 'ptr ++ ', czy wartość przypisanego piksela nie wzrośnie, zamiast spowodować, że wskaźnik wskaże następny piksel? A jeśli późniejszy przypadek, to kiedy i gdzie jest faktyczna wartość piksela przypisanego do 's'? Tak dużo pytań. –

+0

Przeczytaj najpierw: http://c-faq.com/ptrs/index.html –

Odpowiedz

6

Konkretny przykład podać byłoby optymalnie przekształcić w Javie jak

float sum(CvMat mat) { 
    final int rows = mat.rows(); 
    final int cols = mat.cols(); 
    final int step = mat.step()/4; 
    FloatBuffer buf = mat.getFloatBuffer(); 
    float s = 0.0f; 
    for (int row = 0; row < rows; row++) { 
     buf.position(row * step); 
     for (int col = 0; col< cols; col++) { 
      s += buf.get(); 
     } 
    } 
    return s; 
} 
+0

Sam, miło odpowiedzieć od samego autora JavaCV! Już to rozwiązałem. –

+0

OK, świetnie! ale i tak powinieneś przyjąć odpowiedź, jeśli odpowiedź na to, co pierwotnie opublikowałeś, jest ... –

0

Oto wariant Muszę w końcu metodą prób & błędu; do iteracji przez 3-kanałową matrycę i stosowania bardzo prostego filtra (uważam, że przykład Samuela już ładnie obejmuje sumowanie wartości szarości).

static IplImage setSaturate_sv(IplImage imgIn) { 
    IplImage imgOut = cvCloneImage(imgIn); 
    ByteBuffer pointer = imgOut.getByteBuffer(); 

    int height = imgIn.height(); 
    int width = imgIn.width(); 
    int widthStep = imgIn.widthStep(); 
    int nChannels = imgIn.nChannels(); 
    int rowIndex; 

    for (int row = 0; row < height; row++) { 
     rowIndex = row * widthStep; 
     for (int col = 0; col < width; col++) { 
      pointer.put((rowIndex + (col * nChannels) + 1), (byte)255); 
      pointer.put((rowIndex + (col * nChannels) + 2), (byte)255); 
      pointer.put((rowIndex + (col * nChannels) + 3), /* leave alone */); 
     } 
    } 
    return imgOut; 
} 
Powiązane problemy