OpenCV Canny 源码解析.docx

上传人:b****3 文档编号:27315581 上传时间:2023-06-29 格式:DOCX 页数:19 大小:21.99KB
下载 相关 举报
OpenCV Canny 源码解析.docx_第1页
第1页 / 共19页
OpenCV Canny 源码解析.docx_第2页
第2页 / 共19页
OpenCV Canny 源码解析.docx_第3页
第3页 / 共19页
OpenCV Canny 源码解析.docx_第4页
第4页 / 共19页
OpenCV Canny 源码解析.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

OpenCV Canny 源码解析.docx

《OpenCV Canny 源码解析.docx》由会员分享,可在线阅读,更多相关《OpenCV Canny 源码解析.docx(19页珍藏版)》请在冰豆网上搜索。

OpenCV Canny 源码解析.docx

OpenCVCanny源码解析

OpenCVCanny源码解析

OpenCVCanny源码注释与分析

1986年,JohnF.Canny完善了边缘检测理论,Canny算法以此命名。

Canny算法的步骤:

1.使用滤波器卷积降噪

2.使用Sobel导数计算梯度幅值和方向

3.非极大值抑制+滞后阈值

在正式处理前,用高斯滤平滑波器对图像做滤波降噪的操作,避免噪声点的干扰,但在OpenCV的canny源码中,没有进行高斯滤波,需要使用者自行滤波;有些资料将非极大值抑制和滞后阈值视为两个步骤也是可行的,但是在源码中非极大值抑制和滞后阈值是同时进行的。

canny源码的位置:

\opencv\sources\modules\imgproc\src\canny.cpp

参考了网上许多资料,有不足之处请指正,谢谢。

