Canny算子子像素边缘检测方法_薛武
canny用法

Canny算法是一种常用的边缘检测算法,它通过一系列步骤来识别图像中的边缘。
具体步骤如下:
1. 去噪:使用高斯模糊来减少图像中的噪声,因为噪声可能会影响边缘检测的准确性。
高斯模糊可以通过选择一个适当大小的高斯核对图像进行卷积来实现。
2. 计算梯度的幅度与方向:这一步是为了找出图像中亮度变化显著的地方,这些地方通常是边缘所在。
梯度的大小和方向可以帮助确定边缘的强度和方向。
3. 非极大值抑制:在这一步中,算法会细化边缘,确保边缘只有一个像素宽。
这是通过抑制那些在梯度方向上不是最大值的像素来实现的。
4. 双阈值处理:Canny算法使用两个阈值来确定哪些边缘是真实的。
一个高阈值用来识别强边缘,而一个低阈值用来识别弱边缘。
这个步骤有助于区分真正的边缘和由噪声引起的假边缘。
5. 连接边缘:最后,算法会连接那些被标记为弱边缘的像素,如果它们与强边缘相连。
这样可以减少因高斯模糊而导致的边缘丢失问题。
在使用Canny算法时,需要注意选择合适的阈值,因为阈值的选择会影响检测到的边缘数量和质量。
阈值设置得过低可能会导致提取过多的细节边缘,而设置得过高则可能会错过一些真实的边缘。
Canny算法因其优秀的边缘检测性能而被广泛应用于图像处理领域,如图像分割、特征提取等。
在实际应用中,通常需要根据具体的图像内容和需求来调整算法的参数,以获得最佳的边缘检测效果。
Canny算子边缘检测的一种改进方法

Canny算子边缘检测的一种改进方法
王佐成;刘晓冬;薛丽霞
【期刊名称】《计算机工程与应用》
【年(卷),期】2010(046)034
【摘要】传统Canny算子在高斯滤波方差和滞后阈值的选择上需要人工干预,不具备自适应能力.高斯滤波方差的大小选择会影响到去噪和边缘保持效果,用不同尺度的形态学滤波代替高斯滤波,不仅能降低噪声影响,而且可保持边缘强度和细节;滞后阈值的选择会影响到假边缘现象的强弱和真实边缘的连续性,引入Otsu阈值法并将其推广至直方图具有多峰特点的情况,算法可根据图像自身特点选取阈值,使检测出的边缘更加连续并减少假边缘的存在.
【总页数】4页(P202-204,248)
【作者】王佐成;刘晓冬;薛丽霞
【作者单位】重庆邮电大学计算机学院,重庆,400065;重庆邮电大学计算机学院,重庆,400065;重庆邮电大学计算机学院,重庆,400065
【正文语种】中文
【中图分类】TP391
【相关文献】
1.基于Canny算子图像边缘检测的改进方法 [J], 陈世文;丘威;房宜汕
2.一种基于Canny算子的图像边缘检测方法 [J], 辛玉欣;王传洋
3.一种形态学与Canny算子融合的焊接熔池边缘检测算法 [J], 张亚红;覃科;
4.一种形态学与Canny算子融合的焊接熔池边缘检测算法 [J], 张亚红;覃科
5.一种改进型Canny算子边缘检测算法 [J], 朱秋林; 石银涛; 李靖
因版权原因,仅展示原文概要,查看原文内容请购买。
Canny检测算法与实现

Canny检测算法与实现1、原理图象边缘就是图像颜⾊快速变化的位置,对于灰度图像来说,也就是灰度值有明显变化的位置。
图像边缘信息主要集中在⾼频段,图像锐化或检测边缘实质就是⾼通滤波。
数值微分可以求变化率,在图像上离散值求梯度,图像处理中有多种边缘检测(梯度)算⼦,常⽤的包括普通⼀阶差分,Robert算⼦(交叉差分),Sobel算⼦,⼆阶拉普拉斯算⼦等等,是基于寻找梯度强度。
Canny 边缘检测算法是John F. Canny 于1986年开发出来的⼀个多级边缘检测算法,也被很多⼈认为是边缘检测的最优算法, 最优边缘检测的三个主要评价标准是:低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产⽣的误报。
⾼定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。
最⼩响应: 图像中的边缘只能标识⼀次。
Canny算⼦求边缘点具体算法步骤如下:1. ⽤⾼斯滤波器平滑图像.2. ⽤⼀阶偏导有限差分计算梯度幅值和⽅向.3. 对梯度幅值进⾏⾮极⼤值抑制.4. ⽤双阈值算法检测和连接边缘.2、实现步骤2.1、消除噪声使⽤⾼斯平滑滤波器卷积降噪。
下⾯显⽰了⼀个 size = 5 的⾼斯内核⽰例:2.2、计算梯度幅值和⽅向按照Sobel滤波器的步骤,计算⽔平和垂直⽅向的差分Gx和Gy:在vs中可以看到sobel像素值和形状:梯度幅值和⽅向为:梯度⽅向近似到四个可能⾓度之⼀(⼀般 0, 45, 90, 135)。
2.3、⾮极⼤值抑制⾮极⼤值抑制是指寻找像素点局部最⼤值。
sobel算⼦检测出来的边缘太粗了,我们需要抑制那些梯度不够⼤的像素点,只保留最⼤的梯度,从⽽达到瘦边的⽬的。
沿着梯度⽅向,⽐较它前⾯和后⾯的梯度值,梯度不够⼤的像素点很可能是某⼀条边缘的过渡点,排除⾮边缘像素,最后保留了⼀些细线。
在John Canny提出的Canny算⼦的论⽂中,⾮最⼤值抑制就只是在0、90、45、135四个梯度⽅向上进⾏的,每个像素点梯度⽅向按照相近程度⽤这四个⽅向来代替。
Canny算子子像素边缘检测方法

