ฉันจะตรวจสอบได้อย่างไรว่าภาพสองภาพนั้น“ เหมือนกัน” แม้ว่าจะมีการครอบตัด / อัตราส่วนแตกต่างกันเล็กน้อย?


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% ของมัน

PS ฉันจะได้ภาพที่มีความละเอียดสูงกว่าหากช่วยได้ (เช่นสองเท่า)


2
ไม่แน่ใจเกี่ยวกับ RMagick แต่compareเครื่องมือบรรทัดคำสั่งของ ImageMagick มี-subimage-searchสวิตช์
Stefan

นั่นเป็นเรื่องที่น่าสนใจ, คำสั่งจะเป็นอย่างไร
Niels Kristian

2
ไม่เคยใช้ด้วยตัวเองบางทีอาจช่วยได้: stackoverflow.com/q/29062811/477037
Stefan

ขอบคุณนั่นเป็นข้อมูลที่ยอดเยี่ยม ฉันไม่สามารถคิดออกว่าจะทำเช่นนี้จากทับทิม แต่ ...
นีลส์ Kristian

1
ภาพนั้นมีคุณภาพต่ำหรือไม่? หากไม่มีโปรดแบ่งปันรูปภาพที่ใหญ่กว่าด้วยคุณภาพที่มากขึ้น
MH304

คำตอบ:


6

คุณอาจต้องการดูการจับคู่คุณสมบัติ แนวคิดคือการค้นหาคุณสมบัติในสองภาพและจับคู่พวกเขา วิธีนี้มักใช้เพื่อค้นหาแม่แบบ (พูดโลโก้) ในภาพอื่น ในสาระสำคัญสามารถอธิบายเป็นสิ่งที่มนุษย์จะพบว่าน่าสนใจในภาพเช่นมุมหรือพื้นที่เปิดโล่ง มีเทคนิคการตรวจจับคุณสมบัติอยู่หลายประเภท แต่ข้อเสนอแนะของฉันคือการใช้การแปลงคุณสมบัติแบบไม่แปรปรวน (SIFT) เป็นอัลกอริทึมการตรวจจับคุณลักษณะ SIFT ไม่แปรเปลี่ยนไปจากการแปลภาพ, การปรับขนาด, การหมุน, ค่าคงที่บางส่วนเพื่อการเปลี่ยนแปลงความสว่างและความทนทานต่อความผิดเพี้ยนทางเรขาคณิตในท้องถิ่น ดูเหมือนว่าจะตรงกับข้อกำหนดของคุณซึ่งรูปภาพสามารถมีอัตราส่วนต่างกันเล็กน้อย

ป.ร. ให้ไว้สองภาพของคุณที่นี่ความพยายามที่จะตรงกับคุณสมบัติที่ใช้Flann คุณลักษณะจับคู่ เพื่อตรวจสอบว่าภาพสองภาพที่เหมือนกันเราสามารถฐานมันออกบางเกณฑ์ที่กำหนดไว้ซึ่งติดตามจำนวนของการแข่งขันที่ผ่านการทดสอบอัตราส่วนที่อธิบายไว้ในภาพที่โดดเด่นจากคุณสมบัติชั่ง-คง Keypoints โดย เดวิด G โลว์ คำอธิบายอย่างง่ายของการทดสอบคือการทดสอบอัตราส่วนจะตรวจสอบว่าการจับคู่นั้นไม่ชัดเจนและควรลบออกหรือไม่คุณสามารถถือว่าเป็นเทคนิคการกำจัดค่าเดิมได้ เราสามารถนับจำนวนการแข่งขันที่ผ่านการทดสอบนี้เพื่อตรวจสอบว่าภาพทั้งสองเหมือนกันหรือไม่ นี่คือผลลัพธ์ที่ตรงกับคุณสมบัติ:

Matches: 42

จุดแสดงถึงการแข่งขันทั้งหมดที่ตรวจพบในขณะที่เส้นสีเขียวแสดงถึง "การจับคู่ที่ดี" ที่ผ่านการทดสอบอัตราส่วน หากคุณไม่ได้ใช้การทดสอบอัตราส่วนคะแนนทั้งหมดจะถูกวาด ด้วยวิธีนี้คุณสามารถใช้ตัวกรองนี้เป็นเกณฑ์ในการรักษาคุณสมบัติที่ดีที่สุดเท่านั้น


ฉันนำไปใช้ใน Python ฉันไม่คุ้นเคยกับ 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

