Algorytm porównywania obrazów

Staram się porównywać ze sobą obrazy, aby dowiedzieć się, czy są różne. Najpierw starałem się zrobić Pearson correleation wartości RGB, który działa również całkiem dobrze, chyba że zdjęcia są nieco przesunięte. Więc jeśli mają 100% identyczne obrazy, ale jeden jest trochę przeniesiony, dostaję złą wartość korelacji.

Jakieś propozycje lepszego algorytmu?

BTW, chodzi mi o porównanie tysięcy imgage ' ów...

Edytuj: Oto przykład moich zdjęć (mikroskopowo): {]}

Im1:

Tutaj wpisz opis obrazka

Im2:

Tutaj wpisz opis obrazka

Im3:

Tutaj wpisz opis obrazka

Im1 i im2 są takie same, ale trochę przesunięte/przycięte, im3 należy uznać za zupełnie inne...

Edit: Problem został rozwiązany dzięki sugestiom Petera Hansena! Działa bardzo dobrze! Dzięki za wszystkie odpowiedzi! Niektóre wyniki można znaleźć proszę. http://labtools.ipk-gatersleben.de/image%20comparison/image%20comparision.pdf

Author: snowflake, 2009-11-30

8 answers

A podobne pytanie zostało zadane rok temu i ma wiele odpowiedzi, w tym jedną dotyczącą pikselizacji obrazów, które zamierzałem zaproponować jako przynajmniej etap wstępnej kwalifikacji (ponieważ dość szybko wykluczyłoby bardzo Nie podobne obrazy).

Są tam również linki do jeszcze wcześniejszych pytań, które mają jeszcze więcej odniesień i dobrych odpowiedzi.

Oto implementacja wykorzystująca niektóre pomysły z Scipy, używając powyższych trzech obrazów (zapisanych jako im1.. jpg, im2.jpg, im3.jpg, odpowiednio). Końcowe wyjście pokazuje im1 w porównaniu z samym sobą, jako linię bazową, a następnie każdy obraz w porównaniu z innymi.

>>> 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)

Zauważ, że im1 w porównaniu z samym sobą daje wynik 42105, im2 w porównaniu z im1 nie jest daleko, ale im3 w porównaniu z którymkolwiek z pozostałych daje znacznie poniżej połowy tej wartości. Musisz eksperymentować z innymi obrazami, aby zobaczyć, jak dobrze może to działać i jak możesz to poprawić.

Czas trwania jest długi... kilka minuty na mojej maszynie. Spróbowałbym trochę wstępnego filtrowania, aby uniknąć marnowania czasu na porównywanie bardzo różnych obrazów, może z trikiem "porównaj Rozmiar pliku jpg" wspomnianym w odpowiedziach na inne pytanie lub z pikselizacją. Fakt, że masz obrazy o różnych rozmiarach komplikuje rzeczy, ale nie podałeś wystarczająco dużo informacji o zakresie rzezi można się spodziewać, więc trudno jest podać konkretną odpowiedź, która bierze to pod uwagę.
 36
Author: Peter Hansen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:54

Zrobiłem to z porównaniem histogramu obrazu. Mój podstawowy algorytm był taki:

  1. Podziel obraz na czerwony, zielony i niebieski
  2. Utwórz znormalizowane histogramy dla czerwonego, zielonego i niebieskiego kanału i połącz je w wektor (r0...rn, g0...gn, b0...bn) gdzie n jest liczbą "wiadrów", 256 powinno wystarczyć
  3. odjąć ten histogram od histogramu innego obrazu i obliczyć odległość

Oto jakiś kod z numpy i 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()

Jeśli masz dwa histogramy, można uzyskać odległość w ten sposób:

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

Jeśli oba obrazy są identyczne, odległość wynosi 0, im bardziej się różnią, tym większa odległość.

To działało całkiem dobrze dla zdjęć dla mnie, ale nie na grafice jak teksty i logo.

 13
Author: Otto Allmendinger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-14 12:35:37

Naprawdę musisz lepiej sprecyzować pytanie, ale patrząc na te 5 obrazów, wszystkie organizmy wydają się być zorientowane w ten sam sposób. Jeśli tak jest zawsze, możesz spróbować wykonać znormalizowaną korelację krzyżową pomiędzy tymi dwoma obrazami i przyjąć wartość szczytową jako stopień podobieństwa. Nie znam znormalizowanej funkcji korelacji krzyżowej w Pythonie, ale istnieje podobna funkcja fftconvolve () i możesz wykonać kolistą korelację krzyżową yourself:

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)

To nie będzie działać tak, jak napisano, ponieważ obrazy mają różne rozmiary, a wyjście nie jest w ogóle ważone lub znormalizowane.

Położenie szczytowej wartości wyjścia wskazuje przesunięcie między dwoma obrazami, a wielkość szczytu wskazuje na podobieństwo. Powinien istnieć sposób na wagę/normalizację, abyś mógł odróżnić dobry mecz od słabego meczu.

To nie jest tak dobra odpowiedź, jak chcę, ponieważ nie mam wymyśliłem, jak go znormalizować, ale zaktualizuję go, jeśli to rozgryzę, i to da ci pomysł, aby się temu przyjrzeć.

 6
Author: endolith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-04 19:05:27

