webentwicklung-frage-antwort-db.com.de

Einfache und schnelle Methode zum Vergleichen von Bildern auf Ähnlichkeit

Ich brauche eine einfache und schnelle Möglichkeit, um zwei Bilder auf Ähnlichkeit zu vergleichen. Das heißt Ich möchte einen hohen Wert erhalten, wenn sie genau dasselbe enthalten, aber einen etwas anderen Hintergrund haben und möglicherweise um einige Pixel verschoben/in der Größe geändert werden.

(Genauer gesagt, wenn das wichtig ist: Das eine Bild ist ein Symbol und das andere Bild ist ein Teilbereich eines Screenshots, und ich möchte wissen, ob dieser Teilbereich genau das Symbol ist oder nicht.)

Ich habe OpenCV zur Hand, aber ich bin noch nicht so daran gewöhnt.

Eine Möglichkeit, über die ich bisher nachgedacht habe: Teilen Sie beide Bilder in 10x10 Zellen und vergleichen Sie für jede dieser 100 Zellen das Farbhistogramm. Dann kann ich einen bestimmten Schwellenwert festlegen, und wenn der Wert, den ich erhalte, über diesem Schwellenwert liegt, gehe ich davon aus, dass sie ähnlich sind.

Ich habe es noch nicht ausprobiert, wie gut das funktioniert, aber ich denke, es wäre gut genug. Die Bilder sind sich (in meinem Anwendungsfall) bereits ziemlich ähnlich, sodass ich einen ziemlich hohen Schwellenwert verwenden kann.

Ich denke, es gibt Dutzende anderer Lösungsmöglichkeiten, die mehr oder weniger funktionieren würden (da die Aufgabe selbst recht einfach ist, da ich Ähnlichkeiten nur erkennen möchte, wenn sie wirklich sehr ähnlich sind). Was würdest du vorschlagen?


Es gibt ein paar ähnliche Fragen, um eine Signatur/einen Fingerabdruck/einen Hash von einem Bild zu erhalten:

Außerdem bin ich auf diese Implementierungen gestoßen, die solche Funktionen haben, um einen Fingerabdruck zu erhalten:

Einige Diskussionen über Wahrnehmungsbild-Hashes: hier


Ein bisschen offtopic: Es gibt viele Methoden, um Audio-Fingerabdrücke zu erstellen. MusicBrainz , ein Webdienst, der die Suche nach Songs per Fingerabdruck ermöglicht, hat ein gute Übersicht in seinem Wiki . Sie verwenden jetzt AcoustID . Dies dient dazu, genaue (oder meist genaue) Übereinstimmungen zu finden. Schauen Sie sich Echoprint an, um ähnliche Übereinstimmungen zu finden (oder wenn Sie nur einige Ausschnitte oder starkes Rauschen haben). Eine verwandte SO Frage ist hier . Es scheint also, dass dies für Audio gelöst ist. Alle diese Lösungen funktionieren recht gut.

Eine etwas allgemeinere Frage zur Fuzzy-Suche im Allgemeinen ist hier . Z.B. es gibt ortsabhängiges Hashing und Suche nach dem nächsten Nachbarn .

181
Albert

Kann der Screenshot oder das Symbol umgewandelt werden (skaliert, gedreht, verzerrt ...)? Es gibt einige Methoden auf meinem Kopf, die Ihnen möglicherweise helfen könnten:

  • Einfache euklidische Distanz wie von @carlosdc erwähnt (funktioniert nicht mit transformierten Bildern und Sie benötigen einen Schwellenwert).
  • (Normalisierte) Kreuzkorrelation - eine einfache Metrik, mit der Sie Bildbereiche vergleichen können. Es ist robuster als die einfache euklidische Distanz, funktioniert jedoch nicht bei transformierten Bildern und Sie benötigen erneut einen Schwellenwert.
  • Histogrammvergleich - Wenn Sie normalisierte Histogramme verwenden, funktioniert diese Methode gut und wird von affinen Transformationen nicht beeinflusst. Das Problem besteht darin, den richtigen Schwellenwert zu ermitteln. Es ist auch sehr empfindlich gegenüber Farbveränderungen (Helligkeit, Kontrast usw.). Sie können es mit den beiden vorherigen kombinieren.
  • Detektoren für hervorstechende Punkte/Bereiche - wie MSER (Maximally Stable Extremal Regions) , SURF oder SIEBEN . Dies sind sehr robuste Algorithmen, die für Ihre einfache Aufgabe möglicherweise zu kompliziert sind. Gut ist, dass Sie keinen exakten Bereich mit nur einem Symbol haben müssen. Diese Detektoren sind leistungsstark genug, um die richtige Übereinstimmung zu finden. Eine gute Bewertung dieser Methoden finden Sie in diesem Artikel: Detektoren für lokale invariante Merkmale: eine Umfrage .

