Làm cách nào để tôi phát hiện ra rằng hai hình ảnh là cùng một tên lửa ngay cả khi một hình ảnh có tỷ lệ cắt / tỷ lệ hơi khác nhau?


11

Tôi có hai hình ảnh khác nhau:

trong 100px với nhập mô tả hình ảnh ở đâyhoặc 400pxnhập mô tả hình ảnh ở đây

chiều rộng 100px nhập mô tả hình ảnh ở đâyhoặc 400pxnhập mô tả hình ảnh ở đây

Như bạn có thể thấy cả hai rõ ràng là "giống nhau" theo quan điểm của con người. Bây giờ tôi muốn phát hiện theo chương trình rằng chúng giống nhau. Tôi đã sử dụng phép thuật hình ảnh thông qua viên ngọc ruby ​​được gọi rmagicknhư vậy:

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

Mặc dù điều này hoạt động tốt đối với các hình ảnh có cùng tỷ lệ / cắt xén, nhưng nó không lý tưởng khi chúng có khả năng cắt xén hơi khác nhau và đã được thay đổi kích thước theo cùng chiều rộng.

Có cách nào để làm điều đó cho hình ảnh với cắt xén khác nhau? Tôi quan tâm đến một giải pháp mà tôi có thể nói điều gì đó như: Một hình ảnh được chứa bên trong hình ảnh kia và bao phủ đâu đó xung quanh, ví dụ 90% của nó.

Tái bút Tôi có thể có được hình ảnh ở độ phân giải cao hơn nếu điều đó giúp (ví dụ như gấp đôi)


2
Không chắc chắn về RMagick, nhưng comparecông cụ dòng lệnh của ImageMagick có một -subimage-searchcông tắc.
Stefan

Điều đó thật thú vị, một lệnh như thế sẽ như thế nào?
Niels Kristian

2
Không bao giờ sử dụng bản thân mình, có thể điều này giúp: stackoverflow.com/q/29062811/477037
Stefan

Cảm ơn, đó là một phần tuyệt vời của thông tin. Tuy nhiên, tôi không thể tìm ra cách để làm điều này từ ruby ​​...
Niels Kristian

1
Là những hình ảnh chất lượng thấp? Nếu không, vui lòng chia sẻ phiên bản lớn hơn của hình ảnh, với chất lượng cao hơn.
MH304

Câu trả lời:


6

Bạn có thể muốn xem qua tính năng phù hợp. Ý tưởng là tìm các tính năng trong hai hình ảnh và khớp chúng. Phương pháp này thường được sử dụng để tìm một mẫu (giả sử là logo) trong một hình ảnh khác. Một tính năng, về bản chất, có thể được mô tả là những thứ mà con người sẽ thấy thú vị trong một hình ảnh, chẳng hạn như các góc hoặc không gian mở. Có nhiều loại kỹ thuật phát hiện tính năng hiện có tuy nhiên khuyến nghị của tôi là sử dụng biến đổi tính năng bất biến tỷ lệ (SIFT) làm thuật toán phát hiện tính năng. SIFT là bất biến đối với dịch hình ảnh, chia tỷ lệ, xoay, bất biến một phần đối với các thay đổi chiếu sáng và mạnh mẽ đối với biến dạng hình học cục bộ. Điều này dường như phù hợp với đặc điểm kỹ thuật của bạn trong đó các hình ảnh có thể có tỷ lệ hơi khác nhau.

Với hai hình ảnh được cung cấp của bạn, đây là một nỗ lực để khớp các tính năng bằng cách sử dụng trình so khớp tính năng FLANN . Để xác định xem hai hình ảnh có giống nhau hay không, chúng ta có thể căn cứ vào một số ngưỡng được xác định trước để theo dõi số lượng các trận đấu vượt qua bài kiểm tra tỷ lệ được mô tả trong Các tính năng hình ảnh khác biệt từ các Điểm chính không thay đổi tỷ lệ của David G. Lowe . Một lời giải thích đơn giản về kiểm tra là kiểm tra tỷ lệ kiểm tra nếu các kết quả không rõ ràng và cần được loại bỏ, bạn có thể coi đó là một kỹ thuật loại bỏ ngoại lệ. Chúng tôi có thể đếm số lượng trận đấu vượt qua bài kiểm tra này để xác định xem hai hình ảnh có giống nhau không. Đây là kết quả khớp tính năng:

Matches: 42

