Jak mogę określić ilościowo różnicę między dwoma obrazami?

179

Oto, co chciałbym zrobić:

Robię zdjęcia kamerą internetową w regularnych odstępach czasu. Coś w rodzaju filmu poklatkowego. Jeśli jednak nic się naprawdę nie zmieniło, to znaczy obraz wygląda prawie tak samo, nie chcę przechowywać najnowszej migawki.

Wyobrażam sobie, że istnieje sposób na ilościowe określenie różnicy i musiałbym empirycznie określić próg.

Szukam raczej prostoty niż perfekcji. Używam Pythona.

nośnik
źródło

Odpowiedzi:

269

Główny pomysł

Opcja 1: Załaduj oba obrazy jako tablice ( scipy.misc.imread) i oblicz różnicę elementów (piksel po pikselu). Oblicz normę różnicy.

Opcja 2: załaduj oba obrazy. Obliczyć wektor cech dla każdego z nich (jak histogram). Oblicz odległość między wektorami cech, a nie obrazami.

Jednak najpierw trzeba podjąć pewne decyzje.

pytania

Najpierw powinieneś odpowiedzieć na następujące pytania:

  • Czy obrazy mają ten sam kształt i wymiary?

    Jeśli nie, może być konieczna zmiana ich rozmiaru lub przycięcie. Pomoże w tym biblioteka PIL w Pythonie.

    Jeśli są zrobione z tymi samymi ustawieniami i tym samym urządzeniem, prawdopodobnie są takie same.

  • Czy obrazy są dobrze wyrównane?

    Jeśli nie, możesz najpierw przeprowadzić korelację krzyżową, aby najpierw znaleźć najlepsze dopasowanie. SciPy ma funkcje, które to robią.

    Jeśli aparat i scena są nieruchome, obrazy prawdopodobnie będą dobrze wyrównane.

  • Czy ekspozycja obrazów jest zawsze taka sama? (Czy lekkość / kontrast to to samo?)

    Jeśli nie, możesz znormalizować obrazy.

    Ale bądź ostrożny, w niektórych sytuacjach może to przynieść więcej szkody niż pożytku. Na przykład pojedynczy jasny piksel na ciemnym tle sprawi, że znormalizowany obraz będzie zupełnie inny.

  • Czy informacje o kolorze są ważne?

    Jeśli chcesz zauważyć zmiany kolorów, będziesz mieć wektor wartości kolorów na punkt, zamiast wartości skalarnej, jak na obrazie w skali szarości. Pisząc taki kod, potrzebujesz więcej uwagi.

  • Czy obraz ma wyraźne krawędzie? Czy prawdopodobnie się ruszą?

    Jeśli tak, możesz najpierw zastosować algorytm wykrywania krawędzi (np. Obliczyć gradient za pomocą transformaty Sobela lub Prewitta, zastosować jakiś próg), a następnie porównać krawędzie na pierwszym obrazie z krawędziami na drugim.

  • Czy na obrazie jest szum?

    Wszystkie czujniki zanieczyszczają obraz pewną ilością szumów. Niedrogie czujniki mają większy szum. Przed porównaniem zdjęć warto zastosować pewną redukcję szumów. Rozmycie jest tutaj najprostszym (ale nie najlepszym) podejściem.

  • Jakie zmiany chcesz zauważyć?

    Może to wpłynąć na wybór normy używanej dla różnicy między obrazami.

    Rozważ użycie normy Manhattan (suma wartości bezwzględnych) lub normy zerowej (liczba elementów różna od zera), aby zmierzyć, jak bardzo obraz się zmienił. Pierwsza powie ci, jak bardzo obraz jest wyłączony, druga powie tylko, o ile pikseli się różni.

Przykład

Zakładam, że Twoje obrazy są dobrze wyrównane, mają ten sam rozmiar i kształt, prawdopodobnie z różną ekspozycją. Dla uproszczenia konwertuję je na skalę szarości, nawet jeśli są to obrazy kolorowe (RGB).

Będziesz potrzebować tych importów:

