Jak mogę ocenić, jak podobne są dwa obrazy w OpenCV?

141

Czy OpenCV obsługuje porównanie dwóch obrazów, zwracając pewną wartość (może procent), która wskazuje, jak podobne są te obrazy? Np. 100% zostałoby zwrócone, gdyby ten sam obraz został przesłany dwukrotnie, 0% zostałoby zwrócone, gdyby obrazy były zupełnie inne.

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

Boris
źródło
Zobacz także odpowiedzi na stackoverflow.com/questions/4196453/ ...
B. Idź

Odpowiedzi:

208

To obszerny temat, zawierający odpowiedzi z 3 linii kodu na całe magazyny naukowe.

Przedstawię najpopularniejsze takie techniki i ich wyniki.

Porównanie histogramów

Jedna z najprostszych i najszybszych metod. Proponowane dziesiątki lat temu jako sposób na znalezienie podobieństw w obrazach. Chodzi o to, że las będzie miał dużo zieleni, a ludzka twarz dużo różu lub cokolwiek innego. Jeśli więc porównasz dwa zdjęcia z lasami, uzyskasz pewne podobieństwa między histogramami, ponieważ w obu jest dużo zieleni.

Wada: to jest zbyt uproszczone. Banan i plaża będą wyglądać tak samo, ponieważ obie są żółte.

Metoda OpenCV: compareHist ()

Dopasowywanie wzorców

Dobry przykład tutaj matchTemplate znajdujący dobre dopasowanie . Łączy szukany obraz z tym, w który jest przeszukiwany. Zwykle jest używany do znajdowania mniejszych części obrazu w większym.

Wady: zwraca dobre wyniki tylko z identycznymi obrazami, tym samym rozmiarem i orientacją.

Metoda OpenCV: matchTemplate ()

Dopasowanie funkcji

Uważany za jeden z najskuteczniejszych sposobów wyszukiwania obrazów. Z obrazu wyodrębnia się szereg funkcji w sposób gwarantujący, że te same cechy zostaną ponownie rozpoznane nawet po obróceniu, skalowaniu lub pochyleniu. Funkcje wyodrębnione w ten sposób można dopasować do innych zestawów funkcji obrazu. Uważa się, że inny obraz, który ma duży odsetek cech pasujących do pierwszego, przedstawia tę samą scenę.

Znalezienie homografii między dwoma zestawami punktów pozwoli Ci również znaleźć względną różnicę w kącie fotografowania między oryginalnymi obrazami lub stopniem nakładania się.

Istnieje wiele samouczków / próbek OpenCV na ten temat i fajny film tutaj . Dedykowany jest do niego cały moduł OpenCV (features2d).

Wady: może działać wolno. To nie jest doskonałe.


Na stronie z pytaniami i odpowiedziami OpenCV mówię o różnicy między deskryptorami cech, które są świetne przy porównywaniu całych obrazów i deskryptorów tekstur, które są używane do identyfikacji obiektów, takich jak ludzkie twarze lub samochody na obrazie.

Sam
źródło
aby porównać podobne obrazy, które mają tylko kilka różnych obrazów (np. nowy obiekt przeniesiony do tego samego widoku), możesz również pracować z absdiff codota.com/code/java/methods/org.opencv.core.Core/absdiff Ograniczanie wyniku tworzy maskę, która pozwala wyróżnić regiony, które zmieniały się w kolejnych scenach.
Max F.
34

Jeśli w celu 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

Kiran
źródło
12

Rozwiązanie Sama powinno wystarczyć. Użyłem kombinacji różnicy histogramu i dopasowania szablonu, ponieważ żadna metoda nie działała dla mnie w 100% przypadków. Mniejsze znaczenie przypisałem jednak metodzie histogramu. Oto jak zaimplementowałem w prostym skrypcie 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
Priyanshu Chauhan
źródło
Nie rozumiem dobrze Pythona. Ale co to jest typ „commutative_image_diff”? cv.Mat lub double. Jeśli jest to cv.Mat, porównaj „commutative_image_diff <self.minimum_commutative_image_diff”, jak to działa lub jaki jest cel tego porównania. Czy możesz mi to wyjaśnić?
BulletRain
1

Trochę poza tematem, ale przydatne jest numpypodejście pythonowe . Jest 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 zrobienia tego bez openCV i jakiejkolwiek biblioteki do wizji komputerowej jest znormalizowanie tablic obrazów 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żesz po prostu zsumować mnożenie obrazów, które chcesz porównać:

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ść od 0 do 1 (procent, jeśli pomnożymy przez 100):

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

Zwróć uwagę, że jeśli masz kolorowe zdjęcia, musisz to zrobić we wszystkich 3 wymiarach lub po prostu porównać wersję w odcieniach szarości. Często muszę porównywać ogromne ilości zdjęć z dowolną zawartością i to naprawdę szybki sposób na zrobienie tego.

Franz
źródło
2
cześć, po prostu podążam za twoim krokiem, ale stwierdziłem, że część normalizacji nie może uzyskać właściwego wyniku. Ostateczny wynik jest znacznie większy niż 1,0. Dowolny pomysł?
G_cy