[图像]Canny检测的Matlab实现(含代码)

原创文章,欢迎转载。转载请注明:转载自 祥的博客

原文链接:http://blog.csdn.net/humanking7/article/details/46606791



图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是一个阶跃,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。

Canny边缘检测基本特征如下:

(1) 必须满足两个条件:①能有效地抑制噪声;②必须尽量精确确定边缘的位置。

(2) 根据对信噪比与定位乘积进行测度,得到最优化逼近算子。这就是Canny边缘检测算子。

(3) 类似与Marr(LoG)边缘检测方法,也属于先平滑后求导数的方法。

Canny边缘检测算法步骤:

步骤1:用高斯滤波器平滑处理原图像;

步骤2:用一阶偏导的有限差分进行计算梯度的幅值和方向;

步骤3:对梯度幅值进行非极大值抑制;

步骤4:用双阈值算法检测和连接边缘。

步骤详解

步骤1:用高斯滤波器平滑处理原图像

使用平滑滤波的原因从根本上来说是边缘检测算子中的导数计算。导数计算对噪声十分敏感,如果不提前使用滤波器加以改善,则在导数计算后,噪声将会被放大,使得检测出来的虚假边缘变多,不利于边缘的提取。

平滑滤波和边缘检测是一对矛盾的概念。一方面,平滑滤波能够有效的抑制噪声,而在此过程中会使得图像边缘模糊,增加了边缘定位的不确定性。另一方面,平滑滤波能够除去对边缘检测中导数运算敏感的噪声,有效的抑制了虚假边缘的产生。实际工程经验表明,高斯滤波器可以在抗噪声干扰和边缘检测精确定位之间提供一个较好的折中方案。

步骤2:用一阶偏导的有限差分进行计算梯度的幅值和方向

图像的边缘有方向和幅度两个属性,沿边缘方向像素变化平缓,垂直于边缘方向像素变化剧烈,边缘上的这种变化可以用微分算子检测出来,通常用一阶或二阶导数来检测边缘.

由上图可以看出,一阶导数可以用于检测图像中的一个点是否是边缘点(也就是判断一个点是否在斜坡上)。同样,二阶导数的符号可以用于判断一个边缘像素是否在亮的一边还是暗的一边。

用一阶偏导的有限差分来计算梯度的幅值和方向。

下图中,图a经过梯度计算后的得到梯度三维示意图b。图b中x和y代表图像像素位置,竖轴的数值反映了梯度幅值的大小。由公式(3-17)可知,边缘方向与梯度方向是相垂直的,如图b所示。

步骤3:对梯度幅值进行非极大值抑制

步骤4:用双阈值算法检测和连接边缘

代码

主函数代码

主函数代码文件main.m


clear all;
clear
clc;
%读进图像
[filename, pathname] = uigetfile({‘*.jpg‘; ‘*.bmp‘; ‘*.gif‘}, ‘选择图片‘);

%没有图像
if filename == 0
    return;
end

imgsrc = imread([pathname, filename]);
[y, x, dim] = size(imgsrc);

%转换为灰度图
if dim>1
    imgsrc = rgb2gray(imgsrc);
end

sigma = 1;
gausFilter = fspecial(‘gaussian‘, [3,3], sigma);
img= imfilter(imgsrc, gausFilter, ‘replicate‘);

zz = double(img);

 %----------------------------------------------------------
 %自己的边缘检测函数
 [m theta sector canny1  canny2 bin] = canny1step(img, 22);
  [msrc thetasrc sectorsrc c1src  c2src binsrc] = canny1step(imgsrc, 22);
 %Matlab自带的边缘检测
 ed = edge(img, ‘canny‘, 0.5); 

[xx, yy] = meshgrid(1:x, 1:y);

figure(1)
    %mesh(yy, xx, zz);
    surf(yy, xx, zz);
    xlabel(‘y‘);
    ylabel(‘x‘);
    zlabel(‘Grayscale‘);
    axis tight

