2013-06-11 12 views
8

Jestem początkującym użytkownikiem OpenCV dla JAVA. Chcę uzyskać dostęp do indywidualnych wartości pikseli macierzy obrazów. Ponieważ jar JAVA dla OpenCV nie oferuje ładnych funkcji, takich jak C++, wpadłem w kłopoty. Po wielu poszukiwaniach odkryłem dwie różne metody, które nie zostały wyjaśnione w odpowiedni sposób (nawet w dokumentacji). Możemy to zrobić za pomocą funkcji get() i put() lub konwertując dane maty na typ prymitywny Java, taki jak tablice. Próbowałem obu, ale uzyskując różne wyniki wyjściowe! Pomóż wyjaśnić, co robię źle. Czy używam ich źle, czy też jakiegoś innego głupiego problemu. Nadal jestem nowicjuszem, więc proszę wybacz, jeśli to głupie pytanie. :)Używanie get() i put() do uzyskiwania dostępu do wartości pikseli w OpenCV dla Javy

Przypadek 1: Korzystanie z get() funkcja

Mat A = Highgui.imread(image_addr); \\"image_addr" is the address of the image 
Mat C = A.clone(); 
Size sizeA = A.size(); 
for (int i = 0; i < sizeA.height; i++) 
    for (int j = 0; j < sizeA.width; j++) { 
     double[] data = A.get(i, j); 
     data[0] = data[0]/2; 
     data[1] = data[1]/2; 
     data[2] = data[2]/2; 
     C.put(i, j, data); 
    } 

Przypadek 2: Korzystanie Array

Mat A = Highgui.imread(image_addr); \\"image_addr" is the address of the image 
Mat C = A.clone(); 
int size = (int) (A.total() * A.channels()); 
byte[] temp = new byte[size]; 
A.get(0, 0, temp); 
for (int i = 0; i < size; i++) 
    temp[i] = (byte) (temp[i]/2); 
C.put(0, 0, temp); 

Teraz według mojego rozeznania powinien oba robią to samo. Obaj uzyskują dostęp do poszczególnych wartości pikseli (wszystkie 3 kanały) i robią to w połowie. Po uruchomieniu nie pojawia się żaden błąd. Ale wyjściowy obraz, który otrzymuję, jest inny w tych dwóch przypadkach. Czy ktoś może wyjaśnić, na czym polega problem? Być może nie rozumiem dokładnie, jak działa funkcja get()? Czy to z powodu odlewania bajtów()? Proszę pomóż.

Dzięki!

Odpowiedz

9

To się stało z powodu odlewania bajtów(). Zmieniłem typ danych obrazu matowego w drugim przypadku na * CV_64FC3 *, dzięki czemu mogę użyć podwójnego [] zamiast bajtu [] i rozwiązać problem.

Mat A = Highgui.imread(image_addr); //"image_addr" is the address of the image 
Mat C = A.clone(); 
A.convertTo(A, CvType.CV_64FC3); // New line added. 
int size = (int) (A.total() * A.channels()); 
double[] temp = new double[size]; // use double[] instead of byte[] 
A.get(0, 0, temp); 
for (int i = 0; i < size; i++) 
    temp[i] = (temp[i]/2); // no more casting required. 
C.put(0, 0, temp); 

FYI, ja też zrobiłem trochę czasu pomiaru i przy użyciu drugiej metody jest znacznie szybciej niż pierwsza metoda.

+0

dzięki za dobre pytanie, czy możesz wyjaśnić, dlaczego użyłeś: (A.total() * A.channels()); ?? suma (metoda zwraca wysokość withd *, dlaczego jest pomnożona przez numery kanałów, wiem, że obraz RGB ma 3 kanały ... ale potrzebuję więcej wyjaśnienia proszę – rmaik

+0

@rmaik Każdy kanał ma własne wartości intensywności (czerwony, niebieski lub zielony) dla każdego piksela, więc całkowita liczba tych wartości intensywności w obrazie jest równa liczbie pikseli * całkowita liczba kanałów. Tak więc w tym przypadku total() daje całkowitą liczbę pikseli w obrazie i kanale() daje liczbę kanałów – gargsl

1

Znaleziony prosty i pracy rozwiązanie po wielu searching-

Mat img = Highgui.imread("Input.jpg"); //Reads image from the file system and puts into matrix 
int rows = img.rows(); //Calculates number of rows 
int cols = img.cols(); //Calculates number of columns 
int ch = img.channels(); //Calculates number of channels (Grayscale: 1, RGB: 3, etc.) 

for (int i=0; i<rows; i++) 
{ 
    for (int j=0; j<cols; j++) 
    { 
     double[] data = img.get(i, j); //Stores element in an array 
     for (int k = 0; k < ch; k++) //Runs for the available number of channels 
     { 
      data[k] = data[k] * 2; //Pixel modification done here 
     } 
     img.put(i, j, data); //Puts element back into matrix 
    } 
} 
Highgui.imwrite("Output.jpg", img); //Writes image back to the file system using values of the modified matrix 

Uwaga: ważnym punktem, które nie zostały wymienione w dowolnym miejscu w Internecie jest to, że metoda put nie pisze pikseli na Input.jpg. Aktualizuje jedynie wartości macierzy img. Dlatego powyższy kod nie zmienia niczego w obrazie wejściowym. Aby wytworzyć widoczne wyjście, macierz img musi być w tym przypadku zapisana na pliku, to jest Output.jpg. Również użycie img.get(i, j) wydaje się lepszym sposobem na obsługę elementów macierzowych, niż wykorzystanie przyjętego rozwiązania powyżej, ponieważ pomaga to w lepszej wizualizacji i pracy z matrycą obrazu i nie wymaga dużej alokacji pamięci.

+0

Działa, ale jest bardzo powolny.Może zająć 30 sekund dla obrazu 8MP na dobrym komputerze.Ale chcesz czytać wszystkie dane jednocześnie w buforze przy użyciu Mat.get (0,0, bajt [totalNumberOfPixel * bytesPerPixel]) – RenaudBlue

Powiązane problemy