ㄍ๏ สารบัญ ๏ㄟ
๛ การใช้ฟังก์ชัน threshold
๛ การหาจุดเปลี่ยนด้วยวิธีของโอตสึ
๛ การใช้จุดเปลี่ยนแบบปรับตัวเองได้
๛ การใช้ค่าจุดเปลี่ยนเป็นตัวคัดกรองเพื่อเอาหรือตัดส่วนที่เหลือ
ต่อจาก
บทที่ ๙
ในบทนี้จะเป็นเรื่องของการใช้ค่าจุดเปลี่ยน (threshold) เพื่อแบ่งหรือคัดกรองส่วนของรูปภาพ
โดยพิจารณาจากความสว่างในภาพ
โดยทั่วไปจะใช้พิจารณาความสว่างของสีเดียว ถ้าเป็นภาพสีก็แปลงเป็นขาวดำก่อน ดังนั้นในบทนี้จะใช้ภาพขาวดำ
หรือเปิดภาพที่เตรียมไว้ขึ้นมาในโหมดขาวดำเป็นหลัก
การใช้ฟังก์ชัน threshold介
ฟังก์ชัน cv2.threshold() ใช้คัดกรองภาพโดยพิจารณาความสว่าง เพื่อที่จะคัดเอาหรือปรับค่าบางส่วน
ค่าที่ต้องใส่ในฟังก์ชันเป็นดังนี้
ลำดับ |
ชื่อ |
สิ่งที่ต้องใส่ |
ชนิดข้อมูล |
1 |
src |
อาเรย์รูปภาพ |
np.array |
2 |
thresh |
ค่าจุดเปลี่ยน |
int |
3 |
maxval |
ค่าสูงสุด |
int |
4 |
type |
ชนิดวิธีการ |
flag (int) |
ชนิดวิธีการให้ใส่เป็นแฟล็ก โดยมีดังนี้
แฟล็ก |
ค่า |
ความหมาย |
cv2.THRESH_BINARY |
0 |
ถ้าสูงกว่าค่าจุดเปลี่ยนจะเป็น 255 ที่เหลือเป็น 0 |
cv2.THRESH_BINARY_INV |
1 |
ถ้าสูงกว่าค่าจุดเปลี่ยนจะเป็น 0 ที่เหลือเป็น 255 |
cv2.THRESH_TRUNC |
2 |
ถ้าสูงกว่าค่าจุดเปลี่ยนจะกลายเป็นค่าจุดเปลี่ยน ที่เหลือคงเดิม |
cv2.THRESH_TOZERO |
3 |
ถ้าต่ำกว่าค่าจุดเปลี่ยนจะเป็น 0 ที่เหลือคงเดิม |
cv2.THRESH_TOZERO_INV |
4 |
ถ้าสูงกว่าค่าจุดเปลี่ยนจะเป็น 0 ที่เหลือคงเดิม |
cv2.THRESH_OTSU |
8 |
ทำการคำนวณค่าจุดเปลี่ยนอัตโนมัติ ไม่ใช้ค่า thresh ที่ใส่เข้าไป |
ผลที่ได้จากฟังก์ชันนี้จะได้ออกมาเป็น ๒ ตัว โดยค่าแรกคือค่าจุดเปลี่ยน ซึ่งปกติจะเท่ากับค่า thresh ที่ใส่เข้าไป
ยกเว้นใส่แฟล็ก cv2.THRESH_OTSU ซึ่งจะทำให้ค่าจุดเปลี่ยนถูกคำนวณเองอัตโนมัติ
เกี่ยวกับ cv2.THRESH_OTSU จะอธิบายในหัวข้อถัดไป สำหรับตอนนี้ขอแสดงตัวอย่างเพื่อดูความแตกต่างของอีก ๕ ตัว
สร้างอาเรย์ที่มีค่าตั้งแต่ 0-255 ขึ้นมาแล้วลองกรองที่ค่า 127 แล้วดูผลของวิธีต่างๆ
คราวนี้ลองเอาภาพที่เตรียมไว้มาเปิดด้วยโหมดขาวดำแล้วใช้ cv2.threshold() เพื่อกรองค่าตามความสว่าง
ลองเทียบระหว่างค่าจุดเปลี่ยนต่างๆกัน
rin10c01.jpg
การหาจุดเปลี่ยนด้วยวิธีของโอตสึ介
ตรงค่าชนิดวิธีการนั้นเมื่อใส่ cv2.THRESH_OTSU
เพิ่มลงไปก็จะกลายเป็นการให้หาค่าจุดเปลี่ยนโดยอัตโนมัติโดยใช้อัลกอริธึมของโอตสึ
วิธีการนี้คิดโดยอาจารย์โอตสึ โนบุยุกิ (
大津 展之)
แห่งมหาวิทยาลัยทสึกุบะ (
筑波大学) ที่จังหวัดอิบารากิของญี่ปุ่น
วิธีการนี้ทำโดยเอาค่าความสว่างมาแจกแจงเป็นฮิสโทแกรม แล้วพิจารณาหาจุดเปลี่ยนที่เหมาะสม
(เกี่ยวกับเรื่องฮิสโทแกรมจะอธิบายละเอียดอีกทีใน
บทถัดไป)
ลองเอาภาพเดิมจากตัวอย่างที่แล้วมาหาจุดเปลี่ยนโดยใช้ cv2.THRESH_OTSU
ค่าจุดเปลี่ยนที่ได้จากวิธีนี้จะได้มาเป็นค่าคืนกลับตัวแรกของฟังกัน cv2.threshold() ในที่นี้ลองเอาค่ามาดูด้วย
rin10c03.png
cv2.THRESH_OTSU สามารถใส่พร้อมกับแฟล็กอื่นได้ โดยบวกกันไป ถ้าใส่แค่ cv2.THRESH_OTSU จะเป็นการใช้วิธี cv2.THRESH_BINARY
(เพราะแฟล็กตัวนี้มีค่าเป็น 0)
ลองเอาภาพเดิมมาใส่แฟล็กแบบต่างๆร่วมกับแฟล็กขอโอตสึ เปรียบเทียบผลที่ได้
การใช้จุดเปลี่ยนแบบปรับตัวเองได้介
ฟังก์ชัน cv2.threshold() ที่ใช้ในตัวอย่างที่ผ่านมานั้นเป็นการกำหนดค่าจุดเปลี่ยนตายตัวค่าหนึ่งคงตัวตลอดทั้งภาพ
แต่วิธีนี้มีจุดอ่อนอยู่ก็คือเวลาใช้กับภาพที่มีความสว่างโดยรวมในแต่ละบริเวณไม่สม่ำเสมอ
เช่นในภาพ ๓ มิติซึ่งมีแสดงและเงาแบบในตัวอย่างที่แล้ว ทำให้มีบริเวณที่สว่างและมืดกว่าปกติอยู่
หากใช้ค่าจุดเปลี่ยนค่าเดียวในการพิจารณาแบบนั้นจะทำให้บริเวณที่มืดกับสว่างดูแล้วได้ผลต่างกันมาก
เพื่อแก้ปัญหานี้ จึงมีการใช้ค่าจุดเปลี่ยนแบบปรับตัวได้ (adaptive threshold)
คือคิดค่าความสว่างบริเวณใกล้ๆแล้วพิจารณาว่าควรใช้จุดเปลี่ยนที่เท่าไหร่ ซึ่งในแต่ละจุดจะใช้ค่าไม่เท่ากัน
วิธีนี้ใน opencv ทำได้โดยฟังก์ชัน cv2.adaptiveThreshold()
ค่าที่ต้องใส่ในฟังก์ชันนี้มีอยู่ ๖ ตัว ดังนี้
ลำดับ |
ชื่อ |
สิ่งที่ต้องใส่ |
ชนิดข้อมูล |
1 |
src |
อาเรย์รูปภาพ |
np.array |
2 |
maxValue |
ค่าสูงสุด |
int |
3 |
adaptiveMethod |
วิธีการคำนวณปรับตัว |
flag (int) |
4 |
thresholdType |
วิธีพิจารณาค่าจุดเปลี่ยน |
flag (int) |
5 |
blockSize |
ขนาดบล็อก |
int |
6 |
C |
ค่า C |
float |
ค่าคืนกลับที่ได้จาก cv2.adaptiveThreshold() จะมีตัวเดียว คือภาพผลลัพธ์ที่ได้เท่านั้น ไม่ได้คืนมา ๒ ตัวเหมือนอย่าง
cv2.threshold()
ในส่วนของวิธีพิจารณาค่าจุดเปลี่ยนก็ใส่เป็นแฟล็ก ซึ่งมีอยู่ ๒ วิธี คือ
แฟล็ก |
ค่าตัวเลข |
วิธีคำนวณค่าจุดเปลี่ยน |
cv2.ADAPTIVE_THRESH_MEAN_C |
0 |
คำนวณค่าเฉลี่ยรอบข้างขนาด blockSize×blockSize แล้วหักจากค่า C |
cv2.ADAPTIVE_THRESH_GAUSSIAN_C |
1 |
คำนวณค่าเฉลี่ยรอบข้างขนาด blockSize×blockSize โดยถ่วงน้ำหนักด้วยฟังก์ชันเกาส์ แล้วหักจากค่า C |
ลองเทียบดูความแตกต่างระหว่าง ๒ วิธีการ ลองใช้กับภาพเดิมจากตัวอย่างก่อนๆ
จะเห็นว่าผลออกมาดูสม่ำเสมอกว่าเมื่อเทียบกับการใช้ cv2.threshold()
เพราะพิจารณาจุดเปลี่ยนต่างไปตามความสว่างของบริเวณรอบๆ
ไม่ว่าจะบริเวณที่มืดหรือสว่างก็หาจุดที่สว่างหรือมืดเมื่อเทียบกับในบริเวณนั้นได้เหมือนกัน
ต่อมาลองพิจารณาค่า blockSize กับ C ซึ่งใช้ในการคำนวณ ค่าทั้ง ๒ ตัวนี้เมื่อเปลี่ยนแปลงไปก็จะให้ผลต่างกันออกไป
ตัวอย่างเปรียบเทียบเมื่อมี blockSize เป็นค่าต่างๆกันแต่ให้ค่า C คงที่
miku10c01.jpg
ต่อมาลองเปรียบเทียบเมื่อ blockSize คงที่แล้วเปลี่ยนค่า C ดู
การใช้ค่าจุดเปลี่ยนเป็นตัวคัดกรองเพื่อเอาหรือตัดส่วนที่เหลือ介
อีกตัวอย่างหนึ่งที่ใช้ประโยชน์จากการคัดกรองแบ่งภาพเป็นขาวดำตามความเข้มก็คือ
นำมาใช้ตัดส่วนมืดหรือสว่างเกินที่ต้องการออกจากภาพ
เพื่อที่จะทำแบบนี้ได้ก็มีอยู่หลายวิธี เช่นอาจใช้คู่กับ np.where()
เพื่อแยกเงื่อนไขตามค่าที่ได้ให้เก็บบางส่วนหรือแปลงบางส่วน
ตัวอย่าง ลองทำภาพให้จัดการเปลี่ยนเฉพาะส่วนที่มืดหรือสว่าง
gumi10c01.jpg
gumi10c02.jpg
gumi10c03.jpg
หรืออาจใช้ส่วนที่คัดกรองมาทำเป็นค่าความทึบแสงเพื่อลบฉากหลังที่มืดๆออกได้แล้วบันทึกเป็น .png
ที่มีส่วนโปร่งมองเห็นพื้นหลังได้ เช่น
teto10c01.jpg
teto10c02.png
อ่านบทถัดไป >>
บทที่ ๑๑