Проверка изображений на сходство с OpenCV

144

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

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

Борис
источник
См. Также ответы на stackoverflow.com/questions/4196453/…
B. Go

Ответы:

214

Это огромная тема, на которую можно найти ответы от трех строк кода до целых исследовательских журналов.

Я выделю наиболее распространенные такие приемы и их результаты.

Сравнение гистограмм

Один из самых простых и быстрых способов. Предложено несколько десятилетий назад как средство поиска сходства изображений. Идея состоит в том, что в лесу будет много зеленого, а на человеческом лице - розового или чего-то еще. Итак, если вы сравните два изображения с лесами, вы увидите некоторое сходство между гистограммами, потому что на обоих много зеленого.

Обратная сторона: это слишком упрощенно. Банан и пляж будут выглядеть одинаково, поскольку оба они желтые.

Метод OpenCV: compareHist ()

Соответствие шаблонов

Хороший пример здесь matchTemplate поиска подходящего совпадения . Он сворачивает поисковое изображение с тем, по которому выполняется поиск. Обычно он используется, чтобы найти меньшие части изображения в большом.

Недостатки: хорошие результаты получаются только с идентичными изображениями, одинаковым размером и ориентацией.

Метод OpenCV: matchTemplate ()

Соответствие функций

Считается одним из самых эффективных способов поиска изображений. Некоторые функции извлекаются из изображения таким образом, чтобы гарантировать повторное распознавание тех же функций даже при повороте, масштабировании или перекосе. Элементы, извлеченные таким образом, могут быть сопоставлены с другими наборами функций изображения. Считается, что другое изображение с высокой долей признаков, совпадающих с первым, изображает ту же сцену.

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

Есть целый ряд OpenCV учебников / образцов на это, и хорошее видео здесь . Ему посвящен целый модуль OpenCV (features2d).

Минусы: это может быть медленным. Это не идеально.


На сайте вопросов и ответов OpenCV я говорю о разнице между дескрипторами функций, которые отлично подходят при сравнении целых изображений и дескрипторов текстур, которые используются для идентификации таких объектов, как лица людей или автомобили на изображении.

Сэм
источник
для сравнения похожих изображений, в которых есть только несколько отдельных изображений (например, новый объект, перемещенный в то же представление), вы также можете работать с 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
}

Источник

Kiran
источник
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 или double. Если это cv.Mat, сравните 'commutative_image_diff <self.minimum_commutative_image_diff', как это работает или какова цель этого сравнения. Вы можете мне объяснить?
BulletRain,
2

Немного не по теме, но полезен питонический 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

Обратите внимание, что если у вас есть цветные изображения, вы должны сделать это во всех трех измерениях или просто сравнить версию в оттенках серого. Мне часто приходится сравнивать огромное количество изображений с произвольным содержанием, и это действительно быстрый способ сделать это.

Франц
источник
3
привет, я просто следую вашему шагу, но я обнаружил, что часть нормализации не может получить должный результат. Конечный результат намного больше 1.0. Любая идея?
G_cy