ความคิดทั่วไป
ตัวเลือกที่ 1: โหลดรูปภาพทั้งสองเป็นอาร์เรย์ ( scipy.misc.imread
) และคำนวณความแตกต่างขององค์ประกอบ (พิกเซลต่อพิกเซล) คำนวณบรรทัดฐานของความแตกต่าง
ตัวเลือก 2: โหลดภาพทั้งสอง คำนวณเวกเตอร์ฟีเจอร์สำหรับแต่ละรายการ (เช่นฮิสโตแกรม) คำนวณระยะห่างระหว่างคุณสมบัติของเวกเตอร์แทนที่จะเป็นภาพ
อย่างไรก็ตามมีการตัดสินใจบางอย่างก่อน
คำถาม
คุณควรตอบคำถามเหล่านี้ก่อน:
ภาพที่มีรูปร่างและขนาดเท่ากันหรือไม่
ถ้าไม่คุณอาจต้องปรับขนาดหรือครอบตัดพวกเขา ไลบรารี PIL จะช่วยใน Python
หากพวกเขาถ่ายด้วยการตั้งค่าเดียวกันและอุปกรณ์เดียวกันพวกเขาอาจจะเหมือนกัน
ภาพมีการจัดตำแหน่งที่ดีหรือไม่?
ถ้าไม่คุณอาจต้องการเรียกใช้ข้ามสหสัมพันธ์ก่อนเพื่อค้นหาการจัดตำแหน่งที่ดีที่สุดก่อน SciPy มีฟังก์ชั่นให้ทำ
หากกล้องและฉากยังคงอยู่ภาพเหล่านั้นน่าจะสอดคล้องกัน
การเปิดรับแสงของภาพจะเหมือนกันหรือไม่? (ความสว่าง / ความเปรียบต่างเหมือนกันหรือไม่)
หากไม่เป็นเช่นนั้นคุณอาจต้องการทำให้ภาพเป็นปกติ
แต่ระวังในบางสถานการณ์สิ่งนี้อาจทำผิดมากกว่าดี ตัวอย่างเช่นพิกเซลสว่างเดี่ยวบนพื้นหลังสีเข้มจะทำให้ภาพที่ได้มาตรฐานแตกต่างกันมาก
ข้อมูลสีมีความสำคัญหรือไม่?
หากคุณต้องการสังเกตการเปลี่ยนแปลงสีคุณจะมีเวกเตอร์ของค่าสีต่อจุดแทนที่จะเป็นค่าสเกลาร์เหมือนกับภาพระดับสีเทา คุณต้องการความสนใจมากขึ้นเมื่อเขียนรหัสดังกล่าว
มีขอบที่แตกต่างกันในภาพหรือไม่? พวกเขามีแนวโน้มที่จะย้าย?
ถ้าใช่คุณสามารถใช้อัลกอริทึมตรวจจับขอบก่อน (เช่นคำนวณการไล่ระดับสีด้วย Sobel หรือการแปลง Prewitt ใช้เกณฑ์บางอย่าง) จากนั้นเปรียบเทียบขอบบนภาพแรกกับขอบในวินาที
มีสัญญาณรบกวนในภาพหรือไม่
เซ็นเซอร์ทั้งหมดก่อให้เกิดมลพิษกับภาพด้วยเสียงรบกวนบ้าง เซ็นเซอร์ต้นทุนต่ำมีเสียงรบกวนมากขึ้น คุณอาจต้องการใช้การลดจุดรบกวนก่อนที่จะทำการเปรียบเทียบภาพ เบลอเป็นวิธีที่ง่ายที่สุด (แต่ไม่ใช่ดีที่สุด) ที่นี่
คุณต้องการเปลี่ยนแปลงอะไรบ้าง
สิ่งนี้อาจส่งผลต่อการเลือกบรรทัดฐานที่จะใช้สำหรับความแตกต่างระหว่างภาพ
พิจารณาใช้แมนฮัตตันนอร์ม (ผลรวมของค่าสัมบูรณ์) หรือศูนย์นอร์ม (จำนวนองค์ประกอบไม่เท่ากับศูนย์) เพื่อวัดจำนวนภาพที่เปลี่ยนไป อดีตจะบอกให้คุณทราบว่าภาพนั้นถูกปิดลงเท่าใดภาพหลังจะบอกคุณว่าพิกเซลมีความแตกต่างกันเพียงใด
ตัวอย่าง
ฉันคิดว่าภาพของคุณอยู่ในแนวเดียวกันขนาดและรูปร่างเดียวกันอาจมีการเปิดรับแสงที่แตกต่างกัน เพื่อความง่ายฉันแปลงให้เป็นโทนสีเทาแม้ว่าจะเป็นภาพสี (RGB)
คุณจะต้องมีการนำเข้าเหล่านี้:
import sys
from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average
ฟังก์ชั่นหลัก, อ่านสองภาพ, แปลงเป็นสีเทา, เปรียบเทียบและพิมพ์ผลลัพธ์:
def main():
file1, file2 = sys.argv[1:1+2]
# read images as 2D arrays (convert to grayscale for simplicity)
img1 = to_grayscale(imread(file1).astype(float))
img2 = to_grayscale(imread(file2).astype(float))
# compare
n_m, n_0 = compare_images(img1, img2)
print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size
วิธีเปรียบเทียบ img1
และimg2
อาร์เรย์ SciPy 2D อยู่ที่นี่:
def compare_images(img1, img2):
# normalize to compensate for exposure difference, this may be unnecessary
# consider disabling it
img1 = normalize(img1)
img2 = normalize(img2)
# calculate the difference and its norms
diff = img1 - img2 # elementwise for scipy arrays
m_norm = sum(abs(diff)) # Manhattan norm
z_norm = norm(diff.ravel(), 0) # Zero norm
return (m_norm, z_norm)
หากไฟล์เป็นภาพสีให้imread
ส่งคืนอาร์เรย์ 3D ช่องสัญญาณ RGB เฉลี่ย (แกนอาร์เรย์สุดท้าย) เพื่อรับความเข้ม ไม่จำเป็นต้องทำเพื่อภาพสีเทา (เช่น.pgm
):
def to_grayscale(arr):
"If arr is a color image (3D array), convert it to grayscale (2D array)."
if len(arr.shape) == 3:
return average(arr, -1) # average over the last axis (color channels)
else:
return arr
การทำให้เป็นมาตรฐานนั้นไม่สำคัญคุณอาจเลือกที่จะทำให้ปกติเป็น [0,1] แทนที่จะเป็น [0,255] arr
เป็นอาร์เรย์ SciPy ที่นี่ดังนั้นการดำเนินการทั้งหมดจึงเป็นองค์ประกอบที่ชาญฉลาด:
def normalize(arr):
rng = arr.max()-arr.min()
amin = arr.min()
return (arr-amin)*255/rng
เรียกใช้main
ฟังก์ชัน:
if __name__ == "__main__":
main()
ตอนนี้คุณสามารถใส่ทุกอย่างไว้ในสคริปต์แล้ววิ่งข้ามภาพสองภาพ หากเราเปรียบเทียบภาพกับตัวเองจะไม่มีความแตกต่าง:
$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0
หากเราทำให้ภาพเบลอและเปรียบเทียบกับของเดิมมีความแตกต่าง:
$ python compare.py one.jpg one-blurred.jpg
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0
PS ทั้งcompare.pyสคริปต์
อัปเดต: เทคนิคที่เกี่ยวข้อง
เนื่องจากคำถามเกี่ยวกับลำดับวิดีโอที่เฟรมมีแนวโน้มที่จะใกล้เคียงกันและคุณมองหาบางสิ่งที่ผิดปกติฉันต้องการพูดถึงวิธีการอื่น ๆ ที่อาจเกี่ยวข้อง:
- การลบพื้นหลังและการแบ่งส่วน (เพื่อตรวจจับวัตถุเบื้องหน้า)
- การไหลของแสงแบบเบาบาง (เพื่อตรวจจับการเคลื่อนไหว)
- การเปรียบเทียบฮิสโตแกรมหรือสถิติอื่น ๆ แทนภาพ
ฉันขอแนะนำอย่างยิ่งให้ดูที่หนังสือ“ การเรียนรู้ OpenCV” บทที่ 9 (ส่วนภาพและการแบ่งส่วน) และ 10 (การติดตามและการเคลื่อนไหว) อดีตสอนให้ใช้วิธีการลบพื้นหลังหลังให้ข้อมูลเกี่ยวกับวิธีการไหลของแสง วิธีการทั้งหมดจะดำเนินการในห้องสมุด OpenCV ถ้าคุณใช้ Python ฉันแนะนำให้ใช้ OpenCV ≥ 2.3 และcv2
โมดูล Python
เวอร์ชันที่ง่ายที่สุดของการลบพื้นหลัง:
- เรียนรู้ค่าเฉลี่ยμและส่วนเบี่ยงเบนมาตรฐานสำหรับทุกพิกเซลของพื้นหลัง
- เปรียบเทียบค่าพิกเซลปัจจุบันกับช่วงของ (μ-2σ, μ + 2σ) หรือ (μ-σ, μ + σ)
เวอร์ชันขั้นสูงเพิ่มเติมทำให้คำนึงถึงอนุกรมเวลาสำหรับทุกพิกเซลและจัดการกับฉากที่ไม่คงที่ (เช่นต้นไม้หรือหญ้าที่กำลังเคลื่อนที่)
แนวคิดของการไหลของแสงคือการถ่ายภาพสองภาพขึ้นไปและกำหนดเวกเตอร์ความเร็วให้กับทุกพิกเซล (การไหลของแสงที่หนาแน่น) หรือกับบางส่วนของภาพ ในการประมาณการไหลของแสงแบบเบาบางคุณสามารถใช้วิธี Lucas-Kanade (ซึ่งถูกนำไปใช้ใน OpenCV ด้วย) เห็นได้ชัดว่าหากมีการไหลจำนวนมาก (ค่าเฉลี่ยสูงกว่าค่าสูงสุดของเขตข้อมูลความเร็ว) แสดงว่ามีบางสิ่งเคลื่อนไหวในเฟรมและภาพที่ตามมาจะแตกต่างกันมากขึ้น
การเปรียบเทียบฮิสโทแกรมอาจช่วยตรวจจับการเปลี่ยนแปลงอย่างฉับพลันระหว่างเฟรมที่ต่อเนื่องกัน วิธีการนี้ใช้ในCourbon et al, 2010 :
ความคล้ายคลึงกันของเฟรมต่อเนื่อง วัดระยะทางระหว่างสองเฟรมที่ต่อเนื่องกัน หากสูงเกินไปก็หมายความว่าเฟรมที่สองเสียหายและทำให้ภาพถูกกำจัด ระยะ Kullback-Leiblerหรือเอนโทรปีร่วมกันใน histograms ของทั้งสองเฟรม:
โดยที่pและqเป็นฮิสโตแกรมของเฟรมที่ใช้ ขีด จำกัด ได้รับการแก้ไขใน 0.2