ฉันจะวัดความแตกต่างระหว่างสองภาพได้อย่างไร


179

นี่คือสิ่งที่ฉันต้องการจะทำ:

ฉันกำลังถ่ายรูปกับเว็บแคมเป็นระยะ ๆ เรียงลำดับของสิ่งที่เหมือนล่วงเลยเวลา แต่ถ้ามีการเปลี่ยนแปลงอะไรจริงๆนั่นคือภาพสวยมากมีลักษณะเดียวกันผมไม่ต้องการที่จะเก็บภาพรวมล่าสุด

ฉันจินตนาการว่ามีวิธีการหาปริมาณความแตกต่างบางอย่างและฉันจะต้องกำหนดเกณฑ์เชิงประจักษ์

ฉันกำลังมองหาความเรียบง่ายมากกว่าความสมบูรณ์แบบ ฉันใช้หลาม


ที่เกี่ยวข้อง: stackoverflow.com/questions/25977/…
Anoyz

คำตอบ:


269

ความคิดทั่วไป

ตัวเลือกที่ 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 ของทั้งสองเฟรม:

$$ d (p, q) = \ sum_i p (i) \ log (p (i) / q (i)) $$

โดยที่pและqเป็นฮิสโตแกรมของเฟรมที่ใช้ ขีด จำกัด ได้รับการแก้ไขใน 0.2


ฉันได้รับRuntimeWarning: invalid value encountered in double_scalarsในบรรทัดที่ 44 ( return (arr-amin)*255/rng) และValueError: array must not contain infs or NaNsในบรรทัดที่ 30 ( z_norm = norm(diff.ravel(), 0))
BioGeek

@BioGeek นั่นคือถ้าrngเท่ากับศูนย์ เพียงเพิ่มการตรวจสอบและตั้งค่าrng = 1
haisi

76

ทางออกที่ง่าย:

เข้ารหัสภาพเป็นJPEGและมองหาการเปลี่ยนแปลงที่สำคัญในขนาดไฟล์

ฉันใช้สิ่งที่คล้ายกับภาพขนาดย่อของวิดีโอและมีความสำเร็จและความสามารถในการปรับขยายได้มากมาย


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

ชอบมัน. แม้ว่าวิธีการแก้ปัญหาอื่น ๆ จะทำงานเช่นกัน แต่ก็มีข้อได้เปรียบที่ดีสำหรับสถานการณ์ทั่วไป: ถ้าคุณไม่ต้องการบันทึกภาพ "ฐาน" เพียงบันทึกขนาดไฟล์เป็นแฮชแล้วเปรียบเทียบตัวเลขเพียงอย่างเดียวกับการแทนที่ ในกรณีของฉันฉันมี 4 ภาพหนึ่งในนั้นคือ simillar มากและอื่น ๆ 3 แตกต่างกันอย่างแน่นอน เพียงปรับขนาดให้เท่ากันเป็น jpg และ substract ดีจริงๆ.
Diego AndrésDíaz Espinoza

60

คุณสามารถเปรียบเทียบภาพสองภาพโดยใช้ฟังก์ชั่นจากPIL

import Image
import ImageChops

im1 = Image.open("splash.png")
im2 = Image.open("splash2.png")

diff = ImageChops.difference(im2, im1)

วัตถุ diff เป็นภาพที่ทุกพิกเซลเป็นผลมาจากการลบค่าสีของพิกเซลนั้นในภาพที่สองจากภาพแรก การใช้อิมเมจ diff คุณสามารถทำได้หลายอย่าง สิ่งที่ง่ายที่สุดคือdiff.getbbox()ฟังก์ชั่น มันจะบอกคุณสี่เหลี่ยมผืนผ้าเล็ก ๆ น้อย ๆ ที่มีการเปลี่ยนแปลงทั้งหมดระหว่างสองภาพของคุณ

คุณสามารถใช้การประมาณของสิ่งอื่น ๆ ที่กล่าวถึงที่นี่โดยใช้ฟังก์ชั่นจาก PIL ได้เช่นกัน


2
ฉันต้องการบันทึกภาพที่แตกต่าง หมายถึงวัตถุต่าง ๆ ที่เก็บความแตกต่างของภาพ ฉันจะบันทึกมันได้อย่างไร
ซาก้า

2
@Athony คุณสามารถโทร save () บนวัตถุ diff ที่ระบุชื่อภาพ เช่นนี้: diff.save ("diff.png") มันจะบันทึกภาพที่แตกต่างให้คุณ
ซาก้า

