Perbandingan gambar - algoritma cepat

393

Saya mencari untuk membuat tabel dasar gambar dan kemudian membandingkan gambar baru dengan itu untuk menentukan apakah gambar baru adalah duplikat dasar (atau tutup) yang tepat.

Misalnya: jika Anda ingin mengurangi penyimpanan gambar yang sama 100 kali, Anda dapat menyimpan satu salinannya dan memberikan tautan referensi ke sana. Saat gambar baru dimasukkan, Anda ingin membandingkan dengan gambar yang ada untuk memastikan itu bukan duplikat ... ide?

Salah satu ide saya adalah mengurangi menjadi thumbnail kecil dan kemudian secara acak memilih lokasi 100 piksel dan membandingkan.

meade
sumber

Jawaban:

459

Di bawah ini adalah tiga pendekatan untuk menyelesaikan masalah ini (dan ada banyak lainnya).

  • Yang pertama adalah pendekatan standar dalam visi komputer, pencocokan titik kunci. Ini mungkin memerlukan beberapa latar belakang pengetahuan untuk diimplementasikan, dan bisa lambat.

  • Metode kedua hanya menggunakan pemrosesan gambar dasar, dan berpotensi lebih cepat daripada pendekatan pertama, dan mudah untuk diterapkan. Namun, apa yang diperolehnya dalam pemahaman, tidak memiliki ketahanan - pencocokan gagal pada gambar yang diskalakan, diputar, atau berubah warna.

  • Metode ketiga cepat dan kuat, tetapi berpotensi yang paling sulit untuk diterapkan.

Pencocokan Keypoint

Lebih baik daripada memilih 100 poin acak adalah memilih 100 poin penting . Bagian-bagian tertentu dari suatu gambar memiliki lebih banyak informasi daripada yang lain (terutama di bagian tepi dan sudut), dan ini adalah yang Anda ingin gunakan untuk pencocokan gambar yang cerdas. Google " ekstraksi keypoint " dan " pencocokan keypoint " dan Anda akan menemukan beberapa makalah akademis tentang subjek ini. Saat ini, titik kunci SIFT bisa dibilang yang paling populer, karena mereka dapat mencocokkan gambar di bawah skala, rotasi, dan pencahayaan yang berbeda. Beberapa implementasi SIFT dapat ditemukan di sini .

Satu kelemahan untuk pencocokan titik kunci adalah waktu berjalan dari implementasi naif: O (n ^ 2m), di mana n adalah jumlah titik kunci dalam setiap gambar, dan m adalah jumlah gambar dalam database. Beberapa algoritma pintar mungkin menemukan kecocokan terdekat lebih cepat, seperti quadtrees atau partisi ruang biner.


Solusi alternatif: Metode histogram

Solusi lain yang kurang kuat tetapi berpotensi lebih cepat adalah membangun histogram fitur untuk setiap gambar, dan memilih gambar dengan histogram yang paling dekat dengan histogram gambar input. Saya menerapkan ini sebagai undergrad, dan kami menggunakan 3 histogram warna (merah, hijau, dan biru), dan dua histogram tekstur, arah dan skala. Saya akan memberikan detail di bawah ini, tetapi saya harus perhatikan bahwa ini hanya bekerja dengan baik untuk mencocokkan gambar yang SANGAT mirip dengan gambar basis data. Gambar skala ulang, diputar, atau berubah warna bisa gagal dengan metode ini, tetapi perubahan kecil seperti memotong tidak akan merusak algoritme

Menghitung histogram warna sangatlah mudah - cukup pilih rentang untuk kotak histogram Anda, dan untuk setiap rentang, hitung jumlah piksel dengan warna dalam rentang itu. Sebagai contoh, perhatikan histogram "hijau", dan anggaplah kita memilih 4 ember untuk histogram kami: 0-63, 64-127, 128-191, dan 192-255. Kemudian untuk setiap piksel, kita melihat nilai hijau, dan menambahkan penghitungan ke ember yang sesuai. Setelah selesai menghitung, kami membagi setiap ember dengan jumlah piksel di seluruh gambar untuk mendapatkan histogram yang dinormalisasi untuk saluran hijau.