Các dấu chấm đại diện cho tất cả các kết quả được phát hiện trong khi các đường màu xanh lá cây đại diện cho "kết quả phù hợp" vượt qua bài kiểm tra tỷ lệ. Nếu bạn không sử dụng bài kiểm tra tỷ lệ thì tất cả các điểm sẽ được rút ra. Theo cách này, bạn có thể sử dụng bộ lọc này làm ngưỡng để chỉ giữ các tính năng phù hợp nhất.


Tôi đã triển khai nó trong Python, tôi không rành lắm về Rails. Hy vọng điều này sẽ giúp, chúc may mắn!

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
Cách tiếp cận siêu thú vị, tôi sẽ cho nó quay và quay lại ...
Niels Kristian

Tái bút Tôi đã cập nhật hình ảnh ở quy mô lớn hơn
Niels Kristian

1
@nathancy Có phải vì vậy mà trong ví dụ của bạn, các chấm màu xanh lá cây khớp với nhau, nhưng các chấm màu xanh thì không? Hình như có quá nhiều dấu chấm chưa từng có?
Draco Ater

2
@DracoAter câu hỏi hay, các chấm màu xanh đại diện cho tất cả các trận đấu trong khi chúng tôi chỉ vẽ "kết quả phù hợp" vượt qua bài kiểm tra tỷ lệ màu xanh lá cây. Nếu bạn không sử dụng kiểm tra tỷ lệ thì tất cả các điểm sẽ được rút ra nhưng chúng tôi sẽ lọc bằng cách sử dụng kiểm tra tỷ lệ để rút ra các kết quả khớp "tốt hơn". Theo cách này, OP có thể sử dụng thử nghiệm này như một ngưỡng để chỉ giữ các tính năng phù hợp nhất. Vì vậy, tất cả các dấu chấm màu xanh là những tính năng mà SIFT tìm thấy nhưng chúng tôi lọc để giữ cho những người tốt được rút ra trong màu xanh lá cây
nathancy

Cảm ơn. cạnh tranh rất khó về câu trả lời, nhiều câu trả lời hay :-)
Niels Kristian

4

Vì ImageMagick rất cũ, tiên tiến và là một công cụ đa tính năng, nên sẽ rất khó để xây dựng một giao diện bao gồm hầu hết các tính năng. Tuyệt vời như vậy, rmagick không (và cũng không có nhiều nỗ lực mà trăn đã thực hiện) đến gần để bao quát tất cả các tính năng.

Tôi tưởng tượng đối với nhiều trường hợp sử dụng, nó sẽ đủ an toàn và dễ dàng hơn nhiều khi chỉ thực hiện một phương thức dòng lệnh và đọc từ đó. Trong ruby ​​sẽ trông như thế này;

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

Tôi sẽ bao gồm những thứ quan trọng và sau đó nói về ghi chú bổ sung.

Lệnh sử dụng phép so sánh để kiểm tra xem hình ảnh thứ hai ( small) có phải là một tiểu phần của hình ảnh thứ nhất ( large) không. Chức năng này không kiểm tra xem nhỏ có hoàn toàn nhỏ hơn lớn (cả chiều cao và chiều rộng). Số tôi đặt cho độ tương tự là 0,2 (lỗi 20%) và giá trị cho hình ảnh bạn cung cấp là khoảng 0,15. Bạn có thể muốn tinh chỉnh điều này! Tôi thấy rằng hình ảnh là một tập hợp con nghiêm ngặt nhận được ít hơn 0,01.

  • Nếu bạn muốn ít lỗi hơn (số nhỏ hơn) trong trường hợp bạn có 90% trùng lặp nhưng hình ảnh thứ hai có thêm một số thứ không có, bạn có thể chạy nó một lần, sau đó cắt hình ảnh lớn đầu tiên vào nơi chứa ảnh con , sau đó chạy lại với hình ảnh được cắt thành hình "nhỏ" và hình ảnh "nhỏ" ban đầu là hình lớn.
  • Nếu bạn thực sự muốn có một giao diện hướng đối tượng đẹp trong Ruby, rmagick sử dụng API MagicCore. Lệnh (liên kết đến tài liệu) này có thể là những gì bạn muốn sử dụng để thực hiện nó và bạn có thể mở một pr để rmagick hoặc tự đóng gói cext.
  • Sử dụng open3 sẽ bắt đầu một chủ đề ( xem tài liệu ). Đóng stderrstdoutkhông "cần thiết" nhưng bạn phải làm.
  • Hình ảnh "temp" đó là đối số thứ ba chỉ định một tệp để đưa ra phân tích. Với một cái nhìn nhanh chóng, tôi không thể tìm ra cách nào để không yêu cầu nó, nhưng nó chỉ ghi đè tự động và có thể tốt để lưu để gỡ lỗi. Ví dụ của bạn, nó sẽ trông như thế này;

