Sprawdzanie podobieństw obrazów z OpenCV

Czy OpenCV obsługuje porównanie dwóch obrazów, zwracając jakąś wartość (może procent), która wskazuje, jak podobne są te obrazy? Np. 100% zostanie zwrócone, jeśli ten sam obraz zostanie przekazany dwa razy, 0% zostanie zwrócone, jeśli obrazy będą zupełnie inne.

Przeczytałem już wiele podobnych tematów tutaj na StackOverflow. Też trochę Wygooglowałem. Niestety nie mogłem znaleźć satysfakcjonującej odpowiedzi.

Author: Peter O., 2012-07-18

4 answers

To naprawdę ogromny temat, z odpowiedziami z 3 linii kodu do całych czasopism badawczych.

Przedstawię najczęstsze tego typu techniki i ich wyniki.

Porównywanie histogramów

Jedna z najprostszych i najszybszych metod. Zaproponowany kilkadziesiąt lat temu jako środek do znalezienia podobieństw obrazu. Chodzi o to, że las będzie miał dużo zieleni, a ludzka twarz dużo różu, czy cokolwiek. Więc jeśli porównasz dwa zdjęcia z lasami, dostaniesz trochę simmilarity między histogramami, bo w obu masz dużo zieleni.

Minusy: to zbyt uproszczone. Banan i Plaża będą wyglądać tak samo, ponieważ oba są żółte.

Metoda OpenCV: compareHist ()

Dopasowanie szablonu

Dobry przykład tutaj matchTemplate znalezienie dobrego dopasowania. To convolves obraz wyszukiwania z jednym jest szukaj w. Zwykle jest używany do znajdowania mniejszych części obrazu w większym.

Minusy: to tylko zwraca dobre wyniki z identycznymi obrazami, tym samym rozmiarem i orientacją.
Metoda OpenCV: matchTemplate ()

Dopasowanie funkcji

Uważany za jeden z najskuteczniejszych sposobów wyszukiwania obrazów. Wiele funkcji jest wyodrębnianych z obrazu w sposób, który gwarantuje, że te same funkcje będą ponownie rozpoznawane, nawet gdy zostaną obrócone/skalowane / Przekrzywione. Wyodrębnione w ten sposób funkcje można dopasować do innych zestawów funkcji obrazu. Kolejny obraz, który ma duży udział w rysy w pierwszym z nich najprawdopodobniej przedstawiają ten sam obiekt/scenę. Można go użyć, aby znaleźć względną różnicę w kącie fotografowania między zdjęciami lub ilość nakładania się.

Na tej stronie znajduje się wiele samouczków/sampli OpenCV oraz fajny filmik tutaj. Dedykowany jest mu cały moduł OpenCV (features2d).
Minusy: może być powolny. To nie jest idealne.
 164
Author: Sam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:42

Jeśli dla dopasowania identycznych obrazów (ten sam rozmiar/orientacja)

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

Źródło

 27
Author: Kiran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-04 08:11:56

Rozwiązanie sama powinno wystarczyć. Użyłem kombinacji zarówno różnicy histogramu i dopasowania szablonu, ponieważ żadna metoda nie działała dla mnie w 100% razy. Poświęciłem jednak mniej uwagi metodzie histogramu. Oto jak zaimplementowałem prosty skrypt Pythona.

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
 2
Author: Priyanshu Chauhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-03 13:44:45

Trochę off topic, ale przydatne jest podejście pythonic numpy. Jego solidny i szybki, ale po prostu porównuje piksele, a nie Obiekty lub dane, które zawiera obraz (i wymaga obrazów o tym samym rozmiarze i kształcie): {]}

Bardzo prostym i szybkim podejściem do tego bez openCV i żadnej biblioteki do widzenia komputerowego jest normowanie tablic obrazkowych przez

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

Po zdefiniowaniu obu znormalizowanych obrazów (lub macierzy) można po prostu zsumować przez mnożenie obrazów, które lubisz Porównaj:

1) jeśli porównasz Podobne Zdjęcia, suma zwróci 1:

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

2) Jeśli nie są podobne, otrzymasz wartość między 0 a 1 (procent, jeśli pomnożysz przez 100):

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

Proszę zauważyć, że jeśli masz kolorowe zdjęcia, musisz to zrobić we wszystkich 3 wymiarach lub po prostu porównać wersję szarą. Często muszę porównywać ogromne ilości zdjęć z dowolnymi treściami i jest to naprawdę szybki sposób na to.

 0
Author: Franz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-09 13:44:43