国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

這篇具有很好參考價值的文章主要介紹了Canny 邊緣檢測算法-python實現(xiàn)(附代碼)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。


摘要 : Canny 邊緣檢測算法由計算機科學(xué)家 John F. Canny 于 1986 年提出的。其不僅提供了算法,還帶來了一套邊緣檢測的理論,分階段的解釋如何實現(xiàn)邊緣檢測。Canny 檢測算法包含下面幾個階段:
  • 圖像灰度化
  • 高斯模糊處理
  • 圖像梯度、梯度幅值、梯度方向計算
  • NMS(非極大值抑制)
  • 雙閾值的邊界選取

1、調(diào)用opencv進(jìn)行canny邊緣檢測

如果你只是想應(yīng)用canny得到圖片的邊緣的話,那么就沒有必要往下閱讀canny的具體原理與實現(xiàn)了。因為python的opencv庫中提供了很好的功能函數(shù)來實現(xiàn)這一功能。我們以一個示例來說明如何使用opencv進(jìn)行canny邊緣檢測:

這是原圖與使用opencv進(jìn)行canny邊緣檢測的結(jié)果圖:

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

這是代碼實現(xiàn):

import cv2 #導(dǎo)入opencv庫
 #讀取圖片
img = cv2.imread("images/2007\_000032.jpg")
#進(jìn)行canny邊緣檢測
edge = cv2.Canny(img,50,150)
#保存結(jié)果
cv2.imwrite('test.jpg',edge)

這四行代碼的關(guān)鍵在于 cv2.Canny 函數(shù)。我們對它的參數(shù)進(jìn)行詳細(xì)的解讀。希望能對你有幫助。OpenCV-Python中Canny函數(shù)的原型為:

cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]])

必要參數(shù):

  • 第一個參數(shù)是需要處理的原圖像,該圖像必須為單通道的灰度圖;
  • 第二個參數(shù)是閾值1;
  • 第三個參數(shù)是閾值2。

其中較大的閾值2用于檢測圖像中明顯的邊緣,但一般情況下檢測的效果不會那么完美,邊緣檢測出來是斷斷續(xù)續(xù)的。所以這時候用較小的第一個閾值用于將這些間斷的邊緣連接起來。

可選參數(shù)中apertureSize就是Sobel算子的大小。而L2gradient參數(shù)是一個布爾值,如果為真,則使用更精確的L2范數(shù)進(jìn)行計算(即兩個方向的倒數(shù)的平方和再開放),否則使用L1范數(shù)(直接將兩個方向?qū)?shù)的絕對值相加)。

到這其實已經(jīng)可以將canny邊緣檢測應(yīng)用到你的項目中了。當(dāng)然如果你想了解canny邊緣檢測的原理的話,請繼續(xù)往下閱讀。

2、圖像灰度化

對于一張圖片,當(dāng)我們只關(guān)心其邊界的時候,單通道的圖片已經(jīng)足夠提供檢測出邊界的信息。所以我們可以將R、G、B的3通道圖片乃至更高維的高光譜遙感圖像進(jìn)行灰度化?;叶然瘜嶋H上是一種降維操作,它減少了冗余數(shù)據(jù)從而降低了計算開銷。以下是對RGB圖片灰度化的方法:

# 灰度化
def gray(self, img\_path):
	"""
	計算公式:
	Gray(i,j) = [R(i,j) + G(i,j) + B(i,j)] / 3
	or :
	Gray(i,j) = 0.299 \* R(i,j) + 0.587 \* G(i,j) + 0.114 \* B(i,j)
	"""
	
	# 讀取圖片
	img = plt.imread(img_path)
	# BGR 轉(zhuǎn)換成 RGB 格式
	img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
	# 灰度化
	img_gray = np.dot(img_rgb[...,:3], [0.299, 0.587, 0.114])
	return img_gray

3、高斯模糊處理

高斯模糊實際上是對灰度化后的圖像去噪。從數(shù)學(xué)的角度來看,圖像的高斯模糊過程就是圖像與正態(tài)分布做卷積。進(jìn)行高斯濾波之前,需要先得到一個高斯濾波器(kernel)。如何得到一個高斯濾波器呢?其實就是將高斯函數(shù)離散化,將濾波器中對應(yīng)的橫縱坐標(biāo)索引代入高斯函數(shù),即可得到對應(yīng)的值。不同尺寸的濾波器,得到的值也不同,下面是二維高斯函數(shù)與 (2k+1)x(2k+1) 濾波器的計算公式 :

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

