문제

나는 이미지를 서로 비교하여 다른지 여부를 알아 내려고 노력하고 있습니다. 먼저 Pearson RGB 값의 상관 관계를 만들려고 노력했는데, 사진이 조명이 약간 바뀌지 않는 한 매우 좋습니다. 따라서 A가 100% 동일 한 이미지를 가지고 있지만 조금 움직이면 상관 관계가 잘못됩니다.

더 나은 알고리즘에 대한 제안이 있습니까?

BTW, 나는 수천 개의 imgages를 비교하기 위해 이야기하고 있습니다 ...

편집 : 여기 내 사진 (현미경)의 예입니다.

IM1 : IM1

enter image description here

IM2 :

enter image description here

IM3 :

enter image description here

IM1과 IM2는 동일하지만 약간 바뀌거나 절단되며 IM3은 완전히 다른 것으로 인식되어야합니다 ...

편집하다: Peter Hansen의 제안으로 문제가 해결됩니다! 아주 잘 작동합니다! 모든 답변 덕분에! 일부 결과는 여기에서 찾을 수 있습니다http://labtools.ipk-gatersleben.de/image%20comparison/image%20comparision.pdf

도움이 되었습니까?

해결책

비슷한 질문 1 년 전에 질문을 받았으며 이미지를 픽셀 화하는 것에 관한 반응을 포함하여 수많은 응답을 가지고 있으며, 이는 적어도 사전 자격을 갖춘 단계 (매우 유사한 이미지를 매우 빠르게 제외 할 수 있기 때문에)를 제안 할 것입니다.

또한 더 많은 참고 문헌과 좋은 답변이있는 여전히 견고한 질문에 대한 링크도 있습니다.

다음은 Scipy와 함께 일부 아이디어를 사용하여 위의 세 가지 이미지 (IM1.JPG, IM2.JPG, IM3.JPG로 저장)를 사용하는 구현입니다. 최종 출력은 IM1 자체와 비교하여 기준선으로, 각 이미지는 다른 이미지와 비교하여 나타납니다.

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

따라서 IM1 자체와 비교하여 IM1은 42105 점수를 제공하고 IM1과 비교하여 IM2는 그리 멀지 않지만 IM3은 다른 것 중 하나와 비교하여 그 값의 절반 미만을 제공합니다. 이것이 얼마나 잘 수행 될 수 있는지, 어떻게 개선 할 수 있는지 알아보기 위해 다른 이미지를 실험해야합니다.

실행 시간이 길다 ... 내 컴퓨터에서 몇 분. 나는 다른 질문에 대한 응답에 언급 된 "JPG 파일 크기 비교"트릭과 함께 매우 다른 이미지를 비교하는 시간을 낭비하지 않기 위해 약간의 미리 필터링을 시도 할 것입니다. 크기가 다른 이미지가 있다는 사실은 사물을 복잡하게 만들지 만, 정육점의 정도에 대한 정보를 충분히 제공하지 않았으므로이를 고려하는 특정 답변을 제공하기는 어렵습니다.

다른 팁

이미지 히스토그램 비교로 이것을 한 사람이 있습니다. 내 기본 알고리즘은 다음과 같습니다.

  1. 이미지를 빨간색, 녹색 및 파란색으로 나눕니다
  2. 빨간색, 녹색 및 파란색 채널의 정규화 된 히스토그램을 만들어 벡터로 연결합니다. (r0...rn, g0...gn, b0...bn) 여기서 n은 "버킷"의 수, 256은 충분해야합니다.
  3. 이 히스토그램을 다른 이미지의 히스토그램에서 빼고 거리를 계산하십시오.

다음은 몇 가지 코드입니다 numpy 그리고 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()

두 개의 히스토그램이있는 경우 다음과 같은 거리를 얻을 수 있습니다.

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

두 이미지가 동일하면 거리가 0이면 더 많이 분기 될수록 거리가 더 커집니다.

그것은 사진에 대해 잘 작동했지만 텍스트 및 로고와 같은 그래픽에서는 실패했습니다.

당신은 실제로 질문을 더 잘 지정해야하지만, 그 5 개의 이미지를 살펴보면, 유기체는 모두 같은 방식으로 지향적 인 것 같습니다. 이것이 항상 그렇다면, 당신은 정규화 된 교차 상관 두 이미지 사이와 유사성 정도로 최고 값을 취합니다. 파이썬에서 정규화 된 교차 상관 함수를 모르지만 비슷한 점이 있습니다. fftconvolve () 기능하면 원형 상호 상관을 직접 수행 할 수 있습니다.

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)

이미지의 크기가 다르기 때문에 작성된대로 작동하지 않으며 출력은 전혀 가중 또는 정규화되지 않습니다.

출력의 피크 값의 위치는 두 이미지 사이의 오프셋을 나타내고 피크의 크기는 유사성을 나타냅니다. 좋은 경기와 경기가 열악한 경기의 차이를 알 수 있도록 체중/정상화 방법이 있어야합니다.

아직 정상화하는 방법을 찾지 못했기 때문에 이것은 내가 원하는만큼 좋은 대답이 아니지만, 알아 내면 업데이트하겠습니다.

문제가 이동 된 픽셀에 관한 것이면 주파수 변환과 비교해야 할 것입니다.

FFT는 괜찮아야합니다 (Numpy는 2D 매트릭스를 구현했습니다),하지만 나는 항상 이런 종류의 작업에 웨이블릿이 더 좋다는 것을 듣고 있습니다 ^_ ^

