一枪蘑、圖像梯度:
- 圖像梯度损谦,圖像邊界等
- 使用到的函數(shù)有:cv2.Sobel(),cv2.Schar()岳颇,cv2.Laplacian() 等
- cv2.THRESH_TRUNC
- cv2.THRESH_TOZERO
- cv2.THRESH_TOZERO_INV
梯度簡單來說就是求導(dǎo)照捡。
OpenCV 提供了三種不同的梯度濾波器,或者說高通濾波器:
Sobel话侧,Scharr 和Laplacian栗精。
下面會一一介紹他們。
Sobel,Scharr 其實就是求一階或二階導(dǎo)數(shù)悲立。Scharr 是對Sobel(使用
小的卷積核求解求解梯度角度時)的優(yōu)化鹿寨。Laplacian 是求二階導(dǎo)數(shù)。
1:laplacian and sobel
Laplacian 算子
Sobel 算子和Scharr 算子
import numpy as np
import argparse
import cv2
ap = argparse.ArgumentParser()
ap.add_argument("-i","--image",required =True, help="Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv2.imshow("Original",image)
lap = cv2.Laplacian(image,cv2.CV_64F)
#cv2.CV_64F 輸出圖像的深度(數(shù)據(jù)類型)薪夕,可以使用-1, 與原圖像保持一致np.uint8
#當(dāng)我們可以通過參數(shù)-1 來設(shè)定輸出圖像的深度(數(shù)據(jù)類型)與原圖像保持一致脚草,但是我們在代碼中使用的卻是cv2.CV_64F。這是為什么呢
# 原因涉及圖像中的黑色到白色和白色到黑色的轉(zhuǎn)變原献。
# 從黑色到白色的轉(zhuǎn)換被認(rèn)為是正斜率馏慨,而從白色到黑色的轉(zhuǎn)換是負(fù)斜率。如果您還記得我們在第6章中對圖像算術(shù)的討論姑隅,您將會知道一個8位無符號整數(shù)不代表負(fù)值写隶。如果您使用的是OpenCV,則它將被剪裁為零粤策,否則將使用NumPy執(zhí)行模數(shù)運算
#簡短答案是樟澜,如果在計算梯度幅度圖像時不使用浮點數(shù)據(jù)類型,則會錯過邊緣叮盘,特別是白色到黑色的過渡
lap = np.uint8(np.absolute(lap))
# 為了確保捕捉所有的邊緣秩贰,使用浮點數(shù)據(jù)類型,然后獲取梯度圖像的絕對值柔吼,并將其轉(zhuǎn)換回8位無符號整數(shù)
cv2.imshow("Laplacian",lap)
sobelX = cv2.Sobel(image, cv2.CV_64F,1,0) #1,0表示x方向
sobelY = cv2.Sobel(image, cv2.CV_64F,0,1) #0,1表示y方向
sobelX = np.uint8(np.absolute(sobelX))
sobelY = np.uint8(np.absolute(sobelY))
sobelCombined = cv2.bitwise_or(sobelX,sobelY)
cv2.imshow("sobel X ",sobelX)
cv2.imshow("sobel Y ",sobelY)
cv2.imshow("sobel Combined ",sobelCombined)
cv2.waitKey(0)
二毒费、Canny 邊緣檢測:
Canny邊緣檢測器是一個多步驟的過程。它涉及模糊圖像以消除噪聲愈魏,在x和y方向上計算Sobel梯度圖像觅玻,抑制邊緣,最后是確定像素是否“邊緣狀”的滯后閾值階段培漏。
原理
Canny 邊緣檢測是一種非常流行的邊緣檢測算法溪厘,是John F.Canny 在1986 年提出的。它是一個有很多步構(gòu)成的算法牌柄,我們接下來會逐步介紹畸悬。
噪聲去除
由于邊緣檢測很容易受到噪聲影響,所以第一步是使用5x5 的高斯濾波器去除噪聲珊佣,這個前面我們已經(jīng)學(xué)過了蹋宦。
計算圖像梯度
對平滑后的圖像使用Sobel 算子計算水平方向和豎直方向的一階導(dǎo)數(shù)(圖像梯度)(Gx 和Gy)。根據(jù)得到的這兩幅梯度圖(Gx 和Gy)找到邊界的梯度和方向咒锻,公式如下:
梯度的方向一般總是與邊界垂直冷冗。梯度方向被歸為四類:垂直,水平惑艇,和兩個對角線蒿辙。
非極大值抑制
在獲得梯度的方向和大小之后,應(yīng)該對整幅圖像做一個掃描,去除那些非
邊界上的點须板。對每一個像素進(jìn)行檢查碰镜,看這個點的梯度是不是周圍具有相同梯
度方向的點中最大的。如下圖所示:
現(xiàn)在你得到的是一個包含“窄邊界”的二值圖像习瑰。
滯后閾值
現(xiàn)在要確定那些邊界才是真正的邊界。這時我們需要設(shè)置兩個閾值:
minVal 和maxVal秽荤。當(dāng)圖像的灰度梯度高于maxVal 時被認(rèn)為是真的邊界甜奄,
那些低于minVal 的邊界會被拋棄。如果介于兩者之間的話窃款,就要看這個點是
否與某個被確定為真正的邊界點相連课兄,如果是就認(rèn)為它也是邊界點,如果不是
就拋棄晨继。如下圖:
A 高于閾值maxVal 所以是真正的邊界點烟阐,C 雖然低于maxVal 但高于
minVal 并且與A 相連,所以也被認(rèn)為是真正的邊界點紊扬。而B 就會被拋棄蜒茄,因
為他不僅低于maxVal 而且不與真正的邊界點相連。所以選擇合適的maxVal
和minVal 對于能否得到好的結(jié)果非常重要餐屎。
在這一步一些小的噪聲點也會被除去檀葛,因為我們假設(shè)邊界都是一些長的線
段。
OpenCV 中的Canny 邊界檢測
在OpenCV 中只需要一個函數(shù):cv2.Canny()腹缩,就可以完成以上幾步屿聋。
讓我們看如何使用這個函數(shù)。這個函數(shù)的第一個參數(shù)是輸入圖像藏鹊。第二和第三
個分別是minVal 和maxVal润讥。第三個參數(shù)設(shè)置用來計算圖像梯度的Sobel
卷積核的大小,默認(rèn)值為3盘寡。最后一個參數(shù)是L2gradient楚殿,它可以用來設(shè)定
求梯度大小的方程。如果設(shè)為True宴抚,就會使用我們上面提到過的方程勒魔,否則
使用方程:
代替,默認(rèn)值為False菇曲。
import numpy as np
import argparse
import cv2
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,help = "Path to the image")
args = vars(ap.parse_args())
image = cv2.imread(args["image"])
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = cv2.GaussianBlur(image, (5, 5), 0)
# 由于邊緣檢測很容易受到噪聲影響冠绢,所以第一步是使用5x5 的高斯濾波器
# 去除噪聲,通過在邊緣檢測之前應(yīng)用模糊,我們將幫助去除圖像中“我們不感興趣”的“嘈雜”邊緣
cv2.imshow("Blurred", image)
canny = cv2.Canny(image, 30, 150)
# cv2.Canny(image, minVal, maxVal)
# 當(dāng)圖像的灰度梯度高于maxVal 時被認(rèn)為是真的邊界常潮,
# 那些低于minVal 的邊界會被拋棄弟胀。如果介于兩者之間的話,就要看這個點是
# 否與某個被確定為真正的邊界點相連,如果是就認(rèn)為它也是邊界點孵户,如果不是
# 就拋棄萧朝。
cv2.imshow("Canny", canny)
cv2.waitKey(0)
比智力更重要的往往是毅力。
更多文章請關(guān)注我的博客:https://harveyyeung.github.io