20

สองวิธีที่ได้รับความนิยมและค่อนข้างง่ายคือ: (a) ระยะทางแบบยุคลิดที่แนะนำแล้วหรือ (b) ความสัมพันธ์ข้ามแบบปกติ ความสัมพันธ์ข้ามแบบปกติมีแนวโน้มที่จะเห็นได้ชัดว่ามีความทนทานต่อการเปลี่ยนแปลงของแสงมากกว่าความสัมพันธ์ข้ามแบบง่าย Wikipedia ให้สูตรสำหรับการข้ามสหสัมพันธ์แบบปกติ มีวิธีการที่ซับซ้อนมากขึ้นเช่นกัน แต่ก็ต้องใช้งานมากกว่านี้

ใช้ไวยากรณ์เหมือน numpy

dist_euclidean = sqrt (ผลรวม ((i1 - i2) ^ 2)) / i1.size

dist_manhattan = ผลรวม (abs (i1 - i2)) / i1.size

dist_ncc = ผลรวม ((i1 - หมายถึง (i1)) * (i2 - หมายถึง (i2))) / (
  (i1.size - 1) * stdev (i1) * stdev (i2))

สมมติว่าi1และi2เป็น 2D อาร์เรย์ภาพระดับสีเทา


3
ฟังก์ชั่น cross-correlation นั้นถูกสร้างขึ้นใน SciPy ( docs.scipy.org/doc/scipy/reference/generated/… ) และรุ่นที่รวดเร็วโดยใช้ FFT มีให้บริการใน stsci python ( stsci.edu/resources/software_hardware/pyraf/ stsci_python )
endolith

14

สิ่งเล็ก ๆ น้อย ๆ ที่ควรลอง:

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


แต่คุณจะเปรียบเทียบพิกเซลได้อย่างไร
ผู้ให้บริการ

เมื่อคุณมีภาพขนาดย่อคุณสามารถเปรียบเทียบพิกเซลทีละภาพ คุณจะคำนวณ "ระยะทาง" ของค่า RGB หากคุณใช้สีหรือเพียงแค่ความแตกต่างระหว่างโทนสีเทาหากคุณอยู่ในโทนสีเทา
Ates Goral

1
msgstr "เปรียบเทียบพิกเซลทีละภาพ". นั่นหมายความว่าอย่างไร? การทดสอบควรล้มเหลวหรือไม่หากการทดสอบหนึ่งพิกเซล 64 ^ 2 พิกเซลต่อหนึ่งพิกเซลล้มเหลว
Federico A. Ramponi

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