Untuk histogram arah tekstur, kami mulai dengan melakukan deteksi tepi pada gambar. Setiap titik tepi memiliki vektor normal yang menunjuk ke arah tegak lurus terhadap tepi. Kami menghitung sudut vektor normal menjadi salah satu dari 6 ember antara 0 dan PI (karena tepi memiliki simetri 180 derajat, kami mengonversi sudut antara -PI dan 0 menjadi antara 0 dan PI). Setelah menghitung jumlah titik tepi di setiap arah, kami memiliki histogram yang tidak dinormalisasi yang mewakili arah tekstur, yang kami normalkan dengan membagi setiap ember dengan jumlah total titik tepi pada gambar.

Untuk menghitung histogram skala tekstur, untuk setiap titik tepi, kami mengukur jarak ke titik tepi terdekat berikutnya dengan arah yang sama. Misalnya, jika titik tepi A memiliki arah 45 derajat, algoritma berjalan ke arah itu sampai menemukan titik tepi lain dengan arah 45 derajat (atau dalam deviasi yang masuk akal). Setelah menghitung jarak ini untuk setiap titik tepi, kami membuang nilai-nilai tersebut ke dalam histogram dan menormalkannya dengan membaginya dengan jumlah total titik tepi.

Sekarang Anda memiliki 5 histogram untuk setiap gambar. Untuk membandingkan dua gambar, Anda mengambil nilai absolut dari perbedaan antara setiap kotak histogram, dan kemudian menjumlahkan nilai-nilai ini. Misalnya, untuk membandingkan gambar A dan B, kami akan menghitung

|A.green_histogram.bucket_1 - B.green_histogram.bucket_1| 

untuk setiap ember dalam histogram hijau, dan ulangi untuk histogram lainnya, lalu jumlahkan semua hasilnya. Semakin kecil hasilnya, semakin baik pertandingan. Ulangi untuk semua gambar dalam basis data, dan kecocokan dengan hasil terkecil menang. Anda mungkin ingin memiliki ambang, di atas mana algoritma menyimpulkan bahwa tidak ada kecocokan yang ditemukan.


Pilihan Ketiga - Titik Puncak + Pohon Keputusan

Pendekatan ketiga yang mungkin jauh lebih cepat daripada dua lainnya adalah menggunakan hutan semantik texton (PDF). Ini melibatkan penggalian titik kunci sederhana dan menggunakan pohon keputusan koleksi untuk mengklasifikasikan gambar. Ini lebih cepat daripada pencocokan keypoint SIFT sederhana, karena menghindari proses pencocokan yang mahal, dan keypoint jauh lebih sederhana daripada SIFT, jadi ekstraksi keypoint jauh lebih cepat. Namun, ini mempertahankan invariansi metode SIFT untuk rotasi, skala, dan pencahayaan, fitur penting yang tidak dimiliki metode histogram.

Perbarui :

Kesalahan saya - makalah Semantic Texton Forests tidak secara khusus tentang pencocokan gambar, melainkan pelabelan wilayah. Makalah asli yang cocok adalah yang ini: Pengenalan Titik Puncak menggunakan Pohon Acak . Juga, makalah di bawah ini terus mengembangkan ide-ide dan mewakili keadaan seni (c. 2010):