figure(2)
    subplot(4,2,1);
        imshow(imgsrc);%原图
    subplot(4,2,2);
        imshow(img);%高斯滤波后
    subplot(4,2,3);
        imshow(uint8(m));%导数
    subplot(4,2,4);
        imshow(uint8(canny1));%非极大值抑制
    subplot(4,2,5);
        imshow(uint8(canny2));%双阈值
    subplot(4,2,6);
        imshow(ed);%Matlab自带边缘检测
    subplot(4,2,8);
        imshow(bin);%我自己的bin

figure(3)
    edzz = 255*double(ed);
    mesh(yy,xx,edzz);
    xlabel(‘y‘);
    ylabel(‘x‘);
    zlabel(‘Grayscale‘);
    axis tight 

figure(4)
    mesh(yy,xx,m);%画偏导数
    xlabel(‘y‘);
    ylabel(‘x‘);
    zlabel(‘Derivative‘);
    axis tight 

figure(5)
    mesh(yy,xx,theta);
    xlabel(‘y‘);
    ylabel(‘x‘);
    zlabel(‘Theta‘);
    axis tight

figure(6)
    mesh(yy,xx,sector);
    xlabel(‘y‘);
    ylabel(‘x‘);
    zlabel(‘Sector‘);
    axis tight

figure(7)
    mesh(yy,xx,canny2);
    xlabel(‘y‘);
    ylabel(‘x‘);
    zlabel(‘Sector‘);
    axis tight

Canny边缘检测函数代码

Canny边缘检测函数文件canny1step.m

function [ m, theta, sector, canny1,  canny2, bin] = canny1step( src,  lowTh)
%canny函数第一步,求去x,y方向的偏导,模板如下:
% Gx
% 1  -1
% 1  -1
% Gy
% -1  -1
%  1    1
%------------------------------------
% 输入:
% src:图像,如果不是灰度图转成灰度图
% lowTh:低阈值
% 输出:
% m: 两个偏导的平方差,反映了边缘的强度
% theta:反映了边缘的方向
% sector:将方向分为3个区域,具体如下
% 2 1 0
% 3 X 3
% 0 1 2
% canny1:非极大值
% canny2:双阈值抑制
% bin :     二值化
%--------------------------------------- 

[Ay Ax dim ] = size(src);
%转换为灰度图
if dim>1
    src = rgb2gray(src);
end

src = double(src);
m = zeros(Ay, Ax);
theta = zeros(Ay, Ax);
sector = zeros(Ay, Ax);
canny1 = zeros(Ay, Ax);%非极大值抑制
canny2 = zeros(Ay, Ax);%双阈值检测和连接
bin = zeros(Ay, Ax);
for y = 1:(Ay-1)
    for x = 1:(Ax-1)
        gx =  src(y, x) + src(y+1, x) - src(y, x+1)  - src(y+1, x+1);
        gy = -src(y, x) + src(y+1, x) - src(y, x+1) + src(y+1, x+1);
        m(y,x) = (gx^2+gy^2)^0.5 ;
        %--------------------------------
        theta(y,x) = atand(gx/gy)  ;
        tem = theta(y,x);
        %--------------------------------
        if (tem<67.5)&&(tem>22.5)
            sector(y,x) =  0;
        elseif (tem<22.5)&&(tem>-22.5)
            sector(y,x) =  3;
        elseif (tem<-22.5)&&(tem>-67.5)
            sector(y,x) =   2;
        else
            sector(y,x) =   1;
        end
        %--------------------------------
    end
end
%-------------------------
%非极大值抑制
%------> x
%   2 1 0
%   3 X 3
%y  0 1 2
for y = 2:(Ay-1)
    for x = 2:(Ax-1)
        if 0 == sector(y,x) %右上 - 左下
            if ( m(y,x)>m(y-1,x+1) )&&( m(y,x)>m(y+1,x-1)  )
                canny1(y,x) = m(y,x);
            else
                canny1(y,x) = 0;
            end
        elseif 1 == sector(y,x) %竖直方向
            if ( m(y,x)>m(y-1,x) )&&( m(y,x)>m(y+1,x)  )
                canny1(y,x) = m(y,x);
            else
                canny1(y,x) = 0;
            end
        elseif 2 == sector(y,x) %左上 - 右下
            if ( m(y,x)>m(y-1,x-1) )&&( m(y,x)>m(y+1,x+1)  )
                canny1(y,x) = m(y,x);
            else
                canny1(y,x) = 0;
            end
        elseif 3 == sector(y,x) %横方向
            if ( m(y,x)>m(y,x+1) )&&( m(y,x)>m(y,x-1)  )
                canny1(y,x) = m(y,x);
            else
                canny1(y,x) = 0;
            end
        end
    end%end for x
