opencv-python學習筆記(三)---圖像處理(一)

opencv中的圖像處理(一)

改變顏色空間

改變顏色模型

. opencv中有上百中顏色空間的轉換方法,其中最廣泛的是BGR<->Gray和BGR<->HSV。
. 用於顏色轉換的函數是cv2.cvtColor(input_image, flag),其中flag表示使用那種類型的轉換,比如cv2.COLOR_BGR2GRAY或cv2.COLOR_BGR2HSV。可以通過簡單的循環來查看所有的類型:

>>> import cv2
>>> flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
>>> print(flags)

對象追蹤

. HSV顏色模型比BGR模型要更容易表現顏色,HSV模型中的H(色調)的值是0-180,S(飽和度)的取值範圍是0-255,V(明亮度)的取值範圍是0-255.因此在視頻中提取顏色對象的步驟可以分爲:
1.獲取視頻的每一幀;
2.將圖片的色彩控件由BGR轉換爲HSV;
3.設置要提取的顏色對象的閾值;
4.提取顏色對象進行操作。

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

while(1):
    #抓取每一幀
    _,frame = cap.read()
    #轉換爲HSV模型
    hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    #確定要抓取的顏色範圍
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])
    #獲取抓取的遮罩
    mask = cv2.inRange(hsv,lower_blue,upper_blue)
    #做圖像的與處理
    res = cv2.bitwise_and(frame,frame,mask=mask)
    cv2.imshow('frame',frame)
    cv2.imshow('mask', mask)
    cv2.imshow('res', res)
    k = cv2.waitKey(5) & 0xff
    if k == 27:
        break

cv2.destroyAllWindows()

圖像閾值處理

簡單閾值

. 簡單的閾值處理就是將像素點的值與閾值作比較,大於就賦給這個像素點一個值,否則就賦給它另一個值。使用的函數是cv2.threshold,第一個參數是原始圖像(應該是一個灰度化的圖像),第二個參數是指定的閾值,第三個參數是將要位像素點重新指定的值,第四個參數是採用的處理方式,第四個參數的常用值有以下幾種:
1.cv2.THRESH_BINARY:像素點超過閾值就取第三個參數的值,否則爲0;
2.cv2.THRESH_BINARY_INV:第一種方式的反處理;
3.cv2.THRESH_TRUNC:像素點超過閾值就取第三個參數的值,否則保持不變;
4.cv2.THRESH_TOZERO:像素點超過閾值就保持不變,否則爲0;
5.cv2.THRESH_TOZERO_INV:第四種方式的反處理。

import cv2

#以灰度化讀取
img = cv2.imread('../kkxj.jpg',0)

ret,t1 = cv2.threshold(img,125,255,cv2.THRESH_BINARY)
ret,t2 = cv2.threshold(img,125,255,cv2.THRESH_BINARY_INV)
ret,t3 = cv2.threshold(img,125,255,cv2.THRESH_TRUNC)
ret,t4 = cv2.threshold(img,125,255,cv2.THRESH_TOZERO)
ret,t5 = cv2.threshold(img,125,255,cv2.THRESH_TOZERO_INV)
cv2.imshow('img',t1)
cv2.waitKey(0)
cv2.destroyAllWindows()

自適應閾值

. 通常圖像的呈現會受到不同區域中光照或別的原因影響,因此使用簡單的閾值處理得到的圖像可能不太好,這種情況下使用自適應閾值,其可以在不同的區域使用不同的閾值來處理圖像。
. 自適應閾值處理的函數是cv2.adaptiveThreshold,除了之前的幾個參數,還包含了三個特殊的參數:
1.Adaptive Method:自適應處理的方式:
. cv2.ADAPTIVE_THRESH_MEAN_C:表示閾值爲附近區域的平均值;
. cv2.ADAPTIVE_THRESH_GAUSSIAN_C :表示閾值爲附近區域的加權總和,其中權重是高斯窗口(不知道是啥)。
2.Block Size:附近區域的大小;
3.C:作爲一個常數,可以在計算出來的閾值後做減法。

import cv2

#以灰度化讀取
img = cv2.imread('../kkxj.jpg',0)

ret,t1 = cv2.threshold(img,125,255,cv2.THRESH_BINARY)
t2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
                               cv2.THRESH_BINARY,11,2)
