目錄
一、圖像梯度處理
1、垂直邊緣提取
2、Sobel算子
3、Laplacian算子
二、圖像邊緣檢測
1、高斯濾波
2、計算圖像的梯度、方向
3、非極大值抑制
4、雙閾值篩選
?三、繪制圖像輪廓
1、概念
2、尋找輪廓
3、繪制輪廓
一、圖像梯度處理
? ? ? ? 還記得高數中的一階導數求極值嗎?把圖片想象成連續函數,因為邊緣部分的像素值是與旁邊像素明顯有區別的,所以對圖片局部求極值,就可以得到整幅圖片的邊緣信息了。不過圖片是二維的離散函數,導數就變成了差分,這個差分就稱為圖像的梯度
? ? ? ? 1、垂直邊緣提取
????????濾波是應用卷積來實現的,卷積的關鍵就是卷積核
這個核是用來提取圖片中的垂直邊緣的,當前列左右兩側的元素進行差分,由于邊緣的值明顯小于(或大于)周邊像素,所以邊緣的差分結果會明顯不同,這樣就提取出了垂直邊緣
cv2.filter2D(src, ddepth, kernel)
filter2D函數是用于對圖像進行二維卷積(濾波)操作。它允許自定義卷積核(kernel)來實現各種圖像處理效果,如平滑、銳化、邊緣檢測等
src: 輸入圖像
ddepth:輸出圖像的深度,可以是負值(表示與原圖相同)、正值或其他特定值(常用-1 表示輸出與輸入具有相同的深度)
kernel:卷積核,一個二維數組(通常為奇數大小的方形矩陣),用于計算每個像素周圍鄰域的加權和
?同理,把上面那個矩陣轉置一下,就是提取水平邊緣。這種差分操作就稱為圖像的梯度計算
(將卷積核中的矩陣換成k2矩陣即可實現水平邊緣提取,可以找張數獨的圖片效果對比更清晰)
?????????2、Sobel算子
? ? ? ? 上面的 k1、k2 兩個卷積核都叫做Sobel算子,只是方向不同
sobel_image = cv2.Sobel(src, ddepth, dx, dy, ksize)
src:通常應該是一個灰度圖像,因為 Sobel 算子是基于像素亮度梯度計算的。在彩色圖像的情況下,通常需要先將其轉換為灰度圖像
ddepth:輸出圖像的深度,即輸出圖像的數據類型(-1 表示輸出圖像的深度與輸入圖像相同 )
dx,dy:dx=1,dy=0時求x方向的一階導數,意味著我們想要計算圖像在水平方向(x軸)的梯度;
? ? ? ? ? ? ? ? dx=0,dy=1時求y方向的一階導數
ksize:Sobel算子的大小,可選擇3、5、7,默認為3
? ? ? ? 3、Laplacian算子
????????Laplacian算子是一種二階微分算子,通常用于圖像處理中,用來檢測圖像中的邊緣和細節。它對圖像的每個像素應用一個“加權平均”,通過計算每個像素與其鄰域像素的差異,來判斷該點的變化程度。Laplacian算子用于捕捉圖像中亮度變化劇烈的區域。常常用于邊緣檢測,因為邊緣區域的亮度變化非常大,而平坦區域的亮度變化較小。它的優點是能夠檢測到圖像的細節,包括邊緣、角點等
cv2.Laplacian(src, ddepth)
src:輸入圖像
ddepth:代表輸出圖像的深度 ,-1 表示輸出圖像的深度與輸入圖像相同
二、圖像邊緣檢測
(不是算子,接下來是一整套邊緣檢測的流程、方案)
? ? ? ? 1、高斯濾波
? ? ? ? ? ? ? ? 去除噪點,邊緣檢測本身屬于銳化操作,對噪點比較敏感,所以需要進行平滑處理
? ? ? ? 2、計算圖像的梯度、方向
????????????????首先使用sobel算子計算中心像素點的兩個方向上的梯度G_{x}和G_{y},然后就能夠得到? ? ? ? ? ?其具體的梯度值:
????????????????也可以使用來代替。在OpenCV中,默認使用
來計算? ? ? ? ? ?梯度值
?????????????????然后我們根據公式可以得到一個角度值:
?這個角度值其實是當前邊緣的梯度的方向。通過這個公式我們就可以計算出圖片中所有的像素點的梯度值與梯度方向,然后根據梯度方向獲取邊緣的方向
并且如果梯度方向不是0°、45°、90°、135°這種特定角度,那么就要用到插值算法來計算當前像素點在其方向上進行插值的結果了,然后進行比較并判斷是否保留該像素點
(
當值為-22.5°~22.5°,或-157.5°~157.5°,則認為邊緣為水平邊緣;
當法線方向為22.5°~67.5°,或-112.5°~-157.5°,則認為邊緣為45°邊緣;
當法線方向為67.5°~112.5°,或-67.5°~-112.5°,則認為邊緣為垂直邊緣;
當法線方向為112.5°~157.5°,或-22.5°~-67.5°,則認為邊緣為135°邊緣;
)
? ? ? ? 3、非極大值抑制
????????得到每個邊緣的方向之后,其實把它們連起來邊緣檢測就算完了,但是為什么還有這一步與下一步呢?是因為經過第二步得到的邊緣不經過處理是沒辦法使用的,因為高斯濾波的原因,邊緣會變得模糊,導致經過第二步后得到的邊緣像素點非常多,因此我們需要對其進行一些過濾操作,而非極大值抑制就是一個很好的方法,它會對得到的邊緣像素進行一個排除,使邊緣盡可能細一點。
????????在該步驟中,我們需要檢查每個像素點的梯度方向上的相鄰像素,并保留梯度值最大的像素,將其他像素抑制為零。假設當前像素點為(x,y),其梯度方向是0°,梯度值為G(x,y),那么我們就需要比較G(x,y)與兩個相鄰像素的梯度值:G(x-1,y)和G(x+1,y)。如果G(x,y)是三個值里面最大的,就保留該像素值,否則將其抑制為零
? ? ? ? 4、雙閾值篩選
????????經過非極大值抑制之后,我們還需要設置閾值來進行篩選,當閾值設的太低,就會出現假邊緣,而閾值設的太高,一些較弱的邊緣就會被丟掉,因此使用了雙閾值來進行篩選,推薦高低閾值的比例為2:1到3:1之間。
????????當某一像素位置的幅值超過最高閾值時,該像素必是邊緣像素;當幅值低于最低像素時,該像素必不是邊緣像素;幅值處于最高像素與最低像素之間時,如果它能連接到一個高于閾值的邊緣時,則被認為是邊緣像素,否則就不會被認為是邊緣。也就是說,上圖中的A和C是邊緣,B不是邊緣。因為C雖然不超過最高閾值,但其與A相連,所以C就是邊緣
edges = cv2.Canny(image, threshold1, threshold2)
image:輸入的灰度/二值化圖像數據(即使讀到的是彩色圖也可以進行處理 )
threshold1:低閾值,用于決定可能的邊緣點
threshold2:高閾值,用于決定強邊緣點
?三、繪制圖像輪廓
? ? ? ? 1、概念
????????????????輪廓是一系列相連的點組成的曲線,代表了物體的基本外形。相對于邊緣,輪廓是連續? ? ? ? ? ?的,邊緣不一定連續,輪廓是一個閉合的、封閉的形狀
????????(輪廓的作用:形狀分析、目標識別、圖像分割)
? ? ? ? 2、尋找輪廓
????????????????尋找輪廓需要將圖像做一個二值化處理,并且根據圖像的不同選擇不同的二值化方法來? ? ? ? ? ?將圖像中要繪制輪廓的部分置為白色,其余部分置為黑色。也就是說,我們需要對原始的? ? ? ? ? ? ? ?圖像進行灰度化、二值化的處理,令目標區域顯示為白色,其他區域顯示為黑色。之后,對? ? ? ? ? ?圖像中的像素進行遍歷,當一個白色像素相鄰(上下左右及兩條對角線)位置有黑色像素存? ? ? ? ? ?在或者一個黑色像素相鄰(上下左右及兩條對角線)位置有白色像素存在時,那么該像素點? ? ? ? ? ?就會被認定為邊界像素點,輪廓就是有無數個這樣的邊界點組成的
contours,hierarchy = cv2.findContours(image,mode,method)
contours:獲取到的輪廓點的列表,檢測到有多少個輪廓,該列表就有多少子列表,每一個子列表都代表了一個輪廓中所有點的坐標
hierarchy:表示輪廓之間的關系,前一條輪廓、后一條輪廓、子輪廓、父輪廓(該參數的使用情況會比較少 )
image:輸入二值化圖像
mode:輪廓的檢索模式
????????????????RETR_EXTERNAL:只查找最外層的輪廓(只有前、后,沒有父、子)
????????????????RETR_LIST:列出所有的輪廓(只有前、后,沒有父、子)
????????????????RETR_CCOMP:列出所有的輪廓(分為兩個層級:0 外部輪廓,1 內部輪廓)
????????????????RETR_TREE????:列出所有的輪廓(輪廓按照樹的方式顯示:最外層樹根,子輪廓樹枝 )
method:輪廓的表示方法
????????????????CHAIN_APPROX_NONE:存儲所有輪廓點
????????????????CHAIN_APPROX_SIMPLE:只存儲有用的點(默認)
????????????????CHAIN_APPROX_TC89_L1:用 Teh-Chin 算法智能地簡化輪廓,點數更少
(對于mode和method這兩個參數來說,一般使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE這兩個選項 )
? ? ? ? ?3、繪制輪廓
????????????????輪廓找出來后,其實返回的是一個輪廓點坐標的列表,因此我們需要根據這些坐標將輪? ? ? ? ? ?廓畫出來,因此就用到了繪制輪廓的方法
cv2.drawContours(image, contours, contourIdx, color, thickness)
image:原始圖像,一般為單通道或三通道的 numpy 數組
contours:包含多個輪廓的列表,每個輪廓是一個由點坐標構成的二維數組(numpy數組)
contourldx:要繪制的輪廓索引。(如果設為 -1
,則會繪制所有輪廓)
color:繪制輪廓的顏色,可以是 BGR 值或者是灰度值(對于灰度圖像)
thickness:輪廓線的寬度,如果是正數,則畫實線;如果是負數,則填充輪廓內的區域