Image Thresholding

จาก Morange Wiki

Image Thresholding

วัตถุประสงค์

  • เนื้อหาในบทนี้ จะเรียนรู้เกี่ยวกับ แบ่งเส้น แบบง่ายๆ (Simple thresholding) ,การแบ่งแบบ Adaptive,การแบ่งแบบ Otsu's
  • คุณจะได้เรียนรู้ฟังก์ชั่นเหล่านี้: cv2.threshold, cv2.adaptiveThreshold ฯลฯ

Simple Thresholding การแบ่งแบบง่ายๆ

  • ฟังก์ชั่นที่ใช้มีชื่อว่า cv2.threshold ในอาร์กิวเมนต์แรก จะเป็นภาพต้นฉบับ ซึ่งควรจะเป็นภาพสีเทา (Grayscale)
  • อาร์กิวเมนต์ที่สองคือค่าเกณฑ์ที่ใช้ในการจำแนกค่าพิกเซล
  • อาร์กิวเมนต์ที่สามเป็น maxVal ซึ่งหมายถึงค่าที่จะได้รับถ้าค่าพิกเซลเป็นมากกว่า (บางครั้งน้อยกว่า) มูลค่าเกณฑ์ โดย OpenCV จะทำให้รูปแบบที่แตกต่างกันของ thresholding และจะตัดสินใจโดยพารามิเตอร์ที่สี่ของการทำงาน ชนิดที่แตกต่างกัน มีคำสั่งอื่นๆดังนี้ :
    • cv2.THRESH_BINARY
    • cv2.THRESH_BINARY_INV
    • cv2.THRESH_TRUNC
    • cv2.THRESH_TOZERO
    • cv2.THRESH_TOZERO_INV

ทดลองเขียน Code

import cv2
import numpy as np
from matplotlib import pyplot as plt
 
img = cv2.imread('gradient.png',0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
 
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
 
for i in xrange(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

plt.show()

ผลลัพธ์

Figure 1 063.png


Adaptive Thresholding

  • Adaptive Method- มันตัดสินใจว่าค่ากำหนดเกณฑ์ขั้นต่ำที่มีการคำนวณ
    • cv2.ADAPTIVE_THRESH_MEAN_C: ค่าเกณฑ์เป็นค่าเฉลี่ยของพื้นที่เขต
    • cv2.ADAPTIVE_THRESH_GAUSSIAN_C: ค่าเกณฑ์เป็นน้ำหนักรวมของค่าเขตที่น้ำหนักหน้าต่าง Gaussian
  • Block Size - มันตัดสินใจที่ขนาดของพื้นที่บริเวณใกล้เคียง
  • C - เป็นเพียงค่าคงที่ซึ่งถูกหักออกจากค่าเฉลี่ยหรือจากการคำนวณค่าเฉลี่ยถ่วงน้ำหนัก

ทดลองเขียน Code

import cv2
import numpy as np
from matplotlib import pyplot as plt
 
img = cv2.imread('dave.jpg',0)
img = cv2.medianBlur(img,5)
 
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
 
for i in xrange(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()


ผลลัพธ์

Figure 1 064.png


Otsu’s Binarization

  • Otsu’s Binarization คืออะไร?
  • ใน Thresholding เราใช้ค่าที่กำหนดเองสำหรับค่าเกณฑ์เอง ดังนั้นวิธีการที่เราสามารถรู้ค่าที่เราเลือกนั้นเป็นสิ่งที่ดีหรือไม่? คำตอบคือหาจากการทดลองและความผิดพลาด แต่พิจารณาภาพ bimodal สำหรับภาพที่เราสามารถใช้เวลาประมาณค่าในช่วงกลางของยอดเขาเหล่านั้นเป็นค่าเกณฑ์ใช่มั้ย? นั่นคือสิ่งที่ Otsu Binarization ไม่ ดังนั้นในคำง่ายโดยจะคำนวณค่าเกณฑ์จาก histogram ที่ภาพเพื่อดูภาพ bimodal (สำหรับภาพที่ไม่ได้ bimodal, Binarization จะไม่ถูกต้อง
  • สำหรับเรื่องนี้คำสั่งที่จะใช้คือ cv2.threshold() cv2.THRESH_OTSU
  • สามารถทำตัวอย่าง และ ตรวจสอบตัวอย่างว่า ภาพที่นำเข้าเป็นภาพที่มีการแตหรือไม่ ในกรณีแรกที่นำมาใช้กำหนดเกณฑ์ขั้นต่ำ Global ไว้ที่ 127 ในกรณีที่สองใช้ thresholding Otsu โดยตรง ในกรณีที่สามผมกรองภาพที่มีเคอร์เนล Gaussian 5x5 เพื่อลบสี่งรบกวนจากนั้นนำไปใช้ใน Otsu Thresholding ดูวิธีการกรองสิ่งรบกวนแบบดีขึ้น

Code ตัวอย่าง Otsu's Binarization

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('noisy2.png',0)
 
# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
 
for i in xrange(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()


ผลลัพธ์

Figure 1 065.png

ทำยังไง Otsu's Binarization ถึงเวิร์ค ?

  • ในส่วนนี้จะแสดงให้เห็นว่าภาษา Python สามารถใช้งาน Otsu's Binarization เพื่อแสดงให้เห็นวิธีการใช้งาน
  • เนื่องจากมีการทำงานกับภาพที่เป็น algorithm bimodal โดยจะพยายามหาค่า (T) ซึ่งจะช่วยลดการถ่วงน้ำหนักการแปรปรวนในชั้นที่มีความสัมพันธ์

และมีสูตรทางคณิตศาสตร์ดังนี้

Selection 066.png