一、Canny边缘检测算法概述
Canny边缘检测算法是一种经典的边缘检测算法,该算法由 John F. Canny 在 1986 年提出。Canny算法的主要目标是在最小错误率的前提下尽可能正确地检测出图像中的边缘。它采用了多阶段的边缘检测过程,首先使用高斯滤波器对图像进行平滑处理,随后使用 Sobel 算子计算图像梯度,同时获取梯度方向和大小信息。最后,通过非极大值抑制和双阈值筛选来检测并连接真实边缘。
二、Canny边缘检测算法优缺点
1.**优点** Canny算法可以准确地检测出图像中的边缘,并且抑制噪声的能力较强。它能够消除大部分非边缘响应点,以及尽量保留真实边缘的形态和特征。此外,Canny算法还可以自适应地确定双阈值,使得结果更加准确可靠。 2.**缺点** Canny算法还存在一些问题。首先,它对计算资源的需求比较高,这会导致它的处理速度较慢。其次,在边缘非常接近时,Canny算法可能会漏检或错误检测;在边缘弯曲或存在断裂时,也容易造成无法正确检测边缘。
三、Canny边缘检测算法原理
Canny算法主要分为四个步骤:高斯滤波、计算图像梯度、非极大值抑制和双阈值筛选。 1.**高斯滤波** Canny算法首先使用高斯滤波器对原始图像进行平滑化操作,以去除图像中的高频部分和噪声。高斯滤波器是一个平滑权重的过程,它可以使得图像中的像素点变得更加模糊,从而减少噪声的影响。高斯滤波的公式为:G_(x,y)=(1/2∏σ^2)exp(-(x^2+y^2)/2σ^2),其中 σ 表示高斯核的标准差。 2.**图像梯度计算** Canny算法使用 Sobel 算子计算图像的梯度,包括梯度方向和梯度大小。在这个阶段,我们需要对图像进行卷积计算。Sobel算子是一个 3×3 的卷积核,可以用来计算图像的一阶导数。Sobel算子分为水平(Gx)和垂直(Gy)两个方向,分别使用以下卷积核进行卷积:
Gx = [-1 0 1; -2 0 2; -1 0 1]; Gy = [-1 -2 -1; 0 0 0; 1 2 1];3.**非极大值抑制** 非极大值抑制是指只留下梯度值最大的点,而抑制其余梯度值较小或不是局部最大值的点。这个步骤的目的是消除平滑后图像中的较弱点,保留更加突出的边缘。对于每个像素点,我们检查周围 8 个像素点,如果它的梯度值不是周围8个像素中的最大值,则将其梯度值设为0。 4.**双阈值筛选** 双阈值筛选是为了将所有梯度值的点分成三类:强边缘、弱边缘和非边缘。如果一个点的梯度值大于高阈值,我们就将其标记为强边缘;如果一个点的梯度值小于低阈值,我们就将其标记为非边缘;如果一个点的梯度值介于两者之间,则将其标记为弱边缘。在这个阶段,我们尝试将弱边缘通过与强边缘相邻接来转换成强边缘,并且将与非边缘相邻的弱边缘直接去除。
四、Canny边缘检测算法Matlab代码
1. Canny算法Matlab代码
% 读取图像 I = imread('lena.png'); % 将图像转换为灰度图像 I = rgb2gray(I); % 使用高斯滤波器进行平滑化操作 I_smooth = imgaussfilt(I, 2); % 计算梯度,获取梯度幅度和方向 [Gx, Gy] = imgradientxy(I_smooth); [GMag, GDir] = imgradient(Gx, Gy); % 非极大值抑制 GMag_suppressed = zeros(size(GMag)); for i = 2:size(GMag, 1)-1 for j = 2:size(GMag, 2)-1 if (GDir(i,j) <= 22.5 && GDir(i,j) > -22.5) || ... (GDir(i,j) <= -157.5 && GDir(i,j) > 157.5) if (GMag(i,j) >= GMag(i, j-1) && GMag(i,j) >= GMag(i,j+1)) GMag_suppressed(i,j) = GMag(i,j); end elseif (GDir(i,j) > 22.5 && GDir(i,j) <= 67.5) || ... (GDir(i,j) <= -112.5 && GDir(i,j) > -157.5) if (GMag(i,j) >= GMag(i-1, j-1) && GMag(i,j) >= GMag(i+1, j+1)) GMag_suppressed(i,j) = GMag(i,j); end elseif (GDir(i,j) > 67.5 && GDir(i,j) <= 112.5) || ... (GDir(i,j) <= -67.5 && GDir(i,j) > -112.5) if (GMag(i,j) >= GMag(i-1, j) && GMag(i,j) >= GMag(i+1, j)) GMag_suppressed(i,j) = GMag(i,j); end elseif (GDir(i,j) > 112.5 && GDir(i,j) <= 157.5) || ... (GDir(i,j) <= -22.5 && GDir(i,j) > -67.5) if (GMag(i,j) >= GMag(i-1, j+1) && GMag(i,j) >= GMag(i+1, j-1)) GMag_suppressed(i,j) = GMag(i,j); end end end end % 双阈值筛选 T_L = 0.05 * max(max(GMag_suppressed)); T_H = 0.15 * max(max(GMag_suppressed)); G_edge = zeros(size(GMag_suppressed)); for i = 1:size(GMag_suppressed, 1) for j = 1:size(GMag_suppressed, 2) if GMag_suppressed(i,j) > T_H G_edge(i,j) = 1; elseif GMag_suppressed(i,j) > T_L && GMag_suppressed(i,j) < T_H if (GMag_suppressed(i-1,j-1) > T_H || GMag_suppressed(i-1,j) > T_H || GMag_suppressed(i-1,j+1) > T_H || ... GMag_suppressed(i,j-1) > T_H || GMag_suppressed(i,j+1) > T_H || ... GMag_suppressed(i+1,j-1) > T_H || GMag_suppressed(i+1,j) > T_H || GMag_suppressed(i+1,j+1) > T_H) G_edge(i,j) = 1; end end end end % 展示结果 imshow(G_edge);
2. Sobel算子Matlab代码
% 读取图像 I = imread('lena.png'); % 将图像转换为灰度图像 I = rgb2gray(I); % 计算Sobel算子,获取水平和垂直方向的梯度 Sx = [-1 0 1; -2 0 2; -1 0 1]; Sy = [-1 -2 -1; 0 0 0; 1 2 1]; Gx = imfilter(I, Sx); Gy = imfilter(I, Sy); % 显示结果 subplot(1,2,1); imshow(Gx); title('Sobel算子水平梯度'); subplot(1,2,2); imshow(Gy); title('Sobel算子垂直梯度');
3. 图像边缘检测Matlab函数
% 读取图像 I = imread('lena.png'); % 将图像转换为灰度图像 I = rgb2gray(I); % 使用canny函数进行边缘检测 BW = edge(I, 'canny'); % 显示结果 imshow(BW);
五、Canny边缘检测算法Python代码
1. Canny算法Python代码
# 导入Python图片处理库 from PIL import Image # 导入Python图像处理库 from scipy import ndimage import numpy as np # 读取图像 image = Image.open('lena.png').convert('L') # 将图像转换为数组 image_array = np.array(image) # 高斯滤波 image_smooth = ndimage.gaussian_filter(image_array, 2) # 计算梯度 dx, dy = np.gradient(image_smooth) gradient_mag = np.sqrt(dx ** 2 + dy ** 2) gradient_dir = np.arctan2(dy, dx) * 180 / np.pi # 非极大值抑制 grad_suppressed = np.zeros_like(gradient_mag) h, w = gradient_mag.shape for i in range(1, h - 1): for j in range(1, w - 1): if (gradient_dir[i][j] <= 22.5 and gradient_dir[i][j] > -22.5) or (gradient_dir[i][j] <= -157.5 and gradient_dir[i][j] > 157.5): if (gradient_mag[i][j] >= gradient_mag[i][j - 1] and gradient_mag[i][j] >= gradient_mag[i][j + 1]): grad_suppressed[i][j] = gradient_mag[i][j] elif (gradient_dir[i][j] > 22.5 and gradient_dir[i][j] <= 67.5) or (gradient_dir[i][j] <= -112.5 and gradient_dir[i][j] > -157.5): if (gradient_mag[i][j] >= gradient_mag[i - 1][j - 1] and gradient_mag[i][j] >= gradient_mag[i + 1][j + 1]): grad_suppressed[i][j] = gradient_mag[i][j] elif (gradient_dir[i][j] > 67.5 and gradient_dir[i][j] <= 112.5) or (gradient_dir[i][j] <= -67.5 and gradient_dir[i][j] > -112.5): if (gradient_mag[i][j] >= gradient_mag[i - 1][j] and gradient_mag[i][j] >= gradient_mag[i + 1][j]): grad_suppressed[i][j] = gradient_mag[i][j] elif (gradient_dir[i][j] > 112.5 and gradient_dir[i][j] <= 157.5) or (gradient_dir[i