5.18. ฮิสโตแกรมและสถิติ¶
นอกเหนือจากการดำเนินการที่เปลี่ยนแปลงพิกเซลของภาพ คลาส Image ยังมีชุดเมธอดสำหรับ วัดค่า พิกเซลเหล่านั้น ได้แก่ การสรุปการกระจายของค่าพิกเซล การคืนค่าความสว่างเฉลี่ยและมัธยฐาน การหาจุดตัดที่เหมาะสมระหว่างพิกเซลมืดและสว่าง รวมถึงการรายงานการกระจายตัวของช่องสี การวัดเหล่านี้สนับสนุนแอปพลิเคชันใน 2 ลักษณะ คือ ใช้เป็นข้อมูลนำเข้าสำหรับโค้ดที่ตัดสินใจว่าจะใช้ค่าขีดแบ่งใด กำหนดค่าเกนเท่าใด หรือโปรไฟล์โทนสีของฉากเป็นอย่างไร และใช้เป็นสัญญาณวิเคราะห์ เช่น "ฉากสว่างเพียงพอหรือไม่?" ซึ่งแอปพลิเคชันสามารถดำเนินการได้โดยไม่ต้องตัดสินใจในระดับพิกเซล
จุดเริ่มต้นสำหรับการวัดเกือบทุกอย่างคือ ฮิสโตแกรม
5.18.1. ฮิสโตแกรม¶
ฮิสโตแกรมของภาพคือการนับจำนวนพิกเซลที่มีค่าความสว่างแต่ละค่าที่เป็นไปได้ สำหรับภาพระดับสีเทา นั่นคือรายการการนับที่จัดเรียงตามค่า 0 ถึง 255 สำหรับภาพสี จะมีรายการดังกล่าวสามชุด โดยหนึ่งชุดต่อหนึ่งช่องสี
get_histogram() คำนวณค่านี้:
h = img.get_histogram()
วัตถุที่ส่งคืนคือผลลัพธ์ histogram ที่เปิดเผยรายการบินต่อช่องสีและการสอบถามระดับสูงบางส่วน ค่าบินถูก ทำให้เป็นมาตรฐาน เพื่อให้รวมกันเป็น 1.0 ฮิสโตแกรมอธิบายโปรไฟล์ของการกระจายตัวแทนที่จะเป็นจำนวนพิกเซลสัมบูรณ์ ซึ่งทำให้การวัดสามารถเปรียบเทียบได้ระหว่างภาพที่มีขนาดต่างกัน
สำหรับภาพระดับสีเทา ฮิสโตแกรมมีหนึ่งช่องของบิน ซึ่งเข้าถึงได้ผ่าน h.bins() (หรือเทียบเท่ากับ h[0]) สำหรับภาพ RGB565 ฮิสโตแกรมถูกคำนวณในพื้นที่สี LAB ที่แนะนำไว้ในหน้าการทำ binary thresholding โดยมีสามช่องบินที่เข้าถึงได้ผ่าน h.l_bins(), h.a_bins(), h.b_bins() (หรือ h[0], h[1], h[2]) LAB เป็นตัวเลือกเดียวกับที่เมธอดค่าขีดแบ่งและการติดตามใช้ ฮิสโตแกรมจึงสอดคล้องกับค่าขีดแบ่งในด้านพื้นที่ที่ใช้วัดสี
5.18.2. บินและจำนวนบิน¶
ฮิสโตแกรมเริ่มต้นมีหนึ่งบินต่อค่าพิกเซลที่เป็นไปได้ นั่นคือ 256 บินสำหรับช่อง 8 บิต บางครั้งความละเอียดนั้นละเอียดกว่าที่แอปพลิเคชันต้องการ ตัวแบ่งประเภทที่ต้องการเพียงโปรไฟล์คร่าวๆ ของการกระจายตัวอาจได้ประโยชน์จากจำนวนบินที่น้อยกว่า เช่น 32 หรือแม้แต่ 8 บิน ซึ่งทั้งทำงานได้เร็วกว่าและให้ผลลัพธ์ที่สะอาดกว่าเมื่อมีสัญญาณรบกวน คีย์เวิร์ด bins (และ l_bins, a_bins, b_bins ต่อช่องสำหรับภาพสี) กำหนดจำนวน:
h = img.get_histogram(bins=32)
การกำหนดขอบเขต ROI และค่าขีดแบ่งทำงานในลักษณะเดียวกับเมธอดการวัดอื่นๆ ส่ง roi เพื่อจำกัดฮิสโตแกรมให้อยู่ในสี่เหลี่ยมผืนผ้าของพิกเซล ส่งรายการ thresholds เพื่อรวมเฉพาะพิกเซลที่ตรงกับช่วงเหล่านั้น รูปแบบค่าขีดแบ่งนี้คือสิ่งที่ทำให้ "คำนวณฮิสโตแกรมของพิกเซลที่ตรงกันเท่านั้น" เป็นการดำเนินการแบบเรียกครั้งเดียว ซึ่งเป็นรูปแบบที่ใช้บ่อยเมื่อแอปพลิเคชันต้องการกำหนดลักษณะเนื้อสัมผัสของบริเวณที่ตรวจพบแล้วโดยไม่ต้องวนซ้ำพิกเซลเอง
ฮิสโตแกรมระดับสีเทาพร้อมการวัดสรุปสามรายการซ้อนทับ ได้แก่ ค่าขีดแบ่งของ Otsu (จุดตัดที่แบ่งกลุ่มมืดและสว่างได้ดีที่สุด) ค่าเฉลี่ย และมัธยฐาน แต่ละการวัดบอกสิ่งที่แตกต่างกันเกี่ยวกับการกระจายตัวเดียวกัน¶
5.18.3. สถิติ¶
ฮิสโตแกรมคือคำอธิบายความชุกของค่าทุกค่า ส่วน สถิติ คือบทสรุปตัวเลขที่ได้มาจากมัน วัตถุ statistics ที่ส่งคืนโดย get_statistics() มีชุดมาตรฐาน:
mean-- ค่าเฉลี่ยเลขคณิตของค่าพิกเซลmedian-- ค่าที่พิกเซลครึ่งหนึ่งอยู่ต่ำกว่าmode-- ค่าเดี่ยวที่พบบ่อยที่สุดstdev-- ส่วนเบี่ยงเบนมาตรฐาน ซึ่งเป็นการวัดการกระจายรอบค่าเฉลี่ยminและmax-- ค่าพิกเซลที่สว่างที่สุดและมืดที่สุดที่มีอยู่lqและuq-- จุดตัดไตรมาสล่างและบน
สำหรับภาพ RGB565 รูปแบบต่อช่อง (l_mean, a_median, b_mode และอื่นๆ) ให้การวัดเดียวกันทีละช่อง
ตัวเลขส่วนใหญ่เหล่านี้ปรากฏในบริบทเฉพาะ mean และ stdev ร่วมกันให้การประมาณสัญญาณรบกวน ฉากที่ควรสม่ำเสมอจะมี stdev น้อย ในขณะที่เซนเซอร์ที่มีสัญญาณรบกวนจะให้ stdev ที่มากกว่าในฉากเดียวกัน min และ max ให้ ความคมชัด ของภาพ ยิ่งใกล้กันมากเท่าใด ฉากยิ่งแบนเท่านั้น ยิ่งห่างกันมากเท่าใด ช่วงไดนามิกที่อัลกอริทึมต้องทำงานด้วยก็ยิ่งมากขึ้น median เป็นจุดกึ่งกลางที่แข็งแกร่งเมื่อการกระจายมีค่าผิดปกติ (พิกเซลที่สว่างมากเพียงไม่กี่ตัวไม่ดึงค่า median ในลักษณะที่ดึงค่า mean) mode คือค่าที่พบบ่อยที่สุดเพียงค่าเดียว มีประโยชน์สำหรับการหาระดับพื้นหลังของภาพที่พื้นหลังครอบคลุมพิกเซลส่วนใหญ่
get_statistics() รันการผ่านฮิสโตแกรมภายในแล้วสรุปผล การส่งอาร์กิวเมนต์ thresholds และ roi เดียวกันกับฮิสโตแกรมที่คำนวณไว้ก่อนหน้าจะให้สถิติสำหรับชุดพิกเซลเดียวกัน
5.18.4. เปอร์เซ็นไทล์และการค้นหา CDF¶
วัตถุ histogram เปิดเผยเมธอด get_percentile() ที่แปลงเศษส่วนเป็นค่าพิกเซล นั่นคือค่าที่พิกเซลตามสัดส่วนที่ร้องขออยู่ต่ำกว่า h.get_percentile(0.5) คือมัธยฐาน h.get_percentile(0.05) และ h.get_percentile(0.95) ร่วมกันให้ min/max ที่แข็งแกร่งซึ่งละเว้น 5% ล่างและบนเป็นค่าผิดปกติ
นี่คือรูปแบบที่แอปพลิเคชันใช้เมื่อต้องการกำหนดลักษณะ ช่วง ของค่าพิกเซลโดยไม่ให้พิกเซลสว่างหรือมืดที่หลงเหลือเพียงไม่กี่ตัวบิดเบือนคำตอบ min/max ที่แข็งแกร่งจากเปอร์เซ็นไทล์ที่ 5 และ 95 ยังเป็นข้อมูลนำเข้าที่เหมาะสมสำหรับการทำ contrast-stretching ซึ่งเป็นการรีแมปต่อพิกเซลที่หัวข้อการแก้ไขโทนสีครอบคลุม
5.18.5. วิธีการของ Otsu¶
ฮิสโตแกรมตอบคำถามอีกข้อหนึ่งที่ควรกล่าวถึงโดยเฉพาะ: จากภาพที่พิกเซลแบ่งเป็นกลุ่ม "มืด" และ "สว่าง" จุดตัดระหว่างทั้งสองอยู่ที่ไหน? หน้าการทำ thresholding ได้ตั้งชื่อกลไกนี้ตามผลลัพธ์แล้ว นั่นคือค่าขีดแบ่งส่วนกลางเพียงค่าเดียวที่แอปพลิเคชันสามารถส่งให้ binary() แต่เลื่อนการอธิบาย วิธีการ ออกไป วิธีการนั้นคือ วิธีการของ Otsu และมันอยู่บนฮิสโตแกรม
สัญชาตญาณ: ภาพที่มีพื้นหน้าและพื้นหลังชัดเจนมี สอง กลุ่มในฮิสโตแกรมความสว่าง พร้อมหุบเขาระหว่างกัน จุดที่เหมาะสมในการกำหนดค่าขีดแบ่งคือก้นหุบเขา นั่นคือค่าที่แยกสองกลุ่มได้ดีที่สุด วิธีการของ Otsu ค้นหาจุดตัดที่เป็นไปได้ทุกจุดและเลือกจุดที่ความแปรปรวนภายในกลุ่มน้อยที่สุด (ซึ่งเหมือนกับการบอกว่าความแปรปรวนระหว่างกลุ่มมากที่สุด) และผลลัพธ์คือการแยก binary ที่เหมาะสมที่สุดสำหรับการกระจายของภาพนั้นๆ
วัตถุ histogram เปิดเผย Otsu ผ่าน get_threshold:
h = img.get_histogram()
t = h.get_threshold()
วัตถุ threshold ที่ส่งคืนมีแอตทริบิวต์ value (สำหรับภาพระดับสีเทา) หรือ l_value / a_value / b_value (สำหรับภาพสี) ที่บรรจุจุดตัดที่เลือก การป้อนผลลัพธ์กลับเข้าไปใน binary() โดยตรงจะให้ค่าขีดแบ่งส่วนกลางที่ปรับตัวเองได้ โดยจุดตัดถูกเลือกจากภาพเอง:
img.binary([(t.value, 255)])
รูปแบบนี้ไม่แก้ปัญหาแสงสว่างไม่สม่ำเสมอที่ค่าขีดแบ่งแบบ adaptive ที่ใช้ฟิลเตอร์แก้ได้ แต่มันแก้คำถาม "ควรตัดที่ค่าใด?" เมื่อการทำ thresholding แบบส่วนกลางเป็นแนวทางที่ถูกต้องอยู่แล้ว สำหรับฉากที่การแยกพื้นหน้า/พื้นหลังชัดเจน ค่าที่ Otsu เลือกมักอยู่ภายในไม่กี่หน่วยจากสิ่งที่มนุษย์จะเลือกด้วยสายตา
5.18.6. การคำนวณบนภาพผลต่าง¶
รายละเอียดที่เป็นประโยชน์เกี่ยวกับ get_histogram() และ get_statistics(): ทั้งสองรับคีย์เวิร์ด difference ที่รับ Image อีกตัวและคำนวณฮิสโตแกรม (หรือสถิติ) ของผลต่างต่อพิกเซลระหว่างต้นทางและภาพนั้น โดยไม่ จัดสรรภาพผลต่างแยกต่างหาก นี่คือวิธีราคาถูกในการถามว่า "ฉากเปลี่ยนแปลงไปจากเฟรมอ้างอิงมากแค่ไหน?" โดยไม่ต้องจ่ายค่าใช้จ่ายสำหรับการเรียก difference() ที่ชัดเจนเพื่อสร้างภาพที่มีจุดประสงค์เพียงเพื่อวัด สำหรับสคริปต์ตรวจจับการเคลื่อนไหวที่รันต่อเนื่อง การประหยัดนี้สะสมได้มาก