文章目錄
顏色空間轉換
RGB色彩空間
HSV色彩空間
YUV色彩空間
簡單的物體跟蹤示例
HSV空間目標閾值選取
圖像幾何變換
圖像的縮放
圖像的位移
圖像的旋轉
圖像的仿射
圖像的投射
圖像閾值(二值化)
圖像的簡單閾值二值化
圖像的自適應閾值二值化
Otsu’s二值化
圖像模糊操作
均值模糊
中值模糊
自定義模糊
高斯模糊
雙邊沿模糊
本篇接著記錄python-OpenCV的基礎部分:圖像處理
https://docs.opencv.org/3.4.0/d6/d00/tutorial_py_root.html
顏色空間轉換
這里主要說明BRG與HSV兩種應用最為廣泛的色彩空間
RGB色彩空間
在RGB顏色空間中,任意色光F都可以用R、G、B三色不同分量的相加混合而成:F=r[R]+r[G]+r[B]。RGB色彩空間還可以用一個三維的立方體來描述。當三基色分量都為0(最弱)時混合為黑色光;當三基色都為k(最大,值由存儲空間決定)時混合為白色光
RGB色彩空間根據(jù)每個分量在計算機中占用的存儲字節(jié)數(shù)分為如下幾種類型:
RGB555:RGB555是一種16位的RGB格式,各分量都用5位表示,剩下的一位不用。
高字節(jié) -> 低字節(jié)
XRRRRRGGGGGBBBBB
RGB565:RGB565也是一種16位的RGB格式,但是R占用5位,G占用6位,B占用5位。
RGB24R:GB24是一種24位的RGB格式,各分量占用8位,取值范圍為0-255。
RGB32:RGB32是一種32位的RGB格式,各分量占用8位,剩下的8位作Alpha通道或者不用。
RGB色彩空間采用物理三基色表示,因而物理意義很清楚,適合彩色顯象管工作。然而這一體制并不適應人的視覺特點。因而,產生了其它不同的色彩空間表示法。
HSV色彩空間
HSV是一種將RGB色彩空間中的點在倒圓錐體中的表示方法。HSV即色相(Hue)、飽和度(Saturation)、明度(Value),又稱HSB(B即Brightness)。色相是色彩的基本屬性,就是平常說的顏色的名稱,如紅色、黃色等。飽和度(S)是指色彩的純度,越高色彩越純,低則逐漸變灰,取0-100%的數(shù)值。明度(V),取0-max(計算機中HSV取值范圍和存儲的長度有關)。HSV顏色空間可以用一個圓錐空間模型來描述。圓錐的頂點處,V=0,H和S無定義,代表黑色。圓錐的頂面中心處V=max,S=0,H無定義,代表白色。
注意:在opencv的HSV色彩空間中:H取值范圍是[0-179], S的取值范圍是[0-255], V的取值范圍是[0-255]
YUV色彩空間
1、YUV(亦稱YCrCb)是被歐洲電視系統(tǒng)所采用的一種顏色編碼方法。在現(xiàn)代彩色電視系統(tǒng)中,通常采用三管彩色攝像機或彩色CCD攝影機進行取像,然后把取得的彩色圖像信號經分色、分別放大校正后得到RGB,再經過矩陣變換電路得到亮度信號Y和兩個色差信號R-Y(即U)、B-Y(即V),最后發(fā)送端將亮度和兩個色差總共三個信號分別進行編碼,用同一信道發(fā)送出去。這種色彩的表示方法就是所謂的YUV色彩空間表示。采用YUV色彩空間的重要性是它的亮度信號Y和色度信號U、V是分離的。如果只有Y信號分量而沒有U、V信號分量,那么這樣表示的圖像就是黑白灰度圖像。彩色電視采用YUV空間正是為了用亮度信號Y解決彩色電視機與黑白電視機的兼容問題,使黑白電視機也能接收彩色電視信號。
2、YUV主要用于優(yōu)化彩色視頻信號的傳輸,使其向后相容老式黑白電視。與RGB視頻信號傳輸相比,它最大的優(yōu)點在于只需占用極少的頻寬(RGB要求三個獨立的視頻信號同時傳輸)。其中“Y”表示明亮度(Luminance或Luma),也就是灰階值;而“U”和“V” 表示的則是色度(Chrominance或Chroma),作用是描述影像色彩及飽和度,用于指定像素的顏色?!傲炼取笔峭高^RGB輸入信號來建立的,方法是將RGB信號的特定部分疊加到一起?!吧取眲t定義了顏色的兩個方面─色調與飽和度,分別用Cr和Cb來表示。其中,Cr反映了RGB輸入信號紅色部分與RGB信號亮度值之間的差異。而Cb反映的是RGB輸入信號藍色部分與RGB信號亮度值之同的差異。
3、YUV和RGB互相轉換的公式如下(RGB取值范圍均為0-255)︰
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
簡單的物體跟蹤示例
import cv2import numpy as npcap = cv2.VideoCapture(0)while(1): # Take each frame _, frame = cap.read() # Convert BGR to HSV hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # define range of blue color in HSV lower_blue = np.array([110,50,50]) upper_blue = np.array([130,255,255]) # Threshold the HSV image to get only blue colors mask = cv2.inRange(hsv, lower_blue, upper_blue) # Bitwise-AND mask and original image 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: breakcv2.destroyAllWindows()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HSV空間目標閾值選取
如何在HSV空間,跟蹤目標時選擇一個合適的閾值呢?辦法如下:
使用cv2.cvtColor函數(shù),傳入一個BRG顏色值,flag參數(shù)為cv2.COLOR_BGR2HSV,函數(shù)的返回值就是此顏色在HSV空間的取值。示例如下:green = np.uint8([[[0,255,0 ]]])hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV)print hsv_green# [[[ 60 255 255]]]12341234
那么在HSV空間跟蹤此顏色的目標時,選取目標的顏色閾值可為: [H-10, 100,100] 到 [H+10, 255, 255]
圖像幾何變換
圖像的縮放操作主要包括縮小與放大、旋轉、仿射、投射等
圖像的縮放
圖像的縮放操作主要是函數(shù):cv2.resize,函數(shù)原型如下:
cv2.resize(src,dsize,dst=None,fx=None,fy=None,interpolation=None)
關于此函數(shù)的詳細說明記錄在:python進階—OpenCV之常用圖像操作函數(shù)說明
函數(shù)使用示例如下:
import cv2import numpy as npimg = cv2.imread('messi5.jpg')res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)height, width = img.shape[:2]res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
圖像的位移
圖像的旋轉要靠函數(shù)cv2.warpAffine完成,可以完成x或者y方向的上的移動
圖像的移動操作需要一個2*3 的矩陣來指明x、y分別移動的像素大小
矩陣格式為:M = [[1, 0, tx], [0, 1, ty]]
函數(shù)示例如下:import cv2import numpy as npimg = cv2.imread('messi5.jpg',0)rows,cols = img.shapeM = np.float32([[1,0,100],[0,1,50]])dst = cv2.warpAffine(img,M,(cols,rows))cv2.imshow('img',dst)cv2.waitKey(0)cv2.destroyAllWindows()123456789101112123456789101112
注意:cv2.warpAffine此函數(shù)的地撒個參數(shù)是一個元組分別表示圖像的寬、高:(width, height)
函數(shù)的詳細說明記錄在:python進階—OpenCV之常用圖像操作函數(shù)說明
圖像的旋轉
圖像的旋轉要靠函數(shù)cv2.warpAffine完成,此函數(shù)可以將圖像以指定的中心坐標進行旋轉,此處既是圖像的中心。
把圖像以中心店旋轉一個角度,需要依靠一個2*3的旋轉矩陣,可以通過函數(shù)cv2.getRotationMatrix2D來獲得旋轉矩陣
img = cv2.imread('messi5.jpg',0)rows,cols = img.shapeM = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)dst = cv2.warpAffine(img,M,(cols,rows))
1
2
3
4
5
1
2
3
4
5
圖像的仿射
圖像的仿射也是靠函數(shù)cv2.warpAffine完成,此函數(shù)可以將圖像以指定的坐標進行旋轉,
仿射操作也需要依靠一個2*3的旋轉矩陣,可以通過函數(shù)cv2.getAffineTransform來獲得旋轉矩陣import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread('drawing.png')rows,cols,ch = img.shapepts1 = np.float32([[50,50],[200,50],[50,200]])pts2 = np.float32([[10,100],[200,50],[100,250]])M = cv2.getAffineTransform(pts1,pts2)dst = cv2.warpAffine(img,M,(cols,rows))plt.subplot(121),plt.imshow(img),plt.title('Input')plt.subplot(122),plt.imshow(dst),plt.title('Output')plt.show()12345678910111213141516171234567891011121314151617
函數(shù)的詳細說明記錄在:python進階—OpenCV之常用圖像操作函數(shù)說明
圖像的投射
圖像的仿射也是靠函數(shù)cv2.warpPerspective完成,此函數(shù)可以將圖像以指定的坐標進行旋轉,
投射操作也需要依靠一個3*3的旋轉矩陣,可以通過函數(shù)cv2.getPerspectiveTransform來獲得旋轉矩陣
img = cv2.imread('sudokusmall.png')rows,cols,ch = img.shapepts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])M = cv2.getPerspectiveTransform(pts1,pts2)dst = cv2.warpPerspective(img,M,(300,300))plt.subplot(121),plt.imshow(img),plt.title('Input')plt.subplot(122),plt.imshow(dst),plt.title('Output')plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
函數(shù)的詳細說明記錄在:python進階—OpenCV之常用圖像操作函數(shù)說明
圖像閾值(二值化)
圖像的簡單閾值二值化
cv.threshold實現(xiàn)圖像的二值化操作,典型二值化操作如下
cv.THRESH_BINARY
cv.THRESH_BINARY_INV
cv.THRESH_TRUNC
cv.THRESH_TOZERO
cv.THRESH_TOZERO_INV
示例代碼如下:import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('gradient.png',0)ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)ret,thresh5 = cv.threshold(img,127,255,cv.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()1234567891011121314151612345678910111213141516
函數(shù)的詳細說明記錄在:python進階—OpenCV之常用圖像操作函數(shù)說明
圖像的自適應閾值二值化
cv.adaptiveThreshold函數(shù)實現(xiàn)自適應閾值二值化
自適應閾值計算方式有如下兩種
cv.ADAPTIVE_THRESH_MEAN_C : 鄰近閾值計算
cv.ADAPTIVE_THRESH_GAUSSIAN_C : 高斯鄰近閾值計算
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('sudoku.png',0)img = cv.medianBlur(img,5)ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\ cv.THRESH_BINARY,11,2)th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\ cv.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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
函數(shù)的詳細說明記錄在:python進階—OpenCV之常用圖像操作函數(shù)說明
Otsu’s二值化
當在函數(shù)cv.threshold函數(shù)的第4箱參數(shù)flag中使用cv.THRESH_OTSU標識時,表示使用Otsu’s二值化方式,即對那些在灰度圖像的直方圖中具有明顯2個波峰的圖像比較合適。import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('noisy2.png',0)# global thresholdingret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)# Otsu's thresholdingret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# Otsu's thresholding after Gaussian filteringblur = cv.GaussianBlur(img,(5,5),0)ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# plot all the images and their histogramsimages = [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()12345678910111213141516171819202122232425261234567891011121314151617181920212223242526
圖像模糊操作
模糊操作使用卷積計算實現(xiàn)的
均值模糊
均值模糊就是計算卷積核對應所有像素的平均值,然后用平均值替換卷積核中心對應的像素值
典型均值卷積核如下圖:
函數(shù)原型:dst = cv.blur( src, ksize[, dst[, anchor[, borderType]]] )
src:輸入圖像,通道數(shù)任意,每個通道會獨立處理,但是圖像的深度depth只能是 CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
dst:輸出圖像,大小與輸入圖像一致
ksize:卷積核大小
anchor:卷積核中心點默認值是 Point(-1,-1) 表示卷積核的正中心與進行處理的像素重合的點
borderType:邊沿模式
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')blur = cv.blur(img,(5,5))plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(blur),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
以上代碼中blur函數(shù)的ksize參數(shù)對應的卷積核如下圖:
中值模糊
中值模糊就是取卷積核對應所有像素的中值,然后用此中值替換卷積核中心對應的像素值
中值模糊只能定義卷積核的大小,內容不能自定義,卷積核的方式與均值模糊的卷積核相同
中值模糊適合去除椒鹽類圖像噪點
函數(shù)原型:dst = cv.medianBlur( src, ksize[, dst] )
src:輸入圖像,圖像為1、3、4通道的圖像,當模板尺寸為3或5時,圖像深度只能為CV_8U、CV_16U、CV_32F中的一個,如而對于較大尺寸的圖片,圖像深度只能是CV_8U
dst:出圖像,尺寸和類型與輸入圖像一致
ksize:卷積核大小,也叫濾波模板的尺寸大小,必須是大于1的奇數(shù),如3、5、7……import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')median = cv.medianBlur(img,5)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(median),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()1234567891012345678910
自定義模糊
所謂自定義模糊就是,自定義卷積核,即可實現(xiàn)自定義模糊
函數(shù)原型:dst = cv.filter2D( src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]] )
src:輸入圖像
dst:輸出圖像,和輸入圖像具有相同的尺寸和通道數(shù)量
ddepth:目標圖像深度,如果沒寫將生成與原圖像深度相同的圖像。當ddepth輸入值為-1時,目標圖像和原圖像深度保持一致。
kernel:卷積核(或者是相關核),一個單通道浮點型矩陣。如果想在圖像不同的通道使用不同的kernel,可以先使用split()函數(shù)將圖像通道事先分開。
anchor:卷積核的基準點(anchor),其默認值為(-1,-1)表示位于kernel中心位置?;鶞庶c即選取的kernel中心位置與進行處理像素重合的點。
delta:在儲存目標圖像前可選的添加到像素的值,默認值為0
borderType:圖像邊界逼近模式,默認值是BORDER_DEFAULT,即對全部邊界進行計算
import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('opencv_logo.png')kernel = np.ones((5,5),np.float32)/25dst = cv.filter2D(img,-1,kernel)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(dst),plt.title('Averaging')plt.xticks([]), plt.yticks([])plt.show()
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
kernel = np.ones((5,5),np.float32)/25定義的卷積核與上例均值模糊卷積核相同,所以輸出圖像的效果類似
自定義模糊可以實現(xiàn)圖像的銳化
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32)
高斯模糊
高斯模糊對圖像的噪聲去除更為有效
可以通過函數(shù)cv.getGaussianKernel獲取高斯卷積核
函數(shù)原型:dst = cv.GaussianBlur( src, ksize, sigmaX[, dst[, sigmaY[, borderType]]] )
src:輸入圖像,可以是任意通道數(shù)的圖片,每個通道獨立處理;但需要注意,圖片深度應該為CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一
dst:目標圖像,與原圖大小類型一致
ksize:高斯內核的大小,其中ksize.width和ksize.height可以不同,但他們都必須為正數(shù)和奇數(shù);參數(shù)值為0時,將由sigmaX與sigmaY參數(shù)計算得到
sigmaX:表示高斯核函數(shù)在X方向的的標準偏差
sigmaY:表示高斯核函數(shù)在Y方向的的標準偏差;若sigmaY為零,就將它設為sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height計算出來
borderType:圖像邊界逼近模式,默認值是BORDER_DEFAULT,即對全部邊界進行計算import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')blur = cv.GaussianBlur(img,(5,5),0)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(median),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()1234567891012345678910
雙邊沿模糊
雙邊沿模糊主要用于保持圖像的邊沿梯度更加明顯
函數(shù)原型:dst = cv.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]] )
src:輸入圖像,圖像必須是8位或浮點型單通道、三通道的圖像
dst:輸出圖像,和原圖像有相同的尺寸和類型。
d:表示在過濾過程中每個像素鄰域的直徑范圍。如果這個值是非正數(shù),則函數(shù)會從第五個參數(shù)sigmaSpace計算該值。該值越大計算速度越慢。
sigmaColor:顏色空間過濾器的sigma值,這個參數(shù)的值越大,表明該像素鄰域內有越寬廣的顏色會被混合到一起,產生較大的半相等顏色區(qū)域。
sigmaSpace:坐標空間中濾波器的sigma值,如果該值較大,則意味著顏色相近的較遠的像素將相互影響,從而使更大的區(qū)域中足夠相似的顏色獲取相同的顏色。當d>0時,d指定了鄰域大小且與sigmaSpace五官,否則d正比于sigmaSpace
borderType:圖像邊界逼近模式,默認值是BORDER_DEFAULT,即對全部邊界進行計算
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('opencv-logo-white.png')blur = cv.bilateralFilter(img,9,75,75)plt.subplot(121),plt.imshow(img),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(median),plt.title('Blurred')plt.xticks([]), plt.yticks([])plt.show()
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
寫到這,發(fā)現(xiàn)圖像處理的內容太多了,一篇容不下了,只好再寫另一篇了。