canny算子处理流程
1.进行高斯滤波,平滑图像,滤除噪声;
2.计算图像每个像素点的梯度强度和方向;
3.应用非极大值(Non-Maximum Suppression)抑制,用以消除边缘检测带来的杂散效应;
4.应用双阈值(Double-Threshold)检测来确定真实和潜在的边缘;
5.通过孤立弱边缘来完成最终的边缘检测。
1. 高斯平滑滤波
大小为(2k+1)(2k1)的高斯滤波核的生成方程是如下:
下面是一个sigma = 1.4 ,尺寸为3*3的高斯卷积核的例子(归一化):
如图,一个3*3的卷积核A,与需要过滤的像素点为e进行点乘后求和,即高斯滤波之后,像素点e的值为:
注:高斯卷积核大小的选择将影响Canny检测器的性能。尺度越大,检测器对噪声的敏感度月底,但是边缘检测的定位误差也将略有增加。
2. 计算梯度强度
图像中的边缘可以指向各个方向,因此Canny算法使用四个算子来检测图像中的水平,垂直和对角边缘。边缘检测的算子(如Roberts,Prewitt,Sobel等)返回水平Gx和垂直Gy方向的一阶导数值,由此来确定像素点的梯度和方向theta。
其中G为梯度强度,theta为梯度防线方向,arctan为反正切函数。
下面以Sobel算子为例子来讲述计算梯度和方向。
x和y方向的Sobel算子分别为:
其中Sx表示x方向的sobel算子,用于检测y方向的边缘;Sy表示y方向的Sobel算子,用户检测x方向的边缘的。如下,是大小为3*3的Sobel卷积核在x和y方向对像素点e进行卷积之后,该点在x和y方向的梯度值分别为:
- 非极大值抑制
非极大值抑制是一种边缘系数技术,非极大值抑制的作用在于“瘦”边。对图像进行梯度计算后,仅仅梯度值提取的边缘任然很模糊。对于标准“图像中给定的边缘应只被标记一次,并且在可能的情况下,图像的噪声不应产生假的边缘”来说,对边缘有且只有一个准确的响应。而极大值抑制则可以帮助将局部最大值之外的所有梯度值抑制为0,对梯度图线中每个像素进行非极大值抑制的算法是:
(1)将当前像素的梯度强度与沿正负梯度方向上的两个像素进行比较。
(2)如果当前像素的梯度强度与另外两个像素相比最大,则该像素点保留为边缘点,否则该像素点将被抑制。
通常为了更加精确的计算,在跨越梯度方向的两个相邻像素质检使用线性插值来得到要比较的像素梯度,如下:
如上图所示,将梯度分为8个方向,其中0代表0°~45°,1代表45°~90°,2代表-90°~-45°,3代表-45°~0°。像素点P的梯度方向为theta,则像素点P1和P2的梯度线性插值为:
因此非极大值抑制的伪代码描写如下:
- 双阈值检测
在施加非极大值抑制之后,剩余像素可以更加准确的表示图像中的实际边缘。然而,仍然存在由于噪声和颜色变化引起的一些边缘像素。为了解决这些杂散响应,必须用弱梯度值过滤边缘像素,并保留具有高梯度值的边缘像素,可以通过选择高低阈值来实现。如果边缘像素的梯度值高于高阈值,则将其标记为强边缘像素;如果边缘像素的梯度值小于高阈值并且大于低阈值,则将其标记为若边缘线像素;如果边缘像素的梯度值小于低阈值,则会被抑制。阈值的选择取决于输入图像的内容。
双阈值检测的伪代码描写如下:
- 抑制孤立阈值点
到目前为止,被划分为强边缘的像素点已经被确定为边缘,因为它们是从图像中的真实边缘中个提取出来的。然而,对于弱像素边缘,将会有一些争论,因为这些像素可以从真实边缘提取也可以是因为噪声和颜色变化引起的。为了获取准确的结果,应该一直有后者引起的若边缘。通常,由真实边缘的引起的若边缘像素将链接到强边缘像素,而噪声响应未连接。为了跟踪边缘链接,通过查看弱边缘像素及其8个领域像素,只要其中一个为强边缘像素,则该若边缘点就可以保留为真实的边缘。
抑制孤立边缘点的伪代码描述如下
代码实现
import cv2
import numpy as np
m1 = np.array([[-1,0,1],[-1,0,1],[-1,0,1]])
m2 = np.array([[-1,-1,-1],[0,0,0],[1,1,1]])
from matplotlib import pyplot as plt
# 第一步:完成高斯平滑滤波
img = cv2.imread("rice.jpg",0)
img = cv2.GaussianBlur(img,(3,3),2)
# 第二步:完成一阶有限差分计算,计算每一点的梯度幅值与方向
img1 = np.zeros(img.shape,dtype="uint8") # 与原图大小相同
theta = np.zeros(img.shape,dtype="float") # 方向矩阵原图像大小
img = cv2.copyMakeBorder(img,1,1,1,1,borderType=cv2.BORDER_REPLICATE)
rows,cols = img.shape
for i in range(1,rows-1):
for j in range(1,cols-1):
# Gy
Gy = (np.dot(np.array([1, 1, 1]), (m1 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]]))
# Gx
Gx = (np.dot(np.array([1, 1, 1]), (m2 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]]))
if Gx[0] == 0:
theta[i-1,j-1] = 90
continue
else:
temp = (np.arctan(Gy[0] / Gx[0]) ) * 180 / np.pi
if Gx[0]*Gy[0] > 0:
if Gx[0] > 0:
theta[i-1,j-1] = np.abs(temp)
else:
theta[i-1,j-1] = (np.abs(temp) - 180)
if Gx[0] * Gy[0] < 0:
if Gx[0] > 0:
theta[i-1,j-1] = (-1) * np.abs(temp)
else:
theta[i-1,j-1] = 180 - np.abs(temp)
img1[i-1,j-1] = (np.sqrt(Gx**2 + Gy**2))
for i in range(1,rows - 2):
for j in range(1, cols - 2):
if ( ( (theta[i,j] >= -22.5) and (theta[i,j]< 22.5) ) or
( (theta[i,j] <= -157.5) and (theta[i,j] >= -180) ) or
( (theta[i,j] >= 157.5) and (theta[i,j] < 180) ) ):
theta[i,j] = 0.0
elif ( ( (theta[i,j] >= 22.5) and (theta[i,j]< 67.5) ) or
( (theta[i,j] <= -112.5) and (theta[i,j] >= -157.5) ) ):
theta[i,j] = 45.0
elif ( ( (theta[i,j] >= 67.5) and (theta[i,j]< 112.5) ) or
( (theta[i,j] <= -67.5) and (theta[i,j] >= -112.5) ) ):
theta[i,j] = 90.0
elif ( ( (theta[i,j] >= 112.5) and (theta[i,j]< 157.5) ) or
( (theta[i,j] <= -22.5) and (theta[i,j] >= -67.5) ) ):
theta[i,j] = -45.0
# 第三步:进行 非极大值抑制计算
img2 = np.zeros(img1.shape) # 非极大值抑制图像矩阵
for i in range(1,img2.shape[0]-1):
for j in range(1,img2.shape[1]-1):
if (theta[i,j] == 0.0) and (img1[i,j] == np.max([img1[i,j],img1[i+1,j],img1[i-1,j]]) ):
img2[i,j] = img1[i,j]
if (theta[i,j] == -45.0) and img1[i,j] == np.max([img1[i,j],img1[i-1,j-1],img1[i+1,j+1]]):
img2[i,j] = img1[i,j]
if (theta[i,j] == 90.0) and img1[i,j] == np.max([img1[i,j],img1[i,j+1],img1[i,j-1]]):
img2[i,j] = img1[i,j]
if (theta[i,j] == 45.0) and img1[i,j] == np.max([img1[i,j],img1[i-1,j+1],img1[i+1,j-1]]):
img2[i,j] = img1[i,j]
# 第四步:双阈值检测和边缘连接
img3 = np.zeros(img2.shape) #定义双阈值图像
# TL = 0.4*np.max(img2)
# TH = 0.5*np.max(img2)
TL = 50
TH = 100
#关键在这两个阈值的选择
for i in range(1,img3.shape[0]-1):
for j in range(1,img3.shape[1]-1):
if img2[i,j] < TL:
img3[i,j] = 0
elif img2[i,j] > TH:
img3[i,j] = 255
elif (( img2[i+1,j] < TH) or (img2[i-1,j] < TH )or( img2[i,j+1] < TH )or
(img2[i,j-1] < TH) or (img2[i-1, j-1] < TH )or ( img2[i-1, j+1] < TH) or
( img2[i+1, j+1] < TH ) or ( img2[i+1, j-1] < TH) ):
img3[i,j] = 255
cv2.imshow("1",img) # 原始图像
cv2.imshow("2",img1) # 梯度幅值图
cv2.imshow("3",img2) #非极大值抑制灰度图
cv2.imshow("4",img3) # 最终效果图
cv2.imshow("theta",theta) #角度值灰度图
cv2.waitKey(0)
叼茂SEO.bfbikes.com
想想你的文章写的特别好
想想你的文章写的特别好https://www.ea55.com/
兄弟写的非常好 https://www.cscnn.com/
你的文章内容非常卖力,让人点赞。 https://www.yonboz.com/video/9773.html
《灵笼》国产动漫高清在线免费观看:https://www.jgz518.com/xingkong/7459.html
复古传世技能书之寻觅之旅:https://501h.com/jinbi/2111.html
你的才华让人惊叹,请继续保持。 http://www.55baobei.com/SCy5djyvu7.html
你的文章让我感受到了生活的美好,谢谢! https://www.yonboz.com/video/10434.html
哈哈哈,写的太好了https://www.lawjida.com/
哈哈哈,写的太好了https://www.lawjida.com/