Frage

Ich versuche, Bilder miteinander zu vergleichen, um herauszufinden, ob sie anders sind. Zuerst habe ich versucht, einen Pearson correleation der RGB-Werte zu machen, was auch ganz gut funktioniert, es sei denn die Bilder ein litte Bit verschoben sind. Also, wenn ein 100% identische Bilder haben, aber man ist ein wenig bewegt, erhalte ich einen schlechten Korrelationswert.

Haben Sie Vorschläge für einen besseren Algorithmus?

BTW, ich spreche vergleichen tausend imgages ...

Edit: Hier ist ein Beispiel meiner Bilder (mikroskopische):

im1:

eingeben Bild Beschreibung hier

IM2:

eingeben Bild Beschreibung hier

im3:

eingeben Bild Beschreibung hier

im1 und IM2 gleich sind, aber ein wenig verschoben / zerschnitt, sollte IM3 als komplett anders erkannt werden ...

Edit: Problem mit den Vorschlägen von Peter Hansen gelöst! Funktioniert sehr gut! Vielen Dank an alle Antworten! Einige Ergebnisse sind hier zu finden http://labtools.ipk-gatersleben.de/image%20comparison/image % 20comparision.pdf

War es hilfreich?

Lösung

ähnliche Frage vor einem Jahr gefragt wurde, und zahlreiche Antworten hat, darunter ein in Bezug auf die Bilder pixelizing, die ich wollte zumindest einen Vorqualifizierung Schritt vorschlagen (da es sehr nicht-ähnliche Bilder ganz schnell ausschließen würde).

Es gibt auch Links dort noch früher Fragen, die noch mehr Referenzen und gute Antworten haben.

Hier ist eine Implementierung einige der Ideen, mit Scipy Verwendung Ihrer obigen drei Bilder mit (gespeichert als im1.jpg, im2.jpg, im3.jpg, respectively). Die letzte Ausgabe zeigt im1 mit sich selbst verglichen wird, als Grundlage, und jedes Bild dann im Vergleich mit den anderen.

>>> import scipy as sp
>>> from scipy.misc import imread
>>> from scipy.signal.signaltools import correlate2d as c2d
>>>
>>> def get(i):
...     # get JPG image as Scipy array, RGB (3 layer)
...     data = imread('im%s.jpg' % i)
...     # convert to grey-scale using W3C luminance calc
...     data = sp.inner(data, [299, 587, 114]) / 1000.0
...     # normalize per http://en.wikipedia.org/wiki/Cross-correlation
...     return (data - data.mean()) / data.std()
...
>>> im1 = get(1)
>>> im2 = get(2)
>>> im3 = get(3)
>>> im1.shape
(105, 401)
>>> im2.shape
(109, 373)
>>> im3.shape
(121, 457)
>>> c11 = c2d(im1, im1, mode='same')  # baseline
>>> c12 = c2d(im1, im2, mode='same')
>>> c13 = c2d(im1, im3, mode='same')
>>> c23 = c2d(im2, im3, mode='same')
>>> c11.max(), c12.max(), c13.max(), c23.max()
(42105.00000000259, 39898.103896795357, 16482.883608327804, 15873.465425120798)

, so dass im1 mit sich selbst verglichen beachten gibt eine Punktzahl von 42.105, IM2 im Vergleich zu im1 ist nicht weit weg, dass, aber im3 im Vergleich mit einem der anderen Hälfte gibt auch unter diesem Wert. Sie würden mit anderen Bildern experimentieren, um zu sehen, wie gut diese durchführen könnte und wie Sie könnte es verbessern.

Laufzeit ist lang ... einige Minuten auf meiner Maschine. Ich würde eine Vorfilterung versuchen, Zeit zu verschwenden sehr unähnlich Bilder zu vergleichen, vielleicht mit dem „vergleichen jpg Dateigröße“ in Antworten erwähnt Trick auf die andere Frage, oder mit pixelization. Die Tatsache, dass Sie Bilder in verschiedenen Größen haben sich die Dinge kompliziert, aber du hast nicht genügend Informationen über das Ausmaß der geben schlachten man erwarten könnte, so ist es schwer, eine konkrete Antwort zu geben, dass berücksichtigt werden.

Andere Tipps

Ich habe eine dieses mit einem Bild Histogramm Vergleich gemacht. Mein grundlegender Algorithmus war:

  1. Split Bild in rot, grün und blau
  2. Erstellen normalisierten Histogramme für Rot, Grün und Blau-Kanal und verketten sie in einen Vektor (r0...rn, g0...gn, b0...bn) wobei n die Anzahl der „Eimer“ ist, 256 sollte ausreichen
  3. subtrahiert dieses Histogramm aus dem Histogramm eines anderen Bildes und berechnet den Abstand