Kyle Simek
sumber
Pendekatan Histogram tampaknya paling masuk akal. Saya berasumsi Anda dapat memutar gambar untuk melakukan ini di semua sisi untuk berjaga-jaga jika gambar yang dibandingkan telah diubah (memperlakukan gambar yang sama dengan 4) - terima kasih
meade
4
@meade Itu benar. Hal lain yang perlu dipertimbangkan: tergantung pada masalah Anda, Anda mungkin tidak perlu menggunakan semua 5 histogram dalam algoritma Anda. Membuang histogram arah tekstur akan memungkinkan Anda untuk mencocokkan versi yang diputar dari gambar. Membuang histogram skala tekstur akan memungkinkan Anda untuk mencocokkan versi skala ulang gambar. Anda akan kehilangan beberapa kemampuan untuk membandingkan kesamaan, tetapi ini mungkin tidak menjadi masalah, tergantung pada situasi Anda. Juga, karena menghitung informasi tekstur adalah bagian paling mahal dari algoritma, ini akan membuat algoritma Anda juga cepat.
Kyle Simek
@redmoskito: Saya punya pertanyaan. Bagaimana Anda mendapatkan nilai numerik dari histogram hijau misalnya? Jadi Anda bisa menguranginya dengan histogram gambar lainnya? Katakanlah kita memiliki histogram hijau dengan 3 piksel milik 0-63 ember, dan 5 piksel milik 64-127. Apa nilainya?
dinamis
3
@Ikaso jika gambarnya persis sama, Anda mungkin tidak ingin menggunakan yang seperti itu dan mempertimbangkan untuk menggunakan perbandingan CRC atau MD5 sederhana. Jika ini tidak cukup, seperti ada satu piksel yang berbeda atau metadata telah berubah, metode histogram juga cukup. jika gambar Anda sama tetapi diputar atau diskalakan, metode berbasis histogram mungkin cukup tetapi mungkin akan gagal. jika gambar Anda telah berubah warna, Anda perlu menggunakan algoritma berbasis minat.
reox
5
Saya ingin menambahkan bahwa saat ini, ada banyak alternatif cepat untuk SIFT, seperti detektor FAST dan deskriptor biner (SINGKAT, SINGKAT, ORB, FREAK, BinBoost) untuk beberapa nama. Tutorial tentang deskriptor biner dapat ditemukan di sini: gilscvblog.wordpress.com/2013/08/26/…
GilLevi
85

Metode terbaik yang saya tahu adalah menggunakan Perceptual Hash. Tampaknya ada implementasi open source yang baik dari hash yang tersedia di:

http://phash.org/

Gagasan utamanya adalah bahwa setiap gambar direduksi menjadi kode hash kecil atau 'sidik jari' dengan mengidentifikasi fitur-fitur penting dalam file gambar asli dan membuat representasi yang ringkas dari fitur-fitur tersebut (daripada membuat data gambar secara langsung). Ini berarti bahwa tingkat positif palsu jauh berkurang melalui pendekatan sederhana seperti mengurangi gambar ke gambar berukuran sidik jari kecil dan membandingkan sidik jari.

phash menawarkan beberapa jenis hash dan dapat digunakan untuk gambar, audio atau video.

redcalx
sumber
Siapa yang menarik dalam metode ini dapat menemukan realisasi Hash Perceptual Objective-C oleh tautan github.com/ameingast/cocoaimagehashing
Alexey Voitenko
@AlexeyVoitenko Apakah ini kompatibel dengan hash yang dihasilkan oleh phash.org dalam konfigurasi standarnya?
Michael
1
Dalam pengalaman saya, phash bekerja dengan baik untuk menemukan berbagai ukuran gambar yang sama, tetapi tidak untuk gambar yang serupa. Misal dua foto berbeda dari objek yang sama mungkin memiliki hash yang sangat berbeda.
Rena
39

Posting ini adalah titik awal dari solusi saya, banyak ide bagus di sini jadi saya pikir saya akan membagikan hasil saya. Wawasan utama adalah bahwa saya telah menemukan cara untuk mengatasi lambatnya pencocokan gambar berbasis-titik kunci dengan memanfaatkan kecepatan phash.

Untuk solusi umum, sebaiknya gunakan beberapa strategi. Setiap algoritma paling cocok untuk jenis transformasi gambar tertentu dan Anda dapat memanfaatkannya.

Di atas, algoritma tercepat; di bagian bawah paling lambat (meski lebih akurat). Anda mungkin melewatkan yang lambat jika kecocokan yang baik ditemukan di tingkat yang lebih cepat.

  • berbasis file-hash (md5, sha1, dll) untuk duplikat yang tepat
  • perceptual hashing (phash) untuk gambar dengan skala ulang
  • berbasis fitur (SIFT) untuk gambar yang dimodifikasi

Saya memiliki hasil yang sangat baik dengan phash. Akurasi bagus untuk gambar yang diperbesar ulang. Ini tidak baik untuk gambar yang dimodifikasi (secara persepsi) (dipotong, diputar, dicerminkan, dll). Untuk menangani kecepatan hashing, kita harus menggunakan cache disk / database untuk menjaga hash untuk tumpukan jerami.

