Metode sederhana dan cepat untuk membandingkan gambar untuk kesamaan

192

Saya perlu cara sederhana dan cepat untuk membandingkan dua gambar untuk kesamaan. Yaitu saya ingin mendapatkan nilai tinggi jika mengandung hal yang persis sama tetapi mungkin memiliki latar belakang yang sedikit berbeda dan dapat dipindahkan / diubah ukurannya dengan beberapa piksel.

(Lebih konkret, jika itu penting: Satu gambar adalah ikon dan gambar lainnya adalah subarea dari tangkapan layar dan saya ingin tahu apakah subarea itu persis ikon atau tidak.)

Saya memiliki OpenCV di tangan tetapi saya masih belum terbiasa dengannya.

Satu kemungkinan yang saya pikirkan sejauh ini: Membagi kedua gambar menjadi 10x10 sel dan untuk masing-masing 100 sel, bandingkan histogram warna. Kemudian saya dapat mengatur beberapa nilai ambang yang dibuat dan jika nilai yang saya dapatkan di atas ambang itu, saya berasumsi bahwa mereka serupa.

Saya belum mencobanya seberapa bagus itu bekerja tetapi saya kira itu akan cukup baik. Gambar sudah cukup mirip (dalam kasus penggunaan saya), jadi saya bisa menggunakan nilai ambang batas yang cukup tinggi.

Saya kira ada puluhan solusi lain yang mungkin untuk ini yang akan bekerja lebih atau kurang (karena tugas itu sendiri cukup sederhana karena saya hanya ingin mendeteksi kesamaan jika mereka benar-benar sangat mirip). Apa yang kamu sarankan?


Ada beberapa pertanyaan yang sangat terkait / mirip tentang mendapatkan tanda tangan / sidik jari / hash dari sebuah gambar:

Saya juga menemukan implementasi yang memiliki fungsi seperti ini untuk mendapatkan sidik jari:

Beberapa diskusi tentang hash gambar persepsi: di sini


Agak offtopic: Ada banyak metode untuk membuat sidik jari audio. MusicBrainz , layanan web yang menyediakan pencarian berdasarkan sidik jari untuk lagu-lagu, memiliki ikhtisar yang baik dalam wiki mereka . Mereka menggunakan AcoustID sekarang. Ini untuk menemukan kecocokan yang tepat (atau sebagian besar tepat). Untuk menemukan kecocokan serupa (atau jika Anda hanya memiliki cuplikan atau derau tinggi), lihat Echoprint . Pertanyaan SO terkait ada di sini . Jadi sepertinya ini diselesaikan untuk audio. Semua solusi ini bekerja dengan sangat baik.

Pertanyaan yang agak lebih umum tentang pencarian fuzzy secara umum ada di sini . Misalnya ada hashing sensitif-lokalitas dan pencarian tetangga terdekat .

Albert
sumber
1
Mungkin sidik jari gambar bisa membantu? stackoverflow.com/questions/596262/…
GWW
Metrik Wasserstein, juga dikenal sebagai Jarak Penggerak Bumi (EMD), adalah sesuatu yang tampaknya tidak diketahui orang, tetapi akan memberikan apa yang Anda inginkan di sini.
mmgp
3
kemungkinan rangkap dari perbandingan Gambar - algoritma cepat
sashoalm
Hai, saya datang dengan dHash yang lebih baik - Saya menyebutnya IDHash: github.com/Nakilon/dhash-vips
Nakilon

Jawaban:

107

Dapatkah tangkapan layar atau ikon diubah (diskalakan, diputar, miring ...)? Ada beberapa metode di atas kepala saya yang mungkin dapat membantu Anda:

  • Jarak euclidean sederhana seperti yang disebutkan oleh @carlosdc (tidak berfungsi dengan gambar yang diubah dan Anda memerlukan ambang).
  • (Dinormalisasi) Korelasi Silang - metrik sederhana yang dapat Anda gunakan untuk perbandingan area gambar. Ini lebih kuat daripada jarak euclidean sederhana tetapi tidak bekerja pada gambar yang diubah dan Anda lagi akan membutuhkan ambang batas.
  • Perbandingan histogram - jika Anda menggunakan histogram yang dinormalisasi, metode ini berfungsi dengan baik dan tidak terpengaruh oleh transformasi affine. Masalahnya adalah menentukan ambang batas yang benar. Ini juga sangat sensitif terhadap perubahan warna (kecerahan, kontras, dll.). Anda dapat menggabungkannya dengan dua sebelumnya.
  • Detektor titik / area yang menonjol - seperti MSER (Kawasan Ekstrim yang Stabil Maksimal) , SURF atau SIFT . Ini adalah algoritma yang sangat kuat dan mungkin terlalu rumit untuk tugas sederhana Anda. Untung Anda tidak harus memiliki area yang tepat dengan hanya satu ikon, detektor ini cukup kuat untuk menemukan kecocokan yang tepat. Evaluasi yang bagus dari metode ini adalah dalam makalah ini: Detektor fitur invarian lokal: survei .

Sebagian besar sudah diterapkan di OpenCV - lihat misalnya metode cvMatchTemplate (menggunakan pencocokan histogram): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Detektor titik / area yang menonjol juga tersedia - lihat Deteksi Fitur OpenCV .

