2016年10月27日 星期四

OPENCV(4)--Grayscale,Binarization,Threshole(灰階化,二值化,閥值)


    這篇簡單的介紹OPENCV的灰階化(Grayscale),二值化(Binarization),閥值(Threshole)

灰階化(Grayscale):顧名思義將原本讀取進來原本具有B.G.R三個頻道的彩圖,轉換成只有
    一個頻道為0-255,的黑白值分佈,由值0為最黑到255為最白.處於中間的即為漸黑或漸白
   如<圖1 >讀進一原圖為藍白漸層圖,轉成灰階值後呈現在圖中Gray
如果要將讀取進來的圖片做灰階化有兩種方式
a. 在使用 cv2.imread()讀圖時,將第二參數設為0,這樣讀取的img即為灰階化後的圖形矩陣
EX:     img = cv2.imread('bl2w.jpg',0)
b. 使用cv2.cvtColor(),將原圖讀進來的矩陣放置第一參數位置
    將第二參數設為cv2.COLOR_BGR2GRAY
EX:gray=cv2.cvtColor(img_RGB,cv2.COLOR_BGR2GRAY)
    那麼原本img_RGB如果為一BGR 圖檔即可轉成灰值圖矩陣gray

在Python裡處理影像矩陣式利用Numpy矩陣物件來處理.
而Numpy 提供一個.shape 屬性,使用此屬性可得知該矩陣的大小及維數.
如下圖2,在紅色框框裡img_RGB.shape 為(256,256,3) 其256x256 為其圖片像素rows,clos值
也是像素解析度大小,而3代表R.G.B 三通道.
而img_RGB.shape 為(256,256) 代表灰階化後只剩一通道像素解析度大小仍然是256x256.

<圖1>





<圖2>



在上圖2及下圖3 可以比較出,在同樣讀取同一列(row=127)時,那一列從0-255(clos)的像素值變化
上圖二第127列RGB 彩圖仍然是三通道,分別代表(R,G,B)像素色彩值.
而下圖三紅色框框內可看出以灰階化後只剩一通道的灰階值在0-255之間

二值化(Binarization):可視為將灰階圖在進一步區分只剩絕對黑(0)與絕對白(255)的兩個值,
注意:在opencv 裡絕對黑與絕對白,分別代表的數值為0與255,不是0與1.當然,在某些處理上
可以先將絕對白(255)等化為1.即可做邏輯上的運算,如AND 或OR .這也是將圖形座二值化後的
作用之一,將它當一遮罩(mask)則可與原圖做邏輯上的運算.
      而如何從灰階圖產生一二值化的圖?如同上圖1右上<BINARY> 或是<BINARY_INV>
<BINARY_INV>可視為<BINARY> 邏輯NOT 反運算.
 從上面產生的灰階圖方式我們可知灰階為0-255由黑到白的數值,這時我們利用一個門檻(Threshole)的觀念,也就是說我設一個Threshole=127,那麼只要小於127灰階值通通當成0(黑),
而相反只要大於於127灰階值通通當成255(白).於是我們就可以產生如下圖<BINARY>或是<BINARY_INV>二階黑白圖.而另外<TRUNC><TOZERO> 只要知道是OPENCV在做門檻(Threshole)區分時的演算方式不同即可,從結果其實已可直接看出其使用效果.
而在下圖3裡可以仔細看出同一列(row=127)時各clos的像素值變化

而在OPENCV裡提供了 cv2.threshold()函式處裡二值化的動作.
EX: cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
gray :為要處裡的灰階圖,127即為Threshole=127 ,255灰階圖最大像素值
cv2.THRESH_BINARY 即為欲處裡threshold的演算方式

其結果thresh1,2,3,4即為 cv2.threshold () 
cv2.THRESH_BINARY
cv2.THRESH_BINARY_INV
cv2.THRESH_TRUNC
cv2.THRESH_TOZERO
四種轉換結果

<圖3>

<圖4>home.jpg  ,原圖來自opecv source, ..opencv\sources\samples\data 目錄
    可將下原始程式改成讀進home.jpg 圖檔或是別的圖檔,即可直接看出其灰階化(Grayscale),
二值化(Binarization),Threshole的各種效果. 你也可以試著更改程式裡Threshole=127,改為
Threshole=30,Threshole=180或其他值,看看其變化效果如何.





<Python 完整範例程式>

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

#pd.set_option('max_columns', 5)
#pd.set_option('display.max_rows', 5)
#pd.set_option('precision', 5)

img = cv2.imread('bl2w.jpg',1)
#img = cv2.imread('home.jpg',1)
img_RGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
gray=cv2.cvtColor(img_RGB,cv2.COLOR_BGR2GRAY)

print ("Original image shape=",img_RGB.shape)
print ("Gray image shape=",gray.shape)
#print ("Original image row[0]=",img_RGB[0,:])
print ("Original image row[127]=",img_RGB[127,:])
#print ("Gray image row[0]",gray[0,:])
print ("Gray image row[127]=",gray[127,:])

ret,thresh1 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
print ("thresh1 image row[127]=",thresh1[127,:])
ret,thresh2 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY_INV)
print ("thresh2 image row[127]=",thresh2[127,:])
ret,thresh3 = cv2.threshold(gray,127,255,cv2.THRESH_TRUNC)
print ("thresh3 image row[127]=",thresh3[127,:])
ret,thresh4 = cv2.threshold(gray,127,255,cv2.THRESH_TOZERO)
print ("thresh4 image row[127]=",thresh4[127,:])

titles = ['Original Image','Gray','BINARY','BINARY_INV','TRUNC','TOZERO']
images = [img_RGB,gray, thresh1, thresh2, thresh3, thresh4]
for i in range(6):
 plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
 plt.title(titles[i])
 plt.xticks([]),plt.yticks([])
plt.show()



一般傳統在做影像處裡,特別是在擷取特徵值時,都會先做灰階化或二值化的動作,這樣的動作
除了可以減少大量的data運算也可以幫助我們利用後續的演算法使用,如之後提到提取輪廓或是特徵值時都會利用到這樣的前置處理,而類似這樣的前置處裡還有直方圖的均等化,之後我們也會提到.

歡迎一起討論, 加入FB--AI人工智慧與機器人社團
https://www.facebook.com/groups/1852135541678378/2068782386680358/?notif_t=like&notif_id=1477094593187641

加入阿布拉機的3D列印與機器人的FB專頁
https://www.facebook.com/arbu00/