import sys

from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average

Główna funkcja, odczyt dwóch obrazów, konwersja do skali szarości, porównywanie i drukowanie wyników:

def main():
    file1, file2 = sys.argv[1:1+2]
    # read images as 2D arrays (convert to grayscale for simplicity)
    img1 = to_grayscale(imread(file1).astype(float))
    img2 = to_grayscale(imread(file2).astype(float))
    # compare
    n_m, n_0 = compare_images(img1, img2)
    print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
    print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size

Jak porównać. img1i img2są tutaj tablice 2D SciPy:

def compare_images(img1, img2):
    # normalize to compensate for exposure difference, this may be unnecessary
    # consider disabling it
    img1 = normalize(img1)
    img2 = normalize(img2)
    # calculate the difference and its norms
    diff = img1 - img2  # elementwise for scipy arrays
    m_norm = sum(abs(diff))  # Manhattan norm
    z_norm = norm(diff.ravel(), 0)  # Zero norm
    return (m_norm, z_norm)

Jeśli plik jest obrazem kolorowym, imreadzwraca tablicę 3D, średnie kanały RGB (ostatnia oś tablicy) w celu uzyskania intensywności. Nie trzeba tego robić w przypadku obrazów w skali szarości (np. .pgm):

def to_grayscale(arr):
    "If arr is a color image (3D array), convert it to grayscale (2D array)."
    if len(arr.shape) == 3:
        return average(arr, -1)  # average over the last axis (color channels)
    else:
        return arr

Normalizacja jest trywialna, możesz wybrać normalizację do [0,1] zamiast [0,255]. arrjest tablicą SciPy, więc wszystkie operacje są oparte na elementach:

def normalize(arr):
    rng = arr.max()-arr.min()
    amin = arr.min()
    return (arr-amin)*255/rng

Uruchom mainfunkcję:

if __name__ == "__main__":
    main()

Teraz możesz umieścić to wszystko w skrypcie i uruchomić na dwóch obrazach. Jeśli porównamy obraz do samego siebie, nie ma różnicy:

$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0

Jeśli rozmyjemy obraz i porównamy z oryginałem, jest pewna różnica:

$ python compare.py one.jpg one-blurred.jpg 
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0

PS Cały skrypt compare.py .

Aktualizacja: odpowiednie techniki

Ponieważ pytanie dotyczy sekwencji wideo, w której klatki są prawdopodobnie prawie takie same, a szukasz czegoś niezwykłego, chciałbym wspomnieć o kilku alternatywnych podejściach, które mogą być odpowiednie:

  • odejmowanie i segmentacja tła (w celu wykrycia obiektów pierwszego planu)
  • rzadki przepływ optyczny (do wykrywania ruchu)
  • porównywanie histogramów lub innych statystyk zamiast obrazów

Zdecydowanie polecam zajrzeć do książki „Learning OpenCV”, Rozdział 9 (Części obrazu i segmentacja) i 10 (Śledzenie i ruch). Pierwsza uczy metody odejmowania tła, druga podaje pewne informacje o metodach przepływu optycznego. Wszystkie metody są zaimplementowane w bibliotece OpenCV. Jeśli używasz Pythona, sugeruję użycie OpenCV ≥ 2.3 i jego cv2modułu Python.

Najprostsza wersja odejmowania tła:

  • poznaj średnią wartość μ i odchylenie standardowe σ dla każdego piksela tła
  • porównaj aktualne wartości pikseli z zakresem (μ-2σ, μ + 2σ) lub (μ-σ, μ + σ)

Bardziej zaawansowane wersje uwzględniają szeregi czasowe dla każdego piksela i obsługują sceny niestatyczne (jak ruchome drzewa czy trawa).

Ideą przepływu optycznego jest pobranie dwóch lub więcej klatek i przypisanie wektora prędkości każdemu pikselowi (gęsty przepływ optyczny) lub niektórym z nich (rzadki przepływ optyczny). Aby oszacować rzadki przepływ optyczny, możesz użyć metody Lucas-Kanade (jest również zaimplementowana w OpenCV). Oczywiście, jeśli jest duży przepływ (wysoka średnia powyżej maksymalnych wartości pola prędkości), to coś się porusza w kadrze, a kolejne obrazy są bardziej różne.