Canny算子子像素边缘检测方法薛武;张永生;董广军;纪松;于英【期刊名称】《遥感信息》【年(卷),期】2013(028)001【摘要】This paper employs a quadratic interpolation of the values of the gradient norm by using three values in the gradient direction and then returns the position of the local maxima point as the exact position of the edge. The main advantage of this new method over other edge detectors is that it increases the edge detection accuracy to the level of sub-pixels while keeping the original amount of calculation.%在Canny算子的基础上,通过对梯度模值的内插求得沿边缘点梯度方向上相邻像素的梯度模值,利用这些梯度模值拟合二次曲线求出其极大值得到子像素定位的精确位置.通过推导,证明了梯度模在梯度方向上的极大值点就是边缘的精确位置.该算法在几乎没有增加计算量的前提下将Canny算子边缘检测精度提高到了子像素级.【总页数】4页(P8-10,15)【作者】薛武;张永生;董广军;纪松;于英【作者单位】信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052;信息工程大学测绘学院,郑州450052【正文语种】中文【中图分类】TP79【相关文献】1.基于改进的Canny算子和Zernike矩的亚像素边缘检测方法 [J], 马艳娥;高磊;吕晶晶;刘国鹏;张波涛2.融合Canny算子和小波变换的边缘检测方法 [J], 赵静;杨化超3.一种基于Canny算子的图像边缘检测方法 [J], 辛玉欣;王传洋4.基于改进Canny算子的磁共振T2加权图像边缘检测方法研究 [J], 和清源;焦青亮;蒋依芹;傅瑜;刘子龙;于坤;张朋;王永中5.基于改进RGHS和Canny算子的水下图像边缘检测方法 [J], 王慧芳;陈远明;彭荣发;洪晓斌因版权原因,仅展示原文概要,查看原文内容请购买。
(完整版)Canny边缘检测算法总结

一.Canny边缘检测算法原理JohnCanny于1986年提出Canny算子,属于是先平滑后求导数的方法。
其处理过程大体上分为下面四部分。
1. 对原始图像进行灰度化Canny算法通常处理的图像为灰度图,因此如果获取的是彩色图像,那首先就得进行灰度化。
对一幅彩色图进行灰度化,就是根据图像各个通道的采样值进行加权平均。
以RGB格式的彩图为例,通常灰度化采用的方法主要有:方法1:Gray=(R+G+B)/3;方法2:Gray=0.299R+0.587G+0.114B;(这种参数考虑到了人眼的生理特点)至于其他格式的彩色图像,可以根据相应的转换关系转为RGB然后再进行灰度化;在编程时要注意图像格式中RGB的顺序通常为BGR。
2. 对图像进行高斯滤波图像高斯滤波的实现可以用两个一维高斯核分别两次加权实现,也可以通过一个二维高斯核一次卷积实现。
1)高斯核实现上式为离散化的一维高斯函数,确定参数就可以得到一维核向量。
上式为离散化的二维高斯函数,确定参数就可以得到二维核向量。
在求得高斯核后,要对整个核进行归一化处理。
2)图像高斯滤波对图像进行高斯滤波,其实就是根据待滤波的像素点及其邻域点的灰度值按照一定的参数规则进行加权平均。
这样可以有效滤去理想图像中叠加的高频噪声。
通常滤波和边缘检测是矛盾的概念,抑制了噪声会使得图像边缘模糊,这会增加边缘定位的不确定性;而如果要提高边缘检测的灵敏度,同时对噪声也提高了灵敏度。
实际工程经验表明,高斯函数确定的核可以在抗噪声干扰和边缘检测精确定位之间提供较好的折衷方案。
3. 用一阶偏导的有限差分来计算梯度的幅值和方向关于图像灰度值得梯度可使用一阶有限差分来进行近似,这样就可以得图像在x和y 方向上偏导数的两个矩阵。
常用的梯度算子有如下几种:1)Roberts算子上式为其x和y方向偏导数计算模板,可用数学公式表达其每个点的梯度幅值为:2)Sobel算子上式三个矩阵分别为该算子的x向卷积模板、y向卷积模板以及待处理点的邻域点标记矩阵,据此可用数学公式表达其每个点的梯度幅值为:3)Prewitt算子和Sobel算子原理一样,在此仅给出其卷积模板。
一种改进的Canny算子边缘检测算法