[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片

/*M///////////////////////////////////////////////////////////////////////////////////////

//

//IMPORTANT:

READBEFOREDOWNLOADING,COPYING,INSTALLINGORUSING.

//

//Bydownloading,copying,installingorusingthesoftwareyouagreetothislicense.

//Ifyoudonotagreetothislicense,donotdownload,install,

//copyorusethesoftware.

//

//

//IntelLicenseAgreement

//ForOpenSourceComputerVisionLibrary

//

//Copyright(C)2000,IntelCorporation,allrightsreserved.

//Thirdpartycopyrightsarepropertyoftheirrespectiveowners.

//

//Redistributionanduseinsourceandbinaryforms,withorwithoutmodification,

//arepermittedprovidedthatthefollowingconditionsaremet:

//

//*Redistribution'sofsourcecodemustretaintheabovecopyrightnotice,

//thislistofconditionsandthefollowingdisclaimer.

//

//*Redistribution'sinbinaryformmustreproducetheabovecopyrightnotice,

//thislistofconditionsandthefollowingdisclaimerinthedocumentation

//and/orothermaterialsprovidedwiththedistribution.

//

//*ThenameofIntelCorporationmaynotbeusedtoendorseorpromoteproducts

//derivedfromthissoftwarewithoutspecificpriorwrittenpermission.

//

//Thissoftwareisprovidedbythecopyrightholdersandcontributors"asis"and

//anyexpressorimpliedwarranties,including,butnotlimitedto,theimplied

//warrantiesofmerchantabilityandfitnessforaparticularpurposearedisclaimed.

//InnoeventshalltheIntelCorporationorcontributorsbeliableforanydirect,

//indirect,incidental,special,emplary,orconsequentialdamages

//(including,butnotlimitedto,procurementofsubstitutegoodsorservices;

//lossofuse,data,orprofits;orbusinessinterruption)howevercaused

//andonanytheoryofliability,whetherincontract,strictliability,

//ortort(includingnegligenceorotherwise)arisinginanywayoutof

//theuseofthissoftware,evenifadvisedofthepossibilityofsuchdamage.

//

//M*/

#include"precomp.hpp"

/*

#ifdefined(HAVE_IPP)&&(IPP_VERSION_MAJOR>=7)

#defineUSE_IPP_CANNY1

#else

#undefUSE_IPP_CANNY

#endif

*/

#ifdefUSE_IPP_CANNY

namespacecv

{

staticboolippCanny(constMat&_src,Mat&_dst,floatlow,floathigh)

{

intsize=0,size1=0;

IppiSizeroi={_src.cols,_src.rows};

ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(roi,ippMskSize3x3,&size);

ippiFilterSobelHorizGetBufferSize_8u16s_C1R(roi,ippMskSize3x3,&size1);

size=std:

:

max(size,size1);

ippiCannyGetSize(roi,&size1);

size=std:

:

max(size,size1);

AutoBufferbuf(size+64);

uchar*buffer=alignPtr((uchar*)buf,32);

Mat_dx(_src.rows,_src.cols,CV_16S);

if(ippiFilterSobelNegVertBorder_8u16s_C1R(_src.data,(int)_src.step,

_dx.ptr(),(int)_dx.step,roi,

ippMskSize3x3,ippBorderRepl,0,buffer)<0)

returnfalse;

Mat_dy(_src.rows,_src.cols,CV_16S);

if(ippiFilterSobelHorizBorder_8u16s_C1R(_src.data,(int)_src.step,

_dy.ptr(),(int)_dy.step,roi,

ippMskSize3x3,ippBorderRepl,0,buffer)<0)

returnfalse;

if(ippiCanny_16s8u_C1R(_dx.ptr(),(int)_dx.step,

_dy.ptr(),(int)_dy.step,

_dst.data,(int)_dst.step,roi,low,high,buffer)<0)

returnfalse;

returntrue;

}

}

#endif

voidcv:

:

Canny(InputArray_src,OutputArray_dst,

doublelow_thresh,doublehigh_thresh,

intaperture_size,boolL2gradient)

{

Matsrc=_src.getMat();//输入图像,必须为单通道灰度图

CV_Assert(src.depth()==CV_8U);//8位无符号

_dst.create(src.size(),CV_8U);//根据src的大小构造目标矩阵dst

Matdst=_dst.getMat();//输出图像,为单通道黑白图

//low_thresh表示低阈值,high_thresh表示高阈值

//aperture_size表示算子大小,默认为3

//L2gradient计算梯度幅值的标识,默认为false

//如果L2gradient为false并且apeture_size的值为-1(-1的二进制标识为:

11111111)

//L2gradient为false则计算sobel导数时,用G=|Gx|+|Gy|

//L2gradient为true则计算sobel导数时,用G=Math.sqrt((Gx)^2+(Gy)^2)根号下开平方

if(!

L2gradient&&(aperture_size&CV_CANNY_L2_GRADIENT)==CV_CANNY_L2_GRADIENT)

{

//CV_CANNY_L2_GRADIENT宏定义其值为:

Value=(1<<31)1左移31位即2147483648

//backwardcompatibility

//~标识按位取反

aperture_size&=~CV_CANNY_L2_GRADIENT;//相当于取绝对值

L2gradient=true;

}

//判别条件1:

aperture_size是奇数

//判别条件2:

aperture_size的范围应当是[3,7],默认值3

if((aperture_size&1)==0||(aperture_size!

=-1&&(aperture_size<3||aperture_size>7)))

CV_Error(CV_StsBadFlag,"");//报错

if(low_thresh>high_thresh)//如果低阈值>高阈值

std:

:

swap(low_thresh,high_thresh);//则交换低阈值和高阈值

#ifdefHAVE_TEGRA_OPTIMIZATION

if(tegra:

:

canny(src,dst,low_thresh,high_thresh,aperture_size,L2gradient))

return;

#endif

#ifdefUSE_IPP_CANNY

if(aperture_size==3&&!

L2gradient&&

ippCanny(src,dst,(float)low_thresh,(float)high_thresh))

return;

#endif

constintcn=src.channels();//cn为输入图像的通道数

Matdx(src.rows,src.cols,CV_16SC(cn));//存储x方向方向导数的矩阵,CV_16SC(cn):

16位有符号cn通道

Matdy(src.rows,src.cols,CV_16SC(cn));//存储y方向方向导数的矩阵......

/*Sobel参数说明:

(参考cvSobel)

cvSobel(

constCvArr*src,//输入图像

CvArr*dst,//输入图像

intxorder,//x方向求导的阶数

intyorder,//y方向求导的阶数

intaperture_size=3//滤波器的宽和高必须是奇数

);

*/

//BORDER_REPLICATE表示当卷积点在图像的边界时,原始图像边缘的像素会被复制,并用复制的像素扩展原始图的尺寸

//计算x方向的sobel方向导数,计算结果存在dx中

Sobel(src,dx,CV_16S,1,0,aperture_size,1,0,cv:

:

BORDER_REPLICATE);

//计算y方向的sobel方向导数,计算结果存在dy中

Sobel(src,dy,CV_16S,0,1,aperture_size,1,0,cv:

:

BORDER_REPLICATE);

//L2gradient为true时,表示需要根号下开平方运算,阈值也需要平方

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;//高阈值平方运算

}