Porównanie histogramów może pomóc w wykryciu nagłych zmian między kolejnymi klatkami. Takie podejście zastosowano w Courbon i in., 2010 :

Podobieństwo kolejnych klatek. Mierzona jest odległość między dwoma kolejnymi klatkami. Jeśli jest zbyt wysoka, oznacza to, że druga klatka jest uszkodzona, a tym samym obraz jest eliminowany. Odległość Kullbacka – Leiblera lub wzajemna entropia na histogramach dwóch klatek:

$$ d (p, q) = \ sum_i p (i) \ log (p (i) / q (i)) $$

gdzie p i q to histogramy klatek. Próg jest ustalony na 0,2.

śastanin
źródło
Dostaję RuntimeWarning: invalid value encountered in double_scalarsonline 44 ( return (arr-amin)*255/rng) i ValueError: array must not contain infs or NaNsonline 30 ( z_norm = norm(diff.ravel(), 0))
BioGeek
@BioGeek, czyli jeśli rngrówna się zero. Po prostu dodaj czek i ustawrng = 1
haisi
76

Proste rozwiązanie:

Zakoduj obraz jako jpeg i poszukaj znaczącej zmiany w rozmiarze pliku .

Zaimplementowałem coś podobnego w przypadku miniatur wideo i odniosłem duży sukces i skalowalność.

keparo
źródło
3
Jest to bardzo łatwe, proste rozwiązanie i znacznie lepsze niż jakiekolwiek porównanie pikseli. Jeśli na obrazie z kamery internetowej jest trochę szumu lub jeśli obraz jest przesunięty nawet o jeden piksel, bezpośrednie porównanie wykryje wszystkie te bezsensowne zmiany. Bardziej niezawodnym podejściem byłoby obliczenie dyskretnej transformacji kosinusowej, a następnie porównanie obrazów w dziedzinie częstotliwości. Korzystanie z kompresji JPEG w ten sposób zapewnia większość korzyści bez zagłębiania się w teorię Fouriera.
AndrewF,
Lubię to. Chociaż inne rozwiązania również działają, ma to wielką zaletę w typowych sytuacjach: co zrobić, jeśli nie chcesz zapisywać „podstawowego” obrazu? po prostu zapisz rozmiar pliku jako hash, a następnie porównaj same liczby z odejmowaniem. W moim przypadku mam 4 obrazy, jeden z nich jest bardzo podobny, a pozostałe 3 są zupełnie inne. Po prostu skaluj do tych samych wymiarów, do jpg i odejmuj. Bardzo miły.
Diego Andrés Díaz Espinoza
60

Możesz porównać dwa obrazy za pomocą funkcji z PIL .

import Image
import ImageChops

im1 = Image.open("splash.png")
im2 = Image.open("splash2.png")

diff = ImageChops.difference(im2, im1)

Obiekt diff to obraz, w którym każdy piksel jest wynikiem odjęcia wartości koloru tego piksela z drugiego obrazu od pierwszego obrazu. Używając obrazu porównawczego, możesz zrobić kilka rzeczy. Najprostsza to diff.getbbox()funkcja. Pokaże Ci minimalny prostokąt zawierający wszystkie zmiany między dwoma obrazami.

Prawdopodobnie możesz zaimplementować aproksymacje innych wymienionych tutaj rzeczy, używając również funkcji z PIL.

elifiner
źródło
2
Chcę zapisać obraz różnicy. oznacza obiekt diff, który zawiera różnicę obrazów. jak mam to zapisać?
Sagar
2
@Anthony możesz wywołać metodę save () na obiekcie diff, podając nazwę obrazu. w ten sposób: diff.save ("diff.png") zapisze dla ciebie obraz różnicy.
Sagar
20

