자르기 / 비율이 약간 다른 경우에도 두 이미지가 "동일"하다는 것을 어떻게 감지합니까?


11

두 가지 다른 이미지가 있습니다.

100px 여기에 이미지 설명을 입력하십시오또는 400px여기에 이미지 설명을 입력하십시오

100px 여기에 이미지 설명을 입력하십시오또는 400px여기에 이미지 설명을 입력하십시오

보시다시피 두 사람은 분명히 인간의 관점에서 "동일"합니다. 이제 나는 그것들이 동일하다는 것을 프로그램 적으로 감지하고 싶습니다. 나는 rmagick다음과 같은 루비 보석을 통해 이미지 마술을 사용 해왔다 .

img1 = Magick::Image.from_blob(File.read("image_1.jpeg")).first
img2 = Magick::Image.from_blob(File.read("image_2.jpeg")).first

if img1.difference(img2).first < 4000.0 # I have found this to be a good threshold, but does not work for cropped images
  puts "they are the same!!!"
end

이것은 비율 / 자르기가 동일한 이미지에 적합하지만 잘림이 약간 다르고 동일한 너비로 크기가 조정 된 경우에는 적합하지 않습니다.

자르기가 다른 이미지에 적용 할 수있는 방법이 있습니까? 나는 다음과 같이 말할 수있는 솔루션에 관심이 있습니다 : 하나의 이미지가 다른 이미지 안에 포함되어 있고 이미지의 90 % 정도를 커버합니다.

추신. 도움이된다면 이미지를 더 높은 해상도로 얻을 수 있습니다 (예 : 이중)


2
RMagick에 대해서는 확실하지 않지만 ImageMagick의 compare명령 행 도구에는 -subimage-search스위치가 있습니다.
스테판

흥미 롭습니다. 그런 명령이 어떻게 보일까요?
Niels Kristian

2
직접 사용하지 마십시오. 아마도 도움이 될 것입니다. stackoverflow.com/q/29062811/477037
Stefan

고마워, 그것은 훌륭한 정보입니다. 나는 루비에서 이것을하는 방법을 알아낼 수 없다 ...
Niels Kristian

1
이미지가 저품질입니까? 그렇지 않은 경우 더 큰 품질의 이미지를 더 큰 품질로 공유하십시오.
MH304

답변:


6

기능 일치를 살펴볼 수 있습니다. 아이디어는 두 이미지에서 기능을 찾아서 일치시키는 것입니다. 이 방법은 일반적으로 다른 이미지에서 템플릿 (예 : 로고)을 찾는 데 사용됩니다. 본질적으로 기능은 모서리 나 열린 공간과 같이 이미지에서 사람이 흥미롭게 찾을 수있는 것으로 설명 할 수 있습니다. 특징 검출 기술에는 여러 유형이 있지만, SIFT (scale-invariant feature transform)를 특징 검출 알고리즘으로 사용하는 것이 좋습니다. SIFT는 이미지 변환, 스케일링, 회전, 조명 변화에 부분적으로 불변, 로컬 기하학적 왜곡에 강합니다. 이미지의 비율이 약간 다를 수있는 사양과 일치하는 것 같습니다.

제공된 두 개의 이미지가 제공되면 FLANN 기능 매처를 사용하여 기능을 일치 시키려고합니다 . 두 이미지가 동일한 지 확인하기 위해 David G. Lowe의 Scale-Invariant Keypoints의 독특한 이미지 기능에 설명 된 비율 테스트를 통과하는 일치 수를 추적하는 미리 결정된 임계 값을 기준으로 할 수 있습니다. 테스트에 대한 간단한 설명은 비율 테스트에서 일치 항목이 모호하고 제거되어야하는지 검사하여 이상치 제거 기술로 취급 할 수 있다는 것입니다. 이 테스트를 통과 한 일치 횟수를 계산하여 두 이미지가 동일한 지 확인할 수 있습니다. 기능 일치 결과는 다음과 같습니다.

Matches: 42

점은 감지 된 모든 일치를 나타내고 녹색 선은 비율 테스트를 통과 한 "양호한 일치"를 나타냅니다. 비율 테스트를 사용하지 않으면 모든 점이 그려집니다. 이러한 방식으로이 필터를 임계 값으로 사용하여 가장 일치하는 기능 만 유지할 수 있습니다.


파이썬으로 구현했는데 Rails에 익숙하지 않습니다. 이것이 도움이되기를 바랍니다. 행운을 빕니다!

암호

import numpy as np
import cv2

# Load images
image1 = cv2.imread('1.jpg', 0)
image2 = cv2.imread('2.jpg', 0)

# Create the sift object
sift = cv2.xfeatures2d.SIFT_create(700)

# Find keypoints and descriptors directly
kp1, des1 = sift.detectAndCompute(image2, None)
kp2, des2 = sift.detectAndCompute(image1, None)

# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary
flann = cv2.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)

# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]

count = 0
# Ratio test as per Lowe's paper (0.7)
# Modify to change threshold 
for i,(m,n) in enumerate(matches):
    if m.distance < 0.15*n.distance:
        count += 1
        matchesMask[i]=[1,0]

# Draw lines
draw_params = dict(matchColor = (0,255,0),
                   # singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)

# Display the matches
result = cv2.drawMatchesKnn(image2,kp1,image1,kp2,matches,None,**draw_params)
print('Matches:', count)
cv2.imshow('result', result)
cv2.waitKey()

2
매우 흥미로운 접근 방법, 나는 그것을 돌려주고 돌아올 것이다 ...
Niels Kristian

추신. 나는 큰 규모의 이미지 업데이트
닐스 크리스티안

1
@nathancy 귀하의 예에서 녹색 점은 일치하지만 파란색 점은 일치하지 않습니까? 일치하지 않는 점이 너무 많은 것 같습니다.
Draco Ater

2
@DracoAter 좋은 질문, 파란색 점은 모든 일치를 나타내며 녹색으로 비율 테스트를 통과하는 "좋은 일치"만 그립니다. 비율 테스트를 사용하지 않으면 모든 점이 그려 지지만 비율 테스트를 사용하여 필터링하여 "더 나은"일치 항목을 그립니다. 이러한 방식으로 OP는이 테스트를 임계 값으로 사용하여 가장 일치하는 기능 만 유지할 수 있습니다. 따라서 모든 파란색 점은 SIFT가 찾은 기능이지만 녹색으로 그려진 좋은 점을 유지하기 위해 필터링합니다.
nathancy

감사. 답변, 많은 위대한 것들에 경쟁이 힘들었다 :-)
Niels Kristian

4

ImageMagick은 매우 오래되고 고급이며 다양한 기능을 갖춘 도구이므로 대부분의 기능을 다루는 인터페이스를 구축하기가 어렵습니다. rmagick은 모든 기능을 다룰 수는 없습니다 (파이썬이 시도한 많은 시도도 마찬가지입니다).

많은 유스 케이스에서 명령 줄 메소드를 실행하고 읽는 것이 안전하고 훨씬 쉽다는 것을 상상합니다. 루비에서는 다음과 같이 보일 것입니다.

require 'open3'

def check_subimage(large, small)
    stdin, stdout, stderr, wait_thr = Open3.popen3("magick compare -subimage-search -metric RMSE #{large} #{small} temp.jpg")
    result = stderr.gets
    stderr.close
    stdout.close
    return result.split[1][1..-2].to_f < 0.2
end

if check_subimage('a.jpg', 'b.jpg')
    puts "b is a crop of a"
else
    puts "b is not a crop of a"
end

중요한 내용을 다루고 추가 메모에 대해 이야기하겠습니다.

이 명령은 magick compare를 사용하여 두 번째 이미지 ( small)가 첫 번째 이미지 ( )의 하위 이미지인지 확인합니다 large. 이 기능은 small이 큰 것 (높이 및 너비)보다 엄격하게 작은 지 확인하지 않습니다. 유사점으로 입력 한 숫자는 0.2 (오류 20 %)이며 제공 한 이미지의 값은 약 0.15입니다. 이것을 미세 조정하고 싶을 수도 있습니다! 엄격한 서브 세트 인 이미지는 0.01보다 작습니다.

  • 90 %가 겹치지 만 두 번째 이미지에 첫 번째 이미지에없는 추가 항목이있는 경우 오류 (작은 숫자)를 줄이고 싶다면 한 번 실행 한 다음 첫 번째 큰 이미지를 하위 이미지가 포함 된 위치로 자릅니다. 잘라낸 이미지를 "작은"이미지로, 원래 "작은"이미지를 큰 이미지로 다시 실행하십시오.
  • 루비에서 멋진 객체 지향 인터페이스를 원한다면 rmagick은 MagicCore API를 사용합니다. 이 (docs에 링크) 명령은 아마도 그것을 구현하기 위해 사용하려는 것일 수도 있으며, pr을 열어서 cext를 rmagick하거나 패키징 할 수 있습니다.
  • open3을 사용하면 스레드가 시작됩니다 ( docs 참조 ). 닫기 stderr과은 stdout"필요"가 아니라 당신이하는 거 야.
  • 세 번째 arg 인 "temp"이미지는 분석을 출력 할 파일을 지정합니다. 간단히 살펴보면 필요하지 않은 방법을 찾을 수 없었지만 자동으로 덮어 쓰므로 디버깅을 위해 저장하는 것이 좋습니다. 예를 들면 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

  • 전체 출력은 10092.6 (0.154003) @ 0,31 형식입니다. 첫 번째 숫자는 655535 중에서 rmse 값이며 두 번째 숫자는 정규화 된 백분율입니다. 마지막 두 숫자는 작은 이미지가 시작되는 원본 이미지의 위치를 ​​나타냅니다.
  • "유사한"이미지가 어떻게되는지에 대한 객관적인 진실의 원천이 없기 때문에 RMSE를 선택했습니다 ( 여기에서 더 많은 메트릭 옵션 참조 ). 값들 사이의 차이에 대한 상당히 일반적인 척도입니다. AE (Absolute Error Count)는 좋은 생각처럼 보이지만 일부 자르기 소프트웨어가 픽셀을 완벽하게 보존하지 못하는 것처럼 보이므로 퍼즈를 조정해야하고 정규화 된 값이 아니므로 오류 수를 비교해야합니다. 이미지의 크기와 그렇지 않은 것.