Hier ist ein Code mit numpy und pil

r = numpy.asarray(im.convert( "RGB", (1,0,0,0, 1,0,0,0, 1,0,0,0) ))
g = numpy.asarray(im.convert( "RGB", (0,1,0,0, 0,1,0,0, 0,1,0,0) ))
b = numpy.asarray(im.convert( "RGB", (0,0,1,0, 0,0,1,0, 0,0,1,0) ))
hr, h_bins = numpy.histogram(r, bins=256, new=True, normed=True)
hg, h_bins = numpy.histogram(g, bins=256, new=True, normed=True)
hb, h_bins = numpy.histogram(b, bins=256, new=True, normed=True)
hist = numpy.array([hr, hg, hb]).ravel()

Wenn Sie zwei Histogramme haben, können Sie den Abstand wie diese:

diff = hist1 - hist2
distance = numpy.sqrt(numpy.dot(diff, diff))

Wenn die beiden Bilder identisch sind, ist der Abstand 0 ist, desto mehr werden sie auseinandergehen, desto größer ist der Abstand.

Es funktionierte ziemlich gut für Fotos für mich aber nicht auf Grafiken wie Texte und Logos.

Sie müssen wirklich die Frage besser spezifizieren, aber bei diesen 5 Bildern suchen, die Organismen scheinen alle die gleiche Art und Weise ausgerichtet werden. Wenn dies immer der Fall ist, können Sie versuchen, ein normalisierte Kreuzkorrelation zu tun zwischen den beiden Bildern und den Spitzenwert als Maß der Ähnlichkeit nehmen. Ich weiß nicht, von einer normalisierten Kreuzkorrelationsfunktion in Python, aber es gibt ein ähnliches fftconvolve () Funktion und Sie können die Kreiskreuzkorrelation selbst tun:

a = asarray(Image.open('c603225337.jpg').convert('L'))
b = asarray(Image.open('9b78f22f42.jpg').convert('L'))
f1 = rfftn(a)
f2 = rfftn(b)
g =  f1 * f2
c = irfftn(g)

Dies wird nicht als geschrieben arbeiten, da die Bilder unterschiedliche Größe sind, und der Ausgang nicht gewichtet oder normiert überhaupt.

Die Lage des Spitzenwertes des Ausgangs die anzeigt, zwischen den beiden Bildern versetzt, und die Größe des Spitzen zeigt die Ähnlichkeit. Es soll ein Weg, um Gewicht sein / es normalisiert, so dass Sie den Unterschied zwischen einem guten Spiel und einem schlechten Spiel sagen kann.

Das ist nicht so gut für eine Antwort, wie ich will, da ich nicht herausgefunden habe, wie es noch zu normalisieren, aber ich werde es aktualisieren, wenn ich es herausfinden, und es wird Ihnen eine Vorstellung zu sehen in.

Wenn Ihr Problem zu verschobenen Pixel ist, vielleicht sollten Sie vergleichen gegen eine Frequenz-Transformation.

Die FFT sollte in Ordnung sein ( numpy hat eine Implementierung für 2D-Matrizen ), aber ich höre immer, dass Wavelets ist besser für diese Art von Aufgaben ^ _ ^

über die Leistung, wenn alle Bilder von der gleichen Größe sind, wenn ich mich gut erinnere, erstellt das FFTW Paket eine spezielle Funktion für jede FFT Eingangsgröße, so dass Sie einen schönen Leistungsschub bekommen können den gleichen Code wiederverwenden ... ich weiß nicht, ob numpy auf FFTW basiert, aber wenn es nicht vielleicht ist können Sie versuchen, es ein wenig zu untersuchen.

Hier haben Sie einen Prototyp ... Sie ein wenig mit ihm spielen, um zu sehen, welche Schwelle mit Ihren Bildern passen.

import Image
import numpy
import sys

def main():
    img1 = Image.open(sys.argv[1])
    img2 = Image.open(sys.argv[2])

    if img1.size != img2.size or img1.getbands() != img2.getbands():
        return -1

    s = 0
    for band_index, band in enumerate(img1.getbands()):
        m1 = numpy.fft.fft2(numpy.array([p[band_index] for p in img1.getdata()]).reshape(*img1.size))
        m2 = numpy.fft.fft2(numpy.array([p[band_index] for p in img2.getdata()]).reshape(*img2.size))
        s += numpy.sum(numpy.abs(m1-m2))
    print s