Dwie popularne i stosunkowo proste metody to: (a) odległość euklidesowa już zasugerowana lub (b) znormalizowana korelacja krzyżowa. Znormalizowana korelacja krzyżowa wydaje się być zauważalnie bardziej odporna na zmiany oświetlenia niż prosta korelacja krzyżowa. Wikipedia podaje wzór na znormalizowaną korelację krzyżową . Istnieją również bardziej wyrafinowane metody, ale wymagają one nieco więcej pracy.

Używając składni podobnej do numpy,

dist_euclidean = sqrt (suma ((i1 - i2) ^ 2)) / i1.size

dist_manhattan = suma (abs (i1 - i2)) / i1. rozmiar

dist_ncc = suma ((i1 - średnia (i1)) * (i2 - średnia (i2))) / (
  (i1.size - 1) * stdev (i1) * stdev (i2))

zakładając, że i1i i2są tablice obraz 2D w skali szarości.

Panie Fooz
źródło
3
Funkcje korelacji krzyżowej obrazu są wbudowane w SciPy ( docs.scipy.org/doc/scipy/reference/generated/… ), a szybka wersja wykorzystująca FFT jest dostępna w stsci python ( stsci.edu/resources/software_hardware/pyraf/ stsci_python )
endolit
14

Błaha rzecz do wypróbowania:

Ponownie próbkuj oba obrazy do małych miniatur (np. 64 x 64) i porównaj miniatury piksel po pikselu z określonym progiem. Jeśli oryginalne obrazy są prawie takie same, ponownie próbkowane miniatury będą bardzo podobne lub nawet dokładnie takie same. Ta metoda eliminuje szumy, które mogą pojawiać się zwłaszcza w słabo oświetlonych scenach. Może być nawet lepiej, jeśli przejdziesz do skali szarości.

Ates Goral
źródło
ale jak porównać piksele?
przewoźnik
Gdy masz już miniatury, możesz po prostu porównać piksele jeden po drugim. Możesz obliczyć „odległość” wartości RGB, jeśli pracujesz w kolorze lub po prostu różnicę między odcieniami szarości, jeśli jesteś w skali szarości.
Ates Goral
1
„porównaj piksele jeden po drugim”. Co to znaczy? Czy test powinien zakończyć się niepowodzeniem, jeśli JEDEN z testów 64 ^ 2 pikseli na piksel nie powiedzie się?
Federico A. Ramponi
Przez „porównywanie miniatur piksel po pikselu z określonym progiem” miałem na myśli wymyślenie rozmytego algorytmu do porównywania pikseli. Jeśli obliczona różnica (zależna od algorytmu rozmytego) przekracza pewien próg, obrazy „nie są takie same”.
Ates Goral
1
Bardzo prosty przykład, bez "algorytmu rozmytego": równoległa pętla przez każdy piksel (porównaj piksel nr n obrazu nr 1 z pikselem nr n obrazu nr 2) i dodaj różnicę wartości do zmiennej
mk12
7

Odnoszę się konkretnie do pytania, jak obliczyć, jeśli są one „wystarczająco różne”. Zakładam, że możesz dowiedzieć się, jak odejmować piksele jeden po drugim.

Najpierw wziąłbym kilka zdjęć, na których nic się nie zmienia, i ustaliłbym maksymalną wartość, o jaką zmienia się każdy piksel tylko z powodu różnic w przechwytywaniu, szumu w systemie obrazowania, artefaktów kompresji JPEG i chwilowych zmian w oświetleniu. . Być może okaże się, że można się spodziewać różnic 1 lub 2 bitów, nawet jeśli nic się nie porusza.

Następnie do „prawdziwego” testu potrzebujesz takiego kryterium:

  • to samo, jeśli do P pikseli różni się nie więcej niż E.

Tak więc, być może, jeśli E = 0,02, P = 1000, oznaczałoby to (w przybliżeniu), że byłoby „inne”, gdyby jeden piksel zmienił się o więcej niż ~ 5 jednostek (zakładając obrazy 8-bitowe) lub jeśli więcej niż 1000 piksele miały w ogóle jakiekolwiek błędy.