1
그게 정말 좋은 정보 캐롤입니다. 감사합니다
Niels Kristian

이것이 다른 경우에 어떻게 작동하는지 궁금합니다!
캐롤 첸

1
훌륭한 답변에 감사드립니다. 내가 할 수 있다면, 나는 당신에게 이것에 대해서도 100p 보상을주었습니다 :-)
Niels Kristian

3

두 이미지의 히스토그램을 가져 와서 비교하십시오. 이로 인해 너무 급격한 변화가 없다면 자르기와 줌에 매우 효과적입니다.

이것은 이미지를 직접 빼는 현재 방법보다 낫습니다. 그러나이 방법은 여전히 ​​거의 없습니다.


조언을 읽어 주셔서 감사합니다.
Niels Kristian

이것은 목표를 달성하는 방법을 보여주지 않으므로 매우 유용한 대답은 아닙니다. "이 용어를 Google에서 알아서 알아 내십시오."와 같습니다.
anothermh

히스토그램은 이미지 처리에서 사람들이 가장 먼저 배우는 것 중 하나입니다. 구글이 구글을해야한다면 정말 사과드립니다.
Raviteja Narra

3

이러한 상황에서 일반적으로 템플릿 일치 는 좋은 결과를 가져옵니다. 템플릿 일치는 템플릿 이미지 (두 번째 이미지)와 일치하는 이미지 영역을 찾는 기술입니다. 이 알고리즘은 소스 이미지 (두 번째 이미지)에서 가장 좋은 위치에 점수를 매 깁니다.

TM_CCOEFF_NORMED 방법을 사용하는 opencv 에서 점수는 0과 1 사이입니다. 점수가 1이면 템플릿 이미지가 소스 이미지의 일부 (Rect)임을 의미하지만 밝게 또는 원근감 사이에서 약간의 변화가있는 경우 두 이미지의 경우 점수가 1보다 낮습니다.

이제 유사성 점수의 임계 값을 고려하여 동일한 지 여부를 알 수 있습니다. 이 임계 값은 몇 개의 샘플 이미지에서 시행 착오를 통해 얻을 수 있습니다. 나는 당신의 이미지를 시도하고 0.823863 점수를 얻었습니다 . 다음은 코드 (opencv C ++)와 두 이미지 사이의 공통 영역입니다.

여기에 이미지 설명을 입력하십시오

Mat im2 = imread("E:/1/1.jpg", 1);
//Mat im2;// = imread("E:/1/1.jpg", 1);
Mat im1 = imread("E:/1/2.jpg", 1);

//im1(Rect(0, 0, im1.cols - 5, im1.rows - 5)).copyTo(im2);

int result_cols = im1.cols - im2.cols + 1;
int result_rows = im1.rows - im2.rows + 1;

Mat result = Mat::zeros(result_rows, result_cols, CV_32FC1);

matchTemplate(im1, im2, result, TM_CCOEFF_NORMED);

double minVal; double maxVal;
Point minLoc; Point maxLoc;
Point matchLoc;

minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());

cout << minVal << " " << maxVal << " " << minLoc << " " << maxLoc << "\n";
matchLoc = maxLoc;

rectangle(im1, matchLoc, Point(matchLoc.x + im2.cols, matchLoc.y + im2.rows), Scalar::all(0), 2, 8, 0);
rectangle(result, matchLoc, Point(matchLoc.x + im2.cols, matchLoc.y + im2.rows), Scalar::all(0), 2, 8, 0);

imshow("1", im1);
imshow("2", result);
waitKey(0);

훌륭한 답변에 감사드립니다. 내가 할 수 있다면, 나는 당신에게 이것에 대해서도 100p 보상을주었습니다 :-)
Niels Kristian

2

find_similar_region 메소드를 고려하십시오 . 두 이미지 중 작은 이미지를 대상 이미지로 사용하십시오. 이미지 및 대상 이미지에서 퍼지 속성에 대한 다양한 값을 시도하십시오.


고마워, 그러나 나는 그것을 작동시킬 수 없다-당신은 할 수 있습니까?
Niels Kristian
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.