t3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)
cv2.imshow('img',t1)
cv2.waitKey(0)
cv2.destroyAllWindows()

Otsu’s閾值處理

. Otsu算法是日本學者OTSU提出的一種對圖像進行二值化的高效算法。當圖像的直方圖是雙峯一樣的形狀的時候,可以近似的將雙峯之間的中間值作爲閾值。
. 使用OTSU閾值處理還是使用 cv2.threshold函數,只需要在二值化方式後面加上cv2.THRESH_OTSU,因此,第二個參數只需要傳入0就可以了,函數會自動使用算法算出閾值:

ret2,t4 = cv2.threshold(img,0,255,\
			cv2.THRESH_BINARY+cv2.THRESH_OTSU)

圖像的幾何變換

. Opencv提供了兩個幾何變換的函數,cv2.warpAffinecv2.warpPerspective,前者採用2x3的矩陣,後者採用3x3的矩陣作爲輸入。

縮放

. Opencv中隊圖像進行調整大小的函數是resize(),可以手動制定圖像的尺寸,並且可以指定處理圖像時的插值,通常使用cv2.INTER_AREA來進行圖像的縮小,使用cv2.INTER_CUBICcv2.INTER_LINEAR來進行圖像的縮放:

img = cv2.imread('../kkxj.jpg')

res = cv2.resize(img,None,fx=0.5, fy=0.5, interpolation = cv2.INTER_AREA)
height, width = img.shape[:2]
res2 = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)

平移

. 做平移的時候的需要知道圖像在x方向和y方向上的偏移量(tx,ty),然後就能創建一個轉換矩陣:
.            M=[10tx01ty]M =\begin{bmatrix} 1&0&tx\\ 0&1&ty\end{bmatrix}
. 然後使用 cv2.warpAffine() 處理:

img = cv2.imread('../kkxj.jpg',0)
row,col = img.shape
M = np.float32([[1,0,100],[0,1,50]])
#第三個參數是輸出圖像的尺寸,寬對應列,高對應行
dst = cv2.warpAffine(img,M,(col,row))		

旋轉

. 使用cv2.getRotationMatrix2D函數來完成平面圖像的旋轉,函數的第一個參數是旋轉圖像的旋轉中心,第二個參數是旋轉的角度,第三個參數是縮放因子,即可以將旋轉後的圖像放大或縮小:

M = cv2.getRotationMatrix2D((col/2,row/2),60,1)
dst = cv2.warpAffine(img,M,(col,row))

仿射變換

. 仿射變換就像是換個角度看圖像,原圖像的平行線在輸出圖像中依然是平行的。使用cv2.getAffineTransform函數來生成一個仿射變換的2x3矩陣,需要傳入的參數是原圖像的三個點和在它們在輸出圖像中的位置。

pts = np.float32([[50,50],[200,50],[50,200]])
ptd = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts,ptd)

dst = cv2.warpAffine(img,M,(col,row))

透視變換

. 感覺就是做一個四邊形裁剪,使用cv2.getPerspectiveTransform函數來生成矩陣,需要傳入原圖像的四個點的位置的列表,和它們在輸出圖像中的位置列表。使用cv2.warpPerspective來應用這種變換:

pts1 = np.float32([[50,50],[200,50],[50,200],[200,200]])
pts2 = np.float32([[0,0],[200,0],[0,200],[200,200]])
M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img,M,(200,200))

平滑圖像

2D卷積(圖像過濾)

. 圖像中使用卷積是爲了對圖像降噪,噪點是指圖像中一種亮度或顏色信息的隨機變化(被拍攝物體本身並沒有),是圖像本不應該存在的錯誤信息。卷積在圖像處理中的應用主要主要是將像素點及其周圍的像素點組成的矩陣與給定的平均矩陣做卷積公式處理,使得圖像變得平滑,即讓像素點的值根據周圍像素點的值和某個給定的平均矩陣來進行改變。
. opencv中提供了cv2.filter2D函數來完成卷積。下面的例子定義一個5x5的矩陣,把它除以25作爲要進行卷積的一個內核,與圖像中的每個像素點及其周圍5x5的像素點組成的矩陣做卷積運算:

