Pin-Jiun / ComputerVision

0 stars 0 forks source link

15-cv2.threshold, cv2.adaptiveThreshold and Otsu's Threshold #15

Open Pin-Jiun opened 1 year ago

Pin-Jiun commented 1 year ago

cv2.threshold 有點像是np.where

img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 先將圖片轉為灰階

# 將小於閾值的灰度值設為0,其他值設為最大灰度值。>127 =255, <127 =0
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# 將大於閾值的灰度值設為0,其他值設為最大灰度值。>127 =0, <127 =255
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)

# 將大於閾值的灰度值設為閾值,小於閾值的值保持不變。 >127 =127
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)

# 將小於閾值的灰度值設為0,大於閾值的值保持不變。 <127 =0
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)

# 將大於閾值的灰度值設為0,小於閾值的值保持不變。 >127 =0
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

cv2.threshold 最主要的功能是能夠幫助我們將一張圖片做二值化,二值化的意思是圖片只會剩下兩個值,通常是黑(255)與白(0)。

cv2.threshold(img, 閥值, 最大灰度值, 使用的二值化方法)

下圖我們可以參考使用不同的「使用的二值化方法」跑出來的結果。 (假設閥值=127、最大灰度值=255)

cv2.THRESH_BINARY 將小於閾值的灰度值設為0,其他值設為最大灰度值。 白話文:>127 =255, <127 =0 cv2.THRESH_BINARY_INV 將大於閾值的灰度值設為0,其他值設為最大灰度值。 白話文:>127 =0, <127 =255 cv2.THRESH_TRUNC 將大於閾值的灰度值設為閾值,小於閾值的值保持不變。 白話文:>127 =127 cv2.THRESH_TOZERO 將小於閾值的灰度值設為0,大於閾值的值保持不變。 白話文:<127 =0 cv2.THRESH_TOZERO_INV 將大於閾值的灰度值設為0,小於閾值的值保持不變。 白話文:>127 =0

圖片二值化後,對於整張圖片來說就是乾淨的兩個值, 只有乾淨的兩個值,很適合我們做一些輪廓偵測的運算。

而算出輪廓後我們就可以做很多圖形的處理, 例如畫出圖片輪廓、圖片邊緣的銳利度強化、 加粗圖片的輪廓線、依照輪廓線替圖片添加陰影…

因此,這是非常重要的一門技術,搭配其他功能的操作能實現非常多的效果! image

Pin-Jiun commented 1 year ago

OpenCV 的圖片自適應二值化,產生更好效果的黑白圖片!

# 先將圖片轉為灰階
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 

# 將圖片做模糊化,可以降噪
blur_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)

# 一般圖二值化(有模糊降噪)
ret, th4 = cv2.threshold(blur_img,127,255,cv2.THRESH_BINARY)

# 一般圖算術平均法的自適應二值化(有模糊降噪)
th5 = cv2.adaptiveThreshold(blur_img,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,11,2)

# 一般圖高斯加權均值法自適應二值化(有模糊降噪)      
th6 = cv2.adaptiveThreshold(blur_img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)

我們先來討論什麼是 自適應的二值化, 一般的 二值化 我們只會考慮單一點的值,直接去做閥值分析, 但一張圖片的「每個鄰近的像素都是彼此有關連的」。

如果單純只針對單一個點去看,似乎失去了對整張圖相鄰點的考慮, 因此 自適應二值化 就是在幫助我們找到單一點與鄰近區域的關係。

自適應二值化的算法 cv2.adaptiveThreshold 能夠幫助我們將一張圖片做自適應的二值化, 自適應的二值化又分為

cv2.adaptiveThreshold 函數形式

cv2.adaptiveThreshold(image, 255, 自適應二值化算法, 閥值類型, 參考局部大小, 偏移量)

image: 輸入圖片 自適應二值化算法: 可使用 cv2.ADAPTIVE_THRESH_MEAN_C 和 cv2.ADAPTIVE_THRESH_GAUSSIAN_C 閥值類型: 可使用 THRESH_BINARY 和 THRESH_BINARY_INV, 看是超過閥值要「黑白」還是「白黑」。 參考局部大小: 就是參考區域的大小 偏移量: 微調用的參數 自適應二值化 搭配模糊降噪

自適應二值化 搭配模糊降噪,能有更好的效果 通常在做 自適應二值化 之前,我們都會先將圖片做模糊化, 能夠達到降噪的效果,看下圖結果的圖片應該能很明顯地分得出差別。

(文章內容中,我們使用 cv2.medianBlur 來做模糊降噪的示範。)

image

https://www.wongwonggoods.com/all-posts/python/python_opencv/opencv-adaptivethreshold/

Pin-Jiun commented 1 year ago

Otsu's Threshold 大津二值化,他用來幫助我們解決「手動設定閥值的選值困擾」, 我們透過 Otsu's Threshold 演算法,能夠「自動找出最佳的閥值」。

image


# 先將圖片轉為灰階
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 

# 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)

我們可以發現在未做 Otsu's Threshold 的 histogram 中,「0的比例」遠遠比有做 Otsu's Threshold 還高 從結果圖中我們也能發現這點,如果我們只是單純要「提取人像」,很明顯地透過 Otsu's Threshold 給了我們一個更好的答案。

Otsu's Threshold 的算法 重點程式碼也是一行,而有時我們也會先搭配模糊的方法先進行降噪。


ret, th = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
``

https://www.wongwonggoods.com/all-posts/python/python_opencv/opencv-threshold-all-otsu/