Benzerlik için görüntüleri karşılaştırmak için basit ve hızlı yöntem


192

Benzerlik için iki görüntüyü karşılaştırmanın basit ve hızlı bir yoluna ihtiyacım var. Yani tam olarak aynı şeyi içeriyorlarsa ancak biraz farklı bir arka plana sahip olabilirler ve birkaç piksel tarafından taşınabilir / yeniden boyutlandırılabilirlerse yüksek bir değer elde etmek istiyorum.

(Önemli olursa, daha somut: Bir resim bir simge ve diğer resim bir ekran görüntüsünün alt alanıdır ve bu alt alanın tam olarak simge olup olmadığını bilmek istiyorum.)

Elimde OpenCV var ama hala buna alışkın değilim.

Şimdiye kadar düşündüğüm bir olasılık: Her iki resmi de 10x10 hücreye bölün ve bu 100 hücrenin her biri için renk histogramını karşılaştırın. Sonra bir miktar uydurma eşik değeri ayarlayabilirim ve elde ettiğim değer bu eşiğin üzerindeyse, benzer olduklarını varsayıyorum.

Henüz ne kadar iyi çalıştığını henüz denemedim ama sanırım yeterince iyi olurdu. Görüntüler zaten oldukça benzer (benim kullanım durumumda), bu yüzden oldukça yüksek bir eşik değeri kullanabilirim.

Sanırım bunun için az ya da çok işe yarayacak düzinelerce başka çözüm var (görevin kendisi oldukça basit olduğu için, benzerliklerini gerçekten çok benziyorlarsa tespit etmek istiyorum). Ne öneriyorsun?


Bir görüntüden imza / parmak izi / karma elde etme ile ilgili birkaç ilgili / benzer soru var:

Ayrıca, bir parmak izi elde etmek için bu gibi işlevlere sahip olan bu uygulamalara tökezledim:

Algısal görüntü karmaları hakkında bazı tartışmalar: burada


Biraz offtopik: Ses parmak izleri oluşturmak için birçok yöntem var. Şarkılar için parmak izi tabanlı arama sağlayan bir web hizmeti olan MusicBrainz , wiki'lerinde iyi bir genel bakışa sahiptir . Şimdi AcoustID kullanıyorlar . Bu kesin (veya çoğunlukla kesin) eşleşmeleri bulmak içindir. Benzer eşleşmeleri bulmak için (veya yalnızca bazı snippet'leriniz veya yüksek gürültünüz varsa) Echoprint'e göz atın . İlgili bir SO sorusu burada . Yani ses için çözülmüş gibi görünüyor. Tüm bu çözümler oldukça iyi çalışıyor.

Genel olarak bulanık arama hakkında biraz daha genel bir soru burada . Yöreye duyarlı karma ve en yakın komşu arama var .


1
Belki resim parmak izi yardımcı olabilir? stackoverflow.com/questions/596262/…
GWW

Wasserstein metriği, aynı zamanda Earth Mover'ın Mesafesi (EMD) olarak da bilinir, insanların bilmedikleri bir şeydir, ancak burada istediğinizi hemen hemen verir.
mmgp

3
olası görüntü
sashoalm

Merhaba, dHash'i geliştirdim - IDHash olarak adlandırdım: github.com/Nakilon/dhash-vips
Nakilon

Yanıtlar:


107

Ekran görüntüsü veya simge dönüştürülebilir mi (ölçeklendirilebilir, döndürülebilir, eğrilebilir ...)? Başımın üstünde size yardımcı olabilecek birkaç yöntem var:

  • @Carlosdc tarafından belirtildiği gibi basit öklid mesafesi (dönüştürülmüş görüntülerle çalışmaz ve bir eşik değerine ihtiyacınız vardır).
  • (Normalleştirilmiş) Çapraz Korelasyon - görüntü alanlarını karşılaştırmak için kullanabileceğiniz basit bir metriktir. Basit öklid mesafesinden daha sağlamdır, ancak dönüştürülmüş görüntüler üzerinde çalışmaz ve tekrar eşik gerekir.
  • Histogram karşılaştırması - normalleştirilmiş histogramlar kullanıyorsanız, bu yöntem iyi çalışır ve afin dönüşümlerden etkilenmez. Sorun doğru eşiği belirlemektir. Ayrıca renk değişikliklerine (parlaklık, kontrast vb.) Çok duyarlıdır. Önceki iki ile birleştirebilirsiniz.
  • Göze çarpan noktaların / alanların dedektörleri - MSER (Maksimal Kararlı Ekstrem Bölgeler) , SURF veya SIFT gibi . Bunlar çok sağlam algoritmalardır ve basit göreviniz için çok karmaşık olabilirler. İyi bir şey, tek bir simgeyle tam bir alana sahip olmanız gerekmiyor, bu dedektörler doğru eşleşmeyi bulabilecek kadar güçlü. Bu yazıda bu yöntemlerin güzel bir değerlendirmesi yer almaktadır: Yerel değişmez özellik detektörleri: bir anket .