intlow=cvFloor(low_thresh);//cvFloor返回不大于参数的最大整数值,相当于取整

inthigh=cvFloor(high_thresh);

//ptrdiff_t是C/C++标准库中定义的一个数据类型,signed类型,通常用于存储两个指针的差(距离),可以是负数

//mapstep用于存放

ptrdiff_tmapstep=src.cols+2;//+2表示左右各扩展一条边

//AutoBuffer会自动分配一定大小的内存,并且指定内存中的数据类型是uchar

//列数+2表示图像左右各自扩展一条边(用于复制边缘像素,扩大原始图像)

//行数+2表示图像上下各自扩展一条边

AutoBufferbuffer((src.cols+2)*(src.rows+2)+cn*mapstep*3*sizeof(int));

int*mag_buf[3];//定义一个大小为3的int型指针数组,

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);

intmaxsize=std:

:

max(1<<10,src.cols*src.rows/10);//2的10次幂1024

std:

:

vectorstack(maxsize);//定义指针类型向量,用于存地址

uchar**stack_top=&stack[0];//栈顶指针(指向指针的指针),指向stack[0],stack[0]也是一个指针

uchar**stack_bottom=&stack[0];//栈底指针,初始时栈底指针==栈顶指针

//梯度的方向被近似到四个角度之一(0,45,90,135四选一)

/*sectornumbers

(Top-LeftOrigin)

123

***

***

0*******0

***

***

321

*/

//define定义函数块

//CANNY_PUSH(d)是入栈函数,参数d表示地址指针,让该指针指向的内容为2(int型强制转换成uchar型),并入栈,栈顶指针+1

//2表示像素属于某条边缘可以看下方的注释

//CANNY_POP(d)是出栈函数,栈顶指针-1,然后将-1后的栈顶指针指向的值,赋给d

#defineCANNY_PUSH(d)*(d)=uchar

(2),*stack_top++=(d)

#defineCANNY_POP(d)(d)=*--stack_top

//calculatemagnitudeandangleofgradient,performnon-maximasuppression.

//fillthemapwithoneofthellowingvalues:

//0-thepixelmightbelongtoanedge可能属于边缘

//1-thepixelcannotbelongtoanedge不属于边缘

//2-thepixeldoesbelongtoanedge一定属于边缘

//for内进行非极大值抑制+滞后阈值处理

for(inti=0;i<=src.rows;i++)//i表示第i行

{

//i==0时,_norm指向mag_buf[1]

//i>0时,_norm指向mag_buf[2]

//+1表示跳过每行的第一个元素,因为是后扩展的边,不可能是边缘

int*_norm=mag_buf[(i>0)+1]+1;

if(i

{

short*_dx=dx.ptr(i);//_dx指向dx矩阵的第i行

short*_dy=dy.ptr(i);//_dy指向dy矩阵的第i行

if(!

L2gradient)//如果L2gradient为false

{

for(intj=0;j

_norm[j]=std:

:

abs(int(_dx[j]))+std:

:

abs(int(_dy[j]));//用||+||计算

}

else

{

for(intj=0;j

//用平方计算,当L2gradient为true时,高低阈值都被平方了,所以此处_norm[j]无需开平方

_norm[j]=int(_dx[j])*_dx[j]+int(_dy[j])*_dy[j];//

}

if(cn>1)//如果不是单通道

{

for(intj=0,jn=0;j

{

intmaxIdx=jn;

for(intk=1;k

if(_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;//最后一列和第一列的梯度幅值设置为0

}

//当i==src.rows(最后一行)时,申请空间并且每个空间的值初始化为0,存储在mag_buf[2]中

else

memset(_norm-1,0,/*cn**/mapstep*sizeof(int));

//attheverybeginningwedonothaveacompletering

//bufferof3magnituderowsfornon-maximasuppression

if(i==0)

continue;

uchar*_map=map+mapstep*i+1;//_map指向第i+1行,+1表示跳过该行第一个元素

_map[-1]=_map[src.cols]=1;//第一列和最后一列不是边缘,所以设置为1

int*_mag=mag_buf[1]+1;//takethecentralrow中间那一行

ptrdiff_tmagstep1=mag_buf[2]-mag_buf[1];

ptrdiff_tmagstep2=mag_buf[0]-mag_buf[1];

constshort*_x=dx.ptr(i-1);

constshort*

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 职业教育 > 职业技术培训

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1