2013-02-13 19 views
19

[EDIT] Ho creato un codice per il confronto delle immagini. La parte corrispondente è ancora un po 'imperfetta e mi piacerebbe un po' di assenso. Il progetto può essere trovato a - GitHub.Confronto immagini OpenCV in Android

ho questi due immagini Img1 e Img2:

enter image description hereenter image description here

Quando uso il seguente comando in 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 
} 

ottengo un valore doppio per l2_norm. Questo doppio valore varia per coppie di immagini duplicate. Ma se le immagini sono diverse, viene generata un'eccezione. È così che identifico le immagini duplicate? O c'è un metodo migliore? Ho cercato su Google estesamente e non sono riuscito a trovare una risposta davvero convincente. Vorrei il codice e la spiegazione su come confrontare due immagini e ottenere un valore booleano di true o false a seconda delle immagini.

EDIT

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

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

Ho provato questo, ma la condizione if è mai soddisfatto. Presumo che ci siano alcune differenze, ma non esiste la funzione compare per Scalar. Cosa faccio?

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

questo metodo è ancora viziata. Sebbene possa essere utilizzato per confrontare le immagini con una precisione decente, non riesce quando le immagini sono di dimensioni diverse.

Quando le immagini sono di dimensioni diverse e stampare i valori scalari ottengo questo:

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

La variazione tra il secondo e il terzo numero, anche se non molto è piuttosto grande rispetto a quando le immagini della stessa le dimensioni sono confrontate. Il primo numero subisce tuttavia il maggior numero di modifiche.

Quale sarebbe il modo migliore per confrontare i contenuti di due immagini?

[EDIT]

sto usando il codice che ho trovato here.

Quello che non riesco a capire è come inizializzare le variabili MatOfKeyPointkeypoints e logoKeypoints. Ecco il mio frammento di codice:

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

Io, ovviamente, non posso inizializzare le variabili keypoints e logoKeypoints a nulla perchè io ricevo un'eccezione di puntatore nullo allora. Come inizializzarli?

+0

Questo tutorial di OpenCV fornisce alcune informazioni sull'argomento; http://goo.gl/gwN6e. – harism

+2

try-catch è * non * lo stesso di if-else! Se è stata lanciata un'eccezione (blocco catch), qualcosa è andato completamente storto! – sschrass

+0

@SatelliteSD - Lo so. Ecco perché sto chiedendo se c'è un metodo migliore. –

risposta

25

Si dovrebbe capire che questo non è un semplice domanda e si dispone di diversi concetti si potrebbe seguire. Indicherò solo due soluzioni senza codice sorgente.

  1. comparatore Istogramma: Si può convertire sia immagini in scala di grigi effettuare un istogramma nell'intervallo [0, ..., 255]. Ogni valore di pixel verrà conteggiato. Quindi utilizzare entrambi gli istogrammi per il confronto. Se la distribuzione dei pixel-intensità è pari o superiore certa soglia (forse il 90% di tutti i pixel), si potrebbe prendere in considerazione queste immagini come duplicati. MA: Questa è una delle soluzioni più semplici e non è stabile se un'immagine ha una distribuzione uguale.
  2. Rivelatori di punti di interesse/-Discript: Dai un'occhiata ai rilevatori di immagine SIFT/SURF e ai descrittori. Un rilevatore cercherà di determinare le singole keypoits delle intensità in un'immagine. Un descrittore verrà calcolato in questa posizione I (x, y). Un matcher normale con una distanza bruteforce approccio e euclidea può abbinare queste immagini usando i loro descrittori. Se un'immagine è un duplicato, la velocità delle corrispondenze date dovrebbe essere molto alta. Questa soluzione è buona da implementare e potrebbero esserci abbastanza tutorial su questo argomento.

io spero che questo aiuta. Si prega di chiedere se avete domande.

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

Alcuni JavaCV-tutorial: http://code.google.com/p/javacv/w/list

[UPDATE-2] Ecco un esempio con SIFT-Detector e SIFT -Descrittore utilizzando i parametri predefiniti. La soglia RANSAC per l'omografia è 65, l'errore di riproiezione (epsilon) è 10, la convalida incrociata è abilitata. Potresti provare a contare gli abbinati. Se il rapporto Inliner-Outlier è troppo alto potresti vedere questa coppia come duplicata. Matching img1 and img2 using SIFT-detector and SIFT-descriptor Ad esempio: queste immagini producono 180 punti chiave in IMG1 e 198 in IMG2. I descrittori associati sono 163 di cui solo 3 sono valori anomali. Quindi questo offre un rapporto veramente buono che potrebbe significare solo che queste immagini potrebbero essere duplicate.

[UPDATE-3] Non capisco il motivo per cui è possibile inizializzare le MatOfKeypoints. I've read the API e c'è un costruttore pubblico. AND: puoi usare il Mat dell'immagine che vuoi analizzare. Questo è molto carino. =)

MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage); 

per la corrispondenza di utilizzare un BRUTEFORCE_SL2 Descriptor-Matcher causa è necessario la distanza euclidea per il surf o SIFT.

+0

Potresti aggiungere link ai tutorial, per favore? –

+0

Ho aggiunto del materiale aggiuntivo. –

+0

Ho modificato la mia domanda. –

1

Utilizzare cv2.absDiff per calcolare la differenza tra le immagini e cv2.sumElems per ottenere la somma di tutte le differenze di pixel.

Poi inventare una soglia con cui si giudica wether due immagini sono simili o meno.

+0

Puoi chiarire? Dovrei impostare una soglia per absDiff. Quindi, è difettoso. O forse potresti dirmi qual è il valore di soglia più sicuro? –

+0

per prima cosa, mi dispiace che dovrai usare cv.sum dato che sumelems sembra essere solo python. Secondo, hai bisogno della soglia per il valore di ritorno dalla somma! È possibile racchiuderlo in un metodo che restituisce true o false in base al valore restituito della somma e della soglia. – sschrass

+0

Quale sarebbe una buona soglia? –

0

È possibile provare il codice seguente:

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 
} 

Qui nel codice confronta funzione confrontare due immagini e poi se c'è dis similarità tra immagini quindi quindi particolare valore matrice sarà 255 e tutti gli altri valori sarà zero.Quindi puoi contare il numero di valori diversi da zero per determinare se le immagini fossero uguali. Funzionerebbe solo per le stesse immagini esattamente.

Se si desidera confrontare le immagini ignorando gli effetti di luce, suggerisco di generare prima l'immagine del bordo (utilizzando la funzione canny di OpenCV) e quindi confrontare le immagini.

Spero che questa risposta ti aiuti !!

Problemi correlati