2013-02-13 18 views
19

[EDIT] Opracowałem kod do porównywania obrazów. Ta pasująca część jest nadal trochę wadliwa i chciałabym trochę wsparcia. Projekt można znaleźć na stronie - GitHub.Porównanie obrazów OpenCV w systemie Android

mam te dwa obrazy img1 i img2:

enter image description hereenter image description here

Kiedy należy użyć następującego polecenia w OpenCV

Mat img1 = Highgui.imread("mnt/sdcard/IMG-20121228.jpg"); 
Mat img2 = Highgui.imread("mnt/sdcard/IMG-20121228-1.jpg"); 

try{ 
    double l2_norm = Core.norm(img1, img2); 
    tv.setText(l2_norm+""); 
} catch(Exception e) { 
    //image is not a duplicate 
} 

mogę dostać podwójną wartość dla l2_norm. Ta podwójna wartość zmienia się dla duplikatów par obrazów. Ale jeśli obrazy są różne, zostanie zgłoszony wyjątek. Czy w ten sposób identyfikuję zduplikowane obrazy? A może jest lepsza metoda? Zrobiłem wiele badań i nie mogłem znaleźć naprawdę przekonującej odpowiedzi. Chciałbym kodu i wyjaśnienia, jak porównać dwa obrazy i uzyskać wartość boolowską true lub false w zależności od obrazów.

EDIT

Scalar blah= Core.sumElems(img2); 
    Scalar blah1=Core.sumElems(img1); 

    if(blah.equals(blah1)) 
    { 
     tv.setText("same image"); 
    } 
    } 

Próbowałem to, ale stan if nigdy nie jest zadowolony. Zakładam, że jest kilka różnic, ale nie ma funkcji compare dla Scalar. Co ja robię?

EDIT

try{ 
    Scalar blah= Core.sumElems(img2); 
    Scalar blah1=Core.sumElems(img1); 
    String b=blah.toString(); 
    String b1=blah1.toString(); 
    System.out.println(b+" "+b1); 
    double comp=b.compareTo(b1); 
    tv.setText(""+comp); 
    } 

Metoda ta jest ponownie wadliwy. Chociaż można go używać do porównywania obrazów z przyzwoitą dokładnością, nie działa, gdy obrazy mają różne rozmiary.

Gdy obrazy są w różnych rozmiarach i wydrukować wartości skalarne uzyskać to:

[9768383.0, 1.0052889E7, 1.0381814E7, 0.0] [1.5897384E7, 1.6322252E7, 1.690251E7, 0.0]

Różnice pomiędzy drugim i trzecim numerów chociaż nie wiele jest dość duży w porównaniu z sytuacją, gdy obrazy same rozmiar są porównywane. Pierwsza liczba cierpi najwięcej zmian.

Jaki byłby najlepszy najszybszy sposób porównania zawartości dwóch obrazów?

[EDIT]

Używam kod znalazłem here.

Co nie jestem w stanie dowiedzieć się, jak zainicjować MatOfKeyPointkeypoints zmienne i logoKeypoints. Tu jest mój urywek kodu:

  FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF); 
     //FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST); 
     //Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGBA2RGB); 
     //Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGBA2RGB); 

     DescriptorExtractor SurfExtractor = DescriptorExtractor 
     .create(DescriptorExtractor.SURF); 


     //extract keypoints 
     MatOfKeyPoint keypoints, logoKeypoints; 
     long time= System.currentTimeMillis(); 
     detector.detect(img1, keypoints); 
     Log.d("LOG!", "number of query Keypoints= " + keypoints.size()); 
     detector.detect(img2, logoKeypoints); 
     Log.d("LOG!", "number of logo Keypoints= " + logoKeypoints.size()); 
     Log.d("LOG!", "keypoint calculation time elapsed" + (System.currentTimeMillis() -time)); 

     //Descript keypoints 
     long time2 = System.currentTimeMillis(); 
     Mat descriptors = new Mat(); 
     Mat logoDescriptors = new Mat(); 
     Log.d("LOG!", "logo type" + img2.type() + " intype" + img1.type()); 
     SurfExtractor.compute(img1, keypoints, descriptors); 
     SurfExtractor.compute(img2, logoKeypoints, logoDescriptors); 
     Log.d("LOG!", "Description time elapsed" + (System.currentTimeMillis()- time2)); 

I oczywiście nie może zainicjować zmienne keypoints i logoKeypoints NULL bo będę odbierać wyjątku null pointer wtedy. Jak mogę je zainicjować?

+0

Ten tutorial OpenCV ma nadzieję, że zawiera pewne informacje na ten temat; http://goo.gl/gwN6e. – harism

+2

try-catch jest * nie * taki sam jak gdyby-else! Jeśli został zgłoszony wyjątek (catch catch), coś poszło nie tak! – sschrass

+0

@SatelliteSD - Wiem o tym. Dlatego pytam, czy istnieje lepsza metoda. –

Odpowiedz

25