一种改进的Canny算子边缘检测算法宗露艳;吴陈【摘要】边缘是图像的基本特征之一,因此在图像处理中图像边缘检测是图像处理的一个重要部分.由于传统的Canny边缘检测算法是通过在2×2领域内求有限差分来计算梯度幅值的,易受噪声的影响,容易检测出孤立点和伪边缘.在基于传统的Canny边缘检测算法的基础上,采用3×3领域的梯度幅值计算方法,提高了边缘的定位精度,改善了对噪声的敏感性.实验结果表明,该算法在保证实时性的同时,具有更好的检测精度和准确度.%Edge is one of the basic characteristics of the image, so image edge detection is an important part of image proccssing.The traditional Canny edge detection algorithm found finite difference in 2 × 2 field to calculate gradient amplitude, so it can be easily affected by the noise, and the outlier and untrue edge can be easily detected.A 3×3 field gradient magnitude calculation method is used based on the traditional Canny edge detection algorithm.This method proves that it can improve the image's edge positioning accuracy and the sensitivity tonoise.Experimental results indicate that this algorithm has better examination precision and accuracy during guarantee its real-time performance.【期刊名称】《现代电子技术》【年(卷),期】2011(034)004【总页数】3页(P104-106)【关键词】Canny算子;边缘检测;图像处理;梯度幅值【作者】宗露艳;吴陈【作者单位】江苏科技大学,计算机科学与工程学院,江苏镇江212003;江苏科技大学,计算机科学与工程学院,江苏镇江212003【正文语种】中文【中图分类】TN919-34;TP3910 引言图像的边缘是图像灰度发生空间突变或在梯度方向上发生突变的像素集合。
Canny 边缘检测算法

