2013-02-13 13 views
19

[EDIT] Ich habe einige Code für den Bildvergleich entwickelt. Der passende Teil ist immer noch ein bisschen fehlerhaft und ich würde etwas Hilfe mögen. Das Projekt finden Sie unter - GitHub.OpenCV Bildvergleich in Android

Ich habe diese beiden Bilder Img1 und Img2:

enter image description hereenter image description here

Wenn ich den folgenden Befehl in OpenCV verwenden

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 
} 

ich einen doppelten Wert für l2_norm bekommen. Dieser doppelte Wert variiert für doppelte Bildpaare. Wenn die Bilder jedoch unterschiedlich sind, wird eine Ausnahme ausgelöst. Identifiziere ich so doppelte Bilder? Oder gibt es eine bessere Methode? Ich habe ausgiebig gegoogelt und konnte keine wirklich überzeugende Antwort finden. Ich möchte den Code und die Erklärung, wie ich zwei Bilder vergleichen würde und einen booleschen Wert von true oder false abhängig von den Bildern erhalten.

EDIT

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

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

Ich habe dies versucht, aber die if Zustand ist nie zufrieden. Ich nehme an, es gibt ein paar Unterschiede, aber es gibt keine compare Funktion für Scalar. Was mache ich?

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); 
    } 

Diese Methode fehlerhaft ist wieder. Obwohl es verwendet werden kann, um Bilder mit einer angemessenen Genauigkeit zu vergleichen, schlägt es fehl, wenn Bilder von unterschiedlicher Größe sind.

Wenn Bilder in verschiedenen Größen sind und ich drucke die skalare Werte ich dieses:

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

Die Variation zwischen der zweiten und dritten Zahlen, obwohl nicht viel ist recht groß im Vergleich zu, wenn die Bilder der gleichen Größe wird verglichen. Die erste Nummer leidet jedoch am meisten.

Was wäre der schnellste Weg, um den Inhalt von zwei Bildern zu vergleichen?

[EDIT]

Ich verwende den Code, den ich here gefunden.

Was ich nicht herausfinden kann, ist, wie die MatOfKeyPoint Variablen keypoints und logoKeypoints initialisiert werden. Hier ist mein Code-Schnipsel:

  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)); 

Ich kann natürlich nicht die Variablen initialisieren keypoints und logoKeypoints auf null Cuz ich dann eine Null-Zeiger Ausnahme erhalten werden. Wie initialisiere ich sie?

+0

Dieses OpenCV-Tutorial bietet hoffentlich einige Informationen zum Thema; http://goo.gl/gwN6e. – harism

+2

try-catch ist * nicht * das selbe wie wenn-sonst! Wenn eine Ausnahme ausgelöst wurde (Catch-Block), ist etwas völlig falsch gelaufen! – sschrass

+0

@SatelliteSD - das weiß ich. Deshalb frage ich, ob es eine bessere Methode gibt. –

Antwort

25

Sie sollten verstehen, dass dies keine einfache Frage ist und Sie unterschiedliche Konzepte verfolgen können. Ich werde nur auf zwei Lösungen ohne Quellcode hinweisen.

  1. Histogramm Vergleich: Sie könnten beiden Bilder in Graustufen umwandeln machen ein Histogramm im Bereich von [0, ..., 255]. Jeder Pixelwert wird gezählt. Dann verwenden Sie beide Histogramme zum Vergleich. Wenn die Verteilung der Pixelintensitäten gleich oder größer als ein Schwellenwert ist (möglicherweise 90% aller Pixel), könnten Sie diese Bilder als Duplikate betrachten. ABER: Dies ist eine der einfachsten Lösungen und ist nicht stabil, wenn ein Bild gleich verteilt ist.
  2. Interest-Point-Detektoren/-Deskriptoren: Schauen Sie sich SIFT/SURF Bilddetektoren und Deskriptoren an. Ein Detektor versucht, eindeutige Keypoits von Intensitäten in einem Bild zu bestimmen. Ein Deskriptor wird an dieser Stelle I (x, y) berechnet. Ein normaler Matcher mit Bruteforce-Ansatz und euklidischer Distanz kann diese Bilder mit ihren Deskriptoren vergleichen. Wenn ein Bild ein Duplikat ist, sollte die Rate der gegebenen Übereinstimmungen sehr hoch sein. Diese Lösung ist gut zu implementieren und es könnte genug Tutorials zu diesem Thema geben.