if __name__ == "__main__":
    sys.exit(main())

Eine andere Möglichkeit, die Bilder zu verwischen, dann Subtrahieren der Pixelwerte aus den beiden Bildern werden könnten, um fortzufahren. Wenn die Differenz nicht gleich Null ist, dann kann man eines der Bilder 1 Pixel in jeder Richtung verschieben und wieder vergleichen, wenn die Differenz niedriger als im vorhergehenden Schritt ist, kann man in der Richtung des Gradienten wiederholen Verschieben und bis die Differenz subtrahiert niedriger als wieder eine bestimmte Schwelle oder zunimmt. Das sollte funktionieren, wenn der Radius der Unschärfe-Kernel ist größer als die Verschiebung der Bilder.

Sie können aber auch mit einigen der Tools versuchen, die mehrere Ausstellungen zum Mischen oder tun Panoramen in der Fotografie-Workflow häufig verwendet werden, wie die Pano Werkzeuge .

Ich habe einige Bildverarbeitung natürlich getan vor langer Zeit, und denken Sie daran, dass bei der Zuordnung mit der Herstellung der Bildgraustufen, ich normal gestartet und dann die Ränder des Bildes schärft, so dass Sie nur Kanten sehen. Sie (die Software) können dann verschieben und die Bilder subtrahieren, bis die Differenz minimal ist.

Wenn die Differenz größer ist als die Schwellen Sie setzen, sind die Bilder nicht gleich, und Sie können mit dem nächsten weitermachen. Bilder mit einer kleineren Schwelle kann dann nächstes analysiert werden.

Ich glaube, dass am besten an können Sie radikal ausdünnen mögliche Übereinstimmungen, aber persönlich benötigen, um mögliche Übereinstimmungen zu vergleichen, sie gleich sind wirklich zu bestimmen.

Ich kann nicht wirklich zeigen Code, wie es vor langer Zeit war, und ich Khoros / Kantate für diesen Kurs.

Zunächst einmal, Korrelation ist ein sehr viel CPU-Kapazität eher ungenaues Maß für Ähnlichkeit. Warum gehen nicht nur für die Summe der Quadrate, wenn Unterschiede zwischen den einzelnen Pixeln?

Eine einfache Lösung, wenn die maximale Verschiebung ist begrenzt: erzeugen alle möglichen Bilder verschoben und finden, die die beste Übereinstimmung ist. Achten Sie darauf, berechnen Sie Ihre Anpaßvariable (d correllation) nur über die Teilmenge von Pixeln, die Bilder in allen verschoben angepasst werden kann. Auch Ihre maximale Verschiebung sollte deutlich kleiner als die Größe Ihrer Bilder sein.

Wenn Sie einige weitere Fortschritte Bildverarbeitungstechniken verwenden, ich schlage vor, Sie schauen unter SIFT dies ist eine sehr leistungsfähige Methode, die (theoretisch jedenfalls) kann unabhängig von Translation, Rotation und Skalierung richtig Elemente in Bildern entspricht.

Ich denke, man so etwas tun könnte:

  • Schätzung vertikale / horizontale Verschiebung des Referenzbildes vs dem Vergleichsbild. ein SAD einfache (Summe der absoluten Differenzen) mit Bewegungsvektoren tun würden.

  • verschiebt das Vergleichsbild entsprechend

  • berechnen Sie die Pearson-Korrelation Sie vorhatten

Shift-Messung ist nicht schwer.

  • Nehmen Sie eine Region (ca. 32x32 sagen) im Vergleich Bild.
  • Umschalt durch x Pixel in horizontale und y Pixel in vertikaler Richtung.
  • Berechnen Sie die SAD (Summe der absoluten Differenz) w.r.t. Originalbild
  • Tun Sie dies für mehrere Werte von x und y in einem kleinen Bereich (-10, +10)
  • Suchen Sie die Stelle, wo der Unterschied minimal ist
  • Wählen Sie diesen Wert als den Schaltbewegungsvektor

Hinweis:

Wenn das SAD kommt sehr hoch für alle Werte von x und y, dann können Sie auf jeden Fall davon ausgehen, dass die Bilder sehr unähnlich sind und Schichtmessung nicht notwendig ist.

die Importe Um richtig 16.04 auf meinem Ubuntu zu arbeiten (Stand April 2017), installierte ich Python 2.7 und diese:

sudo apt-get install python-dev
sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk
sudo apt-get install python-scipy
sudo pip install pillow

Dann änderte ich Snowflake Importe auf diese:

import scipy as sp
from scipy.ndimage import imread
from scipy.signal.signaltools import correlate2d as c2d