Canny 边缘检测算法【OpenCV】Canny 边缘检测分类:【OpenCV】2012-08-08 10:17 490人阅读评论(10) 收藏举报Canny 边缘检测算法1986年,JOHN CANNY 提出一个很好的边缘检测算法,被称为Canny编边缘检测器[1]。
Canny边缘检测根据对信噪比与定位乘积进行测度,得到最优化逼近算子,也就是Canny算子。
类似与LoG边缘检测方法,也属于先平滑后求导数的方法。
使用Canny边缘检测器,图象边缘检测必须满足两个条件:能有效地抑制噪声;必须尽量精确确定边缘的位置。
算法大致流程:1、求图像与高斯平滑滤波器卷积:2、使用一阶有限差分计算偏导数的两个阵列P与Q:3、幅值和方位角:4、非极大值抑制(NMS ):细化幅值图像中的屋脊带,即只保留幅值局部变化最大的点。
将梯度角的变化范围减小到圆周的四个扇区之一,方向角和幅值分别为:非极大值抑制通过抑制梯度线上所有非屋脊峰值的幅值来细化M[i,j],中的梯度幅值屋脊.这一算法首先将梯度角θ[i,j]的变化范围减小到圆周的四个扇区之一,如下图所示:5、取阈值将低于阈值的所有值赋零,得到图像的边缘阵列阈值τ取得太低->假边缘阈值τ取得太高->部分轮廊丢失选用两个阈值: 更有效的阈值方案.相关代码Canny算法实现:用高斯滤波器平滑图像(在调用Canny之前自己用blur平滑)用一阶偏导的有限差分来计算梯度的幅值和方向.对梯度幅值应用非极大值抑制.用双阈值算法检测和连接边缘.[cpp] view plaincopyprint?void cv::Canny( InputArray _src, OutputArray _dst,double low_thresh, double high_thresh,int aperture_size, bool L2gradient ){Mat src = _src.getMat();CV_Assert( src.depth() == CV_8U );_dst.create(src.size(), CV_8U);Mat dst = _dst.getMat();if (!L2gradient && (aperture_size &CV_CANNY_L2_GRADIENT) ==CV_CANNY_L2_GRADIENT){//backward compatibilityaperture_size &= ~CV_CANNY_L2_GRADIENT;L2gradient = true;}if ((aperture_size & 1) == 0 || (aperture_size != -1 && (aperture_size 7)))CV_Error(CV_StsBadFlag, "");#ifdef HA VE_TEGRA_OPTIMIZATIONif (tegra::canny(src, dst, low_thresh, high_thresh, aperture_size, L2gradient))return;#endifconst int cn = src.channels();cv::Mat dx(src.rows, src.cols, CV_16SC(cn));cv::Mat dy(src.rows, src.cols, CV_16SC(cn));cv::Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0,cv::BORDER_REPLICATE);cv::Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, cv::BORDER_REPLICATE);if (low_thresh > high_thresh)std::swap(low_thresh, high_thresh);if (L2gradient){low_thresh = std::min(32767.0, low_thresh);high_thresh = std::min(32767.0, high_thresh);if (low_thresh > 0) low_thresh *= low_thresh;if (high_thresh > 0) high_thresh *= high_thresh;}int low = cvFloor(low_thresh);int high = cvFloor(high_thresh);ptrdiff_t mapstep = src.cols + 2;cv::AutoBuffer buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int));int* mag_buf[3];mag_buf[0] = (int*)(uchar*)buffer;mag_buf[1] = mag_buf[0] + mapstep*cn;mag_buf[2] = mag_buf[1] + mapstep*cn;memset(mag_buf[0], 0, /* cn* */mapstep*sizeof(int));uchar* map = (uchar*)(mag_buf[2] + mapstep*cn); memset(map, 1, mapstep);memset(map + mapstep*(src.rows + 1), 1, mapstep);int maxsize = std::max(1std::vector stack(maxsize);uchar **stack_top = &stack[0];uchar **stack_bottom = &stack[0];/* sector numbers(Top-Left Origin)1 2 3* * ** * *0*******0* * ** * *3 2 1*/#define CANNY_PUSH(d) *(d) = uchar(2), *stack_top++ = (d)#define CANNY_POP(d) (d) = *--stack_top// calculate magnitude and angle of gradient, performnon-maxima supression.// fill the map with one of the following values:// 0 - the pixel might belong to an edge// 1 - the pixel can not belong to an edge// 2 - the pixel does belong to an edgefor (int i = 0; i{int* _norm = mag_buf[(i > 0) + 1] + 1;if (i{short* _dx = dx.ptrshort>(i);short* _dy = dy.ptrshort>(i);if (!L2gradient){for (int j = 0; j_norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j])); }else{for (int j = 0; j_norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j];}if (cn > 1){for(int j = 0, jn = 0; j{int maxIdx = jn;for(int k = 1; kif(_norm[jn + k] > _norm[maxIdx]) maxIdx = jn + k;_norm[j] = _norm[maxIdx];_dx[j] = _dx[maxIdx];_dy[j] = _dy[maxIdx];}}_norm[-1] = _norm[src.cols] = 0;}elsememset(_norm-1, 0, /* cn* */mapstep*sizeof(int));// at the very beginning we do not have a complete ring// buffer of 3 magnitude rows for non-maxima suppressionif (i == 0)continue;uchar* _map = map + mapstep*i + 1;_map[-1] = _map[src.cols] = 1;int* _mag = mag_buf[1] + 1; // take the central row ptrdiff_t magstep1 = mag_buf[2] - mag_buf[1]; ptrdiff_t magstep2 = mag_buf[0] - mag_buf[1];const short* _x = dx.ptrshort>(i-1);const short* _y = dy.ptrshort>(i-1);if ((stack_top - stack_bottom) + src.cols > maxsize) {int sz = (int)(stack_top - stack_bottom);maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;}int prev_flag = 0;for (int j = 0; j{#define CANNY_SHIFT 15const int TG22 =(int)(0.4142135623730950488016887242097*(1 int m = _mag[j];if (m > low){int xs = _x[j];int ys = _y[j];int x = std::abs(xs);int y = std::abs(ys)int tg22x = x * TG22;if (y{if (m > _mag[j-1] && m >= _mag[j+1]) goto __ocv_canny_push;}else{int tg67x = tg22x + (xif (y > tg67x){if (m > _mag[j+magstep2] && m >= _mag[j+magstep1]) goto __ocv_canny_push;}else{int s = (xs ^ ys)if (m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s]) goto __ocv_canny_push;}}}prev_flag = 0;_map[j] = uchar(1);continue;__ocv_canny_push:if (!prev_flag && m > high && _map[j-mapstep] != 2){CANNY_PUSH(_map + j);prev_flag = 1;}else_map[j] = 0;}// scroll the ring buffer_mag = mag_buf[0];mag_buf[0] = mag_buf[1];mag_buf[1] = mag_buf[2];mag_buf[2] = _mag;}// now track the edges (hysteresis thresholding)while (stack_top > stack_bottom){uchar* m;if ((stack_top - stack_bottom) + 8 > maxsize) {int sz = (int)(stack_top - stack_bottom); maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;}CANNY_POP(m);if (!m[-1]) CANNY_PUSH(m - 1);if (!m[1]) CANNY_PUSH(m + 1);if (!m[-mapstep-1]) CANNY_PUSH(m - mapstep - 1); if (!m[-mapstep]) CANNY_PUSH(m - mapstep);if (!m[-mapstep+1]) CANNY_PUSH(m - mapstep + 1); if (!m[mapstep-1]) CANNY_PUSH(m + mapstep - 1); if (!m[mapstep]) CANNY_PUSH(m + mapstep);if (!m[mapstep+1]) CANNY_PUSH(m + mapstep + 1); }// the final pass, form the final imageconst uchar* pmap = map + mapstep + 1;uchar* pdst = dst.ptr();for (int i = 0; i{for (int j = 0; jpdst[j] = (uchar)-(pmap[j] >> 1);}} void cv::Canny( InputArray _src, OutputArray _dst,double low_thresh, double high_thresh,int aperture_size, bool L2gradient ){Mat src = _src.getMat();CV_Assert( src.depth() == CV_8U );_dst.create(src.size(), CV_8U);Mat dst = _dst.getMat(); if (!L2gradient && (aperture_size & CV_CANNY_L2_GRADIENT) ==CV_CANNY_L2_GRADIENT){//backward compatibilityaperture_size &= ~CV_CANNY_L2_GRADIENT;L2gradient = true;} if ((aperture_size & 1) == 0 || (aperture_size != -1 && (aperture_size 7)))CV_Error(CV_StsBadFlag, "");#ifdefHA VE_TEGRA_OPTIMIZATIONif (tegra::canny(src, dst, low_thresh, high_thresh, aperture_size, L2gradient))return;#endif const int cn = src.channels();cv::Mat dx(src.rows, src.cols, CV_16SC(cn));cv::Mat dy(src.rows, src.cols, CV_16SC(cn));cv::Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0,cv::BORDER_REPLICATE);cv::Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, cv::BORDER_REPLICATE); if (low_thresh > high_thresh) std::swap(low_thresh, high_thresh); if(L2gradient){low_thresh = std::min(32767.0, low_thresh);high_thresh = std::min(32767.0, high_thresh);if (low_thresh > 0) low_thresh *= low_thresh;if (high_thresh > 0) high_thresh *= high_thresh;}int low = cvFloor(low_thresh);int high = cvFloor(high_thresh); ptrdiff_t mapstep =src.cols + 2;cv::AutoBuffer buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int));int* mag_buf[3];mag_buf[0] = (int*)(uchar*)buffer;mag_buf[1] = mag_buf[0] + mapstep*cn;mag_buf[2] = mag_buf[1] + mapstep*cn;memset(mag_buf[0], 0, /* cn* */mapstep*sizeof(int)); uchar* map = (uchar*)(mag_buf[2] + mapstep*cn);memset(map, 1, mapstep);memset(map + mapstep*(src.rows + 1), 1, mapstep);int maxsize = std::max(1 << 10, src.cols * src.rows / 10);std::vector stack(maxsize);uchar **stack_top = &stack[0];uchar **stack_bottom = &stack[0]; /* sector numbers (Top-Left Origin) 1 2 3* * ** * *0*******0* * ** * *3 2 1*/ #define CANNY_PUSH(d) *(d) = uchar(2),*stack_top++ = (d)#define CANNY_POP(d) (d) = *--stack_top // calculate magnitude and angle of gradient, perform non-maxima supression.// fill the map with one of the following values:// 0 - the pixel might belong to an edge// 1 - the pixel can not belong to an edge// 2 - the pixel does belong to an edgefor (int i = 0; i 0) + 1] + 1;if (i < src.rows){short* _dx = dx.ptr(i);short* _dy = dy.ptr(i); if(!L2gradient){for (int j = 0; j < src.cols*cn; j++)_norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j]));}else{for (int j = 0; j 1){for(int j = 0, jn = 0; j _norm[maxIdx]) maxIdx = jn + k;_norm[j] = _norm[maxIdx];_dx[j] = _dx[maxIdx];_dy[j] = _dy[maxIdx];}}_norm[-1] = _norm[src.cols] = 0;}elsememset(_norm-1, 0, /* cn**/mapstep*sizeof(int));// at the very beginning we do not have a complete ring// buffer of 3 magnitude rows for non-maxima suppressionif (i == 0)continue; uchar* _map = map +mapstep*i + 1;_map[-1] = _map[src.cols] = 1; int* _mag = mag_buf[1] + 1; // take the central rowptrdiff_t magstep1 = mag_buf[2] - mag_buf[1];ptrdiff_t magstep2 = mag_buf[0] - mag_buf[1]; const short* _x = dx.ptr(i-1);const short* _y = dy.ptr(i-1); if ((stack_top - stack_bottom) + src.cols > maxsize){int sz = (int)(stack_top - stack_bottom);maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;} int prev_flag = 0;for (int j = 0; j < src.cols; j++){#define CANNY_SHIFT 15const int TG22 =(int)(0.4142135623730950488016887242097*(1 low){int xs = _x[j];int ys = _y[j];int x = std::abs(xs);int y = std::abs(ys) = _mag[j+1]) goto __ocv_canny_push;}else{int tg67x = tg22x + (x =_mag[j+magstep1]) goto __ocv_canny_push;}else{int s = (xs ^ ys)_mag[j+magstep1+s]) goto __ocv_canny_push;}}}prev_flag = 0;_map[j] = uchar(1);continue;__ocv_canny_push:if (!prev_flag && m > high &&_map[j-mapstep] != 2){CANNY_PUSH(_map + j);prev_flag = 1;}else_map[j] = 0;} // scroll the ring buffer_mag = mag_buf[0];mag_buf[0] = mag_buf[1];mag_buf[1] = mag_buf[2];mag_buf[2] = _mag;} // now track the edges (hysteresis thresholding) while (stack_top > stack_bottom){uchar* m;if ((stack_top - stack_bottom) + 8 > maxsize){int sz = (int)(stack_top - stack_bottom);maxsize = maxsize * 3/2;stack.resize(maxsize);stack_bottom = &stack[0];stack_top = stack_bottom + sz;} CANNY_POP(m); if (!m[-1]) CANNY_PUSH(m - 1);if (!m[1]) CANNY_PUSH(m + 1);if (!m[-mapstep-1]) CANNY_PUSH(m - mapstep - 1);if (!m[-mapstep]) CANNY_PUSH(m - mapstep);if (!m[-mapstep+1]) CANNY_PUSH(m - mapstep + 1);if (!m[mapstep-1]) CANNY_PUSH(m + mapstep - 1);if (!m[mapstep]) CANNY_PUSH(m + mapstep);if (!m[mapstep+1]) CANNY_PUSH(m + mapstep + 1);} // the final pass, form the final imageconst uchar* pmap = map + mapstep + 1;uchar* pdst = dst.ptr();for (int i = 0; i 1);}}Canny() 调用接口(C++):[cpp] viewplaincopyprint?void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2,int apertureSize=3, bool L2gradient=false ) voidCanny(InputArray image, OutputArray edges, double threshold1, double threshold2,int apertureSize=3, boolL2gradient=false )实践示例[cpp] viewplaincopyprint?Mat src, src_gray;Mat dst, detected_edges;int edgeThresh = 1;int lowThreshold;int const max_lowThreshold = 100;int ratio = 3;int kernel_size = 3;char* window_name = "Edge Map";void CannyThreshold(int, void*){/// Reduce noise with a kernel 3x3blur( src_gray, detected_edges, Size(3,3) );/// Canny detectorCanny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );dst = Scalar::all(0);src.copyTo( dst, detected_edges);imshow( window_name, dst );}int main( ){src = imread( "images\\happycat.png" );if( !src.data ){ return -1; }dst.create( src.size(), src.type() );cvtColor( src, src_gray, CV_BGR2GRAY ); namedWindow( window_name,CV_WINDOW_AUTOSIZE );createTrackbar( "Min Threshold:", window_name,&lowThreshold, max_lowThreshold, CannyThreshold ); CannyThreshold(0, 0);waitKey(0);return 0;} Mat src, src_gray;Mat dst, detected_edges;int edgeThresh = 1;int lowThreshold;int const max_lowThreshold = 100;int ratio = 3;int kernel_size = 3;char* window_name = "Edge Map";void CannyThreshold(int, void*){/// Reduce noise with a kernel 3x3blur( src_gray, detected_edges, Size(3,3) );/// Canny detectorCanny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );dst = Scalar::all(0);src.copyTo( dst, detected_edges);imshow( window_name, dst );}int main( ){src = imread( "images\\happycat.png" );if( !src.data ){ return -1; }dst.create( src.size(), src.type() );cvtColor( src, src_gray, CV_BGR2GRAY ); namedWindow( window_name,CV_WINDOW_AUTOSIZE );createTrackbar( "Min Threshold:", window_name,&lowThreshold, max_lowThreshold, CannyThreshold ); CannyThreshold(0, 0);waitKey(0);return 0;} 原图:边缘检测效果图:(从左到右lowThread分别为0、50、100)参考文献:[1] Canny. A Computational Approach to Edge Detection, IEEE Trans. on PatternAnalysis and Machine Intelligence, 8(6), pp. 679-698 (1986).转载请注明出处:/xiaowei_cqu/article/details/7839140资源下载:/detail/xiaowei_cqu/4483966。
canny边缘检测原理

canny边缘检测原理Canny边缘检测,是John F. Canny在1986年发表的论文《A Computational Approach to Edge Detection》中对边缘检测(Edge Detection)技术进行了改进,被认为是一种非常有效的图像边缘检测算法。
它是四个步骤(降噪、计算梯度强度、非最大值抑制和双阈值检测)的顺序应用,能够从图像中检测出边缘特征。
Canny边缘检测中的首先步骤是降噪,通过低通滤波器来做图像的高斯模糊处理,有利于减少噪点的影响,使边缘检测更加准确。
接下来是计算梯度强度,即图像梯度。
采用两个Sobel算子来计算图像的水平和垂直梯度,然后相加就得到图像的梯度强度,即边缘的粗略位置。
第三步是非最大值抑制,Canny算法可以自动减少某些边缘点,即抑制非边缘部分的梯度,使边缘更清晰。
双阈值检测(Double Thresholding)是Canny边缘检测的最后一步,采用双阈值的方法,可以用来调节边缘的细节,把不重要的部分过滤掉,有利于边缘的连接以及信息的提取。
总的来说,Canny边缘检测算法能够有效的对图像进行处理,从而清晰的检测出边缘特征,比其他算法更加精准。
因此,Canny边缘检测算法在图像处理中得到了广泛的应用,是一种非常有用的领域。
虽然Canny边缘检测算法具有较高的准确度,但是它也存在一定的局限性,比如在边缘检测的时候,可能会有一些误差,导致无法准确检测到边缘;另外,它也不适用于那种没有清晰轮廓和边界的图片检测。
因此,想要更好地使用Canny边缘检测算法,就需要在应用前进行充分的测试,以便更好地提取图片中边缘信息,清晰地检测出边缘特征,而不会出现不必要的错误。
从上述描述可以看出,Canny边缘检测算法是一种非常有效的边缘检测算法,具有较高的准确度,但也有一定的局限性,因此在使用时需要结合实际情况,特别是在处理含有较复杂边缘的图片时,需要经过充分的测试和调整,以获得更高的准确度。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
A n E d e d e t e c t i o n M e t h o d o f S u b B a s e d o n C a n n O e r a t o r i x e l - -p g y p
, , , , XU E Wu Z HANG Y o n s h e n D ONG G u a n J I S o n YU Y i n u n - - g g g g g j ( ) S u r v e a n d M a i n C o l l e e, I n o r m a t i o n E n i n e e r i n U n i v e r s i t Z h e n z h o u4 5 0 0 5 2 y p p g g f g g y, g : a e r u a d r a t i c r a d i e n t r a d i A b s t r a c t T h i s e m l o s a i n t e r o l a t i o n o f t h e v a l u e s o f t h e n o r m b u s i n t h r e e v a l u e s i n t h e - p p q g g p y p y g e n t d i r e c t i o n a n d t h e n r e t u r n s t h e o f t h e l o c a l m a x i m a a s t h e e x a c t o f t h e e d e . T h e m a i n a d v a n t a e o f t h i s o s i t i o n o i n t o s i t i o n g g p p p n e w i x e l s m e t h o d o v e r o t h e r e d e d e t e c t o r s i s t h a t i t i n c r e a s e s t h e e d e d e t e c t i o n a c c u r a c t o t h e l e v e l o f s u b w h i l e k e e i n t h e -p g g y p g o r i i n a l a m o u n t o f c a l c u l a t i o n . g : ; ; ; K e w o r d s e d e d e t e c t i o n C a n n o e r a t o r r a d i e n t n o r m; u a d r a t i c f i t t i n c u r v e s u b i x e l r e c i s i o n - -p g y p g q g p y
( ) 信息工程大学测绘学院 , 郑州 4 5 0 0 5 2
摘要 : 在C 通过对梯度模值的内插求 得 沿 边 缘 点 梯 度 方 向 上 相 邻 像 素 的 梯 度 模 值 , 利用 a n n y 算子的基础上 , 这些梯度模值拟合二次曲线求出其极大值得到 子 像 素 定 位 的 精 确 位 置 。 通 过 推 导 , 证明了梯度模在梯度方向上 的极大值点就是边缘的精确位置 。 该算法在几乎没有增加计算量的前提下将 C a n n y 算子边 缘 检 测 精 度 提 高 到 了 子像素级 。 关键词 : 边缘检测 ; 梯度模 ; 二次拟合 ; 子像素精度 C a n n y 算子 ; : / . i s s n . 1 0 0 0-3 1 7 7. 2 0 1 3. 0 1. 0 0 2 d o i 1 0. 3 9 6 9 j ( ) 中图分类号 : T P 7 9 文献标识码 : A 文章编号 : 1 0 0 0-3 1 7 7 2 0 1 3 1 2 5-0 0 0 8-0 3
:
( ) 对图像应用高斯平滑处理 1 C a n n y 指出 高 斯 算 子 对 图 像 平 滑 处 理 是 最 优 的 。 二维高斯平滑算子如下 : ( ) 1 沿水平和垂直两个方向进行微分 , 可以得到 :
x, = e σ) g( y,
-( x +y ) 2 2 σ
2
2
3 C a n n y 算子子像素边缘检测的实现
— 8 —
1期
薛武等 : C a n n y 算子子像素边缘检测方法
2 C a n n y 算子基本原理
, 主要由3 C a n n C a n n 1 9 8 6) y边 缘 检 测 算 子 ( y [ 1] 个目标形成 : 无附加响应的最优检测 、 检测边缘位 置和实际边缘位置 之 间 距 离 最 小 的 正 确 定 位 、 减少 单边缘的多重响应而得到单响应 。 为实现以上 3 个 目 标 , C a n n y边缘检测的主要 步骤如下
1 引 言
在数字图像中 “ 边缘 ” 往往包含着丰富且有用的 信息 , 如城市中的 道 路 、 河 流 的 水 涯 线、 建筑物的边 这些边缘信息在数字摄影测量 、 模式识别等领 界等 , 域有着重要的研 究 意 义 。 因 此 , 边缘检测成为备受 关注的问题 , 人们也提出了许多边缘检测的算子 , 如 S o b e l算子 、 P r e w i t t算 子 、 R o b e r t s算 子 、 L o g 算 子、 C a n n C a n n y 算子 等 。 在 众 多 的 边 缘 检 测 算 子 中 , y
3] , 得到子像素边缘位置 [ 或者将数学形态学 、 数 值分
析方法与传统的边缘检测理论相结合实现子像素检
4] 测与 定 位 [ 等, 但是大多数子像素定位算法存在计
子具有良好的信噪比 , 对单一边缘具有唯一响应 , 较 好的定位 性 能 等 优 点 。 很 多 学 者 也 对 C a n n y算子 但主要 集 中 在 高 低 阈 值 的 自 适 应 选 取 进行过改进 , 以提高边缘检测的 正 确 率 上 , 对其定位精度的研究
1] 。C 算子是目前最受欢迎的边缘检测算子 [ a n n y算
相对较少 。 由 于 C a n n y算子的定位精度是像素级
2] 。 的, 无法 满 足 高 精 度 基 础 地 理 信 息 获 取 的 需 要 [
本文通过对梯度模 在 梯 度 方 向 上 的 抛 物 线 拟 合 , 求 将C 出梯度模局部极大值 的 精 确 位 置 , a n n y算子的 定位精度提高到了 子 像 素 级 , 对于提高边缘的定位 精度 , 更好满足特殊领域的需求具有重要意义 。 子像 素 边 缘 检 测 和 定 位 算 法 的 研 究 较 多 , 常见 通过霍夫变换 和 灰 度 矩 边 缘 直 线 拟 合 的 方 法 的有 :
) ) ( 抑制局部非最大 ( 3 MN S
( ) 3 ( ) 4
图 1 判断像元 A 的梯度模是否是沿梯度方向的极大值
8 3. 2 C a n n y算子子像素边缘检测数学模型 以上 所 述 只 是 子 像 素 边 缘 定 位 的 基 本 原 理 , 需 []
数字图像中的边缘对应图像中灰度变化剧烈的 部分 , 即梯度模值比较大的部分 , 因此可以把边缘检 测问题转换为计算 梯 度 模 值 的 局 部 极 大 值 的 问 题 , 即将梯度模值的局 部 极 大 值 点 作 为 边 缘 , 这一过程 就是 抑 制 局 部 非 最 大 的 过 程 ( N o n a x i m a S u -m - p , ) 。 r e s s i o n NMS p 通过 抑 制 局 部 非 最 大 , 可以提取出图像中粗略 的边缘 信 息 。C a n n y算子通过对每个梯度非零的 点, 沿梯度方向上查找相邻像素的梯度模值 , 如果该 点梯度模值小于任 意 一 个 相 邻 像 素 的 梯 度 模 值 , 将 该点剔除 , 并将其梯度模值设为零 ; 如果该点梯度模 值大于相邻两个像素的梯度模值 , 则将该点保留 , 作 为边缘像素的候选点 。
7] 。 如图 1 所 示 , 像元 A 的梯度向 子像素定位位置 [
x, x, σ) σ) g( y, g( y, , ) ( ) x, =( 2 g( y) x y 通过 微 分 , 把二维平滑算子分解为水平和垂直
两个方向的滤波器 , 从而提高了平滑的速度 。 ( ) 计算图像的梯度 2 传统 C a n n y 算子采用 2×2 邻域一阶偏导的有 限差 分 来 计 算 平 滑 后 的 数 据 阵 列 I( 的梯度幅 x, y) 值和方向 , 其中水平和垂直方向的差分算子分别为 : , , ] , Dx [ i =( I[ i - I[ i + j] j+1 j] [ , ] [ ) / Ii +1j+1 - Ii +1, 2 j] , , Dy [ i =( I[ i - I[ i +1, + j] j] j] , ] ] ) / I[ i - I[ i +1, 2 j+1 j+1 相应位置处的梯度模值和方向分别为 :
第2 8卷 第1期 2 0 1 3年2月
遥 感 信 息 R e m o t e S e n s i n I n f o r m a t i o n g
V o l . 2 8, N o . 1 , F e b .2 0 缘检测方法
薛武 , 张永生 , 董广军 , 纪松 , 于英
3. 1 C a n n y 算子子像素边缘检测基本原理 改进后能 实 现 子 像 素 定 位 的 C a n n y算子主要
是在抑制局部非最 大 的 基 础 上 增 加 了 下 面 的 部 分 : , 如果 ( 处的像元是局部梯度模极大值 , 在梯 度 方 i j) , 向上以 ( 为中心的邻域内用梯度模值拟合出二 i j) 次曲线 , 并求出其极 大 值 点 的 精 确 位 置 作 为 边 缘 的
, 量模为局部极大值 g A 点 沿 梯 度 方 向 相 邻 位 置 B、 C 出的 梯 度 模 值 分 别 由 A 3、 A 4和 A 7、 A 8内插得 到, 用 A、 其 B、 C 三点处 的 梯 度 模 值 拟 合 二 次 曲 线 , 极大值点就是边缘的精确位置 。