Hal yang sangat baik tentang phash adalah bahwa begitu Anda membangun basis data hash Anda (yang bagi saya adalah sekitar 1000 gambar / detik), pencarian bisa sangat, sangat cepat, khususnya ketika Anda dapat menyimpan seluruh basis data hash di dalam memori. Ini cukup praktis karena hash hanya 8 byte.

Misalnya, jika Anda memiliki 1 juta gambar, itu akan memerlukan array 1 juta nilai hash 64-bit (8 MB). Pada beberapa CPU ini cocok dengan cache L2 / L3! Dalam penggunaan praktis saya telah melihat corei7 membandingkan lebih dari 1 Giga-hamm / detik, itu hanya masalah bandwidth memori ke CPU. Basis data 1 Miliar-gambar praktis pada CPU 64-bit (RAM 8 GB diperlukan) dan pencarian tidak akan melebihi 1 detik!

Untuk gambar yang dimodifikasi / dipangkas akan tampak fitur fitur-invarian / detektor kunci seperti SIFT adalah cara yang harus dilakukan. SIFT akan menghasilkan titik kunci yang baik yang akan mendeteksi crop / rotate / mirror dll. Namun perbandingan deskriptor sangat lambat dibandingkan dengan jarak tempuh yang digunakan oleh phash. Ini adalah batasan utama. Ada banyak perbandingan yang harus dilakukan, karena ada maksimum IxJxK deskriptor membandingkan untuk mencari satu gambar (I = num gambar tumpukan jerami, J = titik kunci target per gambar tumpukan jerami, K = titik kunci target per gambar jarum).

Untuk mengatasi masalah kecepatan, saya mencoba menggunakan phash di setiap titik kunci yang ditemukan, menggunakan ukuran fitur / radius untuk menentukan sub-persegi panjang. Trik untuk membuat ini bekerja dengan baik, adalah menumbuhkan / mengecilkan jari-jari untuk menghasilkan level sub-rect yang berbeda (pada gambar jarum). Biasanya level pertama (tidak berskala) akan cocok namun seringkali dibutuhkan beberapa kali lagi. Saya tidak 100% yakin mengapa ini bekerja, tapi saya bisa membayangkan itu mengaktifkan fitur yang terlalu kecil untuk phash untuk bekerja (phash skala gambar ke 32x32).

Masalah lainnya adalah SIFT tidak akan mendistribusikan keypoint secara optimal. Jika ada bagian gambar dengan banyak tepi, titik kunci akan mengelompok di sana dan Anda tidak akan mendapatkannya di area lain. Saya menggunakan GridAdaptedFeatureDetector di OpenCV untuk meningkatkan distribusi. Tidak yakin ukuran kisi apa yang terbaik, saya menggunakan kisi kecil (1x3 atau 3x1 tergantung pada orientasi gambar).

Anda mungkin ingin mengatur skala semua gambar tumpukan jerami (dan jarum) ke ukuran yang lebih kecil sebelum deteksi fitur (saya menggunakan 210px sepanjang dimensi maksimum). Ini akan mengurangi noise pada gambar (selalu menjadi masalah untuk algoritma visi komputer), juga akan memfokuskan detektor pada fitur yang lebih menonjol.

Untuk gambar orang, Anda dapat mencoba deteksi wajah dan menggunakannya untuk menentukan ukuran gambar yang akan diukur dan ukuran kisi (misalnya wajah dengan skala terbesar hingga 100px). Detektor fitur menyumbang berbagai tingkat skala (menggunakan piramida) tetapi ada batasan berapa banyak tingkat yang akan digunakan (ini tentu saja bisa disesuaikan).

Detektor keypoint mungkin bekerja paling baik ketika mengembalikan kurang dari jumlah fitur yang Anda inginkan. Misalnya, jika Anda meminta 400 dan mendapatkan 300 kembali, itu bagus. Jika Anda mendapatkan 400 kembali setiap kali, mungkin beberapa fitur bagus harus ditinggalkan.

