OpenCV与图像处理学习八——图像边缘提取(Canny检测代码)
OpenCV與圖像處理學(xué)習(xí)八——圖像邊緣提取(Canny檢測代碼)
- 一、圖像梯度
- 1.1 梯度
- 1.2 圖像梯度
- 二、梯度圖與梯度算子
- 2.1模板卷積
- 2.2 梯度圖
- 2.3 梯度算子
- 2.3.1 Roberts交叉算子
- 2.3.2 Prewitt算子
- 2.3.3 Sobel算子
- 三、Canny邊緣檢測算法(代碼實(shí)現(xiàn))
這次筆記簡單介紹圖像梯度、梯度圖以及梯度算子的概念,并詳細(xì)介紹三種基本的梯度算子,然后簡單的介紹Canny檢測的原理與代碼實(shí)現(xiàn)(因?yàn)镃anny檢測中有很重要的一步用到了Sobel算子計(jì)算梯度,所以先介紹前面的內(nèi)容)。
一、圖像梯度
1.1 梯度
先來看梯度的概念:
梯度是一個(gè)向量,梯度方向指向函數(shù)變化最快的方向,大小就是它的模,也是最大的變化率,對于二元函數(shù)z=f(x,y),它在點(diǎn)(x,y)的梯度記為:
或:
梯度的計(jì)算公式為:
梯度向量的幅值和方向角為:
有了梯度是最大變化率這么一個(gè)認(rèn)識(shí),下面我們拓展到圖像梯度的概念上來。
1.2 圖像梯度
圖像梯度即圖像中灰度變化的度量,求圖像梯度的過程是二維離散函數(shù)求導(dǎo)過程。
因?yàn)閳D像邊緣上的像素值變化非常劇烈,所以圖像的邊緣其實(shí)就是圖像上灰度級變化很快的點(diǎn)的集合。
下圖展示了一個(gè)灰度圖的數(shù)學(xué)化表達(dá),像素點(diǎn)(x,y)的灰度值是f(x,y),它有八個(gè)鄰域(有時(shí)使用四鄰域):
圖像在點(diǎn)(x,y)的梯度為:
分別對應(yīng)圖像的水平方向和豎直方向,可見圖像梯度的求法只是像素值之間的差,而無需求導(dǎo)(因?yàn)閿?shù)字圖像是離散的)。
二、梯度圖與梯度算子
2.1模板卷積
要理解梯度圖的生成,就要先了解模板卷積的過程,模板卷積是模板運(yùn)算的一種方式,其步驟如下:
其實(shí)就是現(xiàn)在的卷積運(yùn)算干的事。
2.2 梯度圖
梯度圖的生成和模板卷積相同,不同的是要生成梯度圖,還需要在模板卷積完成后計(jì)算在點(diǎn)(x,y)梯度的幅值,將幅值作為像素值,這樣才算完。
注意: 梯度圖上每個(gè)像素點(diǎn)的灰度值就是梯度向量的幅度,生成梯度圖需要兩個(gè)模板(求圖像梯度需要兩個(gè)方向),右圖為水平和豎直方向最簡單的模板:
所以水平方向和豎直方向上的梯度為:
2.3 梯度算子
梯度算子是一階導(dǎo)數(shù)算子,是水平G(x)和豎直G(y)方向?qū)?yīng)模板的組合,也有對角線方向,即是上述卷積模板的組合。
常見的一階算子:Roberts交叉算子, Prewitt算子, Sobel算子,下面將分別介紹。
2.3.1 Roberts交叉算子
Roberts交叉算子其本質(zhì)是一個(gè)對角線方向的梯度算子,對應(yīng)的水平方向和豎直方向的梯度分別為:
優(yōu)點(diǎn):邊緣定位較準(zhǔn),適用于邊緣明顯且噪聲較少的圖像。
缺點(diǎn):
2.3.2 Prewitt算子
Prewitt算子是典型的3*3模板,其模板中心對應(yīng)要求梯度的原圖像坐標(biāo)(x,y), (x,y)對應(yīng)的8-鄰域的像素灰度值如下表所示:
通過Prewitt算子的水平模板M(x)卷積后,對應(yīng)的水平方向梯度為:
通過Prewitt算子的豎直模板M(y)卷積后,對應(yīng)的豎直方向梯度為:
輸出梯度圖在(x,y)的灰度值為:
優(yōu)點(diǎn):Prewitt算子引入了類似局部平均的運(yùn)算,對噪聲具有平滑作用,較Roberts算子更能抑制噪聲。
2.3.3 Sobel算子
Sobel算子其實(shí)就是是增加了權(quán)重系數(shù)的Prewitt算子,其模板中心對應(yīng)要求梯度的原圖像坐標(biāo),對應(yīng)的8-鄰域的像素灰度值如下表所示:
通過Sobel算子的水平模板M(x)卷積后,對應(yīng)的水平方向梯度為:
通過Sobel算子的豎直模板M(y)卷積后,對應(yīng)的豎直方向梯度為:
輸出梯度圖在(x,y)的灰度值為:
優(yōu)點(diǎn):Sobel算子引入了類似局部加權(quán)平均的運(yùn)算,對邊緣的定位比要比Prewitt算子好。
因?yàn)镾obel算子的效果較好,實(shí)際使用中相比于另外兩種更多,所以我們只看一下Sobel算子的例子。
函數(shù):
dst = cv2.Sobel( src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]] )參數(shù):
src:輸入圖像。
ddepth:輸出圖像位深度,-1表示采用的是與原圖像相同的深度。目標(biāo)圖像的深度必須大于等于原圖像的深度;
dx:x導(dǎo)數(shù)的階數(shù),0表示這個(gè)方向上沒有求導(dǎo),一般為0、 1、 2;
dy:y導(dǎo)數(shù)的階數(shù),0表示這個(gè)方向上沒有求導(dǎo),一般為0、 1、 2;
ksize:Sobel算子的尺寸,必須是1,3,5或7。還可以是一個(gè)特殊值,ksize = FILTER_SCHARR (-1),那么將會(huì)使用scharr算子,在x方向的算子為:
在y方向上是這個(gè)算子的轉(zhuǎn)置。
scale:(可選)計(jì)算的導(dǎo)數(shù)值的比例因子;默認(rèn)情況下,不應(yīng)用縮放。
delta:(可選)在將結(jié)果存儲(chǔ)到dst中之前添加到結(jié)果中的增量值。
看個(gè)例子:
import numpy as np import cv2 from matplotlib import pyplot as plt img = cv2.imread('./image/girl2.png', 0) sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5) sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)plt.subplot(1, 3, 1), plt.imshow(img, cmap = 'gray') plt.title('Original'), plt.xticks([]), plt.yticks([]) plt.subplot(1, 3, 2), plt.imshow(sobelx, cmap = 'gray') plt.title('Sobel X'), plt.xticks([]), plt.yticks([]) plt.subplot(1, 3, 3),plt.imshow(sobely, cmap = 'gray') plt.title('Sobel Y'), plt.xticks([]), plt.yticks([]) plt.show()得到的就是該圖像在x方向上和y方向上的梯度圖:
從這個(gè)效果中我們也可以看出,梯度圖能夠突出圖像中的邊緣或明暗變化劇烈的地方。
三、Canny邊緣檢測算法(代碼實(shí)現(xiàn))
Canny算法是先平滑后求導(dǎo)數(shù)的方法。 John Canny研究了最優(yōu)邊緣檢測方法所需的特性,給出了評價(jià)邊緣檢測性能優(yōu)劣的三個(gè)指標(biāo):
步驟:
在OpenCV中的函數(shù)為:
edges = cv2.Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] )參數(shù):
看個(gè)例子:
# 加載 opencv 和 numpy import cv2 import numpy as np # 以灰度圖形式讀入圖像 img = cv2.imread('./image/canny.png', 0) v1 = cv2.Canny(img, 80, 150, (3, 3)) v2 = cv2.Canny(img, 50, 100, (5, 5))# np.vstack():在豎直方向上堆疊 # np.hstack():在水平方向上平鋪堆疊 ret = np.hstack((v1, v2)) cv2.imshow('img', ret) cv2.waitKey(0) cv2.destroyAllWindows()原圖如下所示:
通過canny檢測得到該圖的邊緣信息,設(shè)置了兩組參數(shù),得到的結(jié)果分別為:
不同的參數(shù)設(shè)置可能得到不同的結(jié)果,很明顯第一種參數(shù)使得檢測得到的邊緣信息更少更干凈,而第二種得到的更多更全面,實(shí)際使用中可以自己調(diào)節(jié)。
Canny檢測作為傳統(tǒng)的圖像邊緣提取算法,雖然效果上不如現(xiàn)在大火的深度學(xué)習(xí)的各種網(wǎng)絡(luò),但是對于一些邊緣信息較為明顯單一的圖像來說任然有使用價(jià)值,我們將輸入圖像換一下:
再用Canny檢測(上述代碼,換一下輸入圖像即可),得到的結(jié)果為:
可以看到檢測效果已經(jīng)非常不錯(cuò)了,更重要的是,它不需要訓(xùn)練,所以速度非常的快,這是它很大的一個(gè)優(yōu)點(diǎn),所以現(xiàn)在還是會(huì)使用到Canny檢測。
總結(jié)
以上是生活随笔為你收集整理的OpenCV与图像处理学习八——图像边缘提取(Canny检测代码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从‘一边拉琴,一边哭’,看什么是真正的兴
- 下一篇: Libcurl安装与HelloWorld