高斯濾波常用尺寸為 5x5,σ=1.4 的高斯濾波器。下面是 5x5 高斯濾波器的實現(xiàn)代碼:

# 去除噪音 - 使用 5x5 的高斯濾波器
def smooth(self, img\_gray):
	# 生成高斯濾波器
	"""
	要生成一個 (2k+1)x(2k+1) 的高斯濾波器,濾波器的各個元素計算公式如下:
	H[i, j] = (1/(2\*pi\*sigma\*\*2))\*exp(-1/2\*sigma\*\*2((i-k-1)\*\*2 + (j-k-1)\*\*2))
	"""
	sigma1 = sigma2 = 1.4
	gau_sum = 0
	gaussian = np.zeros([5, 5])
	for i in range(5):
		for j in range(5):
			gaussian[i, j] = math.exp((-1/(2*sigma1*sigma2))*(np.square(i-3)+ np.square(j-3)))/(2*math.pi*sigma1*sigma2)
			gau_sum = gau_sum + gaussian[i, j]
	
	# 歸一化處理
	gaussian = gaussian / gau_sum
	
	# 高斯濾波
	W, H = img_gray.shape
	new_gray = np.zeros([W-5, H-5])
	
	for i in range(W-5):
		for j in range(H-5):
			new_gray[i, j] = np.sum(img_gray[i:i+5, j:j+5] * gaussian)
	
	return new_gray

4、圖像梯度、梯度幅值、梯度方向計算

這個步驟的重要性不言而喻。直觀感受上來講我們知道一個圖像上處于邊界附近位置的像素值變化較大。而處于物體內(nèi)部位置的像素值大多相近。這樣我們可以計算當(dāng)前像素與其附近像素的像素值的差值判斷該像素處于物體內(nèi)部還是邊界。這個差值我們稱為圖像梯度。梯度幅值、梯度方向由圖像梯度計算而來。
具體而言,我們用一階導(dǎo)數(shù)來計算梯度:

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

對于上式,實際操作時就是用當(dāng)前像素的下一個像素減去當(dāng)前像素。此時 Δ x = 1 \Delta x=1 Δx=1;

梯度包含x方向的梯度與y方向的梯度。它們是兩個向量。梯度幅值是這兩個向量的向量和:
Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

既然梯度幅值是一個向量,那么我們需要計算它的方向:

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

我們用如下代碼實現(xiàn):

# 計算梯度幅值
def gradients(self, new_gray):
	"""
	:type: image which after smooth
	:rtype:
		dx: gradient in the x direction
		dy: gradient in the y direction
		M: gradient magnitude
		theta: gradient direction
	"""
	W, H = new_gray.shape
	dx = np.zeros([W-1, H-1])
	dy = np.zeros([W-1, H-1])
	M = np.zeros([W-1, H-1])
	theta = np.zeros([W-1, H-1])
	
	for i in range(W-1):
		for j in range(H-1):
		dx[i, j] = new\_gray[i+1, j] - new\_gray[i, j]
		dy[i, j] = new\_gray[i, j+1] - new\_gray[i, j]
		# 圖像梯度幅值作為圖像強度值
		M[i, j] = np.sqrt(np.square(dx[i, j]) + np.square(dy[i, j]))
		# 計算 θ - artan(dx/dy)
		theta[i, j] = math.atan(dx[i, j] / (dy[i, j] + 0.000000001))
	return dx, dy, M, theta

在計算得到的梯度幅值中我們實際上已經(jīng)得到了圖像的邊界(即函數(shù)返回值中的M)。如下:
Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

但是,很容易發(fā)現(xiàn)這個邊緣存在兩個問題:

  • 邊緣較粗;
  • 很多邊緣斷斷續(xù)續(xù)。

針對這兩個問題便有了以下兩個步驟NMS、雙閾值邊界選取。

5、NMS(非極大值抑制)

理想情況下,最終得到的邊緣應(yīng)該是很細(xì)的。因此,需要執(zhí)行非極大值抑制以使邊緣變細(xì)。原理很簡單:遍歷梯度矩陣上的所有點,并保留邊緣方向上具有極大值的像素。就像下面這幅圖一樣。圖中黑色和灰色表示邊界。我們通過NMS找出其中的局部最大值(也就是圖中的黑色)而把其他位置(也就是圖中的灰色)的值取0。

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

