Grund Idee
Option 1: Laden Sie beide Bilder als Arrays ( scipy.misc.imread
) und berechnen Sie eine elementweise Differenz (Pixel für Pixel). Berechnen Sie die Norm der Differenz.
Option 2: Laden Sie beide Bilder. Berechnen Sie für jeden einen Merkmalsvektor (wie ein Histogramm). Berechnen Sie den Abstand zwischen Merkmalsvektoren anstelle von Bildern.
Zunächst müssen jedoch einige Entscheidungen getroffen werden.
Fragen
Sie sollten diese Fragen zuerst beantworten:
Haben Bilder die gleiche Form und Dimension?
Wenn nicht, müssen Sie möglicherweise die Größe ändern oder sie zuschneiden. Die PIL-Bibliothek hilft dabei in Python.
Wenn sie mit denselben Einstellungen und demselben Gerät aufgenommen werden, sind sie wahrscheinlich gleich.
Sind die Bilder gut ausgerichtet?
Wenn nicht, möchten Sie möglicherweise zuerst eine Kreuzkorrelation ausführen, um zuerst die beste Ausrichtung zu finden. SciPy hat Funktionen, um dies zu tun.
Wenn die Kamera und die Szene stillstehen, sind die Bilder wahrscheinlich gut ausgerichtet.
Ist die Belichtung der Bilder immer gleich? (Ist Helligkeit / Kontrast gleich?)
Wenn nicht, möchten Sie möglicherweise Bilder normalisieren .
Aber seien Sie vorsichtig, in manchen Situationen kann dies mehr falsch als gut sein. Beispielsweise macht ein einzelnes helles Pixel auf einem dunklen Hintergrund das normalisierte Bild sehr unterschiedlich.
Ist Farbinformation wichtig?
Wenn Sie Farbänderungen bemerken möchten, haben Sie einen Vektor mit Farbwerten pro Punkt anstelle eines Skalarwerts wie im Graustufenbild. Sie benötigen mehr Aufmerksamkeit beim Schreiben eines solchen Codes.
Gibt es deutliche Kanten im Bild? Bewegen sie sich wahrscheinlich?
Wenn ja, können Sie zuerst den Kantenerkennungsalgorithmus anwenden (z. B. den Gradienten mit Sobel- oder Prewitt-Transformation berechnen, einen bestimmten Schwellenwert anwenden) und dann die Kanten des ersten Bildes mit den Kanten des zweiten Bilds vergleichen.
Gibt es Rauschen im Bild?
Alle Sensoren verschmutzen das Bild mit etwas Rauschen. Kostengünstige Sensoren haben mehr Rauschen. Möglicherweise möchten Sie eine Rauschunterdrückung anwenden, bevor Sie Bilder vergleichen. Unschärfe ist hier der einfachste (aber nicht der beste) Ansatz.
Welche Art von Änderungen möchten Sie bemerken?
Dies kann sich auf die Wahl der Norm auswirken, die für den Unterschied zwischen Bildern verwendet werden soll.
Verwenden Sie die Manhattan-Norm (die Summe der absoluten Werte) oder die Null-Norm (die Anzahl der Elemente ungleich Null), um zu messen, wie stark sich das Bild geändert hat. Ersteres zeigt an, um wie viel das Bild abweicht, letzteres zeigt nur, wie viele Pixel sich unterscheiden.
Beispiel
Ich gehe davon aus, dass Ihre Bilder gut ausgerichtet sind, dieselbe Größe und Form haben, möglicherweise mit unterschiedlicher Belichtung. Der Einfachheit halber konvertiere ich sie in Graustufen, auch wenn es sich um Farbbilder (RGB) handelt.
Sie benötigen diese Importe:
import sys
from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average
Hauptfunktion, zwei Bilder lesen, in Graustufen konvertieren, Ergebnisse vergleichen und drucken:
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
Wie zu vergleichen. img1
und img2
sind hier 2D SciPy Arrays:
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)
Wenn es sich bei der Datei um ein Farbbild handelt, wird imread
ein 3D-Array mit durchschnittlichen RGB-Kanälen (der letzten Array-Achse) zurückgegeben, um die Intensität zu erhalten. Für Graustufenbilder (z. B. .pgm
) ist dies nicht erforderlich :
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
Die Normalisierung ist trivial. Sie können auch die Normalisierung auf [0,1] anstelle von [0,255] wählen. arr
ist hier ein SciPy-Array, daher sind alle Operationen elementweise:
def normalize(arr):
rng = arr.max()-arr.min()
amin = arr.min()
return (arr-amin)*255/rng
Führen Sie die main
Funktion aus:
if __name__ == "__main__":
main()
Jetzt können Sie dies alles in ein Skript einfügen und zwei Bilder ausführen. Wenn wir das Bild mit sich selbst vergleichen, gibt es keinen Unterschied:
$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0
Wenn wir das Bild verwischen und mit dem Original vergleichen, gibt es einen Unterschied:
$ python compare.py one.jpg one-blurred.jpg
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0
PS Das gesamte Skript compare.py .
Update: relevante Techniken
Da es sich bei der Frage um eine Videosequenz handelt, bei der die Frames wahrscheinlich fast gleich sind und Sie nach etwas Ungewöhnlichem suchen, möchte ich einige alternative Ansätze erwähnen, die relevant sein können:
- Hintergrundsubtraktion und -segmentierung (zur Erkennung von Vordergrundobjekten)
- spärlicher optischer Fluss (zur Bewegungserkennung)
- Vergleichen von Histogrammen oder anderen Statistiken anstelle von Bildern
Ich empfehle dringend, das Buch „Learning OpenCV“ in den Kapiteln 9 (Bildteile und Segmentierung) und 10 (Verfolgung und Bewegung) zu lesen. Ersteres lehrt die Verwendung der Hintergrundsubtraktionsmethode, letzteres gibt einige Informationen zu optischen Flussmethoden. Alle Methoden sind in der OpenCV-Bibliothek implementiert. Wenn Sie Python verwenden, empfehle ich die Verwendung von OpenCV ≥ 2.3 und seines cv2
Python-Moduls.
Die einfachste Version der Hintergrundsubtraktion:
- Lernen Sie den Mittelwert μ und die Standardabweichung σ für jedes Pixel des Hintergrunds
- Vergleichen Sie die aktuellen Pixelwerte mit dem Bereich von (μ-2σ, μ + 2σ) oder (μ-σ, μ + σ).
In fortgeschritteneren Versionen werden Zeitreihen für jedes Pixel berücksichtigt und nicht statische Szenen (wie sich bewegende Bäume oder Gras) verarbeitet.
Die Idee des optischen Flusses besteht darin, zwei oder mehr Bilder aufzunehmen und jedem Pixel (dichter optischer Fluss) oder einigen von ihnen (geringer optischer Fluss) einen Geschwindigkeitsvektor zuzuweisen. Um den spärlichen optischen Fluss abzuschätzen, können Sie die Lucas-Kanade-Methode verwenden (sie ist auch in OpenCV implementiert). Wenn viel Fluss fließt (hoher Durchschnitt über den Maximalwerten des Geschwindigkeitsfelds), bewegt sich offensichtlich etwas im Rahmen, und nachfolgende Bilder sind unterschiedlicher.
Der Vergleich von Histogrammen kann helfen, plötzliche Änderungen zwischen aufeinanderfolgenden Bildern zu erkennen. Dieser Ansatz wurde in Courbon et al., 2010, verwendet :
Ähnlichkeit aufeinanderfolgender Frames. Der Abstand zwischen zwei aufeinanderfolgenden Bildern wird gemessen. Wenn es zu hoch ist, bedeutet dies, dass das zweite Bild beschädigt ist und somit das Bild entfernt wird. Der Kullback-Leibler-Abstand oder die gegenseitige Entropie in den Histogrammen der beiden Bilder:
Dabei sind p und q die Histogramme der Frames. Der Schwellenwert ist auf 0,2 festgelegt.