Die meisten davon sind bereits in OpenCV implementiert - siehe zum Beispiel die cvMatchTemplate-Methode (verwendet Histogramm-Matching): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Die Detektoren für hervorstechende Punkte/Bereiche sind ebenfalls verfügbar - siehe OpenCV Feature Detection .

101
Karel Petranek

Ich habe in letzter Zeit die gleichen Probleme, um dieses Problem zu lösen (einfacher und schneller Algorithmus zum Vergleichen von zwei Bildern). Ein für allemal trage ich ein img_hash-Modul zu opencv_contrib bei. Details finden Sie unter dieser Link .

das Modul img_hash bietet sechs Bild-Hash-Algorithmen, die recht einfach zu verwenden sind.

Codebeispiel

Origin lena Herkunft Lena

blur lena Lena verwischen

resize lena Größe ändern Lena

shift lena lena verschieben

#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 diesem Fall liefert ColorMomentHash das beste Ergebnis

  • gaußscher Unschärfeangriff: 0,567521
  • schichtangriff: 0,229728
  • größenänderung Angriff: 0.229358

Vor- und Nachteile der einzelnen Algorithmen

Performance under different attacks

Die Leistung von img_hash ist auch gut

Geschwindigkeitsvergleich mit der PHash-Bibliothek (100 Bilder aus der Ukraine) compute performancecomparison performance

Wenn Sie die empfohlenen Schwellenwerte für diese Algorithmen kennen möchten, überprüfen Sie diesen Beitrag ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html =). Wenn Sie daran interessiert sind, wie ich die Leistung von img_hash-Modulen messe (einschließlich Geschwindigkeit und verschiedener Angriffe), überprüfen Sie diesen Link ( http://qtandopencv.blogspot.my/2016/06/speed-up-image) -hashing-of-opencvimghash.html ).

37
StereoMatching

Enthält der Screenshot nur das Symbol? In diesem Fall kann der L2-Abstand der beiden Bilder ausreichen. Wenn die L2-Distanz nicht funktioniert, versuchen Sie als Nächstes etwas Einfaches und Etabliertes wie: Lucas-Kanade . Was ich sicher bin, ist in OpenCV verfügbar.

10
carlosdc

Wenn Sie einen Index über die Ähnlichkeit der beiden Bilder erhalten möchten, empfehle ich Ihnen aus den Metriken den SSIM-Index. Es ist konsistenter mit dem menschlichen Auge. Hier ist ein Artikel darüber: Structural Similarity Index

Es ist auch in OpenCV implementiert und kann mit GPU beschleunigt werden: OpenCV SSIM mit GP

5
ramez

Wenn Sie sicher sein können, dass Ihre Vorlage (das Symbol) genau auf den Testbereich ausgerichtet ist, funktioniert die alte Summe der Pixeldifferenzen.

Wenn die Ausrichtung nur geringfügig abweicht, können Sie beide Bilder mit cv :: GaussianBlur tiefpas- sen, bevor Sie die Summe der Pixeldifferenzen ermitteln.

Wenn die Qualität der Ausrichtung möglicherweise schlecht ist, würde ich entweder ein Histogramm mit orientierten Verläufen oder einen der bequemen OpenCV-Algorithmen zur Erkennung/Beschreibung von Schlüsselpunkten (wie SIFT oder SURFEN ).

4
rcv

Falls für identische Bilder - Code für L2-Entfernung

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

Schnell. Aber nicht robust gegenüber Änderungen der Beleuchtung/des Blickwinkels usw. Quelle

3
Kiran

Wenn Sie das Bild auf Ähnlichkeit vergleichen möchten, empfehle ich Ihnen, OpenCV zu verwenden. In OpenCV gibt es nur wenige Übereinstimmungen mit Features und Vorlagen. Für die Merkmalsanpassung gibt es den SURF-, SIFT-, FAST- usw. Detektor. Auf diese Weise können Sie das Bild erkennen, beschreiben und abgleichen. Danach können Sie den spezifischen Index verwenden, um die Anzahl der Übereinstimmungen zwischen den beiden Bildern zu ermitteln.

2
Hua Er Lim