Pergunta

Eu estou tentando comparar imagens uns aos outros para descobrir se eles são diferentes. Primeiro eu tentei fazer uma correleation Pearson dos valores RGB, que também funciona muito bem a menos que as imagens são um pouco litte mudou. Portanto, se um tem 100% imagens idênticas, mas é um pouco mudou, eu recebo um valor de correlação ruim.

Todas as sugestões para um algoritmo melhor?

BTW, eu estou falando para comparar milhares de imgages ...

Edit: Aqui está um exemplo das minhas fotos (microscópica):

IM1:

enter descrição da imagem aqui

IM2:

enter descrição da imagem aqui

IM3:

enter descrição da imagem aqui

IM1 e IM2 são os mesmos, mas um pouco deslocado / cortado, IM3 devem ser reconhecidos como completamente diferente ...

Editar: problema é resolvido com as sugestões de Peter Hansen! Funciona muito bem! Graças a todas as respostas! Alguns resultados podem ser encontrados aqui http://labtools.ipk-gatersleben.de/image%20comparison/image % 20comparision.pdf

Foi útil?

Solução

A semelhante pergunta foi perguntado há um ano e tem inúmeras respostas, incluindo um sobre pixelizing as imagens, o que eu ia sugerir como pelo menos uma etapa de pré-qualificação (uma vez que excluiria imagens muito semelhantes não muito rapidamente).

Também existem links lá para perguntas ainda anteriores que têm ainda mais referências e boas respostas.

Aqui está uma implementação usando algumas das idéias com Scipy, usando seus acima de três imagens (gravadas como im1.jpg, im2.jpg, im3.jpg, respectivamente). As mostras finais de saída IM1 em comparação com a própria, como uma linha de base, e, em seguida, cada imagem em comparação com os outros.

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

Assim, nota que IM1 comparado com ele mesmo dá uma pontuação de 42,105, IM2 comparação com IM1 não está longe disso, mas IM3 comparação com qualquer um dos outros dá bem menos da metade desse valor. Você teria que experimentar com outras imagens para ver como isso pode realizar e como você pode melhorá-lo.

Executar tempo é longo ... vários minutos na minha máquina. Gostaria de tentar alguns pré-filtragem para perder tempo Evite comparar imagens muito diferentes, talvez com o truque "comparar o tamanho do arquivo jpg" mencionado em respostas a outra pergunta, ou com pixelização. O fato de que você tem imagens de diferentes tamanhos complica as coisas, mas você não dar informações suficientes sobre a extensão da massacrar se poderia esperar, por isso é difícil dar uma resposta específica que leva isso em conta.

Outras dicas

Eu tenho um feito isso com uma comparação de imagem histograma. Meu algoritmo básico era o seguinte:

  1. Dividir imagem em vermelho, verde e azul
  2. Criar histogramas normalizados para o canal vermelho, verde e azul e concatenar-los em uma (r0...rn, g0...gn, b0...bn) vector em que n é o número de "baldes", 256 deve ser suficiente
  3. subtrair este histograma a partir do histograma de uma outra imagem e calcular a distância

Aqui está um código com numpy e 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()

Se você tem dois histogramas, você pode obter a distância como esta:

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

Se as duas imagens são idênticos, a distância é de 0, mais eles divergem, quanto maior a distância.

Isso funcionou muito bem para fotos para mim, mas falhou em gráficos, como textos e logotipos.

Você realmente precisa especificar a pergunta melhor, mas, olhando para esses 5 imagens, os organismos todos parecem ser orientados da mesma maneira. Se este é sempre o caso, você pode tentar fazer um normalizada correlação cruzada entre as duas imagens e tomando o valor de pico como o seu grau de semelhança. Eu não sei de uma função de correlação cruzada normalizada em Python, mas há um semelhante fftconvolve () função e você pode fazer a correlação cruzada circular-se:

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)

Este não irá funcionar como escrito vez que as imagens são de tamanhos diferentes, e a saída não é ponderado ou normalizada em tudo.

A localização do valor de pico da saída indica o deslocamento entre as duas imagens, e a magnitude do pico indica a semelhança. Deve haver uma maneira de peso / normalizá-lo de modo que você pode dizer a diferença entre um bom jogo e um jogo pobre.

Isto não é tão bom de uma resposta como eu quero, desde que eu ainda não descobri como normalizar-lo ainda, mas eu vou atualizá-lo se eu descobrir isso, e ele vai te dar uma idéia de olhar em.

Se o seu problema é de cerca de pixels deslocado, talvez você deve comparar com uma freqüência transformar.

A FFT deve ser OK ( numpy tem uma implementação para 2D matrizes ), mas eu estou sempre ouvindo que Wavelets são melhores para este tipo de tarefas ^ _ ^

Sobre o desempenho, se todas as imagens são do mesmo tamanho, se me lembro bem, o pacote FFTW criou uma função especializada para cada tamanho de entrada FFT, assim você pode obter um bom aumento de desempenho reutilizar o mesmo código ... Eu não sei se numpy é baseado em FFTW, mas se não for, talvez você poderia tentar investigar um pouco lá.

