두 가지 다른 이미지가 있습니다.
과
보시다시피 두 사람은 분명히 인간의 관점에서 “동일”합니다. 이제 나는 그것들이 동일하다는 것을 프로그램 적으로 감지하고 싶습니다. 나는 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 % 정도를 커버합니다.
추신. 도움이된다면 이미지를 더 높은 해상도로 얻을 수 있습니다 (예 : 이중)
답변
기능 일치를 살펴볼 수 있습니다. 아이디어는 두 이미지에서 기능을 찾아서 일치시키는 것입니다. 이 방법은 일반적으로 다른 이미지에서 템플릿 (예 : 로고)을 찾는 데 사용됩니다. 본질적으로 기능은 모서리 나 열린 공간과 같이 이미지에서 사람이 흥미롭게 찾을 수있는 것으로 설명 할 수 있습니다. 특징 검출 기술에는 여러 유형이 있지만, 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()
답변
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)는 좋은 생각처럼 보이지만 일부 자르기 소프트웨어가 픽셀을 완벽하게 보존하지 못하는 것처럼 보이므로 퍼즈를 조정해야하고 정규화 된 값이 아니므로 오류 수를 비교해야합니다. 이미지의 크기와 그렇지 않은 것.
답변
두 이미지의 히스토그램을 가져 와서 비교하십시오. 이로 인해 너무 급격한 변화가 없다면 자르기와 줌에 매우 효과적입니다.
이것은 이미지를 직접 빼는 현재 방법보다 낫습니다. 그러나이 방법은 여전히 거의 없습니다.
답변
이러한 상황에서 일반적으로 템플릿 일치 는 좋은 결과를 가져옵니다. 템플릿 일치는 템플릿 이미지 (두 번째 이미지)와 일치하는 이미지 영역을 찾는 기술입니다. 이 알고리즘은 소스 이미지 (두 번째 이미지)에서 가장 좋은 위치에 점수를 매 깁니다.
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);
답변
find_similar_region 메소드를 고려하십시오 . 두 이미지 중 작은 이미지를 대상 이미지로 사용하십시오. 이미지 및 대상 이미지에서 퍼지 속성에 대한 다양한 값을 시도하십시오.
답변