end%end for y

%---------------------------------
%双阈值检测
ratio = 2;
for y = 2:(Ay-1)
    for x = 2:(Ax-1)
        if canny1(y,x)<lowTh %低阈值处理
            canny2(y,x) = 0;
            bin(y,x) = 0;
            continue;
        elseif canny1(y,x)>ratio*lowTh %高阈值处理
            canny2(y,x) = canny1(y,x);
            bin(y,x) = 1;
            continue;
        else %介于之间的看其8领域有没有高于高阈值的,有则可以为边缘
            tem =[canny1(y-1,x-1), canny1(y-1,x), canny1(y-1,x+1);
                       canny1(y,x-1),    canny1(y,x),   canny1(y,x+1);
                       canny1(y+1,x-1), canny1(y+1,x), canny1(y+1,x+1)];
            temMax = max(tem);
            if temMax(1) > ratio*lowTh
                canny2(y,x) = temMax(1);
                bin(y,x) = 1;
                continue;
            else
                canny2(y,x) = 0;
                bin(y,x) = 0;
                continue;
            end
        end
    end%end for x
end%end for y

end%end of function

结果对比

对比图像

分析

图2所示的四张图片展示了整个边缘检测的过程。

  • 图(a)显示的为图像的梯度值,其三维图像为图3左所示。
  • 图(b)显示了经过极大值抑制之后的图像,可以看出经过非极大值抑制之后,排除非边缘的像素,仅仅保留了一些细的线条,即就是候选的边缘。
  • 图(c)为经过双阈值算法处理过后的二值化图像(选用的低阈值为22,高低阈值之比为2:1),对比图(b)发现此过程有效的抑制了“虚假边缘”的产生,而且也相应的连接了一些断裂的边缘。
  • 图(d)是利用Matlab自带edge函数的Canny方法,可以看出其效果优于我实现的传统Canny程序,说明Matlab在阈值选取原则和梯度算子两方面有自己相应的改进。

图3展示了梯度幅值在非极大值抑制前后的三维效果,对应于图2中的图(a)和图(b)。



注: 本文所用的图像和代码源自于本人的毕设论文。

时间: 2024-12-28 15:57:04

[图像]Canny检测的Matlab实现(含代码)的相关文章

最新场景文字检测进展(含代码)

关于场景文字检测的定义.应用.意义等科普性质的细节这里就不提了,本文是一篇相对比较专业的文章,如果非此领域的同学请绕行.本文主要探讨场景文字主流的方法,并提供了一些创新思路,以及一个基于文献[1]的场景文字检测系统(在csdn上分享了该代码).就我所知(半年前全面搜索过),十分完善的场景文字检测的代码网上是没有的,有的只是一些算法,或者比较过时的系统,本文的出现正是希望通过本人的一点努力填补这个空白,方便广大研究者能够更快入门,至少一开始研究就有一个基本框架. 目前主流的方法主要有两类:基于区域

【练习4.1】图像转换、Canny检测、图像合并、在图像上输出文字

2014-07-17 第四章 细说HighGUI 练习题第1题 题目大致要求: a:(1)从视频文件读入数据,(2)转换为灰度图,(3)做Canny边缘检测,显示在三个窗口 b:将a的三个视频显示在一个窗口中 c:在b步骤的不同部分写上合适的文字标签 代码: 1 #include "stdafx.h" 2 #include <windows.system.h> 3 #include <iostream> 4 #include <cv.h> 5 #in

canny算法的MATLAB和C++实现(转载)