Aqui você tem um protótipo ... você pode jogar um pouco com ele para ver qual se encaixa limiar com suas imagens.

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

Outra maneira de proceder pode ser esbater as imagens, em seguida, subtraindo os valores de pixels das duas imagens. Se a diferença for não nulo, então você pode mudar uma das imagens 1 px em cada direção e comparar mais uma vez, se a diferença for menor do que na etapa anterior, você pode repetir deslocando na direção do gradiente e subtraindo até que a diferença é menor do que um certo limiar, ou aumenta novamente. Isso deve funcionar se o raio do núcleo de borrar é maior do que a mudança das imagens.

Além disso, você pode tentar com algumas das ferramentas que são comumente usados ??no fluxo de trabalho de fotografia para misturar várias exposições ou fazer panoramas, como o Pano Ferramentas .

Tenho feito algumas processamento de imagem claro há muito tempo, e lembre-se que quando harmonização Eu normalmente iniciado com fazer a escala de cinza da imagem e, em seguida, afiar as bordas da imagem para que você só vê bordas. Você (o software) pode, então, mudar e subtrair as imagens até que a diferença é mínima.

Se essa diferença for maior que o limiar definido, as imagens não são iguais e você pode passar para a próxima. Imagens com um limiar menor pode então ser analisados ??a seguir.

Eu acho que na melhor das hipóteses você pode radicalmente diluir possíveis correspondências, mas terá de comparar pessoalmente possíveis correspondências para determinar que eles são realmente iguais.

Eu não posso realmente mostrar código como era há muito tempo, e eu usei Khoros / Cantata para o referido curso.

Em primeiro lugar, a correlação é muito intensivo da CPU medida bastante impreciso para similaridade. Porque não basta ir para a soma dos quadrados se diferenças entre os pixels individuais?

Uma solução simples, se a mudança máxima é limitada: gerar todas as imagens deslocou possíveis e encontrar o que é o melhor jogo. Certifique-se de calcular o seu jogo variável (ou seja correllation) somente sobre o subconjunto de pixels que podem ser combinados em todos deslocou imagens. Além disso, o desvio máximo deve ser significativamente menor do que o tamanho de suas imagens.

Se você quiser usar alguns mais avanços imagem técnicas de processamento eu sugiro que você olhar para SIFT este é um método muito poderoso que (teoricamente qualquer maneira) pode corresponder adequadamente itens em imagens independente de translação, rotação e escala.

Eu acho que você poderia fazer algo parecido com isto:

  • estimar deslocamento vertical / horizontal imagem de referência de imagem contra a comparação. uma simples SAD (soma da diferença absoluta) com os vectores de movimento faria.

  • deslocar a imagem comparação conformidade

  • calcular a correlação de Pearson você estava tentando fazer

medição da variação não é difícil.

  • Tome uma região (dizer sobre 32x32) imagem comparação em.
  • transferi-lo por x pixels de pixels horizontais e y no sentido vertical.
  • Calcule o SAD (soma da diferença absoluta) w.r.t. imagem original
  • Faça isso por vários valores de x e y em um pequeno intervalo (-10, +10)
  • Encontre o local onde a diferença é mínima
  • Escolha esse valor como a mudança de movimento vector

Nota:

Se a SAD está chegando muito alta para todos os valores de x e y, em seguida, você pode assim mesmo assumir que as imagens são altamente desiguais e medição mudança não é necessária.

Para obter as importações para funcionar corretamente no meu Ubuntu 16.04 (a partir de abril 2017), eu instalei python 2.7 e estes:

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

Então eu mudei importações do floco de neve para estes:

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

Como impressionante que do floco de neve do roteirizado trabalhou para mim 8 anos mais tarde!

Eu propor uma solução com base no índice de Jaccard de similaridade nos histogramas de imagens. Veja: https://en.wikipedia.org/wiki/Jaccard_index#Weighted_Jaccard_similarity_and_distance

Você pode calcular a diferença na distribuição das cores de pixels. Este é realmente muito invariante para traduções.

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

Com relação ao erro quadrático médio, os índice de Jaccard mentiras sempre no intervalo [0,1], permitindo assim comparações entre diferentes tamanhos de imagem.

Em seguida, você pode comparar as duas imagens, mas depois rescaling para o mesmo tamanho! Ou contagem de pixels terá que ser de alguma forma normalizada. Eu usei isso:

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

Os testes em suas imagens:

$ 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

Você também pode considerar a experimentar com diferentes filtros de reamostragem (como mais próximo ou Lanczos), uma vez que, é claro, alterar a distribuição de cor quando o redimensionamento.

Além disso, considere que as imagens trocando alterar os resultados, como a segunda imagem pode ser amostragem reduzida em vez de upsampled (Afinal, recorte pode atender melhor o seu caso em vez de redimensionamento.)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top