精华内容
下载资源
问答
  • canny边缘检测算法matlab实现

    热门讨论 2011-03-24 14:03:25
    canny算法,实现边缘检测。本程序主要分为4步,第一步是输入图像,第二步和第三步实现canny算法,第三步实现输出
  • Canny边缘检测Matlab代码

    热门讨论 2013-06-16 19:31:07
    自编的Canny边缘检测算子,通过与maltab自带的边缘检测算子进行对比发现我们编写的canny算子的性能几乎和matlab自带的性能一致。该程序注重减少for循环,在速度上具有一定的优势,且附带该论文的pdf。希望能够对大家...
  • 数字图像处理中边缘检测canny是最优的边缘检测算法。对图像高斯滤波、求梯度、局部非极大值抑制、设置图像边缘为不可能的边缘
  • 本文件包为canny边缘检测算法代码,matlab编写,用于检测图像边缘。
  • canny边缘检测matlab实现》由会员分享,可在线阅读,更多相关《canny边缘检测matlab实现(8页珍藏版)》请在人人文库网上搜索。1、北京工业大学研究生课程考试答题纸题号分数任课教师签名一二三四五六七八九十...

    《canny边缘检测及matlab实现》由会员分享,可在线阅读,更多相关《canny边缘检测及matlab实现(8页珍藏版)》请在人人文库网上搜索。

    1、北京工业大学研究生课程考试答题纸题号分数任课教师签名一二三四五六七八九十总分考试课程:课程类别: 学位课 选修课研究生学号:研究生姓名:学生类别: 博士 硕士工程硕士 进修生考试时间: 年 月 日一、实验目的:熟悉边缘检测原理,并运用matlab软件实现图像的canny边缘检测,体会canny边缘检测的优缺点。二、实验内容:编写matlab程序,实现对lena图像的边缘检测,输出程序运行结果。三、实验原理或步骤:首先回顾一下边缘检测的一般步骤:边缘检测算法一般包含如下四个步骤:1.滤波(去噪)。2.增强(一般是通过计算梯度幅值)。3.检测(在图像中有许多点的梯度幅值会比较大,而这些点并不都是边。

    2、缘,所以应该用某种方法来确定边缘点,比如最简单的边缘检测判据:梯度幅值阈值)。4.定位(有的应用场合要求确定边缘位置,可以在子像素水平上来估计,指出边缘的位置和方向)Canny边缘检测的算法步骤:1.用高斯滤波器平滑图像(不同尺度的Canny检测子由高斯的不同标准差来表示)用一阶偏导的有限差分来计算梯度的幅值和方向。2.对高斯平滑后的图像进行sobel边缘检测。这里需要求横的竖的还有联合的,所以一共三个需要sobel边缘检测图像。3.对联合的sobel检测图像进行非极大值抑制(Non-Maxima Suppression, NMS)4.用双阈值算法检测和连接边缘,并进行滞后阈值处理。其中非极大。

    3、值抑制细化了幅值图像中的屋脊带,只保留幅值局部变化最大的点。双阈值算法:用两个阈值得到两个阈值图像,然后把高阈值的图像中的边缘连接成轮廓,连接时到达轮廓的端点时,在低阈值图像上找可以连接的边缘。不断收集,直到所有的间隙连接起来为止。四、运行结果和分析每步运行效果:Figure1原图:Figure2 高斯模糊后:Figure3 sobel边缘检测后:Figure4 非极大抑制后:Figure5 上阈值120,下阈值100检测结果:Canny算子的方向性使得它的边缘检测和定位优于其他算子,具有更好的边缘强度估计,能产生梯度方向和强度两个信息。五、算法程序Main.mclear all;close 。

    4、all;clc;img=imread(lena.bmp);imshow(img);m n=size(img);img=double(img);%canny边缘检测的前两步相对不复杂,所以我就直接调用系统函数了%高斯滤波w=fspecial(gaussian,5 5);img=imfilter(img,w,replicate);figure;imshow(uint8(img)%sobel边缘检测w=fspecial(sobel);img_w=imfilter(img,w,replicate); %求横边缘w=w;img_h=imfilter(img,w,replicate); %求竖边缘img=。

    5、sqrt(img_w.2+img_h.2); %注意这里不是简单的求平均,而是平方和在开方。figure;imshow(uint8(img)%下面是非极大抑制new_edge=zeros(m,n);for i=2:m-1for j=2:n-1Mx=img_w(i,j);My=img_h(i,j); if My=0o=atan(Mx/My); %边缘的法线弧度elseif My=0 & Mx0o=pi/2;elseo=-pi/2; end%Mx处用My和img进行插值adds=get_coords(o); %边缘像素法线一侧求得的两点坐标,插值需要 M1=My*img(i+adds(2),j+a。

    6、dds(1)+(Mx-My)*img(i+adds(4),j+adds(3); %插值后得到的像素,用此像素和当前像素比较 adds=get_coords(o+pi); %边缘法线另一侧求得的两点坐标,插值需要M2=My*img(i+adds(2),j+adds(1)+(Mx-My)*img(i+adds(4),j+adds(3); %另一侧插值得到的像素,同样和当前像素比较isbigger=(Mx*img(i,j)M1)*(Mx*img(i,j)=M2)+(Mx*img(i,j)up &new_edge(i,j)=255 %判断上阈值new_edge(i,j)=255;new_edge=co。

    7、nnect(new_edge,i,j,low);endendendfigure;imshow(new_edge=255)get_coords.mfunction re=get_coords(angle) %angle是边缘法线角度,返回法线前后两点sigma=0.;x1=ceil(cos(angle+pi/8)*sqrt(2)-0.5-sigma);y1=ceil(-sin(angle-pi/8)*sqrt(2)-0.5-sigma);x2=ceil(cos(angle-pi/8)*sqrt(2)-0.5-sigma);y2=ceil(-sin(angle-pi/8)*sqrt(2)-0.5-。

    8、sigma);re=x1 y1 x2 y2;endconnect.mfunction nedge=connect(nedge,y,x,low) %种子定位后的连通分析neighbour=-1 -1;-1 0;-1 1;0 -1;0 1;1 -1;1 0;1 1; %八连通搜寻m n=size(nedge);for k=1:8yy=y+neighbour(k,1);xx=x+neighbour(k,2);if yy=1 &yy=1 & xx=low & nedge(yy,xx)=255 %判断下阈值nedge(yy,xx)=255;nedge=connect(nedge,yy,xx,low);endend end end。

    展开全文
  • canny算子进行详细讲解。
  • Canny边缘检测(Matlab版)

    2021-04-18 12:14:57
    Canny边缘检测的主要过程为图像平滑去噪图像梯度(幅度与方向)的求取边缘图像的非最大抑制(去除未边缘)双阈值,使用高阈值图像非零点在低阈值图像中搜索,确定真实边缘位置在过程中有两个参数会影响边缘效果Canny算法...

    Canny(坎尼)边缘检测算法作为数字图像处理接触到的第一个效果较好的边缘检测算法,原理并不复杂。现有很多教程已经对其进行解释,在此不再赘述。

    Canny边缘检测的主要过程为

    图像平滑去噪

    图像梯度(幅度与方向)的求取

    边缘图像的非最大抑制(去除未边缘)

    双阈值,使用高阈值图像非零点在低阈值图像中搜索,确定真实边缘位置

    在过程中有两个参数会影响边缘效果

    Canny算法包含许多可以调整的参数,它们将影响到算法的计算的时间与实效。

    高斯滤波器的大小:第一步所用的平滑滤波器将会直接影响Canny算法的结果。较小的滤波器产生的模糊效果也较少,这样就可以检测较小、变化明显的细线。较大的滤波器产生的模糊效果也较多,将较大的一块图像区域涂成一个特定点的颜色值。这样带来的结果就是对于检测较大、平滑的边缘更加有用,例如彩虹的边缘。

    阈值:使用两个阈值比使用一个阈值更加灵活,但是它还是有阈值存在的共性问题。设置的阈值过高,可能会漏掉重要信息;阈值过低,将会把枝节信息看得很重要。很难给出一个适用于所有图像的通用阈值。目前还没有一个经过验证的实现方法。百度百科

    Matlab版代码

    % author: BetaHu

    % time: 2019/10/23 20:26

    % Matlab version: R2016a

    clc, clear;

    close all;

    tic;

    img0 = double(imread('lena.jpg'));

    gauss = [1 2 1; 2 4 2;1 2 1] / 16; % Gauss平滑模板

    sobelx = [-1 0 1; -2 0 2; -1 0 1]; % Sobel水平边缘模板

    sobely = sobelx'; % Sobel垂直边缘模板

    img = conv2(img0, gauss, 'same'); % 平滑

    gradx = conv2(img, sobelx, 'same'); % 水平边缘卷积

    grady = conv2(img, sobely, 'same'); % 垂直边缘卷积

    M = sqrt(gradx .^ 2 + grady .^ 2); % 边缘高度

    N = zeros(size(M)); % 非最大抑制图像

    alpha = atan(grady ./ gradx); % 边缘方向

    for i = 2: length(M(:, 1)) - 1

    for j = 2: length(M(1, :)) - 1

    dirc = alpha(i, j); % 四个基本方向判断并进行非最大抑制,比如矩阵是

    % [1 2 3;4 5 6;7 8 9],边缘延[4 5 6]方向,那

    % 么我们关心的是元素2和元素8与元素5的大小关系

    if abs(dirc) <= pi / 8

    if M(i, j) == max([(M(i, j - 1)), M(i, j), M(i, j + 1)])

    N(i, j) = M(i, j);

    end

    elseif abs(dirc) >= 3 * pi / 8

    if M(i, j) == max([(M(i - 1, j)), M(i, j), M(i + 1, j)])

    N(i, j) = M(i, j);

    end

    elseif dirc > pi / 8 && dirc < 3 * pi / 8

    if M(i, j) == max([(M(i - 1, j - 1)), M(i, j), M(i + 1, j + 1)])

    N(i, j) = M(i, j);

    end

    elseif dirc > - 3 * pi / 8 && dirc < - pi / 8

    if M(i, j) == max([(M(i + 1, j - 1)), M(i, j), M(i - 1, j + 1)])

    N(i, j) = M(i, j);

    end

    end

    end

    end

    TH = 0.4 * max(max(N)); % 高阈值

    TL = 0.2 * max(max(N)); % 低阈值

    THedge = N;

    TLedge = N;

    THedge(THedge < TH) = 0; % 强边缘

    TLedge(TLedge < TL) = 0; % 弱边缘

    THedge = padarray(THedge, [1, 1], 0, 'both'); % 进行边扩展,防止遍历时出错

    TLedge = padarray(TLedge, [1, 1], 0, 'both');

    TLedge0 = TLedge;

    isvis = ones(size(THedge)); % 是否遍历过某像素,是为0,不是为1(便于计算)

    while(sum(sum(THedge)))

    [x, y] = find(THedge ~= 0, 1); % 寻找8邻域内非0像素,作为下一步搜索的起点

    THedge = THedge .* isvis; % 搜索过的点标记为0

    [TLedge0, isvis] = traverse(TLedge0, x, y, isvis); % 递归遍历,最终剩下的是未遍历的元素,即孤立点或非目标边缘

    end

    TLedge = TLedge - TLedge0; % 作差求出Canny边缘

    THedge(:, end) = []; THedge(end, :) = []; THedge(1, :) = []; THedge(:, 1) = []; % 删去扩展的边缘

    TLedge(:, end) = []; TLedge(end, :) = []; TLedge(1, :) = []; TLedge(:, 1) = [];

    toc;

    figure;

    subplot(221), imshow(img0, []), title('car');

    subplot(222), imshow(M, []), title('Amplitude');

    subplot(223), imshow(alpha, []), title('Alpha');

    subplot(224), imshow(TLedge, []), title('output');

    function [output, isvis] = traverse(mat, i, j, isvis)

    mat(i, j) = 0;

    isvis(i, j) = 0;

    neighbor = mat(i - 1: i + 1, j - 1: j + 1);

    while(sum(sum(neighbor)))

    [x, y] = find(neighbor ~= 0, 1);

    neighbor(x, y) = 0;

    mat(i - 2 + x, j - 2 + y) = 0;

    [mat, isvis] = traverse(mat, i - 2 + x, j - 2 + y, isvis);

    end

    output = mat;

    由于搜索方法选择了递归法,貌似效率比较低。自行优化

    展开全文
  • matlab边缘检测,一种改进型的边缘检测算法,效果比canny好。
  • 数字图像处理作业canny边缘检测坎尼边缘检测MATLAB源码及实验报告
  • 文章目录边缘检测介绍Canny算法的四个基本步骤高斯滤波器平滑处理图像原理高斯滤波器Matlab中的高斯模版生成函数计算图像每一个像素点的梯度值以及梯度方向Sobel算子对梯度值进行非极大值抑制论文中的方法插值法双...

    边缘检测介绍

    • 提取图像的边缘信息是底层数字图像处理的基本任务之一
    • 图象的边缘是指图象局部区域亮度变化显著的部分
    • Canny 是一种常用的边缘检测算法. 1986 年由 John F.Canny 提出

    Canny算法的四个基本步骤

    高斯滤波器平滑处理图像

    原理

    • 使用高斯滤波器的主要目的是为了给图像降噪, 因为之后的导数计算对噪声非常敏感, 如果不对噪声进行提前处理, 进行导数运算后, 这些噪声会被放大, 使得检测出来的虚假边缘增多.
    • 虽然使用滤波器平滑处理图像能够有效的抑制噪声, 但是在此过程中会使得图像边缘模糊, 增加了边缘定位的不确定性.
    • 实际工程经验表明, 使用高斯滤波器是在抗噪声干扰和边缘检测精确定位之间的一个较好的折中方案

    高斯滤波器

    • 高斯滤波器实际上就是一个n*n的矩阵, 将这个矩阵和图像的矩阵进行卷积, 即可达到对图像平滑处理的目的.
    • 这个矩阵由二维高斯函数生成.
      在这里插入图片描述
    • 比如想得到一个3*3的高斯矩阵, 以矩阵的中心位置为坐标原点, 各个位置的坐标如下图所示, 将各个位置的坐标带入高斯函数中得到的值就是高斯核中对应位置的元素的值. (水平向右为x轴正方向, 竖直向上为y轴正方向)
    (-1, 1)(0, 1)(1, 1)
    (-1, 0)(0, 0)(1, 0)
    (-1, -1)(0, -1)(1, -1)
    • 假设模版是k*k的大小, 模版中各个元素的计算值如下, i表示行, j表示列. 最后的计算结果一般为小数, 每个元素都需要除以所有元素的和 (保证所有元素值的和为1)
      在这里插入图片描述
    • 如果要把矩阵化为整数, 则需要在矩阵前面加一个系数 (1/元素和)

    Matlab中的高斯模版生成函数

    • Matlab中可以通过函数fspecial('gaussian', HSIZE, SIGMA) 来生成一个高斯模版, HSIZE是模版大小默认是3*3
    • 使用imfilter(img, h, 'replicate') 对图像进行平滑处理
    • 下面代码中的高斯模版生成函数为自己根据原理实现, 平滑处理使用的是conv2卷积函数

    计算图像每一个像素点的梯度值以及梯度方向

    Sobel算子

    • 边缘是图像局部区域亮度变化显著的部分, 如何衡量亮度变化? 梯度大小和梯度方向
    • Sobel算子认为邻域的像素对当前像素产生的影响不是等价的,所以距离不同的像素具有不同的权值,对算子结果产生的影响也不同。一般来说,距离越远,产生的影响越小 (水平竖直方向的权重大于45度方向)
    • Sobel算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度梯度值
    • 横向 Gx
    -101
    -202
    -101
    • 纵向 Gy
    -1-2-1
    000
    121
    • 图像中每一个像素的梯度值大小用下面公式计算
      在这里插入图片描述
    • 梯度方向
      在这里插入图片描述

    对梯度值进行非极大值抑制

    • 图像梯度值矩阵中的元素值越大, 说明图像在该点的梯度值越大, 并不能说明该点就是边缘(这可能仅仅只是图像亮度增强过程中的某一个点)
    • 非极大值抑制就是说寻找在梯度方向上的像素点的局部梯度最大值, 将非极大值点对应的灰度设为0.

    论文中的方法

    • 在John Canny提出的Canny算子的论文中,非极大值抑制只是在0、45、90、135四个梯度方向上进行的,每个像素点梯度方向按照相近程度用这四个方向来代替
    • 对于某一个像素点, 根据其梯度方向, 近似到上述4个方向的其中一个, 然后将该像素点的灰度值与该方向上相邻的两个像素点的梯度值进行比较, 如果是极大值则保留, 否则设为0.

    插值法

    • 如果不采用近似的方法, 实际数字图像中的像素点是离散的二维矩阵,所以处在某个像素梯度方向两侧的点是不一定存在的,或者说是一个亚像素(sub pixel)点,而这个不存在的点, 以及这个点的梯度值就必须通过对其两侧的点进行插值来得到 (以下图片来源)
      在这里插入图片描述在这里插入图片描述
    • 对这两种方法, 代码中均有实现, 并进行了效果比较

    双阈值检测以及连接边缘

    • 一般情况下设定一个阈值来确定边缘, 高于这个阈值的像素点为边缘像素点, 低于这个阈值的设为0. 但是这样佐会造成一些明明是边缘的点, 却因为梯度值大小(过渡不明显) 而被舍弃
    • 使用启发式的方法确定一个上阀值和下阀值,位于下阀值之上的都有可能作为边缘,这样就可能提高准确度
    • 设置两个阀值(threshold),分别为maxVal和minVal。
      • 大于maxVal的都被检测为边缘
      • 小于minVal的都被检测为非边缘
      • 对于中间的像素点,如果与确定为边缘的像素点邻接,则判定为边缘;否则为非边缘 (即判断领域8个像素点中有没有梯度值大于maxVal的)

    在这里插入图片描述
    图片来源

    Matlab代码实现

    主函数

    %% =============== Part 0: 读取图像 ================
    apple = imread('2.jpg');
    apple_gray = double(rgb2gray(apple));
    figure(1);
    subplot(3,3,1);
    imshow(uint8(apple_gray));
    title('原图')
    
    %% =============== Part 1: 高斯平滑处理 ================
    % 生成高斯模版
    H = gaussian_filter(5, 0.8);
    apple_filter = imfilter(apple_gray, H, 'replicate');
    subplot(3,3,2);
    imshow(uint8(apple_filter));
    title('高斯平滑')
    
    %% =============== Part 2: 索贝尔算子计算梯度值及方向 ================
    [grad, grad_direction] = compute_grad(apple_filter);
    subplot(3,3,3);
    imshow(uint8(grad));
    title('sobel')
    
    %% =============== Part 3: 非极大值抑制 ================
    canny1 = non_maximum_restrain(grad, grad_direction);
    subplot(3,3,4);
    imshow(uint8(canny1));
    title('非极大值抑制 论文法')
    canny2 = non_maximum_restrain_improvement(grad, grad_direction);
    subplot(3,3,7);
    imshow(uint8(canny2));
    title('非极大值抑制 插值法')
    
    %% =============== Part 4: 双阈值检测 ================
    canny11 = dual_threshold_detection(canny1, 50, 100);
    subplot(3,3,5);
    imshow(uint8(canny11));
    title('双阈值检测 论文法')
    canny22 = dual_threshold_detection(canny2, 50, 100);
    subplot(3,3,8);
    imshow(uint8(canny22));
    title('双阈值检测 插值法')
    

    高斯滤波器生成函数

    function gaussian_matrix = gaussian_filter(size, sigma)
        gaussian_matrix = zeros(size, size);
        coef = 1 / (2 * 3.14159265 * sigma * sigma);
        total_sum = 0;
        for i = 1:size
            for j = 1:size
                x2 = (j - (size + 1)  / 2)^2;
                y2 = (i - (size + 1)  / 2)^2;
                gaussian_matrix(i, j) = coef * exp(-(x2 + y2) / (2 * sigma * sigma));
                total_sum = total_sum + gaussian_matrix(i, j);
            end
        end
        % 使得矩阵中所有元素和为1
        gaussian_matrix = gaussian_matrix / total_sum;
    end
    

    梯度计算函数

    function [grad, grad_direction] = compute_grad(img_filter)
        % 索贝尔算子
        sobel = [-1.0 0.0 1.0;-2.0 0.0 2.0;-1.0 0.0 1.0];
    
        % 计算图像的sobel水平梯度 
        gradx=conv2(img_filter, sobel, 'same');
        % gradx = imfilter(apple_filter, sobel, 'replicate');
    
        % 计算图像的sobel垂直梯度 
        grady=conv2(img_filter, sobel', 'same');
        % grady = imfilter(apple_filter, sobel', 'replicate');
    
        % 得到图像的sobel梯度以及方向, 使用绝对值代替平方开方
        grad=sqrt(gradx.^2+grady.^2);
        grad_direction = atan(grady./gradx);
    end
    

    非极大值抑制函数

    论文算法

    function canny = non_maximum_restrain(grad, grad_direction)
        [m, n] = size(grad_direction);
        sector = zeros(m, n);
        canny = zeros(m, n);
        % 构造
        % 2 1 0
        % 3 x 3
        % 0 1 2
        for i=1:m
            for j=1:n
                angle = grad_direction(i, j);
                if (angle < 3*pi/4) && (angle >= pi/4)
                    sector(i, j) = 0;    
                elseif (angle < pi/4) && (angle >= -pi/4)
                    sector(i, j) = 3;    
                elseif (angle < -pi/4) && (angle >= -3*pi/4)
                    sector(i, j) = 2;    
                else
                    sector(i, j) = 1;    
                end    
            end
        end
        % 判断没一点像素的梯度方向,并和该方向上的数值进行比较
        for i=2:m-1
            for j=2:n-1
                if (sector(i, j) == 0) % 45if ((grad(i, j) > grad(i - 1, j + 1) && grad(i, j) > grad(i + 1, j - 1)) || (grad(i, j) > grad(i, j + 1) && grad(i, j) > grad(i, j - 1)) || (grad(i, j) > grad(i - 1, j) && grad(i, j) > grad(i + 1, j)))
                        canny(i,j) = grad(i, j);
                    else
                        canny(i, j) = 0;
                    end
                end
                if (sector(i, j) == 1) % 90if (grad(i, j) > grad(i - 1, j) && grad(i, j) > grad(i + 1, j))
                        canny(i,j) = grad(i, j);
                    else
                        canny(i, j) = 0;
                    end
                end
                if (sector(i, j) == 2) % 135if ((grad(i, j) > grad(i - 1, j - 1) && grad(i, j) > grad(i + 1, j + 1))|| (grad(i, j) > grad(i, j + 1) && grad(i, j) > grad(i, j - 1)) || (grad(i, j) > grad(i - 1, j) && grad(i, j) > grad(i + 1, j)))
                        canny(i,j) = grad(i, j);
                    else
                        canny(i, j) = 0;
                    end
                end
                if (sector(i, j) == 3) % 180if (grad(i, j) > grad(i, j + 1) && grad(i, j) > grad(i, j - 1))
                        canny(i,j) = grad(i, j);
                    else
                        canny(i, j) = 0;
                    end
                end
            end
        end
    end
    

    插值算法

    function canny = non_maximum_restrain_improvement(grad, grad_direction)
        [m, n] = size(grad_direction);
        canny = zeros(m, n);
        for i=2:m-1
            for j=2:n-1
                angle = grad_direction(i, j);
                if (angle > 0 && angle <= pi/4)
                    % 通过差值求的亚像素(实际上不存在)
                   right_top_pixel = tan(angle) * grad(i-1, j+1);
                   right_pixel = (1 - tan(angle)) * grad(i, j+1);
                   pixel1 = right_top_pixel + right_pixel;
                   left_bottom_pixel = tan(angle) * grad(i+1, j-1);
                   left_pixel = (1 - tan(angle)) * grad(i, j-1);
                   pixel2 = left_bottom_pixel + left_pixel;
                   if (grad(i, j) > pixel1 && grad(i, j) > pixel2)
                       canny(i, j) = grad(i, j);
                   else
                       canny(i, j) = 0;
                   end
                elseif (angle > pi/4 && angle < pi/2)
                    right_top_pixel = 1 / tan(angle) * grad(i-1, j+1);
                    top_pixel = (1 - 1 / tan(angle)) * grad(i-1, j);
                    pixel1 = right_top_pixel + top_pixel;
                    left_bottom_pixel = 1 / tan(angle) * grad(i+1, j-1);
                    bottom_pixel = (1 - 1 / tan(angle)) * grad(i+1, j);
                    pixel2 = left_bottom_pixel + bottom_pixel;
                    if (grad(i, j) > pixel1 && grad(i, j) > pixel2)
                       canny(i, j) = grad(i, j);
                    else
                       canny(i, j) = 0;
                    end
                elseif (angle > -pi/2 && angle <= -pi/4)
                    left_top_pixel = -1/tan(angle) * grad(i-1, j-1);
                    top_pixel = (1+1/tan(angle)) * grad(i-1, j);
                    pixel1 = left_top_pixel + top_pixel;
                    right_bottom_pixel = -1/tan(angle) * grad(i+1, j+1);
                    bottom_pixel = (1+1/tan(angle)) * grad(i+1, j);
                    pixel2 = right_bottom_pixel + bottom_pixel;
                    if (grad(i, j) > pixel1 && grad(i, j) > pixel2)
                       canny(i, j) = grad(i, j);
                    else
                       canny(i, j) = 0;
                    end
                elseif (angle > -pi/4 && angle <= 0)
                    left_top_pixel = -tan(angle) * grad(i-1, j-1);
                    left_pixel = (1+tan(angle)) * grad(i, j-1);
                    pixel1 = left_top_pixel + left_pixel;
                    right_bottom_pixel =  -tan(angle) * grad(i+1, j+1);
                    right_pixel = (1+tan(angle)) * grad(i, j+1);
                    pixel2 = right_bottom_pixel + right_pixel;
                    if (grad(i, j) > pixel1 && grad(i, j) > pixel2)
                       canny(i, j) = grad(i, j);
                    else
                       canny(i, j) = 0;
                    end
                elseif (angle == pi/2 || angle == -pi/2)
                    top_pixel = grad(i-1, j);
                    bottom_pixel = grad(i+1, j);
                    if (grad(i, j) > top_pixel && grad(i, j) > bottom_pixel)
                       canny(i, j) = grad(i, j);
                    else
                       canny(i, j) = 0;
                    end
                end    
            end
        end
    end
    

    双阈值检测以及连接边缘函数

    function canny2 = dual_threshold_detection(canny, low_th, high_th)
        [m, n] = size(canny);
        canny2 = zeros(m, n);
        for i=2:m-1
            for j=2:n-1
                if (canny(i, j) < low_th)
                    canny2(i,j) = 0;
                elseif (canny(i, j) > high_th)
                    canny2(i, j) = canny(i, j);
                else
                    neighbor_matrix = [canny(i-1, j-1), canny(i, j-1), canny(i+1, j-1);...
                                       canny(i-1, j), canny(i, j), canny(i+1, j);...
                                       canny(i-1, j+1), canny(i, j+1), canny(i+1, j+1);];
                    max_neighbour = max(neighbor_matrix);
                    if (max_neighbour > high_th)
                        canny2(i, j) = canny(i, j);
                    else
                        canny2(i,j) = 0;
                    end
                end
            end
        end
    end
    

    结果分析

    在这里插入图片描述
    在这里插入图片描述

    • 经过比较可以发现, 插值法最后筛选出来的边缘像素点比论文法少, 因此图像看起来有些地方并不是很连续. 也导致了一些地方细节的丢失
    • 但是在边缘宽度上, 论文方法产生宽度大于1的边缘的可能性比插值法更大,在需要达到高精度单点响应的情况下, 插值法可能会更好

    参考

    1. Canny边缘检测算法
    2. [图像]Canny检测的Matlab实现(含代码)
    3. 图像处理基础(4):高斯滤波器详解
    4. 高斯滤波器原理及其实现
    5. 边缘检测sobel算子
    6. 利用sobel算子进行边缘检测
    7. Canny算子中的非极大值抑制(Non-Maximum Suppression)分析
    展开全文
  • canny代码 matlab
  • clc; clear all; close all; I=im2double(imread('D:\Gray Files\10-26.tif'));...%=============================边缘检测(五)================================= % Canny Edge Detector %------------...
    clc;
    clear all;
    close all;
    I=im2double(imread('D:\Gray Files\10-26.tif'));
    [M,N]=size(I);
    %%
    %=============================边缘检测(五)=================================
    % Canny Edge Detector
    %-------------------------用高斯低通滤波器平滑图像-------------------------
    %建筑图像所设参数
    % n=25;
    % sigma=4;
    %头颅扫描图像所设参数
    n=13;
    sigma=2;
    %lena测试图像所设参数
    % n=5;
    % sigma=1;
    type='symmetric';
    f_s=GaussianBlur(n,I,sigma,type);
    % imshow(f_s)
    % imwrite(f_s,'D:\Gray Files\lena-test.jpg','jpg');
    %-----------------------计算平滑后的图像梯度和角度-------------------------
    n_l=1;
    %Sobel算子
    s_y=[-1 -2 -1;
        0 0 0;
        1 2 1];
    s_x=[-1 0 1;
        -2 0 2;
        -1 0 1];
    %定义梯度和角度
    gx=zeros(M,N);
    gy=zeros(M,N);
    f_s_pad=padarray(f_s,[n_l,n_l],'replicate');
    for i=1:M
        for j=1:N
            Block=f_s_pad(i:i+2*n_l,j:j+2*n_l);
            gx(i,j)=sum(sum(Block.*s_x));
            gy(i,j)=sum(sum(Block.*s_y));        
        end
    end
    type='replicate';
    gx=GaussianBlur(n,gx,sigma,type);
    gy=GaussianBlur(n,gy,sigma,type);
    M_s=sqrt(gx.^2+gy.^2);
    M_s=M_s/max(M_s(:));
    a_s=atan2(gy,gx)*180/pi;
    % imshow(M_s)
    %-----------------------对梯度图像进行非极大值抑制-------------------------
    n_l=1;
    %定义非极大值抑制图像
    g_N=M_s;
    M_s_pad=padarray(M_s,[n_l,n_l],'replicate');
    for i=1:M
        for j=1:N
            %取出中心点的梯度值
            K=M_s_pad(i+1,j+1);
     
            theta=a_s(i,j);
            if (theta>=0 && theta<=45) ||...
                    (theta<-135 && theta>=-180)
                yBot=[M_s_pad(i+1,j+2) M_s_pad(i+2,j+2)];
                yTop=[M_s_pad(i+1,j) M_s_pad(i,j)];
                k=abs(gy(i,j)/M_s_pad(i+1,j+1));
                K1=(yBot(2)-yBot(1))*k+yBot(1);
                K2=(yTop(2)-yTop(1))*k+yTop(1);         
            end    
            if (theta>45 && theta<=90) ||...
                    (theta<-90 && theta>=-135)
                yBot=[M_s_pad(i+2,j+1) M_s_pad(i+2,j+2)];
                yTop=[M_s_pad(i,j+1) M_s_pad(i,j)];
                k=abs(gx(i,j)/M_s_pad(i+1,j+1));
                K1=(yBot(2)-yBot(1))*k+yBot(1);
                K2=(yTop(2)-yTop(1))*k+yTop(1);         
            end            
            if (theta>90 && theta<=135) ||...
                    (theta<-45 && theta>=-90)
                yBot=[M_s_pad(i+2,j+1) M_s_pad(i+2,j)];
                yTop=[M_s_pad(i,j+1) M_s_pad(i,j+2)];
                k=abs(gx(i,j)/M_s_pad(i+1,j+1));
                K1=(yBot(2)-yBot(1))*k+yBot(1);
                K2=(yTop(2)-yTop(1))*k+yTop(1);         
            end                  
            if (theta>135 && theta<=180) ||...
                    (theta<0&& theta>=-45)
                yBot=[M_s_pad(i+1,j) M_s_pad(i+2,j)];
                yTop=[M_s_pad(i+1,j+2) M_s_pad(i,j+2)];
                k=abs(gy(i,j)/M_s_pad(i+1,j+1));
                K1=(yBot(2)-yBot(1))*k+yBot(1);
                K2=(yTop(2)-yTop(1))*k+yTop(1);         
            end                      
            if K<K1 || K<K2 
                g_N(i,j)=0;
            end  
        end
    end
    g_N=g_N/max(g_N(:));
    imshow(g_N)
    
    %-------------------------------设置双门限---------------------------------
    %对非极大值抑制图像进行扩展(0),方便后续的边界处理
    n_l=1;
    g_N_pad=padarray(g_N,[n_l,n_l],'replicate');
    %lena图像所设参数
    % T_max=max(g_N_pad(:));
    % H=0.275;
    % L=0.25;
    %高门限
    % T_H=T_max*H;
    %低门限
    % T_L=T_H*L;
    %-------头颅图像所设参数
    T_H=0.15;
    T_L=0.05;
    %------建筑图像所设参数
    % T_max=max(g_N_pad(:));
    % H=0.1;
    % L=0.04;
    % %高门限
    % T_H=T_max*H;
    % %低门限
    % T_L=T_H*L;
    
    %寻找大于高门限点
    ind_H=find(g_N_pad>T_H);
    g_N_pad(ind_H)=1;
    ind_Zeros=find(g_N_pad<T_L);
    g_N_pad(ind_Zeros)=0;
    % imshow(g_N_pad)
    
    %--------------------------消除未连通的边界点------------------------------
    M_temp=M+2;
    g_N_copy=g_N_pad;
    g_N_copy(ind_H)=0;
    ind_L=find(g_N_copy~=0);
    g_N_pad(ind_L)=1;
    while ~isempty(ind_H)
        %取出第一个点
        p=ind_H(1,1);    
        %初始化连通点集
        Conn=[];
        %查找p点是否有连通点,即在ind_L中是否有值
        [ind_L,Conn]=FindConnected_8(p,ind_L,Conn,M_temp);
        %向下查找所有与p点连通的点
        while ~isempty(Conn)
            %从连通集中取出第一个点,而后删除该点
            p1=Conn(1,:);
            Conn(1,:)=[];
            [ind_L,Conn]=FindConnected_8(p1,ind_L,Conn,M_temp);
        end    
        %标记p点已访问,即从ind_H中删除
        ind_H(1,:)=[];  
    end
    %将ind_L中未与ind_H连通的点,在图像中置零
    g_N_pad(ind_L)=0;
    g_N=g_N_pad(2:M+1,2:N+1);
    % imshow(g_N)
    %-----------------------------图像细化处理---------------------------------
    [g]=ImageThinning(g_N);
    imshow(g)

    高斯模糊GaussianBlur函数:

    function [g]=GaussianBlur(n,I,sigma,type)
        [M,N]=size(I);
        %生成高斯核函数
        G=GaussianKernelG(n,sigma);
        %平滑图像
        n_l=n-1;
        g=zeros(M,N);
        %对原图进行扩展,方便处理边界
        I_pad=padarray(I,[n_l,n_l],type);
        for i=1:M
            for j=1:N
                %获得图像子块区域
                Block=I_pad(i:i+n_l,j:j+n_l);
                %用Kirsch内核对子区域卷积     
                g(i,j)=sum(sum(Block.*G));
            end
        end
        %归一化
        g=g/max(g(:));
    end
    %生成高斯核函数
    % n 核函数的大小
    function G=GaussianKernelG(n,sigma)
        n_l=floor(n/2);
        %初始化
        G=zeros(n,n);
        %产生高斯核矩阵
        for i=-n_l:n_l
            for j=-n_l:n_l  
                d=i^2+j^2;
                G(i+n_l+1,j+n_l+1)=exp(-(d)/(2*sigma^2));
            end
        end
        %寻找最小值
        m=sum(G(:));
        %取整
        G=G/m;
        %将大于3*delta的取值置零
        for i=-n_l:n_l
            for j=-n_l:n_l 
                d=sqrt(i^2+j^2);
                if d>3*sigma
                    G(i+n_l+1,j+n_l+1)=0;
                end
            end
        end
    end

    查找8连通函数,FindConnected_8:

    %查找所有8连通的点
    % p为中心点,ind_L为有效矩阵,Conn为连通矩阵,M为图像矩阵的行数
    function [ind_L,Conn]=FindConnected_8(p,ind_L,Conn,M)
        %查找p点是否有连通点,即在ind_L中是否有值
        %上
        c=find(ind_L==p-1);
        if ~isempty(c)
            Conn=cat(1,Conn,p-1);
            ind_L(c)=[];
        end
        %下
        c=find(ind_L==p+1);
        if ~isempty(c)
            Conn=cat(1,Conn,p+1);
            ind_L(c)=[];
        end    
        %左
        c=find(ind_L==p-M);
        if ~isempty(c)
            Conn=cat(1,Conn,p-M);
            ind_L(c)=[];
        end        
        %左上
        c=find(ind_L==p-M-1);
        if ~isempty(c)
            Conn=cat(1,Conn,p-M-1);
            ind_L(c)=[];
        end  
        %左下
        c=find(ind_L==p-M+1);
        if ~isempty(c)
            Conn=cat(1,Conn,p-M+1);
            ind_L(c)=[];
        end      
        %右
        c=find(ind_L==p+M);
        if ~isempty(c)
            Conn=cat(1,Conn,p+M);
            ind_L(c)=[];
        end        
        %右上
        c=find(ind_L==p+M-1);
        if ~isempty(c)
            Conn=cat(1,Conn,p+M-1);
            ind_L(c)=[];
        end  
        %右下
        c=find(ind_L==p+M+1);
        if ~isempty(c)
            Conn=cat(1,Conn,p+M+1);
            ind_L(c)=[];
        end
        
    end

    图像细化函数,ImageThinning如下:

    %图像细化,目前只对二值图像进行处理
    function [g]=ImageThinning(I)
    n_l=1;
    %对边界图进行扩充,四周各加1行、1列0(与结构元素的大小相对应),目的是为了处理边界点
    I_pad=padarray(I,[n_l,n_l]);
    %获得扩充图像大小
    [M,N]=size(I_pad);
    %寻找图像中的亮点,即值为1的点
    ind=find(I_pad==1);
    ind_c=[];
    while ~isequal(ind_c,ind)
        %备份赋值,以便下一次循环开始进行比较
        ind_c=ind;
        %保存ind中符合条件的下标
        ind_sub=[];
        %按照B1结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p+1)) && ~isempty(find(ind==p-M+1)) && ~isempty(find(ind==p+M+1)) &&...
                    isempty(find(ind==p-1)) && isempty(find(ind==p-M-1)) && isempty(find(ind==p+M-1))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        %将下标符合条件的数值,从ind中清除,以下类似
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end
        ind_sub=[];
        %按照B2结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p+1)) && ~isempty(find(ind==p-M)) && ~isempty(find(ind==p-M+1)) &&...
                    isempty(find(ind==p-1)) && isempty(find(ind==p+M)) && isempty(find(ind==p+M-1))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end   
        ind_sub=[];
        %按照B3结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p-M-1)) && ~isempty(find(ind==p-M)) && ~isempty(find(ind==p-M+1)) &&...
                    isempty(find(ind==p+M-1)) && isempty(find(ind==p+M)) && isempty(find(ind==p+M+1))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end
        ind_sub=[];
        %按照B4结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p-1)) && ~isempty(find(ind==p-M)) && ~isempty(find(ind==p-M-1)) &&...
                    isempty(find(ind==p+1)) && isempty(find(ind==p+M)) && isempty(find(ind==p+M+1))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end    
        ind_sub=[];
        %按照B5结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p-M-1)) && ~isempty(find(ind==p-1)) && ~isempty(find(ind==p+M-1)) &&...
                    isempty(find(ind==p-M+1)) && isempty(find(ind==p+1)) && isempty(find(ind==p+M+1))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end     
        ind_sub=[];
        %按照B6结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p-1)) && ~isempty(find(ind==p+M-1)) && ~isempty(find(ind==p+M)) &&...
                    isempty(find(ind==p+1)) && isempty(find(ind==p-M+1)) && isempty(find(ind==p-M))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end    
        ind_sub=[];
        %按照B7结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p+M-1)) && ~isempty(find(ind==p+M)) && ~isempty(find(ind==p+M+1)) &&...
                    isempty(find(ind==p-M-1)) && isempty(find(ind==p-M)) && isempty(find(ind==p-M+1))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end   
        ind_sub=[];
        %按照B8结构元素搜索
        for i=1:length(ind)
            p=ind(i,1);
            if ~isempty(find(ind==p+1)) && ~isempty(find(ind==p+M)) && ~isempty(find(ind==p+M+1)) &&...
                    isempty(find(ind==p-1)) && isempty(find(ind==p-M)) && isempty(find(ind==p-M-1))
                ind_sub=cat(1,ind_sub,i);
            end
        end
        if ~isempty(ind_sub)
            ind(ind_sub)=[];
        end 
    end            
    %m连通检测
    ind_c=[];
    while ~isequal(ind_c,ind)
        ind_c=ind;    
        ind_back=ind;    
        while ~isempty(ind_back)
            p=ind_back(1,:);
            %如果p点四联通中有三个值为1,则将该点置为零
            if (~isempty(find(ind==p+1)) && ~isempty(find(ind==p+M)) && ~isempty(find(ind==p-M))) ||...
                    (~isempty(find(ind==p-1)) && ~isempty(find(ind==p+M)) && ~isempty(find(ind==p-M))) ||...
                    (~isempty(find(ind==p+1)) && ~isempty(find(ind==p-1)) && ~isempty(find(ind==p-M))) ||...
                    (~isempty(find(ind==p+1)) && ~isempty(find(ind==p-1)) && ~isempty(find(ind==p+M)))
                c=find(ind==p);
                ind(c)=[];
    
            end
            %如果p点四联通中有两个值为1,且其对角为0,则将该点置为零
            if (~isempty(find(ind==p+1)) && ~isempty(find(ind==p+M)) && isempty(find(ind==p-M-1))) ||...
                    (~isempty(find(ind==p-1)) && ~isempty(find(ind==p+M)) && isempty(find(ind==p-M+1))) ||...
                    (~isempty(find(ind==p+1)) && ~isempty(find(ind==p-M)) && isempty(find(ind==p+M-1))) ||...
                    (~isempty(find(ind==p-1)) && ~isempty(find(ind==p-M)) && isempty(find(ind==p+M+1)))
                c=find(ind==p);
                ind(c)=[];
            end             
            ind_back(1,:)=[];
        end       
    end
    
    %删除扩展的边缘
    g=zeros(size(I_pad));
    g(ind)=1;
    g=g(2:M-1,2:N-1);
    end

     

    展开全文
  • 基于matlabCanny算法边缘检测(附源代码)

    千次阅读 多人点赞 2020-07-12 10:48:11
    在经典的边缘检测算法中Roberts算子,Prewitt算子,Sobel算子属于一阶差分算子,LoG算子,Canny算子属于二阶差分算子。一阶差分算子,就是求图像灰度变化曲线的导数,从而可以突出图像中的对象边缘,而二阶差分算子...
  • MATLABcanny算子边缘检测

    万次阅读 多人点赞 2018-11-22 08:46:22
    Canny的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是: 好的检测- 算法能够尽可能多地标识出图像中的实际边缘。 好的定位- 标识出的边缘要与实际图像中的实际边缘尽可能接近。 最小响应- 图像中的...
  • Canny边缘检测算子是John F. Canny于1986年开发出来的一个多级边缘检测算法。它的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:①好的检测- 算法能够尽可能多地标识出图像中的实际边缘。②好的定位- ...
  • 小白学习图像处理6——Canny边缘检测算法原理

    千次阅读 多人点赞 2020-04-14 19:08:12
    Canny边缘检测算法主要步骤:高斯滤波、梯度计算、非极大值抑制和双阈值检测。 一、高斯滤波   使用高斯滤波的目的是平滑图像,滤除图像中的部分噪声(因为微分算子对噪声很敏感)。高斯滤波具体办法是生成一个...
  • 基于Canny算子的边缘检测————MATLAB

    万次阅读 多人点赞 2019-05-14 14:14:46
    一、概念 Canny算子是一种非常重要的边缘检测算子,是最优的阶梯型边缘检测算子。它的最优性主要表现在以下三个方面; 好的检测Canny算子可以尽可能多地标识出原始图像中的实际...①去噪声:任何边缘检测算法都不可...
  • 根据项目要求,作为班级项目的一部分编写。
  • Canny边缘检是在在1986年提出来的,到今天已经30多年过去了,但Canny算法仍然是图像边缘检测算法中最经典、先进的算法之一。 相比Sobel、Prewitt等算子,Canny算法更为优异。Sobel、Prewitt等算子有如下缺点: ...
  • 向柱06-23日五万+[图像]Canny检测matlab实现(含代码... Canny边缘检测的基本特点是: (1)必须满足两个条件: ①能有效地抑制噪声;②必须尽可能准确地确定边缘的位置. (2) 通过测量信噪比和位置的乘积,得到最优逼近...
  • Canny边缘检测算法原理及实现(Python + OpenCV)

    万次阅读 多人点赞 2019-05-20 15:00:48
    Canny算法思想 Canny算子是John F.Canny 大佬在1986年在其发表的论文 《Canny J. A computational approach to edge detection [J]. IEEE Transactions on Pattern Analysis and Machine Intelligence, 1986 (6): ...
  • Canny边缘检测算法

    2020-12-21 17:21:35
    MATLABCanny边缘检测API则采用其默认参数,猜测其中高、低阈值可能由自适应算法自行计算。图3和图4的结果表明,相较API,自行编写的Canny检测程序提取到了更多的细节信息,但也保留了较多的局部噪点;API提取的...
  • 基于canny边缘检测算法matlab程序,亲调可用,直接下载......................................................................................................................................................
  • Canny算子边缘检测详细原理(OpenCV+MATLAB实现)

    千次阅读 多人点赞 2018-05-19 22:11:59
    最近老师布置了一个边缘检测的作业,我借此机会详细学习了一下canny算子,在此进行总结,并分别给出OpenCV代码和MATLAB代码,自己水平有限,若有错误或者更好的编程方法,请广大网友留言,一定虚心学习。好了废话少...
  • 预处理、边缘提取、车牌定位、字符分割、字符识别五大模块①正确地分割文字图像区域;②正确的分离单个文字;③正确识别单个字符。用MATLAB软件编程来实现每一个部分,最后识别出汽车牌照。
  • matlab中sobel和kanny算子的算法有多种实现方法,用简单的可以看懂的方式去编写 希望可以帮到大家
  • Canny 边缘检测算子 MATLAB实现

    千次阅读 2016-07-23 21:19:18
    f=imread('e:\lena.bmp'); subplot(1,2,1); imshow(f); title('原图'); [g,t]=edge(f,'canny'); subplot(1,2,2); imshow(g); title('Canny算子分割图');

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,995
精华内容 798
关键字:

canny边缘检测算法matlab

matlab 订阅