MATLAB实现Canny边缘检测算法

一、算法原理与流程

Canny边缘检测算法由John F. Canny于1986年提出,其核心流程包含5个关键步骤:

  1. 高斯滤波:消除噪声干扰(使用高斯核卷积)
  2. 梯度计算:通过Sobel算子计算梯度幅值和方向
  3. 非极大值抑制:细化边缘宽度(保留局部梯度最大值)
  4. 双阈值检测:区分强/弱边缘(通过高低阈值比例)
  5. 边缘连接:滞后跟踪弱边缘(连接强边缘邻域的弱边缘)

二、代码

1. 基础实现(手动版)
matlab 复制代码
function edge_img = my_canny(I, sigma, low_thresh_ratio, high_thresh_ratio)
    % 输入参数:
    % I: 输入灰度图像
    % sigma: 高斯滤波标准差
    % low_thresh_ratio: 低阈值比例(相对于高阈值)
    % high_thresh_ratio: 高阈值比例(相对于梯度最大值)
    
    % 1. 高斯滤波
    [m,n] = size(I);
    k = 2*ceil(3*sigma)+1;  % 核大小(奇数)
    h = fspecial('gaussian', [k k], sigma);
    blurred = imfilter(I, h, 'same', 'replicate');
    
    % 2. 计算梯度
    [Gx, Gy] = imgradientxy(blurred, 'sobel');
    [G, theta] = imgradient(Gx, Gy);
    
    % 3. 非极大值抑制
    nms = non_maximum_suppression(G, theta);
    
    % 4. 双阈值检测
    high_thresh = max(G(:)) * high_thresh_ratio;
    low_thresh = high_thresh * low_thresh_ratio;
    
    strong_edges = nms > high_thresh;
    weak_edges = (nms >= low_thresh) & (nms <= high_thresh);
    
    % 5. 边缘连接
    edge_img = edge_linking(strong_edges, weak_edges);
end

% 非极大值抑制函数
function nms = non_maximum_suppression(G, theta)
    [m,n] = size(G);
    nms = zeros(m,n);
    theta = theta * 180/pi;  % 转换为角度
    theta(theta < 0) = theta + 180;  % 角度归一化
    
    for i = 2:m-1
        for j = 2:n-1
            % 根据梯度方向选择比较方向
            if (0 <= theta(i,j) && theta(i,j) < 22.5) || (157.5 <= theta(i,j) && theta(i,j) < 180)
                neighbor = [G(i,j-1), G(i,j+1)];
            elseif (22.5 <= theta(i,j) && theta(i,j) < 67.5)
                neighbor = [G(i-1,j+1), G(i+1,j-1)];
            elseif (67.5 <= theta(i,j) && theta(i,j) < 112.5)
                neighbor = [G(i-1,j), G(i+1,j)];
            else
                neighbor = [G(i-1,j-1), G(i+1,j+1)];
            end
            % 保留局部最大值
            if G(i,j) >= max(neighbor)
                nms(i,j) = G(i,j);
            end
        end
    end
end

% 边缘连接函数
function final_edges = edge_linking(strong, weak)
    [m,n] = size(strong);
    final_edges = false(m,n);
    strong_idx = find(strong);
    
    % 使用8邻域连接弱边缘
    for k = 1:length(strong_idx)
        [i,j] = ind2sub([m,n], strong_idx(k));
        if any(any(weak(i-1:i+1, j-1:j+1)))
            final_edges(i,j) = true;
        end
    end
end
2. 内置函数实现(推荐)
matlab 复制代码
% 直接调用edge函数
I = imread('lena.jpg');
gray = rgb2gray(I);
edges = edge(gray, 'Canny', [0.1 0.2], 2);  % 自动计算高低阈值
imshow(edges);

三、参数优化

参数 影响范围 推荐范围 调整建议
sigma 噪声抑制效果 1-3 噪声明显时增大(如σ=2)
高低阈值比 边缘保留数量 0.1-0.3 通过直方图分析确定
滤波核大小 边缘平滑程度 3×3至7×7 核越大边缘越平滑
梯度算子 边缘方向灵敏度 Sobel/Prewitt 复杂纹理建议使用Prewitt

四、工程应用案例

1. 医学图像血管检测
matlab 复制代码
% 加载血管造影图像
img = imread('vessel.png');
gray = rgb2gray(img);

% 自适应Canny参数
sigma = graythresh(gray)*2;  % 基于Otsu方法自动选择
edges = edge(gray, 'Canny', [0.05 0.15], sigma);

% 形态学后处理
se = strel('disk',2);
clean_edges = bwareaopen(edges, 50);
clean_edges = imclose(clean_edges, se);
imshow(clean_edges);
2. 工业检测(裂纹识别)
matlab 复制代码
% 读取金属表面图像
img = imread('metal_surface.jpg');
gray = rgb2gray(img);

% 多尺度Canny检测
edges1 = edge(gray, 'Canny', [0.08 0.12], 1);
edges2 = edge(gray, 'Canny', [0.15 0.25], 2);

% 结果融合
final_edges = imfuse(edges1, edges2, 'blend');
imshow(final_edges);

五、常见问题解决方案

  1. 噪声干扰严重: 增加高斯滤波核大小(如σ=3) 先进行中值滤波预处理
  2. 边缘断裂 : 调整低阈值比例(建议0.1-0.2) 增加形态学闭操作(imclose
  3. 计算效率低: 使用积分图像加速梯度计算 对ROI区域进行检测

六、参考

  1. MathWorks官方文档: Canny Edge Detection ww2.mathworks.cn/help/images/ref/edge.html
  2. 代码 matlab中实现canny边缘检测算法 www.3dddown.com/csa/78285.html
  3. 《数字图像处理》冈萨雷斯著
  4. Canny原始论文: A Computational Approach to Edge Detection(1986)
相关推荐
fie88892 小时前
波束赋形MATLAB代码实现
开发语言·matlab
qq_430855882 小时前
线代第二章矩阵第四课:方阵的幂
算法·机器学习·矩阵
roman_日积跬步-终至千里2 小时前
【计算机设计与算法-习题2】动态规划应用:矩阵乘法与钢条切割问题
算法·矩阵·动态规划
kupeThinkPoem2 小时前
计算机算法导论第三版算法视频讲解
数据结构·算法
sali-tec2 小时前
C# 基于halcon的视觉工作流-章67 深度学习-分类
开发语言·图像处理·人工智能·深度学习·算法·计算机视觉·分类
少许极端2 小时前
算法奇妙屋(十八)-子数组系列(动态规划)
算法·动态规划·子数组
WBluuue2 小时前
Codeforces 1068 Div2(ABCD)
c++·算法
图学习小组2 小时前
Learning to See in the Extremely Dark
图像处理·计算机视觉
地平线开发者3 小时前
征程 6P/H 计算平台部署指南
算法·自动驾驶