Jeśli twój problem dotyczy przesuniętych pikseli, może powinieneś porównać z transformatą częstotliwości.

FFT powinno być OK (numpy ma implementację dla macierzy 2D), ale zawsze słyszę, że do tego typu zadań jest lepiej ^ _ ^

Jeśli chodzi o wydajność, jeśli wszystkie obrazy są tego samego rozmiaru, o ile dobrze pamiętam, pakiet FFTW stworzył wyspecjalizowaną funkcję dla każdego rozmiaru wejściowego FFT, dzięki czemu można uzyskać ładny wzrost wydajności ponownie używając tego samego kod... Nie wiem, czy numpy bazuje na FFTW, ale jeśli nie to może mógłbyś spróbować trochę tam zbadać.

Tutaj masz prototyp... możesz pobawić się z nim trochę, aby zobaczyć, który próg pasuje do Twoich obrazów.
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())

Innym sposobem postępowania może być rozmycie obrazów, a następnie odjęcie wartości pikseli od obu obrazów. Jeśli różnica nie jest zerowa, możesz przesunąć jeden z obrazów o 1 px w każdym kierunku i porównać ponownie, jeśli różnica jest poniżej niż w poprzednim kroku można powtórzyć przesuwanie w kierunku gradientu i odejmowanie, aż różnica będzie niższa niż określony próg lub wzrośnie ponownie. Powinno to zadziałać, jeśli promień jądra rozmycia jest większy niż przesunięcie obrazów.

Możesz również wypróbować niektóre narzędzia, które są powszechnie używane w obiegu pracy z fotografią do mieszania wielu ekspozycji lub wykonywania panoram, takie jak narzędzia Pano .

 6
Author: fortran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-18 11:39:31

Zrobiłem już jakiś kurs obróbki obrazu dawno temu i pamiętaj, że podczas dopasowywania Zwykle zaczynałem od tworzenia skali szarości obrazu, a następnie wyostrzania krawędzi obrazu, aby zobaczyć tylko krawędzie. Ty (oprogramowanie) możesz następnie przesuwać i odejmować obrazy, aż różnica będzie minimalna.

Jeśli różnica jest większa niż ustawiony treshold, obrazy nie są równe i możesz przejść do następnego. Obrazy z mniejszym treshold mogą być następnie analizowane.

I do pomyśl, że w najlepszym razie możesz radykalnie rozrzedzić możliwe mecze, ale będziesz musiał osobiście porównać możliwe Mecze, aby ustalić, że są naprawdę równe.

Naprawdę nie mogę pokazać kodu, jak to było dawno temu, i użyłem Khoros / Cantata do tego kursu.

 2
Author: extraneon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-30 15:12:42

Po pierwsze, korelacja jest bardzo intensywny procesor raczej niedokładna miara podobieństwa. Dlaczego nie po prostu przejść do sumy kwadratów, jeśli różnice między poszczególnymi pikselami?

Proste rozwiązanie, jeśli maksymalne przesunięcie jest ograniczone: Wygeneruj wszystkie możliwe przesunięte obrazy i znajdź ten, który najlepiej pasuje. Upewnij się, że obliczasz zmienną dopasowania (np. korrellację) tylko dla podzbioru pikseli, które mogą być dopasowane we wszystkich przesuniętych obrazach. Ponadto, Twoja maksymalna zmiana powinna być znacznie mniejszy niż rozmiar twoich zdjęć.

Jeśli chcesz użyć bardziej zaawansowanych technik przetwarzania obrazów, proponuję przyjrzeć się SIFT jest to bardzo potężna metoda ,która (teoretycznie) może prawidłowo dopasować elementy w obrazach niezależnie od tłumaczenia, obrotu i skali.

 1
Author: jilles de wit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-30 12:27:13

Myślę, że mógłbyś zrobić coś takiego:

  • Oszacowanie przemieszczenia w pionie / poziomie obrazu referencyjnego w stosunku do obrazu porównawczego. a proste SAD (suma różnicy bezwzględnej) z wektorami ruchu.

  • Przesuń obraz porównawczy odpowiednio

  • Oblicz korelację Pearsona, którą próbowałeś wykonać

Pomiar przesunięcia nie jest trudny.

  • Weź region (powiedzmy o 32x32) w obrazie porównawczym.
  • Przesuń go o x pikseli w poziomie i y pikseli w pionie.
  • Oblicz SAD (sumę różnicy bezwzględnej) w.R.T. oryginalny obraz
  • Zrób to dla kilku wartości x i y w małym zakresie (-10, +10)
  • Znajdź miejsce, w którym różnica jest minimalna
  • Wybierz tę wartość jako wektor ruchu przesunięcia

Uwaga:

Jeśli SAD zbliża się bardzo wysoko dla wszystkich wartości x i y, to można i tak założyć, że obrazy są wysoko odmienny i przesunięcie pomiar nie jest konieczne.

 0
Author: Shailesh Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-30 11:21:26

Aby import działał poprawnie na moim Ubuntu 16.04 (stan na Kwiecień 2017), zainstalowałem Pythona 2.7 i oto one:

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

Potem zmieniłem import śnieżynki na te:

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

Jak wspaniale, że SNOWFLAKE ' s scripted pracował dla mnie 8 lat później!

 0
Author: Doug Null,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-01 22:38:50