Ma to służyć głównie jako dobra technika „segregacji” umożliwiająca szybką identyfikację obrazów, które są wystarczająco blisko, aby nie wymagały dalszego badania. Obrazy, które „zawodzą”, mogą zatem być bardziej skomplikowaną / kosztowną techniką, która nie dawałaby fałszywych alarmów, gdyby na przykład kamera trochę się trzęsła lub była bardziej odporna na zmiany oświetlenia.

Prowadzę projekt open source, OpenImageIO , który zawiera narzędzie o nazwie „idiff”, które porównuje różnice z takimi progami (właściwie nawet bardziej rozbudowanymi). Nawet jeśli nie chcesz używać tego oprogramowania, możesz zajrzeć do źródła, aby zobaczyć, jak to zrobiliśmy. Jest dość często używany komercyjnie, a ta technika progowania została opracowana, abyśmy mogli mieć zestaw testowy do renderowania i oprogramowania do przetwarzania obrazu, z „obrazami referencyjnymi”, które mogą różnić się w zależności od platformy lub gdy wprowadziliśmy drobne poprawki tha algorytmów, więc chcieliśmy wykonać operację „dopasowanie w granicach tolerancji”.

Larry Gritz
źródło
6

Miałem podobny problem w pracy, przerabiałem nasz punkt końcowy transformacji obrazu i chciałem sprawdzić, czy nowa wersja daje takie same lub prawie takie same dane wyjściowe jak stara wersja. Więc napisałem to:

https://github.com/nicolashahn/diffimg

Działający na obrazach o tym samym rozmiarze i na poziomie piksela mierzy różnicę wartości na każdym kanale: R, G, B (, A), bierze średnią różnicę tych kanałów, a następnie uśrednia różnicę wszystkie piksele i zwraca współczynnik.

Na przykład w przypadku obrazu 10x10 białych pikseli i tego samego obrazu, ale jeden piksel zmienił się na czerwony, różnica w tym pikselu wynosi 1/3 lub 0,33 ... (RGB 0,0,0 vs 255,0,0 ), a dla wszystkich innych pikseli wynosi 0. Przy 100 pikselach łącznie 0,33 ... / 100 = ~ 0,33% różnicy w obrazie.

Wierzę, że to działałoby idealnie dla projektu OP (zdaję sobie sprawę, że jest to bardzo stary post, ale publikacja dla przyszłych StackOverflowers, którzy również chcą porównać obrazy w Pythonie).

nicolashahn
źródło
5

Większość udzielonych odpowiedzi nie dotyczy poziomów oświetlenia.

Przed dokonaniem porównania normalizowałbym obraz do standardowego poziomu światła.

Loren Pechtel
źródło
Jeśli robisz okresowe zdjęcia i rozróżniasz sąsiednie pary, prawdopodobnie możesz sobie pozwolić na zatrzymanie pierwszego z nich, gdy ktoś włączy światło.
walkytalky
5

Kolejny fajny, prosty sposób na zmierzenie podobieństwa między dwoma obrazami:

import sys
from skimage.measure import compare_ssim
from skimage.transform import resize
from scipy.ndimage import imread

# get two images - resize both to 1024 x 1024
img_a = resize(imread(sys.argv[1]), (2**10, 2**10))
img_b = resize(imread(sys.argv[2]), (2**10, 2**10))

# score: {-1:1} measure of the structural similarity between the images
score, diff = compare_ssim(img_a, img_b, full=True)
print(score)

Jeśli inni są zainteresowani skuteczniejszym sposobem porównywania podobieństw obrazów, przygotowałem samouczek i aplikację internetową do pomiaru i wizualizacji podobnych obrazów za pomocą Tensorflow.

duhaime
źródło
3
Tak, skimagejest naprawdę przyjemny w użyciu dla tej aplikacji. Używam from skimage.measure import compare_ssim, compare_msedużo. skimage.measure docs .
ximiki
3

