Metodo semplice e veloce per confrontare le immagini per similarità

Ho bisogno di un modo semplice e veloce per confrontare due immagini per similarità. Vale a dire, 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.

(Più concreto, se è importante: l’unica immagine è un’icona e l’altra è una sottozona di uno screenshot e voglio sapere se quella sottozona è esattamente l’icona o no.)

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

Una possibilità a cui ho pensato fino ad ora: dividere entrambe le immagini in 10×10 celle e per ognuna 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 come funziona bene, 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é è abbastanza semplice perché voglio solo rilevare la somiglianza se sono davvero molto simili). Che cosa suggeriresti?


Ci sono alcune domande molto correlate / simili su come ottenere una firma / impronta digitale / hash da un’immagine:

  • OpenCV / SURF Come generare un hash di immagine / impronta digitale / firma fuori dai descrittori?
  • Impronta digitale dell’immagine per confrontare la somiglianza di molte immagini
  • Rilevamento dell’immagine quasi duplicato
  • OpenCV: immagine dell’impronta digitale e confronto con il database .
  • di più , di più , di più , di più , di più , di più , di più

Inoltre, mi sono imbattuto in queste implementazioni che hanno tali funzioni per ottenere un’impronta digitale:

  • phash
  • imgSeek ( GitHub repo ) (GPL) basato sulla ricerca rapida di immagini multirisoluzione su carta
  • immagine-partita . Molto simile a quello che stavo cercando. Simile al pHash, basato sulla firma di un’immagine per qualsiasi tipo di immagine, Goldberg et al . Utilizza Python ed Elasticsearch.
  • iqdb
  • ImageHash . supporta pHash.

Alcune discussioni sugli hash dell’immagine percettiva: qui


Un po ‘fuori moda: esistono molti metodi per creare impronte digitali audio. MusicBrainz , un servizio web che fornisce la ricerca basata sulle impronte digitali per le canzoni, ha una buona panoramica nella loro wiki . Stanno usando AcoustID ora. Questo è per trovare corrispondenze esatte (o per lo più esatte). Per trovare corrispondenze simili (o se hai solo alcuni frammenti o rumore elevato), dai un’occhiata a Echoprint . Una domanda SO correlata è qui . 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 è qui . Es. C’è un hashing sensibile alla località e una ricerca del vicino più vicino .

Lo screenshot o l’icona può essere trasformata (ridimensionata, ruotata, inclinata …)? Ci sono parecchi metodi in cima alla mia testa che potrebbero aiutarti

  • Semplice distanza euclidea come menzionato da @carlosdc (non funziona con le immagini trasformate e hai bisogno di una soglia).
  • Correlazione incrociata (normalizzata) : una metrica semplice che è ansible 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 (massima regione estremamente stabile) , 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: rilevatori di funzionalità invarianti locali: un sondaggio .

Molti 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 inoltre disponibili i rilevatori di punti / aree salienti: vedere Rilevamento di feature OpenCV .

Affronto gli stessi problemi recentemente, per risolvere questo problema (algoritmo semplice e veloce per confrontare due immagini) una volta per tutte, contribuisco con un modulo img_hash a opencv_contrib, puoi trovare i dettagli da questo link .

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

Esempio di codici

origine lena origine lena

sfocatura lena sfocatura lena

ridimensiona lena ridimensiona lena

spostare lena spostare lena

#include  #include  #include  #include  #include  #include  void compute(cv::Ptr 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)<compute(similar_img, hash_similar); std::cout<<"shift attack : "<< algo->compare(hash_input, hash_similar)<compute(similar_img, hash_similar); std::cout<<"resize attack : "<< algo->compare(hash_input, hash_similar)< 

In questo caso, ColorMomentHash ci dà il miglior risultato

  • attacco sfocatura gaussiana: 0,567521
  • attacco a turni: 0,229728
  • attacco di ridimensionamento: 0,229358

Pro e contro di ogni algoritmo

Prestazioni sotto diversi attacchi

Anche le prestazioni di img_hash sono buone

Confronto di velocità con la libreria PHash (100 immagini da ukbench) calcolo delle prestazioni prestazioni di confronto

Se vuoi conoscere le soglie consigliate per questi algoritmi, controlla questo post ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Se sei interessante su come misuro 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 ).

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: Lucas-Kanade . Che sono sicuro è disponibile in OpenCV.

Se puoi essere sicuro di avere un preciso allineamento del tuo modello (l’icona) alla regione di test, allora qualsiasi vecchia sum di differenze di pixel funzionerà.

Se l’allineamento sarà solo un pochino distriggersto, puoi passare in basso entrambe le immagini con cv :: GaussianBlur prima di trovare la sum delle differenze di pixel.

Se la qualità dell’allineamento è potenzialmente scarsa, consiglierei un istogramma di gradienti orientati o uno dei comodi algoritmi di rilevamento / descrittore di punti chiave di OpenCV (come SIFT o SURF ).

Se vuoi ottenere un indice sulla somiglianza delle due immagini, ti suggerisco dalle metriche dell’indice SSIM. È più coerente con l’occhio umano. Ecco un articolo al riguardo: Indice di similarità strutturale

È implementato anche in OpenCV e può essere accelerato con GPU: OpenCV SSIM con GPU

Se per la corrispondenza di immagini identiche – codice per 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 ai cambiamenti di illuminazione / punto di vista, ecc. Fonte

Se vuoi confrontare l’immagine per somiglianza, ti suggerisco di usare 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. È ansible utilizzare questo per rilevare, descrivere e quindi abbinare l’immagine. Successivamente, è ansible utilizzare l’indice specifico per trovare il numero di corrispondenza tra le due immagini.