Memeriksa kemiripan gambar dengan OpenCV

144

Apakah OpenCV mendukung perbandingan dua gambar, mengembalikan beberapa nilai (mungkin persentase) yang menunjukkan seberapa mirip gambar-gambar ini? Misalnya, 100% akan dikembalikan jika gambar yang sama diteruskan dua kali, 0% akan dikembalikan jika gambarnya benar-benar berbeda.

Saya sudah membaca banyak topik serupa di sini di StackOverflow. Saya juga melakukan beberapa Googling. Sayangnya saya tidak bisa mendapatkan jawaban yang memuaskan.

Boris
sumber
Lihat juga jawaban di stackoverflow.com/questions/4196453/…
B. Pergi

Jawaban:

214

Ini adalah topik yang sangat besar, dengan jawaban dari 3 baris kode untuk seluruh majalah penelitian.

Saya akan menjelaskan teknik-teknik yang paling umum dan hasilnya.

Membandingkan histogram

Salah satu metode paling sederhana & tercepat. Diusulkan puluhan tahun lalu sebagai sarana untuk menemukan kemiripan gambar. Idenya adalah bahwa hutan akan memiliki banyak warna hijau, dan wajah manusia akan memiliki banyak warna merah jambu, atau apa pun. Jadi, jika Anda membandingkan dua gambar dengan hutan, Anda akan mendapatkan beberapa kesamaan antara histogram, karena Anda memiliki banyak warna hijau di keduanya.

Sisi negatifnya: terlalu sederhana. Pisang dan pantai akan terlihat sama, karena keduanya berwarna kuning.

Metode OpenCV: bandingkanHist ()

Pencocokan template

Contoh yang bagus di sini matchTemplate menemukan kecocokan yang baik . Ini menggabungkan gambar pencarian dengan yang sedang dicari. Biasanya digunakan untuk menemukan bagian gambar yang lebih kecil di bagian yang lebih besar.

Kerugian: Ini hanya mengembalikan hasil yang baik dengan gambar yang identik, ukuran & orientasi yang sama.

Metode OpenCV: matchTemplate ()

Pencocokan fitur

Dianggap sebagai salah satu cara paling efisien untuk melakukan penelusuran gambar. Sejumlah fitur diekstraksi dari sebuah gambar, dengan cara yang menjamin fitur yang sama akan dikenali lagi bahkan saat diputar, diskalakan, atau dimiringkan. Fitur yang diekstrak dengan cara ini dapat dicocokkan dengan kumpulan fitur gambar lainnya. Gambar lain yang memiliki proporsi fitur tinggi yang cocok dengan gambar pertama dianggap menggambarkan pemandangan yang sama.

Menemukan homografi antara dua set titik akan memungkinkan Anda juga menemukan perbedaan relatif dalam sudut pemotretan antara gambar asli atau jumlah tumpang tindih.

Ada sejumlah tutorial / sampel OpenCV tentang ini, dan video yang bagus di sini . Seluruh modul OpenCV (features2d) didedikasikan untuk itu.

Kerugian: Mungkin lambat. Itu tidak sempurna.


Di situs T&J OpenCV saya berbicara tentang perbedaan antara deskriptor fitur, yang sangat bagus saat membandingkan seluruh gambar dan deskriptor tekstur, yang digunakan untuk mengidentifikasi objek seperti wajah manusia atau mobil dalam sebuah gambar.

Sam
sumber
untuk membandingkan gambar serupa yang hanya memiliki beberapa gambar berbeda (mis. objek baru dipindahkan ke tampilan yang sama) Anda juga dapat bekerja dengan absdiff codota.com/code/java/methods/org.opencv.core.Core/absdiff Thresholding hasil menghasilkan topeng yang memungkinkan Anda menyorot daerah yang berubah dari satu adegan ke adegan lain.
Max F.
34

Jika untuk mencocokkan gambar identik (ukuran / orientasi sama)

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

Sumber

Kiran
sumber
12