图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是一个阶跃,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值.图象的边缘部分集中了图象的大部分信息,图象边缘的确定与提取对于整个图象场景的识别与理解是非常重要的,同时也是图象分割所依赖的重要特征,边缘检测主要是图象的灰度变化的度量.检测和定位,自从1959提出边缘检测以来,经过五十多年的发展,已有许多中不同的边缘检测方法.根据作者的理解和实践,本文对边缘检测的原理进行了描述,在此基础上着重对Canny检

Opencv 读取视频,随播放滚动的视频条,canny检测。

实现视频条的拖动需要使用全局变量g_slider_position,和回调函数onTrackbarSlider(). 拖动条由函数cvCreateTrackbar()函数产生,具体调用为: 1 cvCreateTrackbar("position", 2 "Original", 3 &g_slider_position, 4 frames, 5 onTrackbarSlider); 6 } “position” 为拖动条名称,“Original”为显示窗口名

OPENCV图像轮廓检测

前面在图像转换的时候学到canny算子,可以检测出图像的轮廓信息,但是,该算子检测到的轮廓信息还需要我们手动的用眼睛去识别,而实际工程应用中,我们需要得到轮廓的具体数学信息,这就涉及到今天的主题,图像轮廓检测. 一.图像轮廓检测 在opencv中,轮廓对应着一系列的点的集合,opencv提供了一个函数,用来获得这些点的集合 API:void finContours(输入图像,输出轮廓点集,输出向量,int 轮廓检索模式,int 轮廓近似方法,Point 轮廓点的可选偏移量) 注:1.输入图像,是

改进的二值图像像素标记算法及程序实现(含代码)

笔者实现了一个论文里面的算法程序,论文(可以网上搜索到,实在搜不到可以联系笔者或留下邮箱发给你)讲解比较到位,按照作者的思路写完了代码,测试效果很好,在此分享一下算法思路及实现代码. 此算法优于一般的像素标记算法,只需扫描一遍就可以得出图像边界.面积等等,大大减少了计算量. 算法描述: 一.全图扫描 对二值图像全图扫描,左到右,上到下,一遇到像素边界就进行判断.像素边界指当前像素灰度为1,其他8领域至少有一个灰度值为0. 1.先依次判断当前像素(i,j)的左侧.左上侧.上侧像素和右上侧像素是否被

球体的双目视觉定位(matlab,附代码)

球体的双目视觉定位(matlab,附代码) 标签(空格分隔): 机器视觉 引言 双目视觉定位是我们的一个课程设计,最近刚做完,拿出来与大家分享一下,实验的目的是在拍摄的照片中识别球体,并求出该球体到相机的实际距离吗,我们要求需要用matlab,但是matlab调用双目摄像头(一个USB口)却老是只能调用双目摄像头中的一个,但是利用Python的OpenCV库却可以同时调用两个,因此我们选用了Python用于拍摄图片. 1.基本流程 备注:因为根据得出的视差图识别出圆球略困难,我们没有采用视差图深

(简单调用篇 02) 图像主体检测 - C++ 简单调用

图像主体检测能检测出图片主体的坐标位置,可使用该接口裁剪出图像主体区域,配合图像识别接口提升识别精度.广泛适用于美图类 app.辅助智能识图等业务场景中. 应用场景 智能美图:根据用户上传照片进行主体检测,实现图像裁剪或背景虚化等功能,可应用于含美图功能 app 等业务场景中 图像识别辅助:可使用图像主体检测裁剪出图像主体区域,配合图像识别接口提升识别精度 接口描述 用户向服务请求检测图像中的主体位置. 请求说明 HTTP 方法: POST 请求 URL: https://aip.baidubc

图像物体检测识别中的LBP特征

1        引言 之前讲了人脸识别中的Haar特征,本文则关注人脸检测中的LBP特征,说是对于人脸检测的,其实对于其他物体也能检测,只需修改训练数据集即可.所以本文的题目是物体检测识别,比如可以检测是否汽车是否有车牌号等. 在opencv实现的haar特征的人脸识别算法中,LBP特征也被支持. haar特征的博文链接:http://blog.csdn.net/stdcoutzyx/article/details/34842233. 2        LBP的历史 1996年,Ojala老大