Controllo delle immagini per somiglianza con OpenCV

OpenCV supporta il confronto di due immagini, restituendo un valore (forse una percentuale) che indica quanto queste immagini siano simili? Ad esempio il 100% verrebbe restituito se la stessa immagine fosse passata due volte, lo 0% verrebbe restituito se le immagini fossero totalmente diverse.

Ho già letto molti argomenti simili qui su StackOverflow. Ho anche fatto un po ‘di google. Purtroppo non sono riuscito a trovare una risposta soddisfacente.

    Questo è un argomento davvero enorme, con risposte da 3 righe di codice a intere riviste di ricerca.

    Descriverò le tecniche più comuni e i loro risultati.

    Confronto tra gli istogrammi

    Uno dei metodi più semplici e veloci. Proposto decenni fa come mezzo per trovare similitudini di immagini. L’idea è che una foresta avrà un sacco di verde, e un volto umano molto rosa, o qualsiasi altra cosa. Quindi, se confronti due immagini con le foreste, avrai una certa somiglianza tra gli istogrammi, perché hai molto verde in entrambi.

    Lato negativo: è troppo semplicistico. Una banana e una spiaggia avranno lo stesso aspetto, poiché entrambi sono gialli.

    Metodo OpenCV: compareHist ()

    Corrispondenza del modello

    Un buon esempio qui matchTemplate trovare una buona corrispondenza . Convoglia l’immagine di ricerca con quella in cui viene eseguita la ricerca. Solitamente viene utilizzato per trovare parti di immagini più piccole in una più grande.

    Aspetti negativi: restituisce solo buoni risultati con immagini identiche, stesse dimensioni e orientamento.
    Metodo OpenCV: matchTemplate ()

    Corrispondenza delle caratteristiche

    Considerato uno dei modi più efficaci per fare ricerca di immagini. Un certo numero di funzioni viene estratto da un’immagine, in modo da garantire che le stesse funzioni vengano nuovamente riconosciute anche se ruotate / ridimensionate / inclinate. Le funzionalità estratte in questo modo possono essere confrontate con altre serie di immagini. Un’altra immagine che ha un’alta proporzione delle caratteristiche del primo è molto probabilmente raffigurante lo stesso object / scena. Può essere usato per trovare la differenza relativa nell’angolo di ripresa tra le immagini o la quantità di sovrapposizione.

    Ci sono un certo numero di tutorial / campioni OpenCV su questo, e un bel video qui . Un intero modulo OpenCV (features2d) è dedicato ad esso.
    Aspetti negativi: potrebbe essere lento. Non è perfetto

    Se per la corrispondenza di immagini identiche (stessa dimensione / orientamento)

    // Compare two images by getting the L2 error (square-root of sum of squared error). double getSimilarity( const Mat A, const Mat B ) { if ( A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols ) { // Calculate the L2 relative error between images. double errorL2 = norm( A, B, CV_L2 ); // Convert to a reasonable scale, since L2 error is summed across all pixels of the image. double similarity = errorL2 / (double)( A.rows * A.cols ); return similarity; } else { //Images have a different size return 100000000.0; // Return a bad value } 

    fonte

    La soluzione di Sam dovrebbe essere sufficiente. Ho usato la combinazione della differenza tra l’istogramma e la corrispondenza dei modelli perché non un metodo funzionava per me il 100% delle volte. Però ho dato meno importanza al metodo dell’istogramma. Ecco come ho implementato in un semplice script python.

     import cv2 class CompareImage(object): def __init__(self, image_1_path, image_2_path): self.minimum_commutative_image_diff = 1 self.image_1_path = image_1_path self.image_2_path = image_2_path def compare_image(self): image_1 = cv2.imread(self.image_1_path, 0) image_2 = cv2.imread(self.image_2_path, 0) commutative_image_diff = self.get_image_difference(image_1, image_2) if commutative_image_diff < self.minimum_commutative_image_diff: print "Matched" return commutative_image_diff return 10000 //random failure value @staticmethod def get_image_difference(image_1, image_2): first_image_hist = cv2.calcHist([image_1], [0], None, [256], [0, 256]) second_image_hist = cv2.calcHist([image_2], [0], None, [256], [0, 256]) img_hist_diff = cv2.compareHist(first_image_hist, second_image_hist, cv2.HISTCMP_BHATTACHARYYA) img_template_probability_match = cv2.matchTemplate(first_image_hist, second_image_hist, cv2.TM_CCOEFF_NORMED)[0][0] img_template_diff = 1 - img_template_probability_match # taking only 10% of histogram diff, since it's less accurate than template method commutative_image_diff = (img_hist_diff / 10) + img_template_diff return commutative_image_diff if __name__ == '__main__': compare_image = CompareImage('image1/path', 'image2/path') image_difference = compare_image.compare_image() print image_difference 

    Un po ‘fuori tema ma utile è l’approccio numpico numpy . È robusto e veloce ma confronta solo i pixel e non gli oggetti oi dati contenuti nell’immagine (e richiede immagini della stessa dimensione e forma):

    Un approccio molto semplice e veloce per fare questo senza openCV e qualsiasi libreria per la visione del computer è di normare le matrici di immagini

     import numpy as np picture1 = np.random.rand(100,100) picture2 = np.random.rand(100,100) picture1_norm = picture1/np.sqrt(np.sum(picture1**2)) picture2_norm = picture2/np.sqrt(np.sum(picture2**2)) 

    Dopo aver definito entrambe le immagini normali (o le matrici), puoi semplicemente sumre la moltiplicazione delle immagini che desideri confrontare:

    1) Se confronti immagini simili la sum restituirà 1:

     In[1]: np.sum(picture1_norm**2) Out[1]: 1.0 

    2) Se non sono simili, otterrai un valore compreso tra 0 e 1 (una percentuale se moltiplichi per 100):

     In[2]: np.sum(picture2_norm*picture1_norm) Out[2]: 0.75389941124629822 

    Si prega di notare che se si dispone di immagini colorate è necessario farlo in tutte le 3 dimensioni o solo confrontare una versione greyscaled. Spesso devo confrontare enormi quantità di immagini con contenuti arbitrari e questo è un modo molto veloce per farlo.