성능에 대해, 모든 이미지가 동일한 크기 인 경우, 내가 잘 기억한다면, FFTW 패키지는 각 FFT 입력 크기에 대해 특수한 기능을 만들었으므로 동일한 코드를 재사용하는 멋진 성능 부스트를 얻을 수 있습니다. Numpy가 FFTW를 기반으로하는지 알고 있지만, 그렇지 않다면 조금 조사하려고 시도 할 수 있습니다.

여기에는 프로토 타입이 있습니다 ... 이미지에 어떤 임계 값이 적합한 지 확인할 수 있습니다.

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

진행하는 또 다른 방법은 이미지를 흐리게 한 다음 두 이미지에서 픽셀 값을 빼낼 수 있습니다. 차이가 NIL이 아닌 경우 각 방향으로 이미지 1 PX 중 하나를 이동하고 다시 비교할 수 있습니다. 이전 단계에서 차이가 낮 으면 그라디언트 방향으로 이동하고 차이까지 빼면 반복 할 수 있습니다. 특정 임계 값보다 낮거나 다시 증가합니다. 흐릿한 커널의 반경이 이미지의 이동보다 큰 경우 작동해야합니다.

또한 여러 박람회를 혼합하거나 파노라마를 수행하기 위해 사진 워크 플로우에 일반적으로 사용되는 일부 도구를 사용해 볼 수 있습니다. 파노 도구.

나는 오래 전에 이미지 처리 과정을 수행했으며 일치 할 때 일반적으로 이미지 회색차를 만드는 것으로 시작한 다음 이미지의 가장자리를 깎아 가장자리 만 볼 수 있음을 기억합니다. 그런 다음 (소프트웨어)는 차이가 최소화 될 때까지 이미지를 전환하고 빼게 할 수 있습니다.

해당 차이가 설정 한 미분 값보다 크면 이미지가 같지 않으며 다음으로 이동할 수 있습니다. 그런 다음 더 작은 트레시 폴드가있는 이미지를 다음에 분석 할 수 있습니다.

나는 당신이 가능한 경기를 근본적으로 얇게 할 수 있다고 생각하지만, 가능한 경기를 개인적으로 비교하여 실제로 동일하게 판단해야한다고 생각합니다.

오래 전부터 코드를 보여줄 수는 없으며 그 과정에 Khoros/Cantata를 사용했습니다.

우선, 상관 관계는 유사성에 대한 매우 부정확 한 척도입니다. 개별 픽셀의 차이가있는 경우 사각형의 합을 사용하지 않겠습니까?

최대 변속이 제한된 경우 간단한 솔루션 : 가능한 모든 이동 된 이미지를 생성하고 가장 잘 일치하는 이미지를 찾으십시오. 모든 변속 이미지에서 일치 할 수있는 픽셀의 하위 집합에서만 일치 변수 (즉, 상관)를 계산해야합니다. 또한 최대 이동은 이미지의 크기보다 상당히 작아야합니다.

더 많은 발전 이미지 처리 기술을 사용하려면 살펴보십시오. 체로 치다 이것은 (이론적으로 어쨌든) 번역, 회전 및 스케일과 무관하게 이미지에서 항목을 올바르게 일치시킬 수있는 매우 강력한 방법입니다.

나는 당신이 다음과 같은 일을 할 수 있다고 생각합니다.

  • 참조 이미지의 수직 / 수평 변위를 비교 이미지를 추정하십시오. 모션 벡터와의 단순한 슬픈 (절대적인 차이의 합)가 할 것입니다.

  • 그에 따라 비교 이미지를 이동하십시오

  • 피어슨 상관 관계를 계산하려고했습니다

시프트 측정은 어렵지 않습니다.

  • 비교 이미지에서 영역 (약 32x32)을 찍습니다.
  • 수평으로 x 픽셀로, 수직 방향으로 y 픽셀로 이동하십시오.
  • 슬픈 (절대적인 차이의 합) WRT 원본 이미지 계산
  • 작은 범위 (-10, +10)에서 X와 Y의 여러 값에 대해이 작업을 수행하십시오.
  • 차이가 최소 인 장소를 찾으십시오
  • 해당 값을 시프트 모션 벡터로 선택하십시오

메모:

X와 Y의 모든 값에 대해 SAD가 매우 높아지면 이미지가 매우 비슷하고 시프트 측정이 필요하지 않다고 가정 할 수 있습니다.

Ubuntu 16.04 (2017 년 4 월 기준)에서 수입이 올바르게 작동하도록하려면 Python 2.7을 설치했습니다.

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

그런 다음 눈송이의 수입품을 이것으로 변경했습니다.

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

8 년 후 눈송이의 스크립트가 저를 위해 얼마나 굉장한가!

이미지 히스토그램에서 유사성의 Jaccard 지수를 기반으로 솔루션을 제안합니다. 보다: https://en.wikipedia.org/wiki/jaccard_index#weighted_jaccard_similarity_and_distance

픽셀 색상 분포의 차이를 계산할 수 있습니다. 이것은 실제로 번역에 매우 변하지 않습니다.

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

평균 제곱 오차와 관련하여 Jaccard 인덱스는 항상 [0,1] 범위에 있으므로 다른 이미지 크기를 비교할 수 있습니다.

그런 다음 두 이미지를 비교할 수 있지만 저조한 후 같은 크기로 비교할 수 있습니다! 또는 픽셀 카운트는 어떻게 든 정규화되어야합니다. 나는 이것을 사용했다 :

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

이미지 테스트 :

$ 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

물론 다른 리샘플링 필터 (가장 가까운 또는 lanczos)를 실험하는 것을 고려할 수도 있습니다.

또한 두 번째 이미지가 상향 샘플링 대신 다운 샘플링 될 수 있으므로 이미지 스와핑 이미지가 결과를 변경한다고 생각합니다 (결국 자르기는 재조정보다는 케이스에 더 잘 어울릴 수 있습니다.)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top