Gambar jarum dapat memiliki titik kunci yang lebih sedikit daripada gambar tumpukan jerami dan masih mendapatkan hasil yang baik. Menambahkan lebih banyak tidak selalu memberi Anda keuntungan besar, misalnya dengan J = 400 dan K = 40 hit rate saya adalah sekitar 92%. Dengan J = 400 dan K = 400 hit rate hanya naik hingga 96%.

Kita dapat memanfaatkan kecepatan ekstrem fungsi hamming untuk menyelesaikan penskalaan, rotasi, mirroring dll. Teknik multi-pass dapat digunakan. Pada setiap iterasi, ubah sub-persegi panjang, ulang hash, dan jalankan fungsi pencarian lagi.

wally
sumber
8

Seperti yang ditunjukkan oleh cartman, Anda dapat menggunakan segala jenis nilai hash untuk menemukan duplikat yang tepat.

Satu titik awal untuk menemukan gambar yang dekat bisa ada di sini . Ini adalah alat yang digunakan oleh perusahaan CG untuk memeriksa apakah gambar yang dirubah masih menunjukkan adegan yang sama.

Tobiesque
sumber
7

Saya punya ide, yang dapat bekerja dan kemungkinan besar sangat cepat. Anda dapat melakukan sub-sampel gambar untuk mengatakan resolusi 80x60 atau sebanding, dan mengonversinya menjadi skala abu-abu (setelah subsampling akan lebih cepat). Memproses kedua gambar yang ingin Anda bandingkan. Kemudian jalankan jumlah normal dari perbedaan kuadrat antara dua gambar (gambar permintaan dan masing-masing dari db), atau yang lebih baik, Normalized Cross Correlation, yang memberikan respons lebih dekat ke 1, jika kedua gambar tersebut sama. Kemudian jika gambar serupa Anda dapat melanjutkan ke teknik yang lebih canggih untuk memverifikasi bahwa itu adalah gambar yang sama. Jelas algoritma ini linier dalam hal jumlah gambar dalam database Anda sehingga meskipun akan sangat cepat hingga 10.000 gambar per detik pada perangkat keras modern. Jika Anda memerlukan invarian untuk rotasi, maka gradien dominan dapat dihitung untuk gambar kecil ini, dan kemudian seluruh sistem koordinat dapat diputar ke orientasi kanonik, meskipun ini, akan lebih lambat. Dan tidak, tidak ada invariansi untuk skala di sini.

Jika Anda menginginkan sesuatu yang lebih umum atau menggunakan basis data besar (jutaan gambar), maka Anda perlu melihat ke dalam teori pengambilan gambar (banyak makalah yang muncul dalam 5 tahun terakhir). Ada beberapa petunjuk dalam jawaban lain. Tapi itu mungkin berlebihan, dan pendekatan histogram menyarankan akan melakukan pekerjaan. Meskipun saya akan berpikir kombinasi dari berbagai pendekatan cepat akan lebih baik.

Denis C
sumber
7

Perusahaan saya memiliki sekitar 24 juta gambar yang masuk dari produsen setiap bulan. Saya mencari solusi cepat untuk memastikan bahwa gambar yang kami unggah ke katalog kami adalah gambar baru .

Saya ingin mengatakan bahwa saya telah mencari di internet jauh dan luas untuk mencoba menemukan solusi yang ideal. Saya bahkan mengembangkan algoritma deteksi tepi saya sendiri.
Saya telah mengevaluasi kecepatan dan akurasi beberapa model. Gambar saya, yang memiliki latar belakang putih, bekerja sangat baik dengan phashing. Seperti kata redcalx , saya merekomendasikan phash atau ahash. JANGAN gunakan Hashing MD5 atau hash kriptografis lainnya. Kecuali, Anda hanya menginginkan pencocokan gambar EXACT. Setiap pengubahan ukuran atau manipulasi yang terjadi di antara gambar akan menghasilkan hash yang berbeda.

Untuk phash / ahash, Lihat ini: imagehash

Saya ingin memperpanjang posting * redcalx dengan memposting kode dan keakuratan saya.

Apa yang saya lakukan:

from PIL import Image
from PIL import ImageFilter
import imagehash