下面說說 NMS 的細(xì)節(jié)內(nèi)容。NMS在八個領(lǐng)域:上,下,左,右,左上,左下,右上,右下上進(jìn)行(當(dāng)然,比較的時候不需要將該點與其它八個點比較。只需要將其與其梯度方向上的點比較即可。這個很好理解。因為我們只需要當(dāng)前值在它所屬的邊緣上是局部最大值即可,而不需要它在其它邊緣上也是局部最大)如下圖所示,C 周圍的 8 個點就是其附近的八個領(lǐng)域。

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

NMS 是要找出局部最大值,因此,需要將當(dāng)前的像素的梯度,與其他方向進(jìn)行比較。如下圖所示,g1,g2,g3,g4 分別是 C 八個領(lǐng)域中的 4 個點,藍(lán)線是 C 的梯度方向。如果 C 是局部最大值的話,C 點的梯度幅值就要大于梯度方向直線與 g1g2,g4g3 兩個交點的梯度幅值,即大于點 dTemp1 和 dTemp2 的梯度幅值。上面提到這種方法無法達(dá)到最好的效果,因為 dTemp1 和 dTemp2 不是整像素,而是亞像素。亞像素的意思就是在兩個物理像素之間還有像素。那么,亞像素的梯度幅值怎么求?可以使用線性插值的方法,計算 dTemp1 在 g1,g2 之間的權(quán)重,就可以得到其梯度幅值。計算公式如下:

weight = |gx| / |gy| or |gy| / |gx|
dTemp1 = weight*g1 + (1-weight)*g2
dTemp2 = weight*g3 + (1-weight)*g4

計算時分兩種情況(都是比較當(dāng)前像素與dtemp1與dtemp2的大小,大于這兩個值則保留,小于其中任意一個則將其值取0):

  • 下面兩幅圖是 y 方向梯度值比較大的情況,即梯度方向靠近 y 軸。所以,g2 和 g4 在 C 的上下位置,此時 weight = |gy| / |gx| 。左邊的圖是 x,y 方向梯度符號相同的情況,右邊是 x,y 方向梯度符號相反的情況。
    Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

  • 下面兩幅圖是 x 方向梯度值比較大的情況,即梯度方向靠近 x 軸。所以,g2 和 g4 在 C 的左右位置,此時 weight = |gy| / |gx| 。左邊的圖是 x,y 方向梯度符號相同的情況,右邊是 x,y 方向梯度符號相反的情況。

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)

代碼實現(xiàn)如下:

def NMS(self, M, dx, dy):
	d = np.copy(M)
	W, H = M.shape
	NMS = np.copy(d)
	NMS[0, :] = NMS[W-1, :] = NMS[:, 0] = NMS[:, H-1] = 0
	for i in range(1, W-1):
		for j in range(1, H-1):
			# 如果當(dāng)前梯度為0,該點就不是邊緣點
			if M[i, j] == 0:
				NMS[i, j] = 0
			else:
				gradX = dx[i, j] # 當(dāng)前點 x 方向?qū)?shù)
				gradY = dy[i, j] # 當(dāng)前點 y 方向?qū)?shù)
				gradTemp = d[i, j] # 當(dāng)前梯度點
				
				# 如果 y 方向梯度值比較大,說明導(dǎo)數(shù)方向趨向于 y 分量
				if np.abs(gradY) > np.abs(gradX):
					weight = np.abs(gradX) / np.abs(gradY) # 權(quán)重
					grad2 = d[i-1, j]
					grad4 = d[i+1, j]

					# 如果 x, y 方向?qū)?shù)符號一致
					# 像素點位置關(guān)系
					# g1  g2
					#     c
					#     g4  g3

					if gradX * gradY > 0:
						grad1 = d[i-1, j-1]
						grad3 = d[i+1, j+1]

					# 如果 x,y 方向?qū)?shù)符號相反
					# 像素點位置關(guān)系
					#     g2  g1
					#     c
					# g3  g4
					
					else:
						grad1 = d[i-1, j+1]
						grad3 = d[i+1, j-1]

				# 如果 x 方向梯度值比較大
				else:
					weight = np.abs(gradY) / np.abs(gradX)
					grad2 = d[i, j-1]
					grad4 = d[i, j+1]
					
					# 如果 x, y 方向?qū)?shù)符號一致
					# 像素點位置關(guān)系
					#      g3
					# g2 c g4
					# g1
					if gradX * gradY > 0:
						grad1 = d[i+1, j-1]
						grad3 = d[i-1, j+1]
					
					# 如果 x,y 方向?qū)?shù)符號相反
					# 像素點位置關(guān)系
					# g1
					# g2 c g4
					#      g3
					else:
						grad1 = d[i-1, j-1]
						grad3 = d[i+1, j+1]

				# 利用 grad1-grad4 對梯度進(jìn)行插值
				gradTemp1 = weight \* grad1 + (1 - weight) \* grad2
				gradTemp2 = weight \* grad3 + (1 - weight) \* grad4
				
				# 當(dāng)前像素的梯度是局部的最大值,可能是邊緣點
				if gradTemp >= gradTemp1 and gradTemp >= gradTemp2:
					NMS[i, j] = gradTemp
				else:
					# 不可能是邊緣點
					NMS[i, j] = 0

	return NMS

