Come posso valutare quanto sono simili due immagini con OpenCV?


141

OpenCV supporta il confronto di due immagini, restituendo un valore (forse una percentuale) che indica quanto sono simili queste immagini? 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 abbastanza googling. Purtroppo non sono riuscito a trovare una risposta soddisfacente.


Risposte:


208

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

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

Confronto di istogrammi

Uno dei metodi più semplici e veloci. Proposto decenni fa come mezzo per trovare similitudini di immagine. L'idea è che una foresta avrà molto verde e un viso umano molto rosa, o altro. Quindi, se confronti due immagini con le foreste, otterrai una certa similitudine tra gli istogrammi, perché hai molto verde in entrambe.

Unico inconveniente: è troppo semplicistico. Una banana e una spiaggia appariranno uguali, poiché entrambe sono gialle.

Metodo OpenCV: compareHist ()

Corrispondenza del modello

Un buon esempio qui matchTemplate che trova una buona corrispondenza . Convolge l'immagine di ricerca con quella in cui cercare. Di solito viene utilizzato per trovare parti di immagini più piccole in una più grande.

Lati negativi: restituisce solo buoni risultati con immagini identiche, stesse dimensioni e orientamento.

Metodo OpenCV: matchTemplate ()

Corrispondenza delle caratteristiche

Considerato uno dei modi più efficienti per eseguire la ricerca di immagini. Numerose funzioni vengono estratte da un'immagine, in modo da garantire che le stesse funzioni vengano riconosciute di nuovo anche quando ruotate, ridimensionate o inclinate. Le funzioni estratte in questo modo possono essere confrontate con altri set di funzioni immagine. Un'altra immagine che presenta un'alta percentuale delle caratteristiche corrispondenti alla prima è considerata raffigurante la stessa scena.

Trovare l'omografia tra le due serie di punti ti permetterà anche di trovare la differenza relativa nell'angolo di ripresa tra le immagini originali o la quantità di sovrapposizioni.

Ci sono un certo numero di tutorial / esempi OpenCV su questo e un bel video qui . Un intero modulo OpenCV (features2d) è dedicato ad esso.

Lati negativi: potrebbe essere lento. Non è perfetto


Sul sito di domande e risposte di OpenCV sto parlando della differenza tra descrittori di caratteristiche, che sono grandi quando si confrontano immagini intere e descrittori di trama, che vengono utilizzati per identificare oggetti come volti umani o automobili in un'immagine.


per confrontare immagini simili che hanno solo alcune immagini distinte (ad esempio un nuovo oggetto spostato nella stessa vista altrimenti) puoi anche lavorare con absdiff codota.com/code/java/methods/org.opencv.core.Core/absdiff Soglia del risultato produce una maschera che consente di evidenziare le regioni che sono cambiate da una scena all'altra.
Max F.

34

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


12

La soluzione di Sam dovrebbe essere sufficiente. Ho usato la combinazione della differenza di istogramma e la corrispondenza del modello perché non un metodo funzionava per me il 100% delle volte. Tuttavia, 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

Non capisco bene Python. Ma che cos'è il tipo 'commutative_image_diff'? cv.Mat o double. Se è cv.Mat, confronta 'commutative_image_diff <self.minimum_commutative_image_diff' come funziona o qual è lo scopo di questo confronto. Puoi spiegarmi per me?
BulletRain

1

Un po 'fuori tema ma utile è l' numpyapproccio pitonico . È robusto e veloce, ma confronta solo i pixel e non gli oggetti o i dati contenuti nell'immagine (e richiede immagini della stessa dimensione e forma):

Un approccio molto semplice e veloce per farlo senza openCV e nessuna libreria per la visione artificiale è quello di standardizzare 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 (o matrici) normali, puoi semplicemente sommare la moltiplicazione delle immagini che desideri confrontare:

1) Se confronti immagini simili la somma 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 e 3 le dimensioni o semplicemente confrontare una versione in grigio. Spesso devo confrontare enormi quantità di immagini con contenuti arbitrari e questo è un modo molto veloce per farlo.


2
ciao, ho appena seguito il tuo passaggio ma ho scoperto che la parte normalizzata non ha potuto ottenere il risultato corretto. Il risultato finale è molto maggiore di 1,0. Qualche idea?
G_cy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.