Czy widzieliście już pytanie o algorytm wyszukiwania podobnych obrazów ? Sprawdź to, aby zobaczyć sugestie.

Sugerowałbym transformację falkową twoich ramek (napisałem do tego rozszerzenie C używając transformacji Haara); następnie porównując indeksy największych (proporcjonalnie) współczynników falkowych między dwoma obrazami, powinieneś otrzymać liczbowe przybliżenie podobieństwa.

tzot
źródło
2

Przepraszam, jeśli jest już za późno na odpowiedź, ale ponieważ robię coś podobnego, pomyślałem, że mógłbym w jakiś sposób wnieść swój wkład.

Może z OpenCV mógłbyś użyć dopasowania szablonu. Zakładając, że używasz kamery internetowej, jak powiedziałeś:

  1. Uprość obrazy (może progowanie?)
  2. Zastosuj dopasowanie szablonu i sprawdź wartość max_val za pomocą minMaxLoc

Wskazówka: max_val (lub min_val w zależności od użytej metody) zwróci liczby, duże liczby. Aby uzyskać różnicę w procentach, użyj szablonu dopasowanego do tego samego obrazu - wynik będzie 100%.

Pseudo kod na przykładzie:

previous_screenshot = ...
current_screenshot = ...

# simplify both images somehow

# get the 100% corresponding value
res = matchTemplate(previous_screenshot, previous_screenshot, TM_CCOEFF)
_, hundred_p_val, _, _ = minMaxLoc(res)

# hundred_p_val is now the 100%

res = matchTemplate(previous_screenshot, current_screenshot, TM_CCOEFF)
_, max_val, _, _ = minMaxLoc(res)

difference_percentage = max_val / hundred_p_val

# the tolerance is now up to you

Mam nadzieję, że to pomoże.

zanfranceschi
źródło
1

Odległość poruszających się ziemią może być dokładnie tym, czego potrzebujesz. To może być odrobinę ciężki do realizacji w czasie rzeczywistym chociaż.

shoosh
źródło
Nie wydaje mi się, żeby ta odpowiedź ładnie odpowiadała: „Szukam raczej prostoty niż perfekcji. Używam Pythona”.
PilouPili
Myślę, że ponieważ ten wątek z pytaniami ma duży ruch, a tytuł, który przyciąga większość widzów, dotyczy ilościowego określenia różnicy między dwoma obrazami, ma tutaj wartość.
Danoram
1

A co z obliczeniem odległości Manhattanu dla dwóch obrazów. To daje n * n wartości. Następnie możesz zrobić coś w rodzaju średniej wiersza, aby zredukować do n wartości i wykonać funkcję, aby uzyskać jedną pojedynczą wartość.

Tobias
źródło
1

Miałem dużo szczęścia ze zdjęciami jpg zrobionymi tym samym aparatem na statywie poprzez (1) znaczne uproszczenie (np. Przejście od szerokości 3000 do 100 pikseli lub nawet mniej) (2) spłaszczenie każdej tablicy jpg w jedną wektor (3) parami skorelowane obrazy sekwencyjne z prostym algorytmem korelacji w celu uzyskania współczynnika korelacji (4) współczynnik korelacji do kwadratu, aby uzyskać r-kwadrat (tj. ułamek zmienności na jednym obrazie wyjaśniony zmiennością na następnym) (5) ogólnie w mojej aplikacji jeśli r-kwadrat <0,9, mówię, że te dwa obrazy są różne i coś wydarzyło się pomiędzy.

To jest solidne i szybkie w mojej implementacji (Mathematica 7)

Warto pobawić się częścią obrazu, która Cię interesuje, i skupić się na tym, przycinając wszystkie obrazy do tego małego obszaru, w przeciwnym razie przeoczysz istotną zmianę z dala od aparatu.

Nie wiem, jak używać Pythona, ale czy na pewno robi też korelacje, nie?

Roman Dial
źródło
1

możesz obliczyć histogram obu obrazów, a następnie obliczyć współczynnik Bhattacharyya , jest to bardzo szybki algorytm i użyłem go do wykrycia zmian strzałów w filmie o krykieta (w C przy użyciu openCV)