Powinieneś zrozumieć, że nie jest to proste pytanie i masz różne koncepcje, które możesz zastosować. Wskażę tylko dwa rozwiązania bez kodu źródłowego.

  1. porównanie Histogram: Można konwertować zarówno obrazów w skali szarości sprawiają, histogram w przedziale [0, ..., 255]. Każda wartość piksela zostanie policzona. Następnie użyj obu histogramów do porównania. Jeśli rozkład intensywności pikseli jest równy lub przekracza pewien próg (prawdopodobnie 90% wszystkich pikseli), można uznać te obrazy za duplikaty. ALE: To jedno z najprostszych rozwiązań i nie jest stabilne, jeśli dowolne zdjęcie ma równy rozkład.
  2. Odsetki punktowe/- Opisy: Przyjrzyj się detektorom obrazu i deskryptorów SIFT/SURF. Detektor spróbuje określić unikatowe keypoity intensywności w obrazie. Deskryptor zostanie obliczony w tej lokalizacji I (x, y). Normalny matcher z podejściem bruteforce i odległością euklidesową może dopasować te obrazy za pomocą ich deskryptorów. Jeśli obraz jest duplikatem, stawka podanych meczów powinna być bardzo wysoka. To rozwiązanie jest dobre do wdrożenia i może istnieć wystarczająca ilość samouczków dotyczących tego tematu.

Mam nadzieję, że to pomoże. Zapytaj, jeśli masz pytania.

[Update 1] C++ - poradnik: http://morf.lv/modules.php?name=tutorials&lasit=2#.UR-ewKU3vCk

Niektóre JavaCV-Ćwiczenia: http://code.google.com/p/javacv/w/list

[Update-2] tu przykład z przesiać detektora i SIFT -Deskryptor używający parametrów domyślnych. RANSAC-próg dla homografii wynosi 65, błąd przekierowania (epsilon) wynosi 10, włączona jest weryfikacja krzyżowa. Możesz spróbować policzyć dopasowane. Jeśli współczynnik Inliner-Outlier-Ratio jest zbyt wysoki, możesz zobaczyć tę parę jako duplikaty. Matching img1 and img2 using SIFT-detector and SIFT-descriptor Na przykład: Te obrazy dają 180 punktów kluczowych w IMG1 i 198 w IMG2. Dopasowane deskryptory to 163, z czego tylko 3 to wartości odstające. Daje to naprawdę dobry stosunek, który tylko może oznaczać, że te obrazy mogą być duplikatami.

[UPDATE-3] Nie rozumiem, dlaczego można zainicjować MatOfKeypoints. I've read the API i jest publiczny konstruktor. AND: Możesz użyć Mat obrazu, który chcesz analizować. To jest bardzo miłe. =)

MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage); 

dopasowywania użyć BRUTEFORCE_SL2 Descriptor-Matcher przyczyna trzeba będzie odległość euklidesowa Surf lub SIFT.

+0

Czy możesz dodać linki do samouczków? –

+0

Dodałem trochę dodatkowych materiałów. –

+0

Edytowałem moje pytanie. –

1

Użyj cv2.absDiff, aby obliczyć różnicę między obrazami i cv2.sumElems, aby uzyskać sumę różnic wszystkich pikseli.

Następnie wymyśl próg, według którego oceniasz, że dwa obrazy są podobne lub nie.

+0

Czy mógłbyś wyjaśnić? Musiałbym ustawić próg dla absDiff. To jest wadliwe. A może mógłbyś mi powiedzieć, jaka jest najbezpieczniejsza wartość progowa? –

+0

najpierw, przepraszam, że będziesz musiał użyć cv.sum, ponieważ sumelems wydaje się być tylko pytonem. Po drugie, potrzebujesz progu dla wartości zwrotnej z sumy! Można go zawinąć w metodę, która zwraca wartość true lub false w oparciu o zwracaną wartość sumy i próg. – sschrass

+0

Jaki byłby dobry próg? –

0

Można spróbować następujący kod:

Mat img1 = Highgui.imread("mnt/sdcard/IMG-20121228.jpg"); 
Mat img2 = Highgui.imread("mnt/sdcard/IMG-20121228-1.jpg"); 
Mat result = new Mat(); 

Core.compare(img1,img2,result,Core.CMP_NE); 

int val = Core.countNonZero(result); 

if(val == 0) { 
    //Duplicate Image 
} else { 
    //Different Image 
} 

Tutaj w kodzie porównanie funkcja będzie porównać dwa obrazy, a następnie, jeśli nie istnieje dis podobieństwa pomiędzy obrazami następnie następnie szczególności wartość matryca będzie 255 i wszystkie inne wartości będzie zero.Następnie można policzyć liczbę niezerowych wartości, aby określić, czy obrazy były równe. To działałoby tylko dla dokładnie tych samych obrazów.

Jeśli chcesz porównać obrazy ignorując efekty świetlne, sugeruję najpierw wygenerować obraz krawędzi (używając funkcji Canny OpenCV), a następnie porównać obrazy.

Mam nadzieję, że ta odpowiedź pomoże!

Powiązane problemy