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


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

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

4 112

4 ответа:

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

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

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

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

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

метод OpenCV: compareHist ()

согласование шаблона

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

недостатки: он возвращает только хорошие результаты с одинаковыми изображениями, одинаковым размером и ориентацией.
Метод OpenCV: matchTemplate ()

сопоставление объектов

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

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

Если для сопоставления одинаковых изображений (одинакового размера/ориентации )

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

источник

решение Сэма должно быть достаточным. Я использовал комбинацию как разности гистограмм, так и сопоставления шаблонов, потому что ни один метод не работал для меня в 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

немного не по теме, но полезно это для Python 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-х измерениях или просто сравнить версию в оттенках серого. Мне часто приходится сравнивать огромное количество фотографий с произвольным контентом, и это очень быстрый способ сделать так.