1
ตัวอย่างง่ายๆโดยไม่ต้อง "อัลกอริทึมเลือน": ห่วงขนานผ่านทุกพิกเซล (เทียบพิกเซล # nของภาพ # 1 พิกเซล # nของภาพ # 2) และเพิ่มความแตกต่างในค่าให้กับตัวแปร
MK12

7

ฉันกำลังพูดถึงคำถามที่เฉพาะเจาะจงว่าจะคำนวณอย่างไรหากพวกเขา "แตกต่างพอ" ฉันคิดว่าคุณสามารถหาวิธีลบพิกเซลทีละภาพได้

ก่อนอื่นฉันจะถ่ายภาพจำนวนมากโดยที่ไม่มีอะไรเปลี่ยนแปลงและค้นหาจำนวนสูงสุดที่พิกเซลเปลี่ยนแปลงเพียงเพราะความผันแปรของการจับเสียงในระบบภาพการบีบอัด JPEG และการเปลี่ยนแปลงแสง . บางทีคุณอาจพบว่าจะต้องมีความแตกต่าง 1 หรือ 2 บิตแม้ว่าจะไม่มีอะไรเคลื่อนที่

จากนั้นสำหรับการทดสอบ "ของจริง" คุณต้องการเกณฑ์เช่นนี้:

  • เหมือนกันถ้ามากถึง P พิกเซลแตกต่างกันไม่เกิน E

ดังนั้นบางทีถ้า E = 0.02, P = 1,000 นั่นอาจหมายถึง (โดยประมาณ) ว่าจะ "แตกต่าง" หากมีการเปลี่ยนแปลงพิกเซลเดียวมากกว่า ~ 5 หน่วย (สมมติว่าภาพ 8 บิต) หรือมากกว่า 1,000 พิกเซลมีข้อผิดพลาดใด ๆ

นี่เป็นจุดประสงค์หลักเป็นเทคนิค "triage" ที่ดีในการระบุรูปภาพที่อยู่ใกล้พอที่จะไม่ต้องตรวจสอบเพิ่มเติม ภาพที่ "ล้มเหลว" นั้นอาจเป็นเทคนิคที่ซับซ้อน / มีราคาแพงกว่าซึ่งจะไม่มีผลบวกปลอมหากกล้องสั่นเล็กน้อยหรือมีความทนทานต่อการเปลี่ยนแปลงของแสงมากขึ้น

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


6

ฉันมีปัญหาคล้ายกันในที่ทำงานฉันกำลังเขียนปลายทางการแปลงรูปภาพของเราใหม่และฉันต้องการตรวจสอบว่าเวอร์ชันใหม่สร้างผลลัพธ์เดียวกันหรือใกล้เคียงกับผลลัพธ์เดียวกันกับเวอร์ชันเก่า ดังนั้นฉันจึงเขียนสิ่งนี้:

https://github.com/nicolashahn/diffimg

ซึ่งทำงานกับภาพที่มีขนาดเท่ากันและในระดับต่อพิกเซลวัดความแตกต่างของค่าในแต่ละช่อง: R, G, B (, A) ใช้ความแตกต่างเฉลี่ยของช่องสัญญาณเหล่านั้นแล้วเฉลี่ยความแตกต่าง พิกเซลทั้งหมดและส่งกลับอัตราส่วน

ตัวอย่างเช่นด้วยภาพ 10x10 ของพิกเซลสีขาวและภาพเดียวกัน แต่พิกเซลหนึ่งเปลี่ยนเป็นสีแดงความแตกต่างของพิกเซลนั้นคือ 1/3 หรือ 0.33 ... (RGB 0,0,0 เทียบกับ 255,0,0 ) และพิกเซลอื่น ๆ ทั้งหมดคือ 0 เมื่อรวม 100 พิกเซล 0.33 ... / 100 = ความแตกต่างของรูปภาพประมาณ ~ 0.33%

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


5

คำตอบส่วนใหญ่จะไม่เกี่ยวข้องกับระดับแสง

ฉันจะทำให้ภาพเป็นมาตรฐานในระดับแสงมาตรฐานก่อนทำการเปรียบเทียบ


หากคุณกำลังถ่ายภาพเป็นระยะและแยกคู่ที่อยู่ติดกันคุณอาจจะสามารถเก็บภาพแรกไว้หลังจากที่มีคนเปิดไฟ
walkytalky

5

อีกวิธีที่ดีและเรียบง่ายในการวัดความคล้ายคลึงกันระหว่างสองภาพ:

import sys
from skimage.measure import compare_ssim
from skimage.transform import resize
from scipy.ndimage import imread

# get two images - resize both to 1024 x 1024
img_a = resize(imread(sys.argv[1]), (2**10, 2**10))
img_b = resize(imread(sys.argv[2]), (2**10, 2**10))

# score: {-1:1} measure of the structural similarity between the images
score, diff = compare_ssim(img_a, img_b, full=True)
print(score)

หากคนอื่นสนใจวิธีที่มีประสิทธิภาพมากกว่าในการเปรียบเทียบความคล้ายคลึงกันของภาพฉันได้รวบรวมการสอนและเว็บแอพสำหรับการวัดและการแสดงภาพที่คล้ายกันโดยใช้ Tensorflow


3
ใช่skimageมันดีมากที่จะใช้สำหรับแอปพลิเคชันนี้ ฉันใช้from skimage.measure import compare_ssim, compare_mseมาก เอกสาร skimage.measure
ximiki

3

คุณเคยเห็นอัลกอริทึมสำหรับค้นหาภาพคำถามที่คล้ายกันหรือไม่ ลองใช้ดูคำแนะนำ

ฉันอยากจะแนะนำการแปลงเวฟเล็ตของเฟรมของคุณ (ฉันได้เขียนส่วนขยาย C สำหรับการใช้การแปลง Haar); จากนั้นการเปรียบเทียบดัชนีของปัจจัยเวฟเล็ตที่ใหญ่ที่สุด (ตามสัดส่วน) ระหว่างสองภาพคุณควรได้รับการประมาณความคล้ายคลึงกันเชิงตัวเลข


2

ฉันขอโทษถ้ามันสายเกินไปที่จะตอบ แต่เนื่องจากฉันทำสิ่งที่คล้ายกันฉันคิดว่าฉันสามารถมีส่วนร่วมอย่างใด

บางทีด้วย OpenCV คุณสามารถใช้การจับคู่แม่แบบ สมมติว่าคุณกำลังใช้เว็บแคมดังที่คุณกล่าวไว้:

  1. ลดความซับซ้อนของภาพ (thresholding อาจจะ?)
  2. ใช้การจับคู่แม่แบบและตรวจสอบ max_val ด้วย minMaxLoc

เคล็ดลับ: max_val (หรือ min_val ขึ้นอยู่กับวิธีการที่ใช้) จะให้ตัวเลขจำนวนมาก ในการรับความแตกต่างเป็นเปอร์เซ็นต์ให้ใช้การจับคู่แม่แบบที่มีภาพเดียวกันผลลัพธ์จะเป็น 100% ของคุณ

หลอกรหัสเพื่อเป็นตัวอย่าง:

previous_screenshot = ...
current_screenshot = ...

# simplify both images somehow

# get the 100% corresponding value
res = matchTemplate(previous_screenshot, previous_screenshot, TM_CCOEFF)
_, hundred_p_val, _, _ = minMaxLoc(res)

# hundred_p_val is now the 100%

res = matchTemplate(previous_screenshot, current_screenshot, TM_CCOEFF)
_, max_val, _, _ = minMaxLoc(res)

difference_percentage = max_val / hundred_p_val

# the tolerance is now up to you

หวังว่ามันจะช่วย


1

ระยะทาง Earth moversอาจเป็นสิ่งที่คุณต้องการ มันอาจจะABITหนักในการดำเนินการในเวลาจริงแม้ว่า


ฉันไม่รู้สึกว่าคำตอบนี้จริง ๆ : "ฉันกำลังมองหาความเรียบง่ายมากกว่าความสมบูรณ์แบบฉันใช้งูหลาม"
PilouPili

ฉันคิดว่าเมื่อเธรดคำถามนี้ได้รับการเข้าชมจำนวนมากและชื่อที่ดึงดูดผู้ชมส่วนใหญ่เกี่ยวกับวิธีการหาปริมาณความแตกต่างระหว่างสองภาพมันมีค่าที่นี่
Danoram

1

สิ่งที่เกี่ยวกับการคำนวณระยะทางแมนฮัตตันของสองภาพ นั่นให้ค่า n * n จากนั้นคุณสามารถทำอะไรบางอย่างเช่นค่าเฉลี่ยแถวเพื่อลดค่าเป็น n และฟังก์ชั่นมากกว่านั้นเพื่อรับค่าเดียว


1

ฉันโชคดีมากกับภาพ jpg ที่ถ่ายด้วยกล้องเดียวกันบนขาตั้งโดย (1) ลดความซับซ้อนลงอย่างมาก (เช่นจากความกว้าง 3000 พิกเซลถึง 100 พิกเซลกว้างหรือน้อยกว่า) (2) ทำให้อาร์เรย์ jpg แต่ละชุดแบน เวกเตอร์ (3) จับคู่ภาพตามลำดับที่สัมพันธ์กันโดยใช้อัลกอริทึมสหสัมพันธ์อย่างง่ายเพื่อให้ได้ค่าสัมประสิทธิ์สหสัมพันธ์ (4) สัมประสิทธิ์สหสัมพันธ์กำลังสองเพื่อให้ได้ r-square (เช่นเศษส่วนของความแปรปรวนในภาพหนึ่งอธิบายโดย ถ้า r-square <0.9 ฉันว่ารูปสองรูปนั้นต่างกันและมีบางอย่างเกิดขึ้นระหว่างนั้น

สิ่งนี้แข็งแกร่งและรวดเร็วในการติดตั้งของฉัน (Mathematica 7)

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

ฉันไม่รู้ว่าจะใช้ Python อย่างไร แต่แน่ใจว่ามันสัมพันธ์กันด้วยใช่ไหม


1

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


คุณสามารถคำนวณค่าสัมประสิทธิ์ของภาพเองได้หรือไม่?
endolith

คุณจะต้องคำนวณฮิสโตแกรมของภาพ (ด้วยขนาดช่องเก็บของฮิสโตแกรมตามข้อกำหนด)
vishalv2050

1

ตรวจสอบวิธี Haar Wavelets จะดำเนินการโดยISK-ภูต คุณสามารถใช้รหัส imgdb C ++ เพื่อคำนวณความแตกต่างระหว่างภาพต่างๆได้ทันที:

isk-daemon เป็นเซิร์ฟเวอร์ฐานข้อมูลโอเพนซอร์ซที่มีความสามารถในการเพิ่มการค้นหาภาพตามเนื้อหา (ภาพ) ไปยังเว็บไซต์หรือซอฟต์แวร์ที่เกี่ยวข้องกับภาพ

เทคโนโลยีนี้ช่วยให้ผู้ใช้เว็บไซต์หรือซอฟต์แวร์ใด ๆ ที่เกี่ยวข้องกับภาพวาดบนวิดเจ็ตที่ภาพที่พวกเขาต้องการค้นหาและให้เว็บไซต์ตอบกลับรูปภาพที่คล้ายกันมากที่สุดหรือเพียงแค่ขอภาพถ่ายที่คล้ายกันมากขึ้นในแต่ละหน้ารายละเอียดรูปภาพ


1

ฉันมีปัญหาเดียวกันและเขียนโมดูลหลามอย่างง่ายซึ่งเปรียบเทียบสองภาพขนาดเดียวกันโดยใช้ ImageChops ของหมอนเพื่อสร้างภาพ diff ดำ / ขาวและผลรวมของค่าฮิสโตแกรม

คุณสามารถได้รับคะแนนนี้โดยตรงหรือเป็นค่าร้อยละเมื่อเทียบกับความแตกต่างสีดำกับสีขาว

นอกจากนี้ยังมีฟังก์ชั่น is_equal อย่างง่ายที่มีความเป็นไปได้ที่จะให้เกณฑ์ fuzzy-threshold ภายใต้ (และรวมถึง) ภาพที่ผ่านเป็นเท่ากัน

วิธีการนี้ไม่ได้มีความละเอียดมากนัก แต่อาจจะใช้สำหรับคนอื่น ๆ ที่กำลังดิ้นรนกับปัญหาเดียวกัน

https://pypi.python.org/pypi/imgcompare/


1

หลักการที่ค่อนข้างชัดเจนกว่านั้นคือการใช้ตัวอธิบายทั่วโลกเพื่อเปรียบเทียบภาพเช่น GIST หรือ CENTRIST ฟังก์ชันแฮชตามที่อธิบายไว้ที่นี่ยังมีวิธีแก้ไขปัญหาที่คล้ายคลึงกัน


1
import os
from PIL import Image
from PIL import ImageFile
import imagehash
  
#just use to the size diferent picture
def compare_image(img_file1, img_file2):
    if img_file1 == img_file2:
        return True
    fp1 = open(img_file1, 'rb')
    fp2 = open(img_file2, 'rb')

    img1 = Image.open(fp1)
    img2 = Image.open(fp2)

    ImageFile.LOAD_TRUNCATED_IMAGES = True
    b = img1 == img2

    fp1.close()
    fp2.close()

    return b





#through picturu hash to compare
def get_hash_dict(dir):
    hash_dict = {}
    image_quantity = 0
    for _, _, files in os.walk(dir):
        for i, fileName in enumerate(files):
            with open(dir + fileName, 'rb') as fp:
                hash_dict[dir + fileName] = imagehash.average_hash(Image.open(fp))
                image_quantity += 1

    return hash_dict, image_quantity

def compare_image_with_hash(image_file_name_1, image_file_name_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.
    recommend to use
    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_1 = None
    hash_2 = None
    with open(image_file_name_1, 'rb') as fp:
        hash_1 = imagehash.average_hash(Image.open(fp))
    with open(image_file_name_2, 'rb') as fp:
        hash_2 = imagehash.average_hash(Image.open(fp))
    dif = hash_1 - hash_2
    if dif < 0:
        dif = -dif
    if dif <= max_dif:
        return True
    else:
        return False


def compare_image_dir_with_hash(dir_1, dir_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.

    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_dict_1, image_quantity_1 = get_hash_dict(dir_1)
    hash_dict_2, image_quantity_2 = get_hash_dict(dir_2)

    if image_quantity_1 > image_quantity_2:
        tmp = image_quantity_1
        image_quantity_1 = image_quantity_2
        image_quantity_2 = tmp

        tmp = hash_dict_1
        hash_dict_1 = hash_dict_2
        hash_dict_2 = tmp

    result_dict = {}

    for k in hash_dict_1.keys():
        result_dict[k] = None

    for dif_i in range(0, max_dif + 1):
        have_none = False

        for k_1 in result_dict.keys():
            if result_dict.get(k_1) is None:
                have_none = True

        if not have_none:
            return result_dict

        for k_1, v_1 in hash_dict_1.items():
            for k_2, v_2 in hash_dict_2.items():
                sub = (v_1 - v_2)
                if sub < 0:
                    sub = -sub
                if sub == dif_i and result_dict.get(k_1) is None:
                    result_dict[k_1] = k_2
                    break
    return result_dict


def main():
    print(compare_image('image1\\815.jpg', 'image2\\5.jpg'))
    print(compare_image_with_hash('image1\\815.jpg', 'image2\\5.jpg', 7))
    r = compare_image_dir_with_hash('image1\\', 'image2\\', 10)
    for k in r.keys():
        print(k, r.get(k))


if __name__ == '__main__':
    main()
  • เอาท์พุท:

    False
    True
    image2 \ 5.jpg image1 \ 815.jpg
    image2 \ 6.jpg image1 \ 819.jpg
    image2 \ 7.jpg image1 \ 900.jpg
    image2 \ 8.jpg image1 \ 998.jpg
    image1 \ 1012 .jpg

  • ภาพตัวอย่าง:

    • 815.jpg
      815.jpg

    • 5.jpg
      5.jpg


0

ฉันคิดว่าคุณสามารถคำนวณระยะทางแบบยุคลิด (เช่น sqrt (ผลรวมของความแตกต่าง, พิกเซลต่อพิกเซล) ระหว่างความส่องสว่างของภาพสองภาพและพิจารณาพวกมันเท่ากันถ้ามันอยู่ภายใต้เกณฑ์เชิงประจักษ์ และคุณควรทำฟังก์ชั่น C แทน


0

มีตัวชี้วัดมากมายสำหรับการประเมินว่าภาพสองภาพมีลักษณะเป็นอย่างไร / มีลักษณะอย่างไร

ฉันจะไม่เข้าไปในรหัสใด ๆ ที่นี่เพราะฉันคิดว่ามันควรจะเป็นปัญหาทางวิทยาศาสตร์นอกเหนือจากปัญหาทางเทคนิค

โดยทั่วไปแล้วคำถามเกี่ยวข้องกับการรับรู้ของมนุษย์เกี่ยวกับภาพดังนั้นอัลกอริธึมแต่ละตัวจึงสนับสนุนคุณลักษณะด้านระบบภาพของมนุษย์

แนวทางแบบคลาสสิกคือ:

ความแตกต่างที่มองเห็นได้ทำนาย: อัลกอริทึมสำหรับการประเมินผลของความจงรักภักดีของภาพ ( https://www.spiedigitallibrary.org/conference-proceedings-of-spie/1666/0000/Visible-differences-predictor--an-algorithm-for-the- Assessment-of / 10.1117 / 12.135952.short? SSO = 1 )

การประเมินคุณภาพของภาพ: จากการมองเห็นข้อผิดพลาดไปจนถึงความคล้ายคลึงกันของโครงสร้าง ( http://www.cns.nyu.edu/pub/lcv/wang03-reprint.pdf )

FSIM: ดัชนีความคล้ายคลึงกันของฟีเจอร์สำหรับการประเมินคุณภาพของภาพ ( https://www4.comp.polyu.edu.hk/~cslzhang/IQA/TIP_IQA_FSIM.pdf )

ในหมู่พวกเขา (การประเมินคุณภาพของภาพ: จากข้อผิดพลาดแสดงให้เห็นถึงโครงสร้างคล้ายคลึงกัน) SSIM เป็นที่ง่ายที่สุดในการคำนวณค่าใช้จ่ายและยังมีขนาดเล็กตามที่รายงานในกระดาษอีก "ภาพที่ประเมินคุณภาพบนพื้นฐานของการไล่โทนสีคล้ายคลึงกัน" ( https: //www.semanticscholar .org / กระดาษ / รูปภาพ - การประเมินคุณภาพตามการไล่ระดับสี - Liu-Lin / 2b819bef80c02d5d4cb56f27b202535e119df988 )

มีวิธีอื่นอีกมากมาย ลองดูที่ Google Scholar และค้นหาบางอย่างเช่น "ความแตกต่างของภาพ", "การประเมินคุณภาพของภาพ" ฯลฯ หากคุณสนใจ / สนใจศิลปะจริงๆ


0

มีวิธีที่ง่ายและรวดเร็วในการใช้ numpy โดยการคำนวณข้อผิดพลาดกำลังสองเฉลี่ย:

before = np.array(get_picture())
while True:
    now = np.array(get_picture())
    MSE = np.mean((now - before)**2)

    if  MSE > threshold:
        break

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