2010-11-16 17 views
150

Ho bisogno di un modo semplice e veloce per confrontare due immagini per similarità. Cioè Voglio ottenere un valore elevato se contengono esattamente la stessa cosa ma potrebbero avere uno sfondo leggermente diverso e potrebbero essere spostati/ridimensionati di alcuni pixel.Metodo semplice e veloce per confrontare le immagini per similarità

(più concreto, se quello che conta: Quella immagine è un'icona e l'altra immagine è una sottozona di uno screenshot e voglio sapere se quella sottozona è esattamente l'icona oppure no.)

ho OpenCV a portata di mano ma non sono ancora così abituato.

Una possibilità ho pensato finora: dividere entrambe le immagini in 10x10 celle e per ciascuna di quelle 100 celle, confrontare l'istogramma di colore. Quindi posso impostare un valore soglia composto e se il valore che ottengo è superiore a tale soglia, presumo che siano simili.

Non ho ancora provato quanto bene funzioni, ma immagino che sarebbe abbastanza buono. Le immagini sono già molto simili (nel mio caso d'uso), quindi posso usare un valore di soglia piuttosto alto.

Immagino che ci siano dozzine di altre possibili soluzioni per questo che funzionerebbero più o meno (dato che il compito in sé è piuttosto semplice in quanto voglio solo rilevare la somiglianza se sono davvero molto simili). Che cosa suggeriresti?


Ci sono alcuni molto legati/domande simili su come ottenere una firma/impronta digitale/hash da un'immagine:

Inoltre, sono incappato in queste implementazioni che hanno tali funzioni avere un'impronta digitale:

Alcune discussioni su hash immagine percettivi: here


Un po 'offtopic: Esiste molti metodi per creare impronte digitali audio. MusicBrainz, un servizio Web che fornisce la ricerca basata sulle impronte digitali per le canzoni, ha un good overview in their wiki.Stanno usando AcoustID adesso. Questo è per trovare corrispondenze esatte (o per lo più esatte). Per trovare corrispondenze simili (o se hai solo alcuni frammenti o rumore elevato), dai uno sguardo allo Echoprint. Una domanda SO correlata è here. Quindi sembra che questo sia risolto per l'audio. Tutte queste soluzioni funzionano abbastanza bene.

Una domanda un po 'più generica sulla ricerca fuzzy in generale è here. Per esempio. c'è locality-sensitive hashing e nearest neighbor search.

+1

Forse l'impronta digitale delle immagini potrebbe essere d'aiuto? http: // StackOverflow.it/questions/596262/image-fingerprint-to-compare-similarity-of-many-images – GWW

+0

La metrica di Wasserstein, conosciuta anche come Earth Mover's Distance (EMD), è qualcosa che la gente sembra non sapere, ma darebbe più o meno quello che vuoi qui. – mmgp

+2

possibile duplicato di [confronto immagine - algoritmo veloce] (http://stackoverflow.com/questions/843972/image-comparison-fast-algorithm) – sashoalm

risposta

86

Lo screenshot o l'icona può essere trasformata (ridimensionata, ruotata, inclinata ...)? Ci sono alcuni metodi in cima alla mia testa che si potrebbe aiutare:

  • semplice distanza euclidea come detto da @carlosdc (non funziona con immagini trasformate ed hai bisogno di una soglia).
  • (Normalized) Cross Correlation - una metrica semplice che è possibile utilizzare per confrontare le aree dell'immagine. È più robusto della semplice distanza euclidea, ma non funziona con le immagini trasformate e avrai di nuovo bisogno di una soglia.
  • Confronto istogramma - se si utilizzano gli istogrammi normalizzati, questo metodo funziona bene e non è influenzato dalle trasformazioni affini. Il problema è determinare la soglia corretta. È anche molto sensibile ai cambiamenti di colore (luminosità, contrasto ecc.). Puoi combinarlo con i due precedenti.
  • Rivelatori di punti/aree salienti - come MSER (Maximally Stable Extremal Regions), SURF o SIFT. Questi sono algoritmi molto robusti e potrebbero essere troppo complicati per il tuo compito semplice. La cosa buona è che non devi avere un'area esatta con una sola icona, questi rilevatori sono abbastanza potenti da trovare la corrispondenza giusta. Una buona valutazione di questi metodi è in questo documento: Local invariant feature detectors: a survey.

La maggior parte di questi sono già implementati in OpenCV - si veda ad esempio il metodo cvMatchTemplate (utilizza la corrispondenza dell'istogramma): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html. Sono disponibili anche i rilevatori di punti/aree salienti - vedere OpenCV Feature Detection.

+1

Può essere ridimensionato o spostato leggermente. Anche lo sfondo dell'icona sarà diverso. Ho provato il confronto con l'istogramma, ma ho ricevuto molti falsi positivi. Ho anche provato la distanza euclidea ma anche troppi falsi positivi (ma forse riesco a migliorare un po 'la gestione del valore alfa nell'icona). Ci proverò un po 'oltre, altrimenti controllerò MSER, SURF o SIFT. – Albert

+0

Un'altra idea: non funzionerebbe se si fosse utilizzato il confronto istogramma delle immagini dopo l'applicazione di un operatore sobel? Ciò comparerebbe solo la somiglianza dei bordi. Potrebbe o potrebbe non funzionare, a seconda di quanto sia "tagliente" lo sfondo. –

8

Lo screenshot contiene solo l'icona? In tal caso, la distanza L2 delle due immagini potrebbe essere sufficiente. Se la distanza L2 non funziona, il passo successivo è provare qualcosa di semplice e ben definito, come ad esempio: Lucas-Kanade. Che sono sicuro è disponibile in OpenCV.

+0

La sottoarea contiene esattamente solo l'icona (con qualche sfondo casuale) o qualcosa di diverso. Voglio vedere quale caso è. Però, potrebbe essere leggermente spostato o ridimensionato, ecco perché non ero sicuro di poter solo vedere la distanza (in qualsiasi condizione). Ma proverò con una versione ridotta. – Albert

3

Se si è certi di avere un preciso allineamento del modello (l'icona) nell'area di test, allora qualsiasi vecchia somma di differenze di pixel funzionerà.

Se l'allineamento sarà solo un po 'spento, è possibile passare in basso entrambe le immagini con cv::GaussianBlur prima di trovare la somma delle differenze di pixel.

Se la qualità del allineamento è potenzialmente povera poi consiglio o un Histogram of Oriented Gradients o uno dei punti chiave convenienti algoritmi di rilevamento/descrittori di OpenCV (come SIFT o SURF).

2

Se si desidera confrontare l'immagine per somiglianza, suggerisco di utilizzare OpenCV. In OpenCV, ci sono alcune funzionalità di corrispondenza e corrispondenza dei modelli. Per la corrispondenza delle funzioni, esistono rilevatori SURF, SIFT, FAST e così via. È possibile utilizzare questo per rilevare, descrivere e quindi abbinare l'immagine. Successivamente, è possibile utilizzare l'indice specifico per trovare il numero di corrispondenza tra le due immagini.

+0

hai detto "Dopo, puoi usare l'indice specifico per trovare il numero di corrispondenza tra le due immagini." quale può essere il numero minimo di corrispondenze tra le due immagini per dire che "contengono" lo stesso oggetto? –

4

Se si desidera ottenere un indice sulla somiglianza delle due immagini, suggerisco dalle metriche l'indice SSIM. È più coerente con l'occhio umano. Ecco un articolo su di esso: Structural Similarity Index

Si è implementato in OpenCV troppo, e può essere accelerato con GPU: OpenCV SSIM with GPU

3

Se per corrispondenza immagini identiche - code L2 distanza

// 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 
} 

veloce . Ma non è robusto per cambiamenti di illuminazione/punto di vista ecc Source

26

affronto gli stessi problemi di recente, per risolvere questo problema (semplice e veloce algoritmo per confrontare due immagini) una volta per tutte, contribuisco un img_hash module a opencv_contrib, potete trovare i dettagli da this link.

Il modulo img_hash fornisce sei algoritmi di hash di immagine, abbastanza facili da usare.

Codici esempio

origin lena origine lena

blur lena sfocatura lena

resize lena ridimensionamento lena

shift lena spostamento lena

#include <opencv2/core.hpp> 
#include <opencv2/core/ocl.hpp> 
#include <opencv2/highgui.hpp> 
#include <opencv2/img_hash.hpp> 
#include <opencv2/imgproc.hpp> 

#include <iostream> 

void compute(cv::Ptr<cv::img_hash::ImgHashBase> algo) 
{ 
    auto input = cv::imread("lena.png"); 
    cv::Mat similar_img; 

    //detect similiar image after blur attack 
    cv::GaussianBlur(input, similar_img, {7,7}, 2, 2); 
    cv::imwrite("lena_blur.png", similar_img); 
    cv::Mat hash_input, hash_similar; 
    algo->compute(input, hash_input); 
    algo->compute(similar_img, hash_similar); 
    std::cout<<"gaussian blur attack : "<< 
       algo->compare(hash_input, hash_similar)<<std::endl; 

    //detect similar image after shift attack 
    similar_img.setTo(0); 
    input(cv::Rect(0,10, input.cols,input.rows-10)). 
      copyTo(similar_img(cv::Rect(0,0,input.cols,input.rows-10))); 
    cv::imwrite("lena_shift.png", similar_img); 
    algo->compute(similar_img, hash_similar); 
    std::cout<<"shift attack : "<< 
       algo->compare(hash_input, hash_similar)<<std::endl; 

    //detect similar image after resize 
    cv::resize(input, similar_img, {120, 40}); 
    cv::imwrite("lena_resize.png", similar_img); 
    algo->compute(similar_img, hash_similar); 
    std::cout<<"resize attack : "<< 
       algo->compare(hash_input, hash_similar)<<std::endl; 
} 

int main() 
{ 
    using namespace cv::img_hash; 

    //disable opencl acceleration may(or may not) boost up speed of img_hash 
    cv::ocl::setUseOpenCL(false); 

    //if the value after compare <= 8, that means the images 
    //very similar to each other 
    compute(ColorMomentHash::create()); 

    //there are other algorithms you can try out 
    //every algorithms have their pros and cons 
    compute(AverageHash::create()); 
    compute(PHash::create()); 
    compute(MarrHildrethHash::create()); 
    compute(RadialVarianceHash::create()); 
    //BlockMeanHash support mode 0 and mode 1, they associate to 
    //mode 1 and mode 2 of PHash library 
    compute(BlockMeanHash::create(0)); 
    compute(BlockMeanHash::create(1)); 
} 

In questo caso, ColorMomentHash darci miglior risultato

  • gaussiana attacco mosso: 0,567521
  • attacco del cambio: 0,229728
  • attacco di ridimensionamento: 0.229358

Pro e contro di ogni algoritmo

Performance under different attacks

Le prestazioni di img_hash è troppo buono

confronto velocità con biblioteca phash (100 immagini da ukbench) compute performance comparison performance

Se volete sapere il consiglio soglie di questi algoritmi, si prega di controllare questo post (http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html). Se sei interessato a come misurare le prestazioni dei moduli img_hash (includi velocità e attacchi diversi), controlla questo link (http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of-opencvimghash.html).

+2

Grazie per l'ottima risposta. Potresti dirci la fonte del confronto della velocità? – ocolot

+2

@ocolot Ovviamente, faccio in modo che il link in questo post sia più ovvio, basta fare clic su di essi e troverai la tua risposta. Sto sviluppando un'app basata su questo modulo, in futuro supporterò anche l'impronta video – StereoMatching

Problemi correlati