Wie genial, dass Snowflake 8 Jahre später für mich im Skript gearbeitet!

Ich schlage vor, eine Lösung auf dem Jaccard Index der Ähnlichkeit auf dem Bild Histogramm basiert. Siehe: https://en.wikipedia.org/wiki/Jaccard_index#Weighted_Jaccard_similarity_and_distance

Sie können den Unterschied in der Verteilung der Pixelfarben berechnen. Dies ist in der Tat ziemlich invariant Übersetzungen.

from PIL.Image import Image
from typing import List

def jaccard_similarity(im1: Image, im2: Image) -> float:
    """Compute the similarity between two images.
    First, for each image an histogram of the pixels distribution is extracted.
    Then, the similarity between the histograms is compared using the weighted Jaccard index of similarity, defined as:
    Jsimilarity = sum(min(b1_i, b2_i)) / sum(max(b1_i, b2_i)
    where b1_i, and b2_i are the ith histogram bin of images 1 and 2, respectively.

    The two images must have same resolution and number of channels (depth).

    See: https://en.wikipedia.org/wiki/Jaccard_index
    Where it is also called Ruzicka similarity."""

    if im1.size != im2.size:
        raise Exception("Images must have the same size. Found {} and {}".format(im1.size, im2.size))

    n_channels_1 = len(im1.getbands())
    n_channels_2 = len(im2.getbands())
    if n_channels_1 != n_channels_2:
        raise Exception("Images must have the same number of channels. Found {} and {}".format(n_channels_1, n_channels_2))

    assert n_channels_1 == n_channels_2

    sum_mins = 0
    sum_maxs = 0

    hi1 = im1.histogram()  # type: List[int]
    hi2 = im2.histogram()  # type: List[int]

    # Since the two images have the same amount of channels, they must have the same amount of bins in the histogram.
    assert len(hi1) == len(hi2)

    for b1, b2 in zip(hi1, hi2):
        min_b = min(b1, b2)
        sum_mins += min_b
        max_b = max(b1, b2)
        sum_maxs += max_b

    jaccard_index = sum_mins / sum_maxs

    return jaccard_index

In Bezug quadratische Fehler bedeutet, der Jaccard Index liegt immer im Bereich [0,1], so dass Vergleiche zwischen den verschiedenen Bildgrößen.

Dann können Sie die beiden Bilder vergleichen, aber nach auf die gleiche Größe neu zu skalieren! Oder Pixelzahlen müssen irgendwie normalisiert werden. Ich habe diese:

import sys

from skincare.common.utils import jaccard_similarity

import PIL.Image
from PIL.Image import Image

file1 = sys.argv[1]
file2 = sys.argv[2]

im1 = PIL.Image.open(file1)  # type: Image
im2 = PIL.Image.open(file2)  # type: Image

print("Image 1: mode={}, size={}".format(im1.mode, im1.size))
print("Image 2: mode={}, size={}".format(im2.mode, im2.size))

if im1.size != im2.size:
    print("Resizing image 2 to {}".format(im1.size))
    im2 = im2.resize(im1.size, resample=PIL.Image.BILINEAR)

j = jaccard_similarity(im1, im2)
print("Jaccard similarity index = {}".format(j))

Test auf Ihren Bildern:

$ python CompareTwoImages.py im1.jpg im2.jpg
Image 1: mode=RGB, size=(401, 105)
Image 2: mode=RGB, size=(373, 109)
Resizing image 2 to (401, 105)
Jaccard similarity index = 0.7238955686269157
$ python CompareTwoImages.py im1.jpg im3.jpg 
Image 1: mode=RGB, size=(401, 105)
Image 2: mode=RGB, size=(457, 121)
Resizing image 2 to (401, 105)
Jaccard similarity index = 0.22785529941822316
$ python CompareTwoImages.py im2.jpg im3.jpg 
Image 1: mode=RGB, size=(373, 109)
Image 2: mode=RGB, size=(457, 121)
Resizing image 2 to (373, 109)
Jaccard similarity index = 0.29066426814105445

Sie könnten auch erwägen mit verschiedenen Resampling-Filter (wie NÄCHSTE oder lanczos) experimentieren, wie sie, natürlich, die Farbverteilung ändern, wenn die Größenänderung.

Darüber hinaus berücksichtigen, dass Swapping Bilder, die Ergebnisse zu ändern, wie das zweite Bild könnte statt Upsampling heruntergemischt wird (Immerhin Zuschneiden besser könnte Ihren Fall passen, anstatt neu zu skalieren.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top