vishalv2050
źródło
Czy możesz obliczyć współczynnik na samych obrazach?
endolit
Będziesz musiał obliczyć histogramy dla obrazów (z rozmiarem przedziału histogramu zgodnie z wymaganiami).
vishalv2050
1

Sprawdź, jak Haar Wavelets są implementowane przez isk-daemon . Możesz użyć jego kodu imgdb C ++, aby obliczyć różnicę między obrazami w locie:

isk-daemon to serwer bazy danych typu open source, który umożliwia dodawanie opartego na treści (wizualnego) wyszukiwania obrazów do dowolnej witryny lub oprogramowania związanego z obrazami.

Technologia ta pozwala użytkownikom dowolnej witryny internetowej lub oprogramowania związanego z obrazami na szkicowanie na widżecie, który obraz chcą znaleźć, a witryna odpowiada na najbardziej podobne obrazy lub po prostu prosi o więcej podobnych zdjęć na każdej stronie ze szczegółami obrazu.

Ricardo Cabral
źródło
1

Miałem ten sam problem i napisałem prosty moduł Pythona, który porównuje dwa obrazy tego samego rozmiaru za pomocą ImageChops poduszki, aby utworzyć czarno-biały obraz różnicowy i podsumowuje wartości histogramu.

Możesz uzyskać ten wynik bezpośrednio lub wartość procentową w porównaniu do pełnego porównania czerni i bieli.

Zawiera również prostą funkcję is_equal, z możliwością podania rozmytego progu pod (i włączając) obraz przechodzi jako równy.

Podejście nie jest zbyt wyszukane, ale może być przydatne dla innych osób borykających się z tym samym problemem.

https://pypi.python.org/pypi/imgcompare/

datenhahn
źródło
1

Nieco bardziej pryncypialnym podejściem jest użycie globalnego deskryptora do porównywania obrazów, takich jak GIST lub CENTRIST. Funkcja skrótu, jak opisano tutaj , również zapewnia podobne rozwiązanie.

Felix Goldberg
źródło
1
import os
from PIL import Image
from PIL import ImageFile
import imagehash
  
#just use to the size diferent picture
def compare_image(img_file1, img_file2):
    if img_file1 == img_file2:
        return True
    fp1 = open(img_file1, 'rb')
    fp2 = open(img_file2, 'rb')

    img1 = Image.open(fp1)
    img2 = Image.open(fp2)

    ImageFile.LOAD_TRUNCATED_IMAGES = True
    b = img1 == img2

    fp1.close()
    fp2.close()

    return b





#through picturu hash to compare
def get_hash_dict(dir):
    hash_dict = {}
    image_quantity = 0
    for _, _, files in os.walk(dir):
        for i, fileName in enumerate(files):
            with open(dir + fileName, 'rb') as fp:
                hash_dict[dir + fileName] = imagehash.average_hash(Image.open(fp))
                image_quantity += 1

    return hash_dict, image_quantity

