概要
OpenCV中,可以使用各種函數(shù)實(shí)現(xiàn)圖像梯度和Canny邊緣檢測(cè),這些操作對(duì)于圖像處理和分析非常重要。
圖像梯度通常用于尋找圖像中的邊緣和輪廓。在OpenCV中,可以使用cv2.Sobel()函數(shù)計(jì)算圖像的梯度,該函數(shù)可以計(jì)算圖像在水平和垂直方向上的梯度。梯度的方向和大小可以幫助理解圖像中的邊緣信息。
Canny邊緣檢測(cè)是一種經(jīng)典的邊緣檢測(cè)算法,它通過(guò)多個(gè)步驟來(lái)檢測(cè)圖像中的邊緣。首先,Canny算法使用Sobel算子計(jì)算圖像的梯度。然后,它通過(guò)非極大值抑制(Non-Maximum Suppression)來(lái)細(xì)化邊緣。接著,Canny算法使用雙閾值(Double Thresholding)來(lái)檢測(cè)強(qiáng)邊緣和弱邊緣,并通過(guò)連接強(qiáng)邊緣來(lái)得到最終的邊緣圖像。Canny邊緣檢測(cè)在圖像處理中被廣泛應(yīng)用,因?yàn)樗軌驕?zhǔn)確地檢測(cè)出圖像中的邊緣。
在OpenCV中,可以使用cv2.Sobel()函數(shù)計(jì)算圖像的梯度,而Canny邊緣檢測(cè)則可以通過(guò)cv2.Canny()函數(shù)實(shí)現(xiàn)。通過(guò)這些函數(shù),可以方便地在OpenCV中實(shí)現(xiàn)圖像梯度和Canny邊緣檢測(cè),進(jìn)而進(jìn)行各種圖像分析和處理任務(wù)。
圖像梯度
尋找圖像梯度,邊緣等等。
函數(shù):cv.Sobel(), cv.Scharr(), cvLaplacian() 等等。
Sobel和Scharr導(dǎo)數(shù):
Sobel算子是一種結(jié)合了高斯平滑和微分操作的濾波器,因此它對(duì)圖像中的噪聲具有較好的抵抗能力。使用Sobel算子時(shí),可以指定所需導(dǎo)數(shù)的方向,通過(guò)參數(shù)yorder和xorder來(lái)確定是垂直方向還是水平方向的導(dǎo)數(shù)。此外,還可以通過(guò)參數(shù)ksize指定核(kernel)的大小。當(dāng)ksize設(shè)為-1時(shí),OpenCV會(huì)使用3×3的Scharr濾波器,其結(jié)果通常比3×3的Sobel濾波器更為精確。
拉普拉斯導(dǎo)數(shù)
它計(jì)算了由關(guān)系式給出的圖像的拉普拉斯算子,其中關(guān)系式為
其中每一個(gè)導(dǎo)數(shù)都是用 Sobel 導(dǎo)數(shù)找到的。如果 ksize = -1,濾波器會(huì)使用下面這個(gè)內(nèi)核。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 讀取圖像
img = cv.imread('dave.jpg', 0)
# 計(jì)算拉普拉斯邊緣
laplacian = cv.Laplacian(img, cv.CV_64F)
# 計(jì)算Sobel邊緣(x和y方向)
sobelx = cv.Sobel(img, cv.CV_64F, 1, 0, ksize=5)
sobely = cv.Sobel(img, cv.CV_64F, 0, 1, ksize=5)
# 繪制原始圖像
plt.subplot(2, 2, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
# 繪制拉普拉斯邊緣圖像
plt.subplot(2, 2, 2), plt.imshow(laplacian, cmap='gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
# 繪制Sobel X邊緣圖像
plt.subplot(2, 2, 3), plt.imshow(sobelx, cmap='gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
# 繪制Sobel Y邊緣圖像
plt.subplot(2, 2, 4), plt.imshow(sobely, cmap='gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
# 顯示圖像
plt.show()
在我們的最后一個(gè)例子中,我們使用了Sobel濾波器來(lái)檢測(cè)圖像中的邊緣。然而,當(dāng)我們將輸出數(shù)據(jù)類(lèi)型轉(zhuǎn)換為cv.CV_8U或者np.uint8時(shí),存在一個(gè)小問(wèn)題。在圖像中,從黑色到白色的過(guò)渡被視為正斜率(它具有正值),而從白色到黑色的過(guò)渡被視為負(fù)斜率(它具有負(fù)值)。因此,當(dāng)我們將數(shù)據(jù)類(lèi)型轉(zhuǎn)換為np.uint8時(shí),所有負(fù)斜率都被截?cái)酁?,也就是說(shuō),我們會(huì)錯(cuò)過(guò)所有負(fù)斜率對(duì)應(yīng)的邊緣。
如果我們希望找到所有的邊緣,更好的方法是將輸出的數(shù)據(jù)類(lèi)型保持在一個(gè)更高的精度范圍內(nèi),例如cv.CV_16S、cv.CV_64F等,然后取其絕對(duì)值,最后再轉(zhuǎn)換回cv.CV_8U類(lèi)型。下面的代碼演示了這個(gè)過(guò)程,特別是在處理水平Sobel濾波器時(shí),以及結(jié)果的差異。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 讀取灰度圖像
img = cv.imread('img.png', 0)
# 使用Sobel濾波器,輸出數(shù)據(jù)類(lèi)型為cv.CV_8U
sobelx8u = cv.Sobel(img, cv.CV_8U, 1, 0, ksize=5)
# 使用Sobel濾波器,輸出數(shù)據(jù)類(lèi)型為cv.CV_64F,然后取絕對(duì)值并轉(zhuǎn)換為cv.CV_8U
sobelx64f = cv.Sobel(img, cv.CV_64F, 1, 0, ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
# 顯示原始圖像、Sobel輸出(cv.CV_8U)和Sobel絕對(duì)值(cv.CV_64F)
plt.subplot(1, 3, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 2), plt.imshow(sobelx8u, cmap='gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 3), plt.imshow(sobel_8u, cmap='gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
# 顯示圖像
plt.show()
Canny邊緣檢測(cè)
Canny邊緣檢測(cè)的概念
OpenCV函數(shù):cv.Canny()
Canny邊緣檢測(cè)是一種廣泛應(yīng)用的邊緣檢測(cè)算法,由John F. Canny開(kāi)發(fā)而成。該算法包含多個(gè)階段,下面我們將詳細(xì)介紹每個(gè)階段的過(guò)程:
噪聲減少:
由于邊緣檢測(cè)對(duì)圖像中的噪聲非常敏感,第一步是通過(guò)一個(gè)5X5的高斯濾波器對(duì)圖像進(jìn)行平滑處理,以去除噪聲。
尋找圖像中的變化(梯度)強(qiáng)度:
接下來(lái),使用Sobel核在水平和垂直方向上對(duì)平滑后的圖像進(jìn)行濾波,得到水平方向($G_x$)和垂直方向($G_y$)的一階導(dǎo)數(shù)。通過(guò)這兩個(gè)導(dǎo)數(shù),我們可以計(jì)算每個(gè)像素點(diǎn)的邊緣梯度幅值和方向。梯度方向始終與邊緣垂直,通常近似為水平、垂直和兩個(gè)對(duì)角線(xiàn)方向中的一個(gè)。
非極大值抑制:
在得到梯度大小和方向之后,在每個(gè)像素點(diǎn)上進(jìn)行全圖掃描。對(duì)于每個(gè)像素,檢查其梯度值是否在相鄰像素中是最大的。如果是,保留該值,否則將其置為0。這一步驟產(chǎn)生了一個(gè)"薄邊"的二值圖像。
滯后閾值:
在此階段,我們需要確定哪些邊緣是真實(shí)的,哪些是噪聲或者假的。為此,我們使用兩個(gè)閾值,minVal(最小值)和maxVal(最大值)。所有強(qiáng)度大于maxVal的邊緣被視為真正的邊緣,低于minVal的被丟棄。介于兩者之間的邊緣會(huì)基于連通性來(lái)判斷是否為邊緣。如果它們與確定的邊緣相連,則保留,否則被拋棄。這一步驟也基于邊緣是長(zhǎng)線(xiàn)的假設(shè)來(lái)去除小的像素噪聲。
邊緣 A 因?yàn)樵?maxVal 上面,所以是肯定的邊緣。盡管邊緣 C 的位置在 maxVal 下面,但是因?yàn)樗瓦吘?A 相連接,所以我們認(rèn)為它也是個(gè)有效邊緣,如此得到了一條完整的曲線(xiàn)。但是對(duì)于邊緣 B 來(lái)說(shuō),哪怕它在 minVal 上面,和邊緣 C 處在同一個(gè)區(qū)域上,可是它并不和任何一條有效邊緣連接,所以會(huì)被丟棄。所以,為了得到正確的結(jié)果,我們需要確定好 minVal 和 maxVal 的值。
最終,經(jīng)過(guò)這些步驟,我們就能得到一條完整的邊緣在圖像中。
OpenCV中的Canny邊緣檢測(cè)
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 讀取灰度圖像
img = cv.imread('img.png', 0)
# 使用Canny邊緣檢測(cè)算法,閾值設(shè)置為100和200
edges = cv.Canny(img, 100, 200)
# 顯示原始圖像和Canny邊緣檢測(cè)結(jié)果
plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(edges, cmap='gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
小結(jié)
圖像梯度:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-732701.html
OpenCV提供了多種方法來(lái)計(jì)算圖像的梯度,包括Sobel、Scharr和拉普拉斯濾波器。
Sobel算子是一種聯(lián)合高斯平滑和微分操作的濾波器,可以計(jì)算圖像在水平和垂直方向上的梯度。
使用Sobel算子時(shí),你可以指定所需導(dǎo)數(shù)的方向(水平或垂直)以及核的大小。
拉普拉斯濾波器用于計(jì)算圖像的拉普拉斯算子,通過(guò)將圖像的二階導(dǎo)數(shù)與Sobel導(dǎo)數(shù)相關(guān)聯(lián)來(lái)實(shí)現(xiàn)。
Canny邊緣檢測(cè):文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-732701.html
Canny邊緣檢測(cè)是一種多階段算法,用于檢測(cè)圖像中的邊緣。
第一階段是噪聲減少,通常通過(guò)應(yīng)用高斯濾波器來(lái)實(shí)現(xiàn),以平滑圖像并減少噪聲。
第二階段是計(jì)算圖像的梯度,通常使用Sobel濾波器,以獲得圖像的水平和垂直梯度。
接下來(lái)進(jìn)行非極大值抑制,以去除可能不構(gòu)成邊緣的像素,僅保留邊緣像素。
最后一個(gè)階段是滯后閾值,需要設(shè)置兩個(gè)閾值(minVal和maxVal),以確定哪些邊緣是真實(shí)的。根據(jù)這些閾值,邊緣可能被分類(lèi)為強(qiáng)邊緣、弱邊緣或非邊緣,并進(jìn)行相應(yīng)的處理。
到了這里,關(guān)于【OpenCV實(shí)現(xiàn)圖像梯度,Canny邊緣檢測(cè)】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!