Bunların çoğu zaten OpenCV'de uygulanmıştır - örneğin cvMatchTemplate yöntemine bakın (histogram eşleşmesini kullanır): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Göze çarpan nokta / alan dedektörleri de mevcuttur - bkz. OpenCV Özellik Tespiti .


1
Hafifçe ölçeklendirilebilir veya taşınabilir. Ayrıca simgenin arka planı farklı olacaktır. Histogram karşılaştırmasını denedim ama birçok yanlış pozitif aldım. Ayrıca öklid mesafesini denedim ama bu da çok fazla yanlış pozitif verir (ama belki de simgede alfa değeri için biraz daha iyi bir işlem yapabilirim). Bunu biraz daha deneyeceğim, aksi takdirde MSER, SURF veya SIFT'i kontrol edeceğim.
Albert

1
Başka bir fikir - bir sobel operatörü uyguladıktan sonra görüntülerin histogram karşılaştırmasını kullanırsanız işe yaramaz mı? Bu sadece kenarların benzerliğini karşılaştırır. Arka planın ne kadar "sinirli" olduğuna bağlı olarak çalışabilir veya çalışmayabilir.
Karel Petranek

44

Son zamanlarda aynı sorunlarla karşılaşıyorum, bu sorunu (iki görüntüyü karşılaştırmak için basit ve hızlı algoritma) bir kez ve herkes için, opencv_contrib'e bir img_hash modülüne katkıda bulunuyorum, ayrıntıları bu bağlantıdan bulabilirsiniz .

img_hash modülü, kullanımı oldukça kolay altı görüntü karma algoritmaları sağlar.

Kodlar örneği

kökeni lenakökeni lena

lena bulanıklıklena bulanıklık

lena'yı yeniden boyutlandırlena'yı yeniden boyutlandır

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

Bu durumda, ColorMomentHash bize en iyi sonucu verir

  • gauss bulanıklığı saldırısı: 0.567521
  • vardiya saldırısı: 0.229728
  • yeniden boyutlandırma saldırısı: 0.229358

Her algoritmanın artıları ve eksileri

Farklı saldırılar altında performans

İmg_hash'ın performansı da iyidir

PHash kütüphanesi ile hız karşılaştırması (ukbench'ten 100 görüntü) hesaplama performansı karşılaştırma performansı

Bu algoritmalar için önerilen eşikleri bilmek istiyorsanız, lütfen bu gönderiyi kontrol edin ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). İmg_hash modüllerinin performansını nasıl ölçeceğimi merak ediyorsanız (hız ve farklı saldırılar dahil), lütfen bu bağlantıyı kontrol edin ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html ).


11

Ekran görüntüsü yalnızca simge içeriyor mu? Eğer öyleyse, iki görüntünün L2 mesafesi yeterli olabilir. L2 mesafesi işe yaramazsa, bir sonraki adım basit ve sağlam bir şey denemek, örneğin: Lucas-Kanade . Eminim OpenCV'de mevcuttur.


Alt alan tam olarak yalnızca simgeyi (bazı rastgele arka planlarla) veya farklı bir şey içerir. Hangi durumda olduğunu görmek istiyorum. Yine de, çok hafifçe kaydırılabilir veya yeniden boyutlandırılabilir, bu yüzden mesafeye bakıp bakamayacağımı bilmiyordum (hangi normda). Ama ölçeklendirilmiş bir versiyonla deneyeceğim.
Albert


5

Şablonunuzun (simge) test bölgesine tam olarak hizalandığından emin olabilirseniz, eski piksel farklılıkları toplamı işe yarayacaktır.

Hizalama yalnızca küçük bir bitecekse , piksel farklılıklarının toplamını bulmadan önce her iki görüntüyü cv :: GaussianBlur ile düşük geçirebilirsiniz .

Hizalamanın kalitesi potansiyel olarak düşükse , Yönlendirilmiş Degradelerin Histogramını veya OpenCV'nin uygun anahtar noktası algılama / tanımlayıcı algoritmalarından birini ( SIFT veya SURF gibi) öneririm .


4

Aynı görüntüleri eşleştirmek için - L2 mesafesi kodunu

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

Hızlı. Ancak aydınlatma / bakış açısı vb. Değişikliklere karşı sağlam değildir. Kaynak


2

Resmi benzerlik açısından karşılaştırmak isterseniz, OpenCV kullanmanızı öneririz. OpenCV'de, birkaç özellik eşlemesi ve şablon eşlemesi vardır. Özellik eşleme için SURF, SIFT, FAST ve benzeri dedektörler vardır. Görüntüyü algılamak, tanımlamak ve daha sonra eşleştirmek için bunu kullanabilirsiniz. Bundan sonra, iki görüntü arasındaki eşleşme sayısını bulmak için belirli bir dizini kullanabilirsiniz.


1
"Bundan sonra, iki resim arasındaki eşleşme sayısını bulmak için belirli bir dizini kullanabilirsiniz." aynı nesne "içerdiklerini" söylemek için iki resim arasındaki minimum eşleşme sayısı ne olabilir?
Inês Martins
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.