Як я можу оцінити, наскільки схожі два зображення з OpenCV?


141

Чи підтримує OpenCV порівняння двох зображень, повертаючи якесь значення (можливо, відсоток), яке вказує на схожість цих зображень? Наприклад, 100% буде повернуто, якщо одне і те ж зображення було передано двічі, 0% повернеться, якби зображення були абсолютно іншими.

Я вже читав багато подібних тем тут на StackOverflow. Я також робив досить гуглінг. На жаль, я не зміг придумати задовільну відповідь.


Дивіться також відповіді на сайті stackoverflow.com/questions/4196453/…
B. Ідіть

Відповіді:


208

Це величезна тема, з відповідями з 3 рядків коду до цілих наукових журналів.

Я викладу найпоширеніші такі методи та їх результати.

Порівнюючи гістограми

Один із найпростіших та найшвидших методів. Запропонований десятиліттями тому, як засіб пошуку однозначності зображення. Ідея полягає в тому, що в лісі буде багато зеленого, а людське обличчя - багато рожевого, чи ще чого. Отже, якщо порівнювати дві картинки з лісами, ви отримаєте деяку схожість між гістограмами, оскільки у вас багато зеленого в обох.

Знизу: це занадто спрощено. Банан і пляж будуть виглядати однаково, оскільки обидва жовті.

Метод OpenCV: порівнятиHist ()

Збіг шаблонів

Хороший приклад тут matchTemplate, який знаходить хорошу відповідність . Він поєднує зображення пошуку з тим, на якому здійснюється пошук. Зазвичай використовується для пошуку менших частин зображення у більшій.

Недоліки: вона повертає лише хороші результати з однаковими зображеннями, однакового розміру та орієнтації.

Метод OpenCV: matchTemplate ()

Відповідність функцій

Вважається одним із найефективніших способів пошуку зображень. Ряд функцій витягується із зображення таким чином, що гарантує однакові функції знову будуть розпізнані навіть при повороті, масштабуванні чи перекосі. Витягнуті таким чином функції можна співставити з іншими наборами зображень. Ще одне зображення, що має високу частку характеристик, що відповідають першому, вважається таким, що зображує ту саму сцену.

Пошук гомографії між двома наборами точок дозволить вам також знайти відносну різницю кута зйомки між вихідними зображеннями або величину перекриття.

Є цілий ряд OpenCV підручників / зразків на це, і гарне відео тут . Цьому присвячений цілий модуль OpenCV (features2d).

Недоліки: це може бути повільним. Це не ідеально.


На сайті OpenCV Q&A я говорю про різницю між дескрипторами функцій, які чудові при порівнянні цілих зображень та дескрипторів текстур, які використовуються для ідентифікації об'єктів, таких як обличчя людини чи машини на зображенні.


для порівняння подібних зображень, які містять лише декілька чітких зображень (наприклад, новий об’єкт переміщено в інший вигляд), ви також можете працювати з absdiff codota.com/code/java/methods/org.opencv.core.Core/absdiff Пороговий результат створює маску, яка дозволяє виділити регіони, які змінилися від сцени до сцени.
Макс Ф.

34

Якщо для відповідності однакових зображень (однаковий розмір / орієнтація)

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

Джерело


12

Розв’язання Сема повинно бути достатньо. Я використовував комбінацію різниці гістограм і відповідності шаблонів, оскільки жоден метод не працював для мене у 100% разів. Хоча я приділяв меншому значенню методу гістограми. Ось як я реалізований у простому сценарії python.

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

Я не розумію добре пітон. Але що таке тип "commutative_image_diff"? cv.Mat або подвійний. Якщо це cv.Mat, порівняйте 'commutative_image_diff <self.minimum_commutative_image_diff', як це працює або з якою метою цього порівняння. Ви можете мені пояснити?
BulletRain

1

Трохи поза темою, але корисним є пітонічний numpyпідхід. Його надійний і швидкий, але просто порівнює пікселі, а не об'єкти або дані, які містить зображення (і для цього потрібні зображення однакового розміру і форми):

Дуже простий і швидкий підхід зробити це без openCV та будь-якої бібліотеки для комп'ютерного зору - це нормалізація масивів зображень

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))

Визначивши обидва нормовані зображення (або матриці), ви можете просто підсумувати множення зображень, які ви хочете порівняти:

1) Якщо порівняти подібні малюнки, сума поверне 1:

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

2) Якщо вони не схожі, ви отримаєте значення від 0 до 1 (відсоток, якщо помножити на 100):

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

Зауважте, що якщо у вас є кольорові малюнки, ви повинні робити це у всіх трьох вимірах або просто порівнювати версію з відтінком сірого. Мені часто доводиться порівнювати величезну кількість фотографій з довільним змістом, і це дійсно швидкий спосіб зробити це.


2
привіт, я просто дотримуюся твого кроку, але я виявив, що нормалізація не може отримати належного результату. Кінцевий результат значно перевищує 1,0. Будь-яка ідея?
G_cy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.