nhập mô tả hình ảnh ở đây

  • Đầu ra đầy đủ có định dạng 10092.6 (0.154003) @ 0,31. Số đầu tiên là giá trị rmse trong số 655535, số thứ hai (mà tôi sử dụng) là tỷ lệ phần trăm chuẩn hóa. Hai số cuối biểu thị vị trí của ảnh gốc mà từ đó ảnh nhỏ bắt đầu.
  • Vì không có nguồn sự thật khách quan cho việc hình ảnh "tương tự" như thế nào, tôi đã chọn RMSE (xem thêm các tùy chọn số liệu ở đây ). Đó là một thước đo khá phổ biến về sự khác biệt giữa các giá trị. Số lỗi tuyệt đối (AE) có vẻ là một ý tưởng hay, tuy nhiên có vẻ như một số phần mềm cắt xén không bảo toàn pixel một cách hoàn hảo nên bạn có thể phải điều chỉnh fuzz và đó không phải là giá trị chuẩn hóa, do đó bạn phải so sánh số lỗi với kích thước của hình ảnh và không có gì.

1
Đó là một số thông tin thực sự tuyệt vời đó Carol. Cảm ơn
Niels Kristian

Tò mò muốn biết làm thế nào điều này làm việc cho các trường hợp khác của bạn!
Carol Chen

1
Cảm ơn câu trả lời siêu tuyệt vời. Nếu tôi có thể, tôi cũng đã trao cho bạn phần thưởng 100p cho cái này :-)
Niels Kristian

3

Lấy biểu đồ của cả hai hình ảnh và so sánh chúng. Điều này sẽ hoạt động rất tốt cho crop và Zoom trừ khi có quá nhiều thay đổi vì những điều này.

Điều này tốt hơn so với phương pháp hiện tại nơi bạn đang trừ trực tiếp các hình ảnh. Nhưng cách tiếp cận này vẫn còn ít.


Cảm ơn lời khuyên tôi sẽ xem xét nó.
Niels Kristian

Đây không phải là một câu trả lời rất hữu ích vì nó không thể hiện cách hoàn thành mục tiêu. Nó tương đương với "Google thuật ngữ này và tự mình tìm ra nó."
Anothermh

Biểu đồ là một trong những điều đầu tiên mọi người học được trong xử lý hình ảnh. Nếu một số phải google nó, sau đó tôi xin lỗi sâu sắc.
Raviteja Narra

3

Khớp mẫu thường có kết quả tốt trong những tình huống này. Khớp mẫu là một kỹ thuật để tìm các khu vực của hình ảnh khớp (tương tự) với hình ảnh mẫu (hình ảnh thứ hai). Thuật toán này cho điểm cho vị trí macthed tốt nhất trong ảnh nguồn (cái thứ hai).

Trong opencv sử dụng TM_CCOEFF_NORMED phương pháp , cho điểm từ 0 đến 1. Nếu điểm là 1, điều đó có nghĩa là hình ảnh mẫu chính xác là một phần (Rect) của hình ảnh nguồn, nhưng nếu bạn có một chút thay đổi về độ sáng hoặc phối cảnh giữa hai hình ảnh, điểm sẽ thấp hơn 1.

Bây giờ Bằng cách xem xét một ngưỡng cho điểm tương tự, bạn có thể tìm hiểu xem chúng có giống nhau hay không. Ngưỡng đó có thể đạt được bằng một số thử nghiệm và lỗi trên một vài hình ảnh mẫu. Tôi đã thử hình ảnh của bạn và nhận được số điểm 0.823863 . Đây là mã (opencv C ++) và khu vực chung giữa hai hình ảnh, thu được bằng cách khớp:

nhập mô tả hình ảnh ở đây

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

Cảm ơn câu trả lời siêu tuyệt vời. Nếu tôi có thể, tôi cũng đã trao cho bạn phần thưởng 100p cho cái này :-)
Niels Kristian

2

Hãy xem xét phương thức find_similar_region . Sử dụng nhỏ hơn trong hai hình ảnh làm hình ảnh mục tiêu. Hãy thử các giá trị khác nhau cho các thuộc tính fuzz trên ảnh và ảnh đích.


Cảm ơn, tuy nhiên tôi không thể làm cho nó hoạt động - bạn có thể?
Niels Kristian
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.