Solusi Sam seharusnya cukup. Saya telah menggunakan kombinasi perbedaan histogram dan pencocokan template karena tidak ada satu metode pun yang berhasil untuk saya 100%. Saya tidak terlalu mementingkan metode histogram. Inilah cara saya menerapkan dalam skrip python sederhana.

import cv2

class CompareImage(object):

    def __init__(self, image_1_path, image_2_path):
        self.minimum_commutative_image_diff = 1
        self.image_1_path = image_1_path
        self.image_2_path = image_2_path

    def compare_image(self):
        image_1 = cv2.imread(self.image_1_path, 0)
        image_2 = cv2.imread(self.image_2_path, 0)
        commutative_image_diff = self.get_image_difference(image_1, image_2)

        if commutative_image_diff < self.minimum_commutative_image_diff:
            print "Matched"
            return commutative_image_diff
        return 10000 //random failure value

    @staticmethod
    def get_image_difference(image_1, image_2):
        first_image_hist = cv2.calcHist([image_1], [0], None, [256], [0, 256])
        second_image_hist = cv2.calcHist([image_2], [0], None, [256], [0, 256])

        img_hist_diff = cv2.compareHist(first_image_hist, second_image_hist, cv2.HISTCMP_BHATTACHARYYA)
        img_template_probability_match = cv2.matchTemplate(first_image_hist, second_image_hist, cv2.TM_CCOEFF_NORMED)[0][0]
        img_template_diff = 1 - img_template_probability_match

        # taking only 10% of histogram diff, since it's less accurate than template method
        commutative_image_diff = (img_hist_diff / 10) + img_template_diff
        return commutative_image_diff


    if __name__ == '__main__':
        compare_image = CompareImage('image1/path', 'image2/path')
        image_difference = compare_image.compare_image()
        print image_difference
Priyanshu Chauhan
sumber
Saya tidak mengerti dengan baik python. Tapi apa itu tipe 'commutative_image_diff'? cv.Mat atau double. Jika itu adalah cv.Mat, bandingkan 'commutative_image_diff <self.minimum_commutative_image_diff' bagaimana cara kerjanya atau apa tujuan dari perbandingan ini. Bisakah Anda menjelaskan untuk saya?
BulletRain
2

Sedikit keluar dari topik tetapi berguna adalah numpypendekatan pythonic . Ini kuat dan cepat tetapi hanya membandingkan piksel dan bukan objek atau data yang dikandung gambar (dan ini membutuhkan gambar dengan ukuran dan bentuk yang sama):

Pendekatan yang sangat sederhana dan cepat untuk melakukan ini tanpa openCV dan library apa pun untuk computer vision adalah mengatur susunan gambar

import numpy as np
picture1 = np.random.rand(100,100)
picture2 = np.random.rand(100,100)
picture1_norm = picture1/np.sqrt(np.sum(picture1**2))
picture2_norm = picture2/np.sqrt(np.sum(picture2**2))

Setelah menentukan kedua gambar bernorma (atau matriks), Anda bisa menjumlahkan perkalian gambar yang ingin Anda bandingkan:

1) Jika Anda membandingkan gambar yang serupa, jumlahnya akan menghasilkan 1:

In[1]: np.sum(picture1_norm**2)
Out[1]: 1.0

2) Jika tidak sama, Anda akan mendapatkan nilai antara 0 dan 1 (persentase jika Anda mengalikan dengan 100):

In[2]: np.sum(picture2_norm*picture1_norm)
Out[2]: 0.75389941124629822

Harap perhatikan bahwa jika Anda memiliki gambar berwarna, Anda harus melakukan ini dalam semua 3 dimensi atau hanya membandingkan versi skala abu-abu. Saya sering kali harus membandingkan gambar dalam jumlah besar dengan konten yang berubah-ubah dan itulah cara yang sangat cepat untuk melakukannya.

Franz
sumber
3
hai, saya hanya mengikuti langkah Anda tetapi saya menemukan bahwa bagian normalisasi tidak bisa mendapatkan hasil yang tepat. Hasil akhirnya jauh lebih besar dari 1,0. Ada ide?
G_cy