6、雙閾值的邊界選取

這個階段決定哪些邊緣是真正的邊緣,哪些邊緣不是真正的邊緣。為此,需要設(shè)置兩個閾值,minVal 和 maxVal。梯度大于 maxVal 的任何邊緣肯定是真邊緣,而 minVal 以下的邊緣肯定是非邊緣,因此被丟棄。位于這兩個閾值之間的邊緣會基于其連通性而分類為邊緣或非邊緣,如果它們連接到"可靠邊緣"像素,則它們被視為邊緣的一部分。否則,也會被丟棄。代碼如下所示:

def double\_threshold(self, NMS):
	W, H = NMS.shape
	DT = np.zeros([W, H])
	
	# 定義高低閾值
	TL = 0.1 \* np.max(NMS)
	TH = 0.3 \* np.max(NMS)
	
	for i in range(1, W-1):
		for j in range(1, H-1):
			# 雙閾值選取
			if (NMS[i, j] < TL):
				DT[i, j] = 0
			elif (NMS[i, j] > TH):
				DT[i, j] = 1
			# 連接
			elif (NMS[i-1, j-1:j+1] < TH).any() or (NMS[i+1, j-1:j+1].any() or (NMS[i, [j-1, j+1]] < TH).any()):
				DT[i, j] = 1	
	return DT

進(jìn)行完所有的步驟后,結(jié)果如下圖所示:

Canny 邊緣檢測算法-python實現(xiàn)(附代碼)文章來源地址http://www.zghlxwxcb.cn/news/detail-443956.html

