5.25. การค้นหาบลอบ¶
การ Thresholding แปลงเฟรมที่จับภาพได้ให้เป็นมาสก์แบบไบนารี: แต่ละพิกเซลจะผ่านหรือไม่ผ่านการทดสอบค่าขีดแบ่ง ซึ่งตอบคำถามว่า สีใดที่แอปพลิเคชันสนใจปรากฏในฉาก แต่ไม่ตอบว่าอยู่ ที่ไหน -- มาสก์เป็นเพียงทะเลของ 1 และ 0 ขั้นตอนต่อไปคือการตรวจจับบลอบ: การเดินผ่านมาสก์ หาบริเวณที่ต่อเนื่องกันของพิกเซลที่ผ่าน และส่งคืนแต่ละบริเวณเป็นอ็อบเจ็กต์ที่มีตำแหน่ง ขนาด ทิศทาง และคุณสมบัติอื่น ๆ ที่แอปพลิเคชันสามารถนำไปใช้ได้
find_blobs() คือเมธอดหลักสำหรับขั้นตอนนี้ และเป็นจุดเข้าหลักสู่โลกของอ็อบเจ็กต์ผลลัพธ์ในโมดูล image การติดตามลูกบอลสี การตามเส้นที่วาดบนพื้น การนับจุดสว่างที่ thermal sensor เห็น การตัดสินใจว่า LED สีน้ำเงินเปิดหรือปิด -- การเรียกใช้เดียวกันครอบคลุมทั้งหมด อินพุตที่เปลี่ยนไปได้แก่ ค่าขีดแบ่ง บริเวณที่ค้นหา และตัวกรองที่ใช้กับผลลัพธ์ แต่รูปแบบการเรียกยังคงเหมือนเดิม
5.25.1. การเรียกพื้นฐาน¶
find_blobs รับรายการของค่าขีดแบ่งและส่งคืนรายการของอ็อบเจ็กต์ผลลัพธ์บลอบ:
thresholds = [(30, 100, 15, 127, 15, 127)] # LAB threshold for red
blobs = img.find_blobs(thresholds)
for b in blobs:
img.draw_rectangle(b.rect, color=(255, 0, 0))
img.draw_cross(b.cx, b.cy, color=(255, 0, 0))
แต่ละทูเพิลค่าขีดแบ่งมีรูปแบบเดียวกับค่าขีดแบ่งที่ส่งให้ binary() -- หกรายการ (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi) สำหรับภาพ RGB565 (ขอบเขตอยู่ใน LAB) และสองรายการ (lo, hi) สำหรับภาพ grayscale สามารถระบุได้ถึง 32 ค่าขีดแบ่งในการเรียกครั้งเดียว ซึ่งทำให้ find_blobs() มีความยืดหยุ่นสูง: บีคอนสีแดง เขียว และน้ำเงินสามารถติดตามพร้อมกันได้ แต่ละสีมีส่วนร่วมกับบลอบของตัวเองในรายการที่ส่งคืน และคุณสมบัติ code ของแต่ละบลอบระบุว่าตรงกับค่าขีดแบ่งใด
การเรียก draw_rectangle() และ draw_cross() ด้านบนใช้ใส่คำอธิบายประกอบบนเฟรมที่จับภาพสำหรับการแสดงผลใน IDE ผลลัพธ์ของบลอบมี b.rect (กรอบล้อมรอบในรูปแบบ 4-ทูเพิล) และ b.cx / b.cy (จุดศูนย์กลางในรูปแบบจำนวนเต็ม) อยู่แล้ว ดังนั้นการวาดการตรวจจับกลับเข้าเฟรมทำได้ด้วยการเรียกเมธอดสองครั้ง
5.25.2. สิ่งที่ผลลัพธ์ประกอบด้วย¶
แต่ละ Blob คืออาร์เรย์แบบแอตทริบิวต์ที่รวมทุกสิ่งที่ตัวตรวจจับวัดได้เกี่ยวกับบริเวณนั้น คุณสมบัติแบ่งออกเป็นสี่กลุ่ม
กลุ่ม กรอบล้อมรอบและจุดศูนย์กลาง -- x, y, w, h, rect, cx, cy, cxf, cyf -- อธิบายตำแหน่งของบลอบ rect คือ 4-ทูเพิล (x, y, w, h) ที่เมธอดการวาดคาดหวัง cx และ cy คือจุดศูนย์กลางในพิกัดพิกเซลจำนวนเต็ม cxf และ cyf คือจุดศูนย์กลางในพิกัดทศนิยมระดับย่อยพิกเซล มีประโยชน์เมื่อการสอบเทียบต้นน้ำสนใจตำแหน่งเชิงเศษส่วน
กลุ่ม ตัวบ่งชี้รูปร่าง -- pixels, area, density, perimeter, roundness, elongation, compactness, rotation -- อธิบายว่าบลอบมีลักษณะอย่างไร pixels คือจำนวนพิกเซลที่ผ่าน area คือพื้นที่ของกรอบล้อมรอบที่ตรงแกน (w * h) density คืออัตราส่วนของสองค่านี้ ซึ่งเข้าใกล้ 1.0 สำหรับสี่เหลี่ยมผืนผ้าทึบ และลดลงเข้าใกล้ 0.0 สำหรับเส้นทแยงมุมบาง roundness และ compactness ทั้งคู่ให้คะแนนความกลมของบลอบจากมุมมองเรขาคณิตที่แตกต่างกัน (roundness จากโมเมนต์อันดับสอง compactness จากอัตราส่วนเส้นรอบวงต่อพื้นที่) elongation คือ 1.0 - roundness เพื่อความสะดวก rotation คือทิศทางของแกนหลักในหน่วยเรเดียน ซึ่งแม่นยำที่สุดบนบลอบยาวและมีความผิดพลาดบนบลอบที่เกือบกลม (แกนที่คลุมเครือไม่มีทิศทางที่ชัดเจน)
กลุ่ม ค่าขีดแบ่งและข้อมูลเมตาการรวม -- code, count -- ระบุว่าค่าขีดแบ่งใดตรงกันและมีกี่บลอบต้นทางที่ถูกรวมเข้าด้วยกันในผลลัพธ์ code คือบิตแมป 32 บิตที่มีหนึ่งบิตต่อค่าขีดแบ่งที่ตรงกัน (ค่าขีดแบ่งเดียวให้ code == 1 บลอบหลายสีที่รวมกันสามารถมีหลายบิตที่ตั้ง) count คือ 1 เว้นแต่ merge=True จะรวมการตรวจจับหลายรายการเป็นหนึ่ง
กลุ่ม มุม -- corners, min_corners -- ให้รูปทรงเรขาคณิตแบบหมุนของบลอบ corners คือ 4-ทูเพิลของค่าสุดขีด (x, y) ที่นำมาจากคอนทัวร์ของบลอบ เรียงตามเข็มนาฬิกาจากบนซ้าย min_corners คือ 4-ทูเพิลของมุมสำหรับสี่เหลี่ยมผืนผ้าหมุนที่มีพื้นที่น้อยที่สุดซึ่งล้อมรอบบลอบ สี่เหลี่ยมผืนผ้าพื้นที่น้อยที่สุดคือการพอดีแน่น rect ที่ตรงแกนคือการพอดีหลวมที่ตรงกับตารางพิกเซล ทั้งสองมีประโยชน์ขึ้นอยู่กับว่าขั้นตอนปลายน้ำต้องการกรอบที่มีทิศทางหรือกรอบธรรมดา
บลอบมีกรอบล้อมรอบที่ตรงแกน (rect, x, y, w, h) จุดศูนย์กลาง (cx, cy หรือระดับย่อยพิกเซล cxf, cyf) สี่เหลี่ยมผืนผ้าหมุนพื้นที่น้อยที่สุด (min_corners บวกกับ rotation) และเส้นแกนหลัก/แกนรองที่เป็นตัวเลือกซึ่งคำนวณโดยฟังก์ชันระดับโมดูลด้านล่าง¶
5.25.3. การกรองการค้นหา¶
เฟรมที่จับภาพได้โดยทั่วไปมีพิกเซลที่ตรงกับค่าขีดแบ่งด้วยเหตุผลอื่นนอกจากวัตถุที่แอปพลิเคชันสนใจ: แสงสะท้อนแบบ specular วัตถุในฉากหลังที่อยู่ไกล พิกเซลที่มีสัญญาณรบกวนซึ่งเกิดขึ้นในช่วง LAB อาร์กิวเมนต์คีย์เวิร์ดของ find_blobs() คือแนวป้องกันแรก
roi จำกัดการค้นหาให้อยู่ในบริเวณของเฟรม เช่นเดียวกับเมธอดอื่น ๆ ในโมดูล image แอปพลิเคชันที่รู้ว่าวัตถุสามารถปรากฏได้เฉพาะในครึ่งล่างของภาพสามารถส่ง roi=(0, h//2, w, h//2) และละเว้นทุกอย่างด้านบน เวลาที่ประหยัดได้จะนำกลับไปเพิ่มอัตราเฟรม
area_threshold และ pixels_threshold ทั้งคู่กรองบลอบที่เล็กเกินไปจนไม่สำคัญ area_threshold ตัดบลอบที่กรอบล้อมรอบมีพิกเซลน้อยกว่าค่านั้น (เหมาะสำหรับกรองสัญญาณรบกวนที่กระจัดกระจาย) pixels_threshold ตัดบลอบที่มีพิกเซล ที่ผ่าน น้อยกว่าค่านั้น (เหมาะสำหรับกรองบลอบที่ใหญ่แต่กระจาย เช่น รูปแบบจุดที่ถูก threshold ซึ่งมีพิกเซลตรงกันหนึ่งหรือสองพิกเซลที่นี่และที่นั่น) ค่าเริ่มต้นของทั้งคู่คือ 10 การเพิ่มเป็นหลายร้อยสำหรับเป้าหมายพื้นหน้าที่อยู่ห่างไม่กี่เซนติเมตรจะกำจัดสัญญาณรบกวนขนาดเล็กทุกรอยได้
x_stride และ y_stride กำหนดขั้นพิกเซลที่สแกนเนอร์ใช้ขณะ ค้นหา บลอบเพื่อเริ่มติดตาม Stride ไม่ใช่ความละเอียดการติดตาม -- การติดตามจะตามขอบเขตบลอบจริงเสมอที่รายละเอียดพิกเซลเดียว -- แต่ควบคุมว่าการสแกนค้นหาพิกเซลเริ่มต้นได้เร็วแค่ไหน เมื่อบลอบมีขนาดใหญ่ที่รู้จัก (เป้าหมายสีขนาดกำปั้นอยู่ห่างหนึ่งฟุตจากกล้อง มีขนาดหลักร้อยพิกเซลได้ง่าย) x_stride=4, y_stride=4 ลดเวลาสแกนลงสิบหกเท่าโดยไม่สูญเสียการตรวจจับในทางปฏิบัติ เมื่อบลอบมีขนาดเล็ก (บีคอน LED ที่อยู่ไกล มีขนาดไม่กี่พิกเซล) stride ต้องอยู่ที่ 1 เพื่อไม่ให้ก้าวข้ามไปทั้งหมด invert พลิกการทดสอบค่าขีดแบ่ง: การตรงกันกลายเป็นไม่ตรงกัน และรูทีนส่งคืนบลอบของพิกเซล ที่ไม่ผ่าน แทน
threshold_cb คือ Python callback ที่ถูกเรียกบนบลอบแต่ละอันหลังจาก thresholding แต่ก่อนที่รายการผลลัพธ์สุดท้ายจะถูกสร้าง คอลแบ็กรับบลอบและส่งคืน True เพื่อเก็บหรือ False เพื่อทิ้ง นี่คือที่สำหรับใช้ตัวกรอง Python ระดับใดก็ได้กับคุณสมบัติที่อาร์กิวเมนต์คีย์เวิร์ดไม่เปิดเผยโดยตรง -- ความหนาแน่นขั้นต่ำ ช่วงการหมุนที่ระบุ การรวมบิตโค้ดแบบกำหนดเองหลังการรวม อาร์กิวเมนต์คีย์เวิร์ดเป็นตัวกรองในโค้ดเนทีฟและทำงานเร็ว คอลแบ็กทำงานใน Python และช้ากว่าแต่ไม่จำกัดในสิ่งที่สามารถแสดงออกได้
5.25.4. การรวมบลอบที่ทับซ้อนกัน¶
merge=True ประมวลผลรายการผลลัพธ์ภายหลังเพื่อรวมบลอบที่กรอบล้อมรอบทับซ้อนกัน การใช้งานตามธรรมชาติคือการตรวจจับเป้าหมายที่กล้องเห็นสีเป็นหลายบริเวณที่ถูก threshold เนื่องจากแสงสะท้อน เส้นเงา หรือแสงที่ไม่เท่ากันทั่ววัตถุ: ลูกบอลสีแดงอาจส่งคืนเป็นบลอบสีแดงสามหรือสี่อันขนาดเล็กที่รวมกันติดตามลูกบอล ด้วย merge=True สามบลอบกลายเป็นบลอบใหญ่หนึ่งอัน rect ครอบคลุมการรวม code คือ OR แบบบิตไวส์ของโค้ดของบลอบที่รวมกัน (ดังนั้นการรวมหลายสีระบุว่าสีใดมีส่วนร่วม) และ count รายงานจำนวนบลอบต้นทางที่รวมกัน
margin ขยายหรือลดกรอบล้อมรอบก่อนการทดสอบการทับซ้อน ด้วย margin=2 บลอบที่กรอบล้อมรอบอยู่ห่างกัน 2 พิกเซลก็ยังรวมกัน ด้วย margin=-2 เฉพาะบลอบที่กรอบล้อมรอบทับซ้อนกันอย่างน้อย 2 พิกเซลเท่านั้นที่จะรวมกัน การปรับจูนตามธรรมชาติ: margin บวกเพื่อจัดการบลอบที่ค่าขีดแบ่งแบ่งออกเป็นชิ้นที่อยู่ติดกัน margin ลบเพื่อแยกวัตถุที่แตกต่างกันที่อยู่ใกล้ชิดกัน
merge_cb ทำงานบนแต่ละคู่ที่เป็นตัวเลือกก่อนที่การรวมจะเกิดขึ้น คอลแบ็กรับบลอบสองอันและส่งคืน True เพื่ออนุญาตการรวมหรือ False เพื่อป้องกัน นี่คือเครื่องมือที่เหมาะสำหรับการตรวจสอบการรวมที่กฎเรขาคณิตพลาด -- ตัวอย่างเช่น ปฏิเสธการรวมบลอบสองอันที่มุม rotation ต่างกันมากกว่าค่าขีดแบ่ง หรือปฏิเสธการรวมบลอบขนาดเล็กเข้ากับบลอบขนาดใหญ่กว่ามากหากบลอบขนาดเล็กเป็นแค่สัญญาณรบกวน
5.25.5. ฮิสโตแกรมการฉาย¶
x_hist_bins_max และ y_hist_bins_max แนบ ฮิสโตแกรมการฉาย ที่เป็นตัวเลือกกับแต่ละบลอบ ฮิสโตแกรมการฉายคือการนับพิกเซลที่ผ่านตามแกนหนึ่ง: ฮิสโตแกรมแกน X รวมพิกเซลที่ผ่านต่อคอลัมน์ภายในกรอบล้อมรอบของบลอบ และฮิสโตแกรมแกน Y รวมต่อแถว ทั้งคู่มีค่าเริ่มต้นเป็นศูนย์ -- ฮิสโตแกรมจะไม่ถูกคำนวณเว้นแต่จะระบุ max ที่ไม่ใช่ศูนย์ เนื่องจากมิฉะนั้นจะเพิ่มงานให้กับทุกการตรวจจับ
เมื่อคำนวณแล้ว ฮิสโตแกรมให้สัญญาณ 1 มิติที่ราคาถูกซึ่งแอปพลิเคชันสามารถวิเคราะห์เพิ่มเติม: ตรวจจับตำแหน่งของแถบแนวตั้งภายในบลอบ หาจุดเปลี่ยนของเป้าหมายสองสี นับจำนวนช่องว่างตามแกนยาว พวกมันถูกเก็บเป็นคุณสมบัติ x_hist_bins และ y_hist_bins บนแต่ละ Blob
5.25.6. ฟังก์ชันช่วยเหลือเรขาคณิตเพิ่มเติม¶
ค่าการวัดเรขาคณิตเพิ่มเติมอีกหลายค่าอยู่เป็นฟังก์ชันระดับโมดูลที่รับบลอบและส่งคืนการวัดที่ต้องการ:
image.get_solidity()ส่งคืน solidity ของบลอบ -- จำนวนพิกเซลหารด้วยพื้นที่ของ convex hull บริเวณทึบที่เต็มจะใกล้1.0บลอบที่มีรอยเว้า (รูปเกือกม้า มือที่กางนิ้ว) จะต่ำกว่ามากimage.get_convexity()ส่งคืน convexity -- เส้นรอบวงของ convex hull หารด้วยเส้นรอบวงของบลอบ บลอบที่นูนสมบูรณ์คือ1.0บลอบที่หยักหรือมีรอยบากจะต่ำกว่าimage.get_major_axis_line()และimage.get_minor_axis_line()ส่งคืนอ็อบเจ็กต์Lineตามแกนหลักและแกนรองของบลอบ ซึ่งได้มาจากสี่เหลี่ยมผืนผ้าหมุนพื้นที่น้อยที่สุดimage.get_enclosing_circle()ส่งคืนCircleที่ล้อมรอบบลอบ -- มีประโยชน์เมื่อขั้นตอนปลายน้ำต้องการวงกลมเพื่อวาดหรือทดสอบimage.get_enclosed_ellipse()ส่งคืน 5-ทูเพิล(cx, cy, rx, ry, rotation)สำหรับรูปวงรีที่ถูกล้อมในสี่เหลี่ยมผืนผ้าหมุนพื้นที่น้อยที่สุดของบลอบ ค่าเหล่านี้ป้อนโดยตรงเข้าdraw_ellipse()
5.25.7. การเรียนรู้ค่าขีดแบ่งอัตโนมัติ¶
ตัวตรวจจับบลอบดีได้เท่าค่าขีดแบ่งที่ใช้งาน และการ หา ค่าขีดแบ่งที่ถูกต้องสำหรับสีเป้าหมายเป็นปัญหาของตัวเอง รูปแบบทั่วไปสองแบบช่วยลดงานนั้น
แบบแรกคือ การเลือกแบบโต้ตอบใน IDE: จับภาพเฟรม ลากสี่เหลี่ยมรอบตัวอย่างของสีเป้าหมาย และให้ ตัวแก้ไขค่าขีดแบ่ง ของ IDE รายงานขอบเขต LAB ที่เห็น ขอบเขตเหล่านั้นถูกนำไปใส่ในสคริปต์เป็นค่าขีดแบ่งของ find_blobs() และตัวตรวจจับก็พร้อมใช้งาน
แบบที่สองคือการเรียนรู้อัตโนมัติแบบโปรแกรม: รูทีนการสอบเทียบที่ทำงานบนกล้องจับภาพเฟรม นำฮิสโตแกรมของแพตช์ที่รู้จักซึ่งเป้าหมายอยู่ (get_histogram() พร้อม roi=) และอ่านช่วงค่าของแพตช์จากฮิสโตแกรมด้วย get_percentile() เปอร์เซ็นไทล์ที่ 5 กำหนดขอบเขตต่ำของแต่ละช่อง และที่ 95 กำหนดขอบเขตสูง โดยละเว้นพิกเซลที่ผิดปกติที่ทั้งสองปลาย บนภาพ RGB565 การเรียก percentile หนึ่งครั้งรายงานช่อง LAB ทั้งสามพร้อมกัน ดังนั้นการเรียกสองครั้งให้ตัวเลขหกค่าที่ find_blobs() คาดหวัง:
h = img.get_histogram(roi=patch)
lo = h.get_percentile(0.05)
hi = h.get_percentile(0.95)
threshold = (lo.l_value, hi.l_value,
lo.a_value, hi.a_value,
lo.b_value, hi.b_value)