Karel Petranek
sumber
1
Itu dapat ditingkatkan atau dipindahkan sedikit. Juga latar belakang ikon akan berbeda. Saya mencoba perbandingan histogram tetapi saya mendapat banyak kesalahan positif. Saya juga mencoba jarak euclidean tapi itu juga memberikan terlalu banyak false positive (tapi mungkin saya bisa membuatnya sedikit lebih baik untuk penanganan nilai alpha pada ikon). Saya akan mencoba itu sedikit lebih jauh, kalau tidak saya akan memeriksa MSER, SURF atau SIFT.
Albert
1
Gagasan lain - tidak akan bekerja jika Anda menggunakan perbandingan histogram dari gambar setelah menerapkan operator sobel? Itu hanya akan membandingkan kesamaan tepi. Mungkin atau mungkin tidak berfungsi, tergantung pada seberapa "edgy" latar belakangnya.
Karel Petranek
44

Saya menghadapi masalah yang sama baru-baru ini, untuk menyelesaikan masalah ini (algoritma sederhana dan cepat untuk membandingkan dua gambar) sekali dan untuk semua, saya berkontribusi modul img_hash ke opencv_contrib, Anda dapat menemukan detail dari tautan ini .

Modul img_hash menyediakan enam algoritma hash gambar, cukup mudah digunakan.

Contoh kode

asal lenaasal lena

mengaburkan lenamengaburkan lena

mengubah ukuran lenamengubah ukuran lena

bergeser lenabergeser 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));
}

Dalam hal ini, ColorMomentHash memberi kami hasil terbaik

  • gaussian blur attack: 0.567521
  • shift serangan: 0.229728
  • mengubah ukuran serangan: 0,229358

Pro dan kontra dari masing-masing algoritma

Performa di bawah serangan berbeda

Kinerja img_hash juga bagus

Perbandingan kecepatan dengan pustaka PHash (100 gambar dari ukbench) menghitung kinerja kinerja perbandingan

Jika Anda ingin mengetahui ambang rekomendasi untuk algoritma ini, silakan periksa posting ini ( http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html ). Jika Anda tertarik tentang bagaimana cara mengukur kinerja modul img_hash (termasuk kecepatan dan serangan yang berbeda), silakan periksa tautan ini ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html ).

StereoMatching
sumber
11

Apakah tangkapan layar hanya berisi ikon? Jika demikian, jarak L2 dari kedua gambar mungkin cukup. Jika jarak L2 tidak berhasil, langkah selanjutnya adalah mencoba sesuatu yang sederhana dan mapan, seperti: Lucas-Kanade . Yang saya yakin tersedia di OpenCV.

carlosdc
sumber
Subarea hanya mengandung ikon saja (dengan beberapa latar belakang acak) atau sesuatu yang berbeda. Saya ingin melihat yang mana. Meskipun, mungkin sedikit bergeser atau mengubah ukuran, itu sebabnya saya tidak yakin apakah saya bisa melihat jarak (dalam norma apa pun). Tetapi saya akan mencoba dengan versi yang diperkecil.
Albert
6

Jika Anda ingin mendapatkan indeks tentang kesamaan kedua gambar, saya sarankan Anda dari metrik indeks SSIM. Ini lebih konsisten dengan mata manusia. Inilah artikel tentang itu: Indeks Kesamaan Struktural

Ini diimplementasikan dalam OpenCV juga, dan dapat dipercepat dengan GPU: OpenCV SSIM dengan GPU

Milan Tenk
sumber
5

Jika Anda yakin memiliki keselarasan yang tepat dari template Anda (ikon) dengan wilayah pengujian, maka semua perbedaan piksel yang lama akan berfungsi.

Jika penyejajaran hanya akan sedikit mati, maka Anda dapat mengirimkan dua gambar dengan cv :: GaussianBlur sebelum menemukan jumlah perbedaan piksel.

Jika kualitas pelurusan berpotensi buruk maka saya akan merekomendasikan Histogram of Oriented Gradients atau salah satu algoritma keypoint detection / descriptor OpenCV yang nyaman (seperti SIFT atau SURF ).

rcv
sumber
4

Jika untuk pencocokan gambar identik - kode untuk jarak L2

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

Cepat. Tetapi tidak kuat untuk perubahan pencahayaan / sudut pandang dll. Sumber

Kiran
sumber
2

Jika Anda ingin membandingkan gambar untuk kesamaan, saya sarankan Anda menggunakan OpenCV. Di OpenCV, ada beberapa pencocokan fitur dan pencocokan templat. Untuk pencocokan fitur, ada SURF, SIFT, FAST dan detektor lainnya. Anda dapat menggunakan ini untuk mendeteksi, menjelaskan, dan kemudian mencocokkan gambar. Setelah itu, Anda dapat menggunakan indeks spesifik untuk menemukan jumlah kecocokan antara dua gambar.

Hua Er Lim
sumber
1
Anda berkata "Setelah itu, Anda dapat menggunakan indeks spesifik untuk menemukan jumlah kecocokan antara dua gambar." apa yang bisa menjadi jumlah minimum kecocokan antara dua gambar untuk mengatakan bahwa mereka "contais" objek yang sama?
Inês Martins