Ich hoffe, das hilft. Bitte fragen Sie, wenn Sie Fragen haben.

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

Einige JavaCV-Tutorials: http://code.google.com/p/javacv/w/list

[UPDATE-2] Hier ein Beispiel mit SIFT-Detektor ist und SIFT -Descriptor mit Standard-Parameter. RANSAC-Schwellenwert für Homographie ist 65, Reprojektionsfehler (Epsilon) ist 10, Kreuzvalidierung aktiviert. Sie könnten versuchen, die Übereinstimmung zu zählen. Wenn das Inliner-Outlier-Verhältnis zu hoch ist, könnten Sie dieses Paar als Duplikate sehen. Matching img1 and img2 using SIFT-detector and SIFT-descriptor Zum Beispiel: Diese Bilder erzeugen 180 Schlüsselpunkte in IMG1 und 198 in IMG2. Die übereinstimmenden Deskriptoren sind 163, von denen nur 3 Ausreißer sind. Das ergibt ein wirklich gutes Verhältnis, was nur bedeuten könnte, dass diese Bilder Duplikate wären.

[UPDATE-3] Ich verstehe nicht, warum Sie die MatOfKeepoints initialisieren können. I've read the API und es gibt einen öffentlichen Konstruktor. UND: Sie können die Matte des Bildes verwenden, das Sie analysieren möchten. Das ist sehr nett. =)

MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage); 

Für eine BRUTEFORCE_SL2 Descriptor-Matcher Passende verwenden führen, dass Sie die euklidische Distanz für SURF oder SIFT müssen.

+0

Könnten Sie bitte Links zu Tutorials hinzufügen? –

+0

Ich habe etwas zusätzliches Material hinzugefügt. –

+0

Ich habe meine Frage bearbeitet. –

1

Verwenden Sie cv2.absDiff, um den Unterschied zwischen den Bildern zu berechnen, und cv2.sumElems, um die Summe aller Pixelunterschiede zu erhalten.

Dann erfinden Sie eine Schwelle, mit der Sie beurteilen, ob zwei Bilder ähnlich sind oder nicht.

+0

Könnten Sie aufklären? Ich müsste eine Schwelle für absDiff setzen. Also, das ist fehlerhaft. Oder könnten Sie mir vielleicht sagen, was der sicherste Schwellenwert ist? –

+0

zuerst, tut mir leid, dass Sie cv.sum verwenden müssen, da sumelems nur Python zu sein scheint. Zweitens brauchen Sie die Schwelle für den Rückgabewert aus der Summe! Sie könnten es in eine Methode einbetten, die basierend auf dem Rückgabewert von sum und Ihrem Schwellenwert true oder false zurückgibt. – sschrass

+0

Was wäre eine gute Schwelle? –

0

können Sie versuchen, den folgenden Code:

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 
} 

Hier im Code vergleichen Funktion zwei Bilder vergleichen und dann, wenn es dis Ähnlichkeit zwischen den Bildern gibt es dann dann bestimmten Matrixwert 255 und alle anderen Werte wird Null sein.Dann können Sie die Anzahl der von Null verschiedenen Werte zählen, um festzustellen, ob die Bilder gleich waren. Dies funktioniert nur für genau die gleichen Bilder.

Wenn Sie Bilder vergleichen wollen, die die Lichteffekte ignorieren, empfehle ich Ihnen, das Kantenbild zuerst zu erzeugen (Using cannyy Funktion von OpenCV) und dann die Bilder zu vergleichen.

Hoffe, diese Antwort hilft Ihnen !!