PS ฉันอัปเดตภาพในขนาดที่ใหญ่ขึ้น
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 เปรียบเทียบเพื่อตรวจสอบว่าภาพที่สอง ( small) เป็นภาพย่อยของภาพแรก ( large) ฟังก์ชั่นนี้ไม่ได้ตรวจสอบว่าขนาดเล็กมีขนาดเล็กกว่าขนาดใหญ่อย่างเคร่งครัด (ทั้งความสูงและความกว้าง) จำนวนที่ฉันใส่สำหรับความคล้ายคลึงกันคือ 0.2 (ข้อผิดพลาด 20%) และค่าสำหรับรูปภาพที่คุณระบุมีค่าประมาณ 0.15 คุณอาจต้องการปรับแต่งนี้! ฉันพบว่ารูปภาพที่เป็นชุดย่อยที่เข้มงวดได้รับน้อยกว่า 0.01

  • หากคุณต้องการข้อผิดพลาดน้อยลง (จำนวนน้อยกว่า) ในกรณีที่คุณมีการทับซ้อนกัน 90% แต่ภาพที่สองมีสิ่งพิเศษบางอย่างที่ภาพแรกไม่สามารถทำได้คุณสามารถเรียกใช้หนึ่งครั้งจากนั้นครอบตัดภาพขนาดใหญ่แรก จากนั้นเรียกใช้อีกครั้งโดยใช้ภาพที่ครอบตัดเป็นภาพ "เล็ก" และภาพต้นฉบับ "เล็ก" เป็นภาพใหญ่
  • หากคุณต้องการอินเทอร์เฟซที่เน้นวัตถุใน Ruby เป็นอย่างยิ่ง rmagick ใช้ MagicCore API คำสั่งนี้ (ลิงก์ไปยังเอกสาร)อาจเป็นสิ่งที่คุณต้องการใช้เพื่อนำไปใช้และคุณสามารถเปิด pr เพื่อ rmagick หรือแพ็คเกจ cext ด้วยตัวคุณเอง
  • การใช้ open3 จะเริ่มกระทู้ ( ดูเอกสาร ) การปิดstderrและstdoutไม่ใช่ "จำเป็น" แต่คุณควรจะทำ
  • อิมเมจ "temp" ที่ ARG ตัวที่สามระบุไฟล์ที่จะวิเคราะห์ผลลัพธ์ ด้วยรูปลักษณ์ที่รวดเร็วฉันไม่สามารถหาวิธีที่จะไม่ต้องการมันได้ แต่มันจะเขียนทับโดยอัตโนมัติและอาจดีสำหรับการดีบัก สำหรับตัวอย่างของคุณมันจะเป็นแบบนี้

ป้อนคำอธิบายรูปภาพที่นี่

  • เอาต์พุตเต็มอยู่ในรูปแบบของ 10092.6 (0.154003) @ 0,31 ตัวเลขแรกคือค่า rmse จาก 655535 ตัวเลขที่สอง (ซึ่งฉันใช้) คือเปอร์เซ็นต์ที่ทำให้เป็นมาตรฐาน ตัวเลขสองตัวสุดท้ายแทนตำแหน่งของภาพต้นฉบับที่ภาพเล็กเริ่มขึ้น
  • เนื่องจากไม่มีแหล่งที่มาของความจริงสำหรับภาพที่คล้ายกันฉันจึงเลือก RMSE (ดูตัวเลือกการวัดเพิ่มเติมที่นี่ ) เป็นการวัดความแตกต่างระหว่างค่าทั่วไป การนับจำนวนข้อผิดพลาดแบบสัมบูรณ์ (AE) อาจดูเหมือนเป็นความคิดที่ดีอย่างไรก็ตามดูเหมือนว่าซอฟต์แวร์การครอบตัดบางตัวไม่รักษาพิกเซลอย่างสมบูรณ์ดังนั้นคุณอาจต้องปรับ fuzz และไม่ใช่ค่าปกติดังนั้นคุณต้องเปรียบเทียบจำนวนข้อผิดพลาด ด้วยขนาดของภาพและอะไรก็ตาม

1
นั่นคือข้อมูลที่ยอดเยี่ยมจริงๆที่นั่นแครอล ขอบคุณ
Niels Kristian

อยากทราบว่าวิธีนี้ใช้ได้กับกรณีอื่นของคุณหรือไม่!
Carol Chen

1
ขอบคุณสำหรับคำตอบที่ยอดเยี่ยมที่สุด ถ้าฉันทำได้ฉันได้ให้รางวัล 100p ให้กับคุณเช่นกัน :-)
Niels Kristian

3

รับฮิสโตแกรมของทั้งภาพและเปรียบเทียบ สิ่งนี้จะทำงานได้ดีมากสำหรับการครอบตัดและซูมเว้นแต่จะมีการเปลี่ยนแปลงที่รุนแรงเกินไปเนื่องจากสิ่งเหล่านี้

นี่จะดีกว่าวิธีการในปัจจุบันที่คุณลบภาพโดยตรง แต่วิธีการนี้ยังมีไม่กี่


ขอบคุณสำหรับคำแนะนำฉันจะดูมัน
Niels Kristian

นี่ไม่ใช่คำตอบที่มีประโยชน์มากเพราะมันไม่ได้แสดงให้เห็นว่าจะบรรลุเป้าหมายได้อย่างไร มันเทียบเท่ากับ "Google คำนี้และคิดออกเอง"
Anothermh

ฮิสโตแกรมเป็นหนึ่งในสิ่งแรกที่ผู้คนเรียนรู้ในการประมวลผลภาพ หากบางคนต้อง google มันแล้วฉันขอโทษอย่างสุดซึ้ง
Raviteja Narra

3

โดยปกติการจับคู่แม่แบบมีผลดีในสถานการณ์เหล่านี้ การจับคู่เทมเพลตเป็นเทคนิคในการค้นหาพื้นที่ของภาพที่จับคู่ (คล้ายกัน) กับภาพเทมเพลต (ภาพที่สอง) อัลกอริธึมนี้ให้คะแนนสำหรับตำแหน่งที่ดีที่สุดในภาพต้นฉบับ (ภาพที่สอง)

ใน opencv ที่ใช้เมธอดTM_CCOEFF_NORMEDให้คะแนนระหว่าง 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 ใช้ภาพขนาดเล็กกว่าสองภาพเป็นภาพเป้าหมาย ลองใช้ค่าต่างๆสำหรับแอตทริบิวต์ fuzz บนภาพและภาพเป้าหมาย


ขอบคุณ แต่ฉันไม่สามารถทำงานได้ - ได้ไหม
Niels Kristian
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.