img = cv2.imread('../kkxj.jpg')
kernel = np.ones((5,5),np.float32)/25
#第二個參數是指定輸出圖像的深度(指存儲每個像素所用的位數,
#也用於量度圖像的色彩分辨率),如果是-1表示和原圖像深度相同
dst = cv2.filter2D(img,-1,kernel)

圖像模糊

. 通過將圖像與低通濾波器內核進行卷積來實現圖像模糊,主要是爲了消除噪點。實際上,他會從圖像中刪除高頻內容(噪點、邊緣等)。opencv主要提供四種模糊技術:

1.平均化

. 通過獲取內核區域的平均值來替換中心元素的值,使用**cv2.blur()cv2.boxFilter()**來完成。一個3x3的過濾器可能如下所示:
.       M=19[111111111]M =\frac{1}{9}\begin{bmatrix} 1&1&1\\ 1&1&1\\ 1&1&1\end{bmatrix}

blur = cv2.blur(img,(3,3))

2.高斯濾波

. 高斯濾波對去除高斯噪聲(概率密度函數服從高斯分佈,即正態分佈的一類噪聲)很有效,其使用高斯內核來進行卷積運算,opencv中使用的函數是cv2.GaussianBlur,需要傳遞的參數是內核的寬度和高度,這兩個值都應該爲正數和奇數,還要指定X方向和Y方向上的標準偏差(sigmaX和sigmaY),如果僅指定sigmaX,則默認sigmaY和它相等,如果都爲0,它會根據內核大小進行計算。

blur = cv2.GaussianBlur(img,(5,5),0)

3.中值過濾

. 中值濾波對消除椒鹽噪聲很有效,它通過計算內核(內核大小應爲正整數)窗口下所有元素的中值(統計總體當中的各個變量值按大小順序排列起來,處於變量數列中間位置的變量值),再和中心元素的值進行替換。opencv中使用**cv2.medianBlur()**來完成,第二個參數是線性度,應當置爲大於1的奇數。

median = cv2.medianBlur(img,5)

4.雙邊濾波

. 雙邊濾波能完成高斯濾波類似的模糊操作,於此同時能保留邊緣的值,其在完成運濾波時多考慮兩個權重域:空間域(spatial domain S)和像素範圍域(range domain R),在圖像的平坦區域,像素值變化很小,對應的像素範圍域權重接近於1,此時空間域權重起主要作用,相當於進行高斯模糊;在圖像的邊緣區域,像素值變化很大,像素範圍域權重變大,從而保持了邊緣的信息。
. opencv中使用cv2.bilateralFilter完成濾波,第二個參數表示濾波期間使用的每個像素鄰域的直徑,第三個參數表示色彩空間中的過濾值,第四個參數表示再座標空間中的過濾值,

blur = cv2.bilateralFilter(img,9,75,75)

形態學操作

. 形態學操作通常使用再二值化的圖像處理上,兩個基礎的操作時腐蝕和膨脹,通過這兩種可以擴展其它的一些操作。

腐蝕

. 腐蝕的原理時內核再圖像上滑動的時候,僅當內核下的所有元素都爲1的時候,纔將原始圖像元素的值視爲1,否則將被腐蝕(視爲0)。這對於分割兩個連接的部分很有用:

img = cv2.imread('../j.png')
kenel = np.ones((5,5),np.uint8)
#iterations表示施加腐蝕的次數
dst = cv2.erode(img,kenel,iterations=1)

膨脹

. 膨脹與腐蝕的操作相反,當內核下有一個元素爲1的時候,九江原始圖像元素的值視爲1,否則視爲0。在做連接對象的損壞部分的操作的時候很有用:

dst2 = cv2.dilate(img,kenel,iterations=1)

開放

. 開放的操作時先腐蝕再膨脹,通過傳遞給 cv2.morphologyEx函數標誌位來實現:

opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

關閉

. 關閉與開放相反,先膨脹再腐蝕:

closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

形態梯度

. 與之前的處理結果不同,形態梯度處理的結果像是取得圖像的輪廓:

gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)

不一樣的內核

. 之前可以使用numpy模塊手動創建矩形的內核,但有時可能需要圓形或其它形狀的內核,通過使用**cv2.getStructuringElement()**來自動創建內核,只需要傳遞內核形狀和內核尺寸:

>>> import cv2
>>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]], dtype=uint8)
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)
>>> cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章