開頭一下: 上一篇學習完了圖像的基礎操作,這一篇博客是記錄圖像處理的一部分。回顧python版的OpenCV第二篇,對於相關的圖像處理也有一定的了解。視頻參考B站唐宇迪博士,也是來自一位計算機視覺的大佬推薦。
ret,dst=cv2.threshold(src,thresh,maxval,type)
src:輸入圖,只能輸入單通道圖像,一般為灰度圖
dst:輸出圖
thresh:阈值
maxval:當像素值超過阈值(或者小於阈值),所賦予的值
type:二值化(大於取一個值,小於取另一個值)操作的類型,包含五種類型
THRESH_BINARY:超過阈值部分取maxval,否則為0
THRESH_BINARY_INV: THRESH_BINARY的反轉
THRESH_TRUNC:大於阈值部分設為阈值,否則不變
THRESH_TOZERO:大於阈值部分不改變,否則設為0
THRESH_TOZERO_INV: THRESH_TOZERO的反轉
#圖像阈值
#顯示原圖
#img=cv.cvtColor(img,cv.COLOR_BGR2GRAY) #圖像取灰
cv_show("yuantu",img)
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)
title=['Original','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images=[img,thresh1,thresh2,thresh3,thresh4,thresh5]
for i in range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(title[i])
plt.xticks([]),plt.yticks([])
plt.show()
說明:通過構造一個卷積矩陣,做內積。
image=cv.imread('E:\\Pec\\zao.jpg')
cv.imshow('image',image)
cv.waitKey(0)
cv.destroyAllWindows() #如果之前沒有釋放掉內存的操作的話destroyallWIndows會釋放掉被那個變量占用的內存
#簡單的平均卷積操作
blur=cv.blur(image,(3,3))
#cv_show('blur',blur)
說明:基本和均值濾波一樣,可以選擇歸一化
box=cv.boxFilter(image,-1,(3,3),normalize=False)#-1表示輸入的元素一致。
# normalize=True表示做歸一化,與均值濾波一直。若為false,不做歸一化,不除以矩陣長和寬,但是容易越界。
#大於255,則取255
#cv_show('box',box)
說明:高斯模糊的卷積核裡面的數值滿足高斯分布(就是凸曲線,更重視中間的)
aussian=cv.GaussianBlur(image,(5,5),1)
#cv_show('aussian',aussian)
說明:取一個卷積之後,然後取中間值代替
median=cv.medianBlur(image,5)
#cv_show("median",median)
#集中展示
res=np.hstack((blur,aussian,median))
#np.hatack:按水平方向堆疊數組,構成一個新數組
#np.vstack:按垂直方向堆疊數組,構成一個新數組
print(res)
cv_show("average",res)
[[[226 134 53]
[226 134 53]
[226 134 53]
...
[226 134 53]
[226 134 53]
[226 134 53]]
#形態學-腐蝕操作
image=cv.imread('E:\\Pec\\fushi.jpg')
cv_show("fushi-Ori",image)
kernel=np.ones((2,2),np.uint8)#(2,2)表示腐蝕的核大小,就是腐蝕的半徑
erosion=cv.erode(image,kernel,iterations=1)#iterations=1表示腐蝕的次數
cv_show("fushi-eff",erosion)
原圖:
腐蝕之後:
接著連續圖片介紹腐蝕過程:
pie=cv.imread('E:\\Pec\\fushiyuan.jpg')
cv_show("pie",pie)
kernel=np.ones((20,20),np.uint8)
erosion1=cv.erode(pie,kernel,iterations=1)
erosion2=cv.erode(pie,kernel,iterations=2)
erosion3=cv.erode(pie,kernel,iterations=3)
res=np.hstack((erosion1,erosion2,erosion3))
cv_show('fushilianhuantu',res)
#形態學-膨脹操作
image=cv.imread('E:\\Pec\\fushi.jpg')
cv_show("fushi-Ori",image)
kernel=np.ones((3,3),np.uint8)#(2,2)表示腐蝕的核大小,就是腐蝕的半徑
erosion=cv.erode(image,kernel,iterations=1)#iterations=1表示腐蝕的次數
cv_show("fushi-eff",erosion)
dige_dilate=cv.dilate(erosion,kernel,iterations=1)
cv_show('dilate',dige_dilate)
#開:先腐蝕,再膨脹
image=cv.imread('E:\\Pec\\fushi.jpg')
kernel=np.ones((3,3),np.uint8)#(2,2)表示腐蝕的核大小,就是腐蝕的半徑
opening=cv.morphologyEx(image,cv.MORPH_OPEN,kernel)
#cv_show("opening",opening)
#閉:先膨脹,再腐蝕
image=cv.imread('E:\\Pec\\fushi.jpg')
kernel=np.ones((3,3),np.uint8)#(2,2)表示腐蝕的核大小,就是腐蝕的半徑
closeing=cv.morphologyEx(image,cv.MORPH_CLOSE,kernel)
#cv_show("close",closeing)
res=np.hstack((image,opening,closeing))
cv_show('fushilianhuantu',res)
說明:#梯度=膨脹-腐蝕
pie=cv.imread('E:\\Pec\\fushiyuan.jpg')
kernel=np.ones((20,20),np.uint8)
erode=cv.erode(pie,kernel,iterations=2)
dilate=cv.dilate(pie,kernel,iterations=2)
res=np.hstack((pie,erode,dilate))
cv_show("zhanshi",res)
gradient=cv.morphologyEx(pie,cv.MORPH_GRADIENT,kernel)
cv_show("gradient",gradient)
#禮帽和黑帽
image=cv.imread('E:\\Pec\\fushi.jpg')
kernel=np.ones((3,3),np.uint8)#(2,2)表示腐蝕的核大小,就是腐蝕的半徑
topat=cv.morphologyEx(image,cv.MORPH_TOPHAT,kernel)
res=np.hstack((image,topat))
cv_show("limao",res)
blackhat=cv.morphologyEx(image,cv.MORPH_BLACKHAT,kernel)
res=np.hstack((image,blackhat))
cv_show("heimao",res)
說明:
Sobel算子是像素圖像邊緣檢測中最重要的算子之一。在技術上,它是一個離散的一階差分算子,用來計算圖像亮度函數的一階梯度之近似值。在圖像的任何一點使用此算子,將會產生該點對應的梯度矢量或是其法矢量。該方法能通過增強圖像的邊緣效果來突出圖像的輪廓特征。
為什麼要檢測邊緣?
比如自動駕駛裡面,我們至少要做的一個工作就是道路的邊緣檢測,只有正確的檢測到道路的邊緣我們的車才會行駛在道路上而不是開到馬路牙子外。
或者從另一個角度解釋,我們做邊緣檢測不是讓人眼去欣賞一張道路圖片裡面的道路邊緣的,我們正確檢測出一張圖像的邊緣是為了讓模型更好的去認識這張圖片中的道路。所以精確的邊緣檢測可以幫助電腦模型很好的識別這是道路還是道路外面,從而做出正確的反饋——指導汽車正確行使。
d s t = c v . S o b e l ( s r c , d d e p t h , d x , d y , k s i z e ) dst=cv.Sobel(src,ddepth,dx,dy,ksize) dst=cv.Sobel(src,ddepth,dx,dy,ksize)
#cv.CV_64F,opencv默認把負值重新定義為0.加上這個就允許有負值
pie=cv.imread('E:\\Pec\\fushiyuan.jpg')
cv_show("yuan",pie)
sobelx=cv.Sobel(pie,cv.CV_64F,1,0,ksize=3)#1,0只算水平方向
#右邊-左邊:白到黑是正數,黑到白是負數,所有的負數都會截斷成0,所以要取絕對值
sobelx=cv.convertScaleAbs(sobelx)
#cv_show("sobelx",sobelx)
#豎直方向
sobely=cv.Sobel(pie,cv.CV_64F,0,1,ksize=3)#1,0只算水平方向
#右邊-左邊:白到黑是正數,黑到白是負數,所有的負數都會截斷成0,所以要取絕對值
sobely=cv.convertScaleAbs(sobely)
res=np.hstack((sobelx,sobely))
cv_show("sobel",res)
#若要求Gx和Gy不建議直接相加,把上述(1,0)或者(0,1)寫成(1,1)
sobelxy=cv.addWeighted(sobelx,0.5,sobely,0.5,0)#是一種飽和操作,通過各自占的權重相加
cv_show("sobelxy",sobelxy)
具體例子:
#一個例子
pie=cv.imread('E:\\Pec\\cat.jpg')
ima=cv.cvtColor(pie,cv.COLOR_BGR2GRAY)
#cv_show("pie",ima)
sobelx=cv.Sobel(ima,cv.CV_64F,1,0,ksize=3)
sobelx=cv.convertScaleAbs(sobelx)
sobely=cv.Sobel(ima,cv.CV_64F,0,1,ksize=3)#1,0只算水平方向
sobely=cv.convertScaleAbs(sobely)
sobelxy=cv.addWeighted(sobelx,0.5,sobely,0.5,0)
#cv_show("sobelxy",sobelxy)
sobelxy1=cv.Sobel(ima,cv.CV_64F,1,1,ksize=3)#1,0只算水平方向
sobelxy1=cv.convertScaleAbs(sobelxy1)
#cv_show("sobelxy1",sobelxy1)
res=np.hstack((ima,sobelxy,sobelxy1))
cv_show("zong",res)
把卷積的數值變得更大、更敏感;描繪的更細致
二階導,一階導的變化率;更敏感;對噪音點比較敏感;與其他算子一塊使用
線性插值法:設g1的梯度幅值M(g1),g2的梯度幅值M(g2),則dtmp1可以得到:
M ( d t m p 1 ) = w ∗ M ( g 2 ) + ( 1 − w ) ∗ M ( g 1 ) M(dtmp1)=w*M(g2)+(1-w)*M(g1) M(dtmp1)=w∗M(g2)+(1−w)∗M(g1)
w = d i s t a n c e ( d t m p 1 , g 2 ) / d i s t a n c e ( g 1 , g 2 ) / / d i s t a n c e ( g 1 , g 2 ) 表示兩點距離 w=distance(dtmp1,g2)/distance(g1,g2) //distance(g1,g2)表示兩點距離 w=distance(dtmp1,g2)/distance(g1,g2)//distance(g1,g2)表示兩點距離
最後,通過計算,比較C點梯度幅值是否大於Q、Z,然後抑制非極大值點
說明:minVal:80; MaxVal:150;自己指定。若minVal設置過小的時候,篩選范圍變小,要求非常低了。maxVal同理
#邊緣檢測
cat=cv.imread('E:\\Pec\\loufang.jpg',cv.IMREAD_GRAYSCALE)
v1=cv.Canny(cat,120,250)
#minVal:80; MaxVal:150;自己指定。
#若minVal設置過小的時候,篩選范圍變小,要求非常低了。maxVal同理
v2=cv.Canny(cat,50,100)
res=np.hstack((v1,v2))
cv_show("res",res)
結果可以分析出來:阈值設置的范圍越廣,圖像的細節描述的越清晰