img1=Image.open(r"C:\yourlocation")
img2=Image.open(r"C:\yourlocation")
if img1.width<img2.width:
    img2=img2.resize((img1.width,img1.height))
else:
    img1=img1.resize((img2.width,img2.height))
img1=img1.filter(ImageFilter.BoxBlur(radius=3))
img2=img2.filter(ImageFilter.BoxBlur(radius=3))
phashvalue=imagehash.phash(img1)-imagehash.phash(img2)
ahashvalue=imagehash.average_hash(img1)-imagehash.average_hash(img2)
totalaccuracy=phashvalue+ahashvalue

Inilah beberapa hasil saya:

item1  item2  totalsimilarity
desk1  desk1       3
desk1  phone1     22
chair1 desk1      17
phone1 chair1     34

Semoga ini membantu!

Tanner Clark
sumber
6

Saya percaya bahwa menurunkan ukuran gambar ke ukuran hampir ikon, katakanlah 48x48, lalu mengonversi ke skala abu-abu, lalu mengambil perbedaan antara piksel, atau Delta, harus bekerja dengan baik. Karena kami membandingkan perubahan warna piksel, daripada warna piksel sebenarnya, tidak masalah jika gambarnya sedikit lebih terang atau lebih gelap. Perubahan besar akan berpengaruh karena piksel yang terlalu terang / gelap akan hilang. Anda dapat menerapkan ini di satu baris, atau sebanyak yang Anda inginkan untuk meningkatkan akurasi. Paling banyak Anda akan memiliki 47x47 = 2.209 pengurangan untuk membuat untuk membentuk Kunci yang sebanding.

Tanoshimi
sumber
3

Memilih 100 poin acak bisa berarti bahwa gambar yang serupa (atau kadang-kadang bahkan berbeda) akan ditandai sebagai sama, yang saya anggap bukan yang Anda inginkan. Hash MD5 tidak akan berfungsi jika gambar format yang berbeda (png, jpeg, dll), memiliki ukuran yang berbeda, atau memiliki metadata yang berbeda. Mengurangi semua gambar ke ukuran yang lebih kecil adalah taruhan yang baik, melakukan perbandingan piksel-untuk-piksel tidak boleh terlalu lama selama Anda menggunakan pustaka gambar / bahasa cepat yang baik, dan ukurannya cukup kecil.

Anda dapat mencoba membuatnya kecil, kemudian jika mereka melakukan perbandingan yang sama pada ukuran yang lebih besar - bisa menjadi kombinasi yang baik antara kecepatan dan akurasi ...

Harry
sumber
Jika Anda mencari duplikat yang tepat tetapi dengan format / metadata yang berbeda, Anda dapat melakukan hash (mis. MD5) dari nilai piksel aktual. Imagemagick menyebut ini tanda tangan (tidak terkait dengan penandatanganan kriptografi). Anda juga dapat menguranginya terlebih dahulu, misalnya memotong menjadi 4 bit per piksel untuk mengurangi dampak artefak JPEG, atau mengonversi ke skala abu-abu untuk mencocokkan gambar yang sedikit berubah warna.
Rena
2

Jika Anda memiliki banyak gambar, lihat ke filter Bloom , yang menggunakan banyak hash untuk hasil yang probablistik namun efisien. Jika jumlah gambar tidak besar, maka hash kriptografis seperti md5 harus memadai.

jigital
sumber
Jadi (mencoba memahami filter Bloom) - apakah itu berarti Anda memilih titik piksel acak pada gambar dasar, mendapatkan nilai piksel merah / hijau / biru secara acak - kemudian dibandingkan dengan gambar baru? dan kemudian gunakan tingkat probabilitas (kecocokan 90%) untuk menentukan seberapa mirip kedua gambar tersebut?
meade
5
Ini bukan pemeriksaan kesamaan, ini adalah pemeriksaan kesetaraan. Jika Anda membutuhkan kesamaan, maka hashing bukanlah pendekatan yang tepat. Gagasan di balik Bloom adalah menggunakan beberapa algoritma hash untuk meningkatkan kemungkinan identifikasi unik. Memilih titik acak bukanlah pendekatan terbaik untuk algoritma hashing karena akan menghasilkan hasil yang berbeda setiap kali.
jdigital