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ć. img1
i img2
są 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, imread
zwraca 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]. arr
jest 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 main
funkcję:
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 cv2
moduł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:
gdzie p i q to histogramy klatek. Próg jest ustalony na 0,2.