到了這里,關(guān)于Canny 邊緣檢測算法-python實現(xiàn)(附代碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • OpenCV——Canny邊緣檢測算法

    OpenCV——Canny邊緣檢測算法

    圖像分割是將數(shù)字圖像細(xì)分為多個子區(qū)域的過程,在計算機視覺/機器視覺領(lǐng)域被廣泛應(yīng)用。它的目的是簡化或改變圖像的表示形式,以便更容易理解和分析。常見的圖像分割方法包括閾值處理、聚類法、邊緣檢測和區(qū)域生長等。解決圖像分割問題通常需要結(jié)合領(lǐng)域知識,以提

    2024年04月17日
    瀏覽(27)
  • python Canny邊緣檢測

    python Canny邊緣檢測

    ? ? 參考文獻(xiàn) Canny邊緣檢測算法(python 實現(xiàn))_Master_miao的博客-CSDN博客_python canny 使用Pytorch從頭實現(xiàn)Canny邊緣檢測?

    2024年02月06日
    瀏覽(18)
  • 計算機視覺算法中的Canny邊緣檢測(Canny Edge Detection)

    在計算機視覺領(lǐng)域,邊緣檢測是一項重要的任務(wù)。邊緣是圖像中物體之間的邊界,通過邊緣檢測可以幫助我們識別出圖像中的物體。Canny邊緣檢測是一種經(jīng)典且常用的邊緣檢測算法。本文將對Canny邊緣檢測算法進(jìn)行介紹和分析。 Canny邊緣檢測算法由約翰·Canny在1986年提出,是一

    2024年02月08日
    瀏覽(22)
  • Python Opencv實踐 - Canny邊緣檢測

    Python Opencv實踐 - Canny邊緣檢測

    ?

    2024年02月11日
    瀏覽(25)
  • 【OpenCV實現(xiàn)圖像梯度,Canny邊緣檢測】

    【OpenCV實現(xiàn)圖像梯度,Canny邊緣檢測】

    OpenCV中,可以使用各種函數(shù)實現(xiàn)圖像梯度和Canny邊緣檢測,這些操作對于圖像處理和分析非常重要。 圖像梯度通常用于尋找圖像中的邊緣和輪廓。在OpenCV中,可以使用cv2.Sobel()函數(shù)計算圖像的梯度,該函數(shù)可以計算圖像在水平和垂直方向上的梯度。梯度的方向和大小可以幫助

    2024年02月07日
    瀏覽(21)
  • Python實現(xiàn):高斯濾波 均值濾波 中值濾波 Canny(邊緣檢測)PCA主成分分析 直方圖規(guī)定化 Mean_Shift

    Python實現(xiàn):高斯濾波 均值濾波 中值濾波 Canny(邊緣檢測)PCA主成分分析 直方圖規(guī)定化 Mean_Shift

    左側(cè)為原圖右側(cè)為高斯濾波后的圖 左圖為帶有噪聲的輸入原圖,右圖為經(jīng)過均值濾波后的圖片 左圖為帶有噪聲的輸入原圖,右圖為經(jīng)過中值濾波后的圖 上圖為輸入原圖,下圖為經(jīng)過Canny邊緣檢測后的圖 上圖為原圖 中圖為規(guī)定目標(biāo)圖 下圖為原圖經(jīng)過規(guī)定化后的圖 左圖為原輸

    2024年02月07日
    瀏覽(26)
  • python使用Canny算法和HoughCiecle算法實現(xiàn)圓的檢測與定位

    python使用Canny算法和HoughCiecle算法實現(xiàn)圓的檢測與定位

    任務(wù)是編寫一個錢幣定位系統(tǒng),其不僅能夠檢測出輸入圖像中各個錢幣的邊緣,同時,還能給出各個錢幣的圓心坐標(biāo)與半徑。 ① 使用高斯濾波器濾波; ② 計算圖像的梯度圖并獲得梯度方向; ③ 對梯度圖進(jìn)行非極大化抑制; ④ 使用雙閾值法獲得最終的邊緣圖。 高斯濾波

    2024年02月01日
    瀏覽(16)
  • python數(shù)字圖像處理基礎(chǔ)(五)——Canny邊緣檢測、圖像金字塔、圖像分割

    python數(shù)字圖像處理基礎(chǔ)(五)——Canny邊緣檢測、圖像金字塔、圖像分割

    梯度是什么? 梯度就是變化的最快的那個方向 edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]]) 第一個參數(shù)是需要處理的原圖像,該圖像必須為單通道的灰度圖; 第二個參數(shù)是閾值1; 第三個參數(shù)是閾值2。 原理步驟 1)使用高斯濾波器,以平滑圖像,濾除噪

    2024年01月18日
    瀏覽(28)
  • Canny算子邊緣檢測原理講解及其完整C語言實現(xiàn)(不使用opencv)

    Canny算子邊緣檢測原理講解及其完整C語言實現(xiàn)(不使用opencv)

    作者:隊友調(diào)車我吹空調(diào) 日期:2023/05/17 版權(quán):遵循CC 4.0 BY-SA版權(quán)協(xié)議 這里是后期的筆者,本文算是筆者的學(xué)習(xí)筆記,主要是在單片機中使用的,再者就是由于某些原因,筆者不想使用opencv,因此嘗試跟著原理手搓了這份代碼,筆者也盡力將代碼寫到最簡和效率最優(yōu)了。然而

    2024年04月27日
    瀏覽(22)
  • Python圖像銳化及邊緣檢測(Roberts、Prewitt、Sobel、Lapllacian、Canny、LOG)

    Python圖像銳化及邊緣檢測(Roberts、Prewitt、Sobel、Lapllacian、Canny、LOG)

    目錄 圖像銳化概述 算法方法介紹 ?代碼實現(xiàn) 效果展示 圖像銳化 (image sharpening) 是補償圖像的輪廓,增強圖像的邊緣及灰度跳變的部分,使圖像變得清晰,分為空間域處理和頻域處理兩類。圖像銳化是為了突出圖像上地物的邊緣、輪廓,或某些線性目標(biāo)要素的特征。這種濾波

    2023年04月17日
    瀏覽(96)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包