畫圖:
def show(image):
? ? plt.imshow(image)
? ? plt.axis('off')
? ? plt.show()
image = np.zeros((300,300,3),dtype='uint8')
畫線:
green = (0,255,0)
cv2.line(image, (0,0), (300,300), green)
show(image)
畫矩形:
red = (255,0,0)
cv2.rectangle(image, (10,10), (60,60), red, 2)
show(image)
畫圓形:
image = np.zeros((300,300,3),dtype='uint8')
(cX, cY) = image.shape[1]//2, image.shape[0]//2
white = (255,255,255)
for r in range(0,151,15):
? ? cv2.circle(image, (cX,cY), r, white, 2)
show(image)
image = np.zeros((300,300,3),dtype='uint8')
for i in range(10):
? ? # 半徑取值
? ? radius = np.random.randint(5,200)
? ? # 顏色取值
? ? color = np.random.randint(0,255,size=(3,)).tolist()
? ? # 圓心取值
? ? pt = np.random.randint(0,300,size=(2,))
? ? # 畫圖
? ? cv2.circle(image, tuple(pt), radius, color, -1)
show(image)
# 水平翻轉
image = cv2.flip(image,1)
# 垂直翻轉
image = cv2.flip(image,0)
# 水平+垂直翻轉
image = cv2.flip(image,-1)
#裁剪
image = image[0:200,50:200]
# 圖像加法
print(cv2.add(np.uint8([200]),np.uint8([100])))
# 普通加法
print(np.uint8([200])+np.uint8([100]))
# 生成跟圖片形狀相同的并且全為100的數據
M = np.ones(image.shape, dtype='uint8')*100
# 所有的像素加100
image = cv2.add(image, M)
# 生成跟圖片形狀相同的并且全為100的數據
M = np.ones(image.shape, dtype='uint8')*100
# 所有的像素減100
image = cv2.subtract(image, M)
bitwise_and是對二進制數據進行“與”操作螟够,即對圖像(灰度圖像或彩色圖像均可)每個像素值進行二進制“與”操作伞租,1&1=1缚俏,1&0=0,0&1=0,0&0=0
bitwise_or是對二進制數據進行“或”操作冗尤,即對圖像(灰度圖像或彩色圖像均可)每個像素值進行二進制“或”操作库正,1|1=1,1|0=1朦前,0|1=1介杆,0|0=0
bitwise_xor是對二進制數據進行“異或”操作,即對圖像(灰度圖像或彩色圖像均可)每個像素值進行二進制“異或”操作韭寸,1^1=0,1^0=1,0^1=1,0^0=0
bitwise_not是對二進制數據進行“非”操作春哨,即對圖像(灰度圖像或彩色圖像均可)每個像素值進行二進制“非”操作,~1=0恩伺,~0=1
rectangle = np.zeros((300,300,3),dtype='uint8')
white = (255,255,255)
cv2.rectangle(rectangle, (25,25), (275,275), white, -1)
show(rectangle)
circle = np.zeros((300,300,3), dtype='uint8')
cv2.circle(circle, (150,150), 150, white, -1)
show(circle)
# AND赴背,與操作,有黑就變黑
image = cv2.bitwise_and(rectangle, circle)
# OR莫其,或操作癞尚,有白就變白
image = cv2.bitwise_or(rectangle, circle)
show(image)
# NOT, 非操作,顏色取反
image = cv2.bitwise_not(circle)
show(image)
# 創(chuàng)建遮擋
mask = np.zeros(image.shape,dtype='uint8')
white = (255,255,255)
cv2.rectangle(mask, (50,50), (250,350), white, -1)
show(mask)
# 對圖像遮擋
masked = cv2.bitwise_and(image, mask)
show(masked)
#切片
(R, G, B) = cv2.split(image)
# 拉普拉斯金字塔
image = imread('image.jpg')
down_image1 = cv2.pyrDown(image)
down_image2 = cv2.pyrDown(down_image1)
up_image = cv2.pyrUp(down_image2)
laplacian = down_image1-up_image
show(laplacian)
Erosion腐蝕
其原理是在原圖的小區(qū)域內取局部最小值,其函數是cv2.erode()乱陡。這個核也叫結構元素浇揩,因為形態(tài)學操作其實也是應用卷積來實現(xiàn)的,結構元素可以是矩形/橢圓/十字形,可以用cv2.getStructuringElement()來生成不同形狀的結構元素憨颠。
for i in range(3):
? ? erosion = cv2.erode(image, kernel1, iterations=i+1)
? ? show(erosion)
Dilation膨脹
膨脹與腐蝕相反胳徽,取的是局部最大值。cv2.dilate()
for i in range(3):
? ? dilation = cv2.dilate(image, kernel1, iterations=i+1)
? ? show(dilation)
Opening開運算
先腐蝕后膨脹叫開運算爽彤,其作用是消除小白點养盗。這類形態(tài)學操作用cv2.morphologyEx()函數實現(xiàn)。
# 去除白點
opening = cv2.morphologyEx(image2, cv2.MORPH_OPEN, kernel1)
show(opening)
Closing閉運算
閉運算則相反:先膨脹后腐蝕适篙。其作用是消除小黑點往核。
# 去除黑點
closing = cv2.morphologyEx(image2, cv2.MORPH_CLOSE, kernel1)
show(closing)
Gradient形態(tài)學梯度
膨脹圖減去腐蝕圖,dilation - erosion嚷节,得到物體的輪廓
gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel1)
show(gradient)
Top Hat頂帽/White Hat白帽
原圖減去開運算后的圖:src - opening
tophat = cv2.morphologyEx(image2, cv2.MORPH_TOPHAT, kernel1)
show(tophat)
Black Hat黑帽
閉運算后的圖減去原圖:closing - src
blackhat = cv2.morphologyEx(image2, cv2.MORPH_BLACKHAT, kernel1)
show(blackhat)
Averaging平均
計算卷積框覆蓋區(qū)域所有像素的平均值得到卷積的結果
[[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]]
kernelsizes = [(3,3),(9,9),(15,15)]
plt.figure(figsize=(15,15))
for i,kernel in enumerate(kernelsizes):
? ? plt.subplot(1,3,i+1)
? ? # 平均平滑
? ? blur = cv2.blur(image, kernel)
? ? # 不顯示坐標
? ? plt.axis('off')
? ? # 設置標題
? ? plt.title('Blurred'+str(kernel))
? ? plt.imshow(blur)
plt.show()
Gaussian高斯模糊
現(xiàn)在把卷積核換成高斯核(簡單來說聂儒,方框不變虎锚,將原來每個方框的值是 相等的,現(xiàn)在里面的值是符合高斯分布的衩婚,方框中心的值最大窜护,其余方框根據 距離中心元素的距離遞減,構成一個高斯小山包非春。原來的求平均數現(xiàn)在變成求 加權平均數柱徙,全就是方框里的值)
kernelsizes = [(3,3),(9,9),(15,15)]
plt.figure(figsize=(15,15))
for i,kernel in enumerate(kernelsizes):
? ? plt.subplot(1,3,i+1)
? ? # 平均平滑
? ? blur = cv2.GaussianBlur(image, kernel, 0)
? ? # 不顯示坐標
? ? plt.axis('off')
? ? # 設置標題
? ? plt.title('Blurred'+str(kernel))
? ? plt.imshow(blur)
plt.show()
Median中值模糊?
顧名思義就是用與卷積框對應像素的中值來替代中心像素的值。
plt.figure(figsize=(15,15))
for i,kernel in enumerate((3,9,15)):
? ? plt.subplot(1,3,i+1)
? ? # 平均平滑
? ? blur = cv2.medianBlur(image, kernel)
? ? # 不顯示坐標
? ? plt.axis('off')
? ? # 設置標題
? ? plt.title('Blurred'+str(kernel))
? ? plt.imshow(blur)
plt.show()
Bilateral雙邊濾波
能在保持邊界清晰的情況下有效的去除噪音奇昙。我們已經知道高斯濾波器是求中心點鄰近區(qū)域像素的高斯加權平均值护侮。這種高斯濾波器只考慮像素之間的空間關系,而不會考慮像素值之間的關系(像素的相似度)敬矩。所以這種方法不會考慮一個像素是否位于邊界概行。因此邊界也會別模糊掉,而這正不是我們想要弧岳。
雙邊濾波在同時使用空間高斯權重和灰度值相似性高斯權重凳忙。空間高斯函數確保只有鄰近區(qū)域的像素對中心點有影響禽炬,灰度值相似性高斯函數確保只有與中心像素灰度值相近的才會被用來做模糊運算涧卵。所以這種方法會確保邊界不會被模糊掉,因為邊界處的灰度值變化比較大腹尖。
params = [(11,21,7),(11,41,21),(15,75,75)]
plt.figure(figsize=(15,15))
# 鄰域直徑柳恐,灰度值相似性高斯函數標準差,空間高斯函數標準差
for i,(diameter,sigmaColor,sigmaSpace) in enumerate(params):
? ? plt.subplot(1,3,i+1)
? ? # 平均平滑
? ? blur = cv2.bilateralFilter(image, diameter,sigmaColor,sigmaSpace)
? ? # 不顯示坐標
? ? plt.axis('off')
? ? # 設置標題
? ? plt.title('Blurred'+str((diameter,sigmaColor,sigmaSpace)))
? ? plt.imshow(blur)
plt.show()
RGB
FAO
FAO
RGB是從顏色發(fā)光的原理來設計定的热幔,通俗點說它的顏色混合方式就好像有紅乐设、綠、藍三盞燈绎巨,當它們的光相互疊合的時候近尚,色彩相混,而亮度卻等于兩者亮度之總和场勤,越混合亮度越高戈锻,即加法混合。
紅和媳、綠格遭、藍三個顏色通道每種色各分為256階亮度,在0時“燈”最弱——是關掉的留瞳,而在255時“燈”最亮拒迅。當三色灰度數值相同時,產生不同灰度值的灰色調,即三色灰度都為0時坪它,是最暗的黑色調骤竹;三色灰度都為255時,是最亮的白色調往毡。
在電腦中,RGB的所謂“多少”就是指亮度靶溜,并使用整數來表示开瞭。通常情況下,RGB各有256級亮度罩息,用數字表示為從0嗤详、1、2...直到255瓷炮。注意雖然數字最高是255葱色,但0也是數值之一,因此共256級娘香。
256 x 256 x 256 = 16,777,216
image = imread('image.jpg')
(R, G, B) = cv2.split(image)
zeros = np.zeros(image.shape[:2],dtype='uint8')
show(cv2.merge([R,zeros,zeros]))
show(cv2.merge([zeros,G,zeros]))
show(cv2.merge([zeros,zeros,B]))
HSV
HSV是一種比較直觀的顏色模型苍狰,HSV顏色空可以更好的數字化處理顏色。這個模型中顏色的參數分別是:色調(H, Hue)烘绽,飽和度(S,Saturation)淋昭,明度(V, Value)。
色調H:
用角度度量安接,取值范圍為0°~360°翔忽,從紅色開始按逆時針方向計算,紅色為0°盏檐,綠色為120°,藍色為240°歇式。它們的補色是:黃色為60°,青色為180°,品紅為300°
飽和度S:
飽和度S表示顏色接近光譜色的程度胡野。一種顏色材失,可以看成是某種光譜色與白色混合的結果。其中光譜色所占的比例愈大给涕,顏色接近光譜色的程度就愈高豺憔,顏色的飽和度也就愈高。飽和度高够庙,顏色則深而艷恭应。光譜色的白光成分為0,飽和度達到最高耘眨。通常取值范圍為0%~100%昼榛,值越大,顏色越飽和。
明度V:?
明度表示顏色明亮的程度胆屿,對于光源色奥喻,明度值與發(fā)光體的光亮度有關;對于物體色非迹,此值和物體的透射比或反射比有關环鲤。通常取值范圍為0%(黑)到100%(白)。
image = imread('image.jpg')
hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
zeros = np.zeros(image.shape[:2],dtype='uint8')
for (name,chan) in zip(('H','S','V'), cv2.split(hsv)):
? ? cv2.imshow(name,chan)
cv2.waitKey(0)
cv2.destroyAllWindows()
L*a*b*
CIE1976Lab色空間(CIE LAB 色空間)憎兽,是1976年由國際照明學會(CIE)推薦的均勻色空間冷离。Lab顏色空間用于計算機色調調整和彩色校正。該空間是三維直角坐標系統(tǒng)纯命。是目前最受廣用的測色系統(tǒng)西剥。以明度L和色度坐標a、b來表示顏色在色空間中的位置亿汞。l表示顏色的明度瞭空,a正值表示偏紅,負值表示偏綠疗我;b*正值表示偏黃咆畏,負值表示偏藍
L* 表示顏色的明度;
a* 正值表示紅色碍粥,負值表示綠色鳖眼;
b* 正值表示黃色,負值表示藍色嚼摩;
image = imread('image.jpg')
lab = cv2.cvtColor(image, cv2.COLOR_RGB2LAB)
zeros = np.zeros(image.shape[:2],dtype='uint8')
for (name,chan) in zip(('L','A','B'), cv2.split(lab)):
? ? cv2.imshow(name,chan)
cv2.waitKey(0)
cv2.destroyAllWindows()
在圖像處理中钦讳,Thresholding中文翻譯過來叫二值化或者閾值化。二值化就是把圖片傳換成只有white和black這兩種顏色枕面。通過Thresholding愿卒,可以讓圖片中感興趣的顏色變成主角--white,其余的顏色全部隱藏--black潮秘。另外琼开,二值化后的圖片也便于計算機進行分析,因為邊緣輪廓十分清晰枕荞,所以計算機可以輕松找到邊界線柜候。然而,在找邊界這方面躏精,Thresholding并不是特別好的算法渣刷,有些時候遇到某些特殊圖片效果也不好。
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
plt.imshow(gray,'gray')
plt.axis('off')
plt.show()
ret1,thresh1 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
ret2,thresh2 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY_INV)
ret3,thresh3 = cv2.threshold(gray,127,255,cv2.THRESH_TRUNC)
ret4,thresh4 = cv2.threshold(gray,127,255,cv2.THRESH_TOZERO)
ret5,thresh5 = cv2.threshold(gray,127,255,cv2.THRESH_TOZERO_INV)
titles = ['original','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [gray, thresh1, thresh2, thresh3, thresh4, thresh5]
plt.figure(figsize=(15,5))
for i in range(6):
? ? plt.subplot(2,3,i+1)
? ? plt.imshow(images[i],'gray')
? ? plt.title(titles[i])
? ? plt.axis('off')
plt.show()
Otsu’s Method
自動選擇閾值
image = imread('image/opencv_logo.png')
show(image)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
plt.imshow(gray,'gray')
plt.axis('off')
plt.show()
ret1,thresh1 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
ret2,thresh2 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
print('ret1:',ret1)
print('ret2:',ret2)
plt.imshow(thresh1,'gray')
plt.axis('off')
plt.show()
plt.imshow(thresh1,'gray')
plt.axis('off')
plt.show()
### Adaptive Thresholding自適應閾值
在前面的部分我們使用是全局閾值矗烛,整幅圖像采用同一個數作為閾值辅柴。當
時這種方法并不適應與所有情況,尤其是當同一幅圖像上的不同部分的具有不
同亮度時。這種情況下我們需要采用自適應閾值碌嘀。此時的閾值是根據圖像上的
每一個小區(qū)域計算與其對應的閾值涣旨。因此在同一幅圖像上的不同區(qū)域采用的是
不同的閾值,從而使我們能在亮度不同的情況下得到更好的結果股冗。
Adaptive Method- 指定計算閾值的方法霹陡。?
– cv2.ADPTIVE_THRESH_MEAN_C:閾值取自相鄰區(qū)域的平
均值?
– cv2.ADPTIVE_THRESH_GAUSSIAN_C:閾值取值相鄰區(qū)域
的加權和,權重為一個高斯窗口魁瞪。?
? Block Size - 鄰域大心侣伞(用來計算閾值的區(qū)域大小)导俘。?
? C - 這就是是一個常數,閾值就等于平均值或者加權平均值減去這個常
數剔蹋。
# 變灰度圖
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
# 中值濾波
image = cv2.medianBlur(image,5)
# 普通二值化
ret,th1 = cv2.threshold(image,127,255,cv2.THRESH_BINARY)
# 平均值閾值
th2 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
# 高斯閾值
th3 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)
titles = ['original', 'Global Thresholding', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [image, th1, th2, th3]
plt.figure(figsize=(10,5))
for i in range(4):
? ? plt.subplot(2,2,i+1)
? ? plt.imshow(images[i],'gray')
? ? plt.axis('off')
? ? plt.title(titles[i])
plt.show()
# 變灰度圖
image = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
# 中值濾波
image = cv2.medianBlur(image,5)
# 普通二值化
ret,th1 = cv2.threshold(image,127,255,cv2.THRESH_BINARY)
# 平均值閾值
th2 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
# 高斯閾值
th3 = cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)
titles = ['original', 'Global Thresholding', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [image, th1, th2, th3]
plt.figure(figsize=(10,5))
for i in range(4):
? ? plt.subplot(2,2,i+1)
? ? plt.imshow(images[i],'gray')
? ? plt.axis('off')
? ? plt.title(titles[i])
plt.show()
圖像梯度:
I是圖像像素的值(如:RGB值)
一階導數:
x的梯度:Gx = I(x+1,y)-I(x,y)
y的梯度:Gy = I(x,y+1)-I(x,y)
二階導數:
x的梯度:I(x+1,y)+I(x-1,y)-2I(x,y) y的梯度:I(x,y+1)+I(x,y-1)-2I(x,y) OpenCV 提供了三種不同的梯度濾波器旅薄,或者說高通濾波器: Sobel,Scharr 和 Laplacian泣崩。Sobel少梁, Scharr 其實就是求一階或二階導數。 Scharr 是對 Sobel的優(yōu)化矫付。Laplacian 是求二階導數凯沪。
梯度大小和方向的公式為:
G=(G2x+G2y)????????????????√G=(Gx2+Gy2)
θ=tan?1(GxGy)θ=tan?1(GxGy) 梯度的方向一般總是與邊界垂直。梯度方向被歸為四類:垂直买优,水平妨马,和兩個對角線。
FAO
Sobel算子和Scharr算子:
Sobel 算子是高斯平滑與微分操作的結合體杀赢,所以它的抗噪聲能力很好烘跺。你可以設定求導的方向(xorder 或 yorder)。還可以設定使用的卷積核的大兄蕖(ksize)滤淳。
FAO
如果 ksize=-1,會使用 3x3 的 Scharr 濾波器砌左,它的的效果要比 3x3 的 Sobel 濾波器好(而且速度相同脖咐,所以在使用 3x3 濾波器時應該盡量使用 Scharr 濾波器)。 3x3 的 Scharr 濾波器卷積核如下:
FAO
Laplacian算子:
def gradient(image):
? ? image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
? ? # cv2.CV_64F輸出圖像的深度(數據類型)汇歹,64位float類型屁擅,因為梯度可能是正也可能是負
? ? laplacian = cv2.Laplacian(image, cv2.CV_64F)
? ? # 1, 0表示在x方向求一階導數,最大可以求2階導數
? ? sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
? ? # 0, 1表示在y方向求一階導數秤朗,最大可以求2階導數
? ? sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
? ? titles = ['Original', 'Laplacian', 'SobelX', 'SobelY']
? ? images = [image,laplacian,sobelx,sobely]
? ? plt.figure(figsize=(10,5))
? ? for i in range(4):
? ? ? ? plt.subplot(2,2,i+1)
? ? ? ? plt.imshow(images[i],'gray')
? ? ? ? plt.title(titles[i])
? ? ? ? plt.axis('off')
? ? plt.show()
Canny邊緣檢測
Canny 邊緣檢測是一種非常流行的邊緣檢測算法煤蹭,是 John F.Canny 在1986 年提出的。它是一個有很多步構成的算法,我們接下來會逐步介紹硝皂。
1.噪聲去除
由于邊緣檢測很容易受到噪聲影響常挚,所以第一步是使用 5x5 的高斯濾波器去除噪聲,這個前面我們已經學過了稽物。
2.計算圖像梯度
對平滑后的圖像使用 Sobel 算子計算水平方向和豎直方向的一階導數(圖像梯度)(Gx 和 Gy)奄毡。根據得到的這兩幅梯度圖(Gx 和 Gy)找到邊界的梯度和方向,公式如下:
G=(G2x+G2y)????????????????√G=(Gx2+Gy2)
θ=tan?1(GxGy)θ=tan?1(GxGy) 梯度的方向一般總是與邊界垂直贝或。梯度方向被歸為四類:垂直吼过,水平,和兩個對角線咪奖。
3.非極大值抑制
在獲得梯度的方向和大小之后盗忱,應該對整幅圖像做一個掃描兵志,去除那些非邊界上的點列吼。對每一個像素進行檢查宠叼,看這個點的梯度是不是周圍具有相同梯度方向的點中最大的宏邮。如下所示:
FAO
上圖中的數字代表了像素點的梯度強度癞志,箭頭方向代表了梯度方向撕贞。以第二排第三個像素點為例决采,由于梯度方向向上域滥,則將這一點的強度(7)與其上下兩個像素點的強度(5和4)比較靡挥,由于這一點強度最大序矩,則保留。
4.滯后閾值
現(xiàn)在要確定那些邊界才是真正的邊界跋破。這時我們需要設置兩個閾值:minVal 和 maxVal簸淀。當圖像的灰度梯度高于 maxVal 時被認為是真的邊界,那些低于 minVal 的邊界會被拋棄幔烛。如果介于兩者之間的話啃擦,就要看這個點是否與某個被確定為真正的邊界點相連,如果是就認為它也是邊界點饿悬,如果不是就拋棄令蛉。如下圖:
FAO
A 高于閾值 maxVal 所以是真正的邊界點, B 雖然低于 maxVal 但高于minVal 并且與 A 相連狡恬,所以也被認為是真正的邊界點珠叔。而 C 就會被拋棄,因為他不僅低于 maxVal 而且不與真正的邊界點相連弟劲。D也會被拋棄祷安,因為低于minVal。所以選擇合適的 maxVal和 minVal 對于能否得到好的結果非常重要兔乞。在這一步一些小的噪聲點也會被除去汇鞭,因為我們假設邊界都是一些長的線段凉唐。
Canny使用
在 OpenCV 中只需要一個函數: cv2.Canny(),就可以完成以上幾步霍骄。讓我們看如何使用這個函數台囱。這個函數的第一個參數是輸入圖像。第二和第三個分別是 minVal 和 maxVal读整。第四個參數設置用來計算圖像梯度的 Sobel卷積核的大小簿训,默認值為 3。最后一個參數是 L2gradient米间,它可以用來設定求梯度大小的方程强品。如果設為 True,就會使用我們上面提到過的方程: G=(G2x+G2y)????????????????√G=(Gx2+Gy2) 屈糊,否則使用方程: G=|G2x|+|G2y|G=|Gx2|+|Gy2| 代替的榛,默認值為 False。
def edge_detection(image,minVal=100,maxVal=200):
? ? image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
? ? edges = cv2.Canny(image,minVal,maxVal)
? ? plt.imshow(edges,'gray')
? ? plt.axis('off')
? ? plt.show()
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
image = cv2.GaussianBlur(image, (3,3), 0)
Value = [(10,150),(100,200),(180,230)]
plt.figure(figsize=(20,5))
for i,(minVal,maxVal) in enumerate(Value):
? ? plt.subplot(1,3,i+1)
? ? edges = cv2.Canny(image,minVal,maxVal)
? ? edges = cv2.GaussianBlur(edges, (3,3), 0)
? ? plt.imshow(edges,'gray')
? ? plt.title(str((minVal,maxVal)))
? ? plt.axis('off')
plt.show()
# 自動確定閾值的一種方法
def auto_canny(image, sigma=0.33):
? ? v = np.median(image)
? ? lower = int(max(0, (1.0-sigma) * v))
? ? upper = int(min(255, (1.0+sigma) * v))
? ? edged = cv2.Canny(image, lower, upper)
? ? print(lower,upper)
? ? return edged
edges = auto_canny(image)
edges = cv2.GaussianBlur(edges, (3,3), 0)
plt.imshow(edges,'gray')
plt.axis('off')
plt.show()
# 從攝像頭獲取圖像數據
cap = cv2.VideoCapture(0)
while(True):
? ? # ret 讀取成功True或失敗Falseq
? ? # frame讀取到的圖像的內容
? ? # 讀取一幀數據
? ? ret,frame = cap.read()
? ? # 變?yōu)榛叶葓D
? ? gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
? ? cv2.imshow('frame',gray)
? ? # waitKey功能是不斷刷新圖像逻锐,單位ms困曙,返回值是當前鍵盤按鍵值
? ? # ord返回對應的ASCII數值
? ? if cv2.waitKey(1) & 0xff == ord('q'):
? ? ? ? break
cap.release()
cv2.destroyAllWindows()
cap.read() 返回一個布爾值(True/False)。如果幀讀取的是正確的谦去,就是 True。所以最后你可以通過檢查他的返回值來查看視頻文件是否已經到了結尾蹦哼。
有時 cap 可能不能成功的初始化攝像頭設備鳄哭。這種情況下上面的代碼會報錯。你可以使用 cap.isOpened()纲熏,來檢查是否成功初始化了妆丘。如果返回值是True,那就沒有問題局劲。否則就要使用函數 cap.open()勺拣。
你可以使用函數 cap.get(propId) 來獲得視頻的一些參數信息。這里propId 可以是 0 到 18 之間的任何整數鱼填。每一個數代表視頻的一個屬性药有。
FAO
其中的一些值可以使用 cap.set(propId,value) 來修改, value 就是你想要設置成的新值苹丸。
例如愤惰,我可以使用 cap.get(3) 和 cap.get(4) 來查看每一幀的寬和高。默認情況下得到的值是 640X480赘理。但是我們可以使用 ret=cap.set(3,320)和 ret=cap.set(4,240) 來把寬和高改成 320X240宦言。
# 從文件讀取視頻內容
cap = cv2.VideoCapture('videos/cats.mp4')
# 視頻每秒傳輸幀數
fps = cap.get(cv2.CAP_PROP_FPS)
# 視頻圖像的寬度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# 視頻圖像的長度
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(fps)
print(frame_width)
print(frame_height)
while(True):
? ? # ret 讀取成功True或失敗False
? ? # frame讀取到的圖像的內容
? ? # 讀取一幀數據
? ? ret,frame = cap.read()
? ? if ret!=True:
? ? ? ? break
? ? cv2.imshow('frame',frame)
? ? # waitKey功能是不斷刷新圖像,單位ms商模,返回值是當前鍵盤按鍵值
? ? # ord返回對應的ASCII數值
? ? if cv2.waitKey(25) & 0xff == ord('q'):
? ? ? ? break
cap.release()
cv2.destroyAllWindows()
視頻寫入
在我們捕獲視頻奠旺,并對每一幀都進行加工之后我們想要保存這個視頻蜘澜。對于圖片來時很簡單只需要使用 cv2.imwrite()。但對于視頻來說就要多做點工作响疚。
這次我們要創(chuàng)建一個 VideoWriter 的對象鄙信。我們應該確定一個輸出文件的名字。接下來指定 FourCC 編碼(下面會介紹)稽寒。播放頻率和幀的大小也都需要確定扮碧。最后一個是 isColor 標簽。如果是 True杏糙,每一幀就是彩色圖慎王,否則就是灰度圖。
FourCC 就是一個 4 字節(jié)碼宏侍,用來確定視頻的編碼格式赖淤。可用的編碼列表可以從fourcc.org查到谅河。
? In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 gives very small size video)
# 從文件讀取視頻內容
cap = cv2.VideoCapture('videos/cats.mp4')
# 視頻每秒傳輸幀數
fps = cap.get(cv2.CAP_PROP_FPS)
# 視頻圖像的寬度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# 視頻圖像的長度
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(fps)
print(frame_width)
print(frame_height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('videos/output.avi',fourcc,fps,(frame_width,frame_height))
while(True):
? ? ret, frame = cap.read()
? ? if ret==True:
? ? ? ? # 水平翻轉
? ? ? ? frame = cv2.flip(frame,1)
? ? ? ? out.write(frame)
? ? ? ? cv2.imshow('frame',frame)
? ? ? ? if cv2.waitKey(25) & 0xff == ord('q'):
? ? ? ? ? ? break
? ? else:
? ? ? ? break
out.release()
cap.release()
cv2.destroyAllWindows()
# 系統(tǒng)操作
import os
# 判斷文件類型
import imghdr
from imutils import *
# 人臉檢測并保存人臉
def facedetect(image, output):
? ? # 獲取文件名
? ? name = os.path.basename(image)
? ? # 讀入圖片
? ? image = cv2.imread(image)
? ? # 變成灰度圖
? ? image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
? ? # 級聯(lián)分類器咱旱,檢測人臉
? ? detector = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")
? ? rects = detector.detectMultiScale(image, scaleFactor=1.1, minNeighbors=3, minSize=(20, 20), flags=cv2.CASCADE_SCALE_IMAGE)
? ? # 循環(huán)每個人臉
? ? for (x,y,w,h) in rects:
? ? ? ? # 截取人臉,并且都轉化為200*200的固定大小
? ? ? ? f = cv2.resize(image[y:y+h, x:x+w], (200,200))
? ? ? ? # 寫入指定路徑
? ? ? ? cv2.imwrite(os.path.join(output, name), f)
# 檢測并截取人臉
def predict_face(path, output):
? ? # 如果該文件夾不存在則創(chuàng)建文件夾
? ? if not os.path.exists(output):
? ? ? ? os.makedirs(output)
? ? # 循環(huán)每個人物的文件夾下的圖片
? ? for files in os.listdir(path):
? ? ? ? # 檢測是不是文件夾
? ? ? ? if os.path.isdir(os.path.join(path, files)):
? ? ? ? ? ? # 定義截取到的人臉的輸出路徑
? ? ? ? ? ? output2 = os.path.join(output, files)
? ? ? ? ? ? # 如果該文件夾不存在則創(chuàng)建文件夾
? ? ? ? ? ? if not os.path.exists(output2):
? ? ? ? ? ? ? ? os.makedirs(output2)
? ? ? ? ? ? # 人物文件夾的完整路徑
? ? ? ? ? ? files = os.path.join(path, files)
? ? ? ? ? ? # 循環(huán)每個人的每張照片
? ? ? ? ? ? for file in os.listdir(files):
? ? ? ? ? ? ? ? # 照片完整路徑
? ? ? ? ? ? ? ? file = os.path.join(files, file)
? ? ? ? ? ? ? ? # 檢測人臉并保存
? ? ? ? ? ? ? ? facedetect(file, output2)
# 生成label文件
def get_label(path):
? ? fh = open("label.txt", 'w')
? ? # 表示人臉label
? ? label = 0
? ? for root, dirs, files in os.walk(path):
? ? ? ? # 循環(huán)每個文件夾
? ? ? ? for subdir in dirs:
? ? ? ? ? ? # 文件夾完整路徑
? ? ? ? ? ? subdir_path = os.path.join(root,subdir)
? ? ? ? ? ? # 循環(huán)每個人物文件夾下面每張照片
? ? ? ? ? ? for file in os.listdir(subdir_path):
? ? ? ? ? ? ? ? # 照片完整路徑
? ? ? ? ? ? ? ? filepath = os.path.join(subdir_path, file)
? ? ? ? ? ? ? ? # 判斷文件類型是不是圖片類型
? ? ? ? ? ? ? ? imgType = imghdr.what(filepath)
? ? ? ? ? ? ? ? if imgType == 'jpeg' or imgType == 'png':
? ? ? ? ? ? ? ? ? ? # 保存圖片路徑
? ? ? ? ? ? ? ? ? ? fh.write(filepath);
? ? ? ? ? ? ? ? ? ? fh.write(";")
? ? ? ? ? ? ? ? ? ? # 標簽
? ? ? ? ? ? ? ? ? ? fh.write(str(label))
? ? ? ? ? ? ? ? ? ? fh.write("\n")
? ? ? ? ? ? # 每個人的標簽不一樣绷耍,從0開始計數
? ? ? ? ? ? label = label + 1? ? ? ? ? ?
? ? fh.close()
# 保存圖片數據
images = []
# 保存標簽
labels = []
# 打開文件
fh = open("label.txt")
# 循環(huán)每一行
for line in fh:
? ? # 以;切分字符串
? ? arr = line.split(";")
? ? # 第0部分為圖片路徑吐限,讀取文件
? ? img = cv2.imread(arr[0],0)
? ? # 保存圖片數據
? ? images.append(img)
? ? # 保存對應的標簽數據
? ? labels.append(int(arr[1]))
# 安裝opencv擴展包
# pip install opencv-contrib-python
# 定義人臉識別模型
model = cv2.face.EigenFaceRecognizer_create()
# model = cv2.face.FisherFaceRecognizer_create()
# model = cv2.face.LBPHFaceRecognizer_create()
# 訓練模型
model.train(np.array(images), np.array(labels))
# 保存模型
model.save("predict_face_XiaoMing_AB.xml")
# 定義人物名字
name= ['ab','xiaoming']
# 定義人臉識別模型
model = cv2.face.EigenFaceRecognizer_create()
# 載入訓練好的模型
model.read('predict_face_XiaoMing_AB.xml')
# 讀入測試圖片來做測試
for file in os.listdir('test'):
? ? file = os.path.join('test', file)
? ? # 判斷文件類型
? ? imgType = imghdr.what(file)
? ? if imgType == 'jpeg' or imgType == 'png':
? ? ? ? # 讀入圖片
? ? ? ? image = imread(file)
? ? ? ? # 變?yōu)榛叶葓D
? ? ? ? gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
? ? ? ? # 級聯(lián)分類器
? ? ? ? detector = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")
? ? ? ? rects = detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(20, 20), flags=cv2.CASCADE_SCALE_IMAGE)
? ? ? ? # 循環(huán)每個人臉
? ? ? ? for (x,y,w,h) in rects:
? ? ? ? ? ? # 畫矩形框
? ? ? ? ? ? cv2.rectangle(image, (x,y), (x+w,y+h), (0,255,0), 2)
? ? ? ? ? ? # 人臉識別
? ? ? ? ? ? face = cv2.resize(gray[y:y+h,x:x+w], (200,200))
? ? ? ? ? ? # 預測人物
? ? ? ? ? ? params = model.predict(face)
? ? ? ? ? ? # 寫上人物名字
? ? ? ? ? ? cv2.putText(image,name[params[0]],(x,y-20),cv2.FONT_HERSHEY_SIMPLEX,1,(255,0,0),2)
? ? ? ? show(image)