def compare_image_with_hash(image_file_name_1, image_file_name_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.
    recommend to use
    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_1 = None
    hash_2 = None
    with open(image_file_name_1, 'rb') as fp:
        hash_1 = imagehash.average_hash(Image.open(fp))
    with open(image_file_name_2, 'rb') as fp:
        hash_2 = imagehash.average_hash(Image.open(fp))
    dif = hash_1 - hash_2
    if dif < 0:
        dif = -dif
    if dif <= max_dif:
        return True
    else:
        return False


def compare_image_dir_with_hash(dir_1, dir_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.

    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_dict_1, image_quantity_1 = get_hash_dict(dir_1)
    hash_dict_2, image_quantity_2 = get_hash_dict(dir_2)

    if image_quantity_1 > image_quantity_2:
        tmp = image_quantity_1
        image_quantity_1 = image_quantity_2
        image_quantity_2 = tmp

        tmp = hash_dict_1
        hash_dict_1 = hash_dict_2
        hash_dict_2 = tmp

    result_dict = {}

    for k in hash_dict_1.keys():
        result_dict[k] = None

    for dif_i in range(0, max_dif + 1):
        have_none = False

        for k_1 in result_dict.keys():
            if result_dict.get(k_1) is None:
                have_none = True

        if not have_none:
            return result_dict

        for k_1, v_1 in hash_dict_1.items():
            for k_2, v_2 in hash_dict_2.items():
                sub = (v_1 - v_2)
                if sub < 0:
                    sub = -sub
                if sub == dif_i and result_dict.get(k_1) is None:
                    result_dict[k_1] = k_2
                    break
    return result_dict


def main():
    print(compare_image('image1\\815.jpg', 'image2\\5.jpg'))
    print(compare_image_with_hash('image1\\815.jpg', 'image2\\5.jpg', 7))
    r = compare_image_dir_with_hash('image1\\', 'image2\\', 10)
    for k in r.keys():
        print(k, r.get(k))


if __name__ == '__main__':
    main()
  • wynik:

    Fałsz
    True
    image2 \ 5.jpg image1 \ 815.jpg
    image2 \ 6.jpg image1 \ 819.jpg
    image2 \ 7.jpg image1 \ 900.jpg
    image2 \ 8.jpg image1 \ 998.jpg
    image2 \ 9.jpg image1 \ 1012 .jpg

  • przykładowe zdjęcia:

    • 815.jpg
      815.jpg

    • 5.jpg
      5.jpg

Administrator
źródło
0

Myślę, że można po prostu obliczyć odległość euklidesową (tj. Sqrt (suma kwadratów różnic, piksel po pikselu)) między luminancją dwóch obrazów i uznać je za równe, jeśli mieści się poniżej jakiegoś empirycznego progu. I lepiej zrób to opakowując funkcję C.

Federico A. Ramponi
źródło
0

Istnieje wiele wskaźników służących do oceny, czy dwa obrazy wyglądają / jak wyglądają.

Nie będę się tutaj rozpisywał, bo myślę, że powinien to być problem naukowy inny niż techniczny.

Ogólnie rzecz biorąc, pytanie dotyczy postrzegania obrazów przez człowieka, więc każdy algorytm ma swoje wsparcie dla cech ludzkiego układu wzrokowego.

Klasyczne podejścia to:

Predyktor widocznych różnic: algorytm oceny wierności obrazu ( https://www.spiedigitallibrary.org/conference-proceedings-of-spie/1666/0000/Visible-differences-predictor--an-algorithm-for-the- assessment-of / 10.1117 / 12.135952.short? SSO = 1 )

Ocena jakości obrazu: od widoczności błędów do podobieństwa strukturalnego ( http://www.cns.nyu.edu/pub/lcv/wang03-reprint.pdf )

FSIM: indeks podobieństwa funkcji do oceny jakości obrazu ( https://www4.comp.polyu.edu.hk/~cslzhang/IQA/TIP_IQA_FSIM.pdf )

Wśród nich SSIM (ocena jakości obrazu: od widoczności błędów do podobieństwa strukturalnego) jest najłatwiejszy do obliczenia, a jego narzut jest również niewielki, jak podano w innym artykule „Ocena jakości obrazu w oparciu o podobieństwo gradientu” ( https: //www.semanticscholar .org / papier / Ocena-jakości-obrazu-na-podstawie-gradientu-Liu-Lin / 2b819bef80c02d5d4cb56f27b202535e119df988 ).

Istnieje wiele innych podejść. Spójrz na Google Scholar i wyszukaj coś takiego jak „różnica wizualna”, „ocena jakości obrazu” itp., Jeśli jesteś zainteresowany / naprawdę zależy Ci na sztuce.

cyfex
źródło
0

Istnieje proste i szybkie rozwiązanie za pomocą numpy, obliczając średni kwadratowy błąd:

before = np.array(get_picture())
while True:
    now = np.array(get_picture())
    MSE = np.mean((now - before)**2)

    if  MSE > threshold:
        break

    before = now
Arian Soltani
źródło