博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Canny边缘检测原理与C++实现(2)实现部分
阅读量:4952 次
发布时间:2019-06-11

本文共 10063 字,大约阅读时间需要 33 分钟。

转载请说明出处:

  http://blog.csdn.net/zhubaohua_bupt/article/details/73844187

                   本代码实现完全脱离opencv,如果需要显示,可以调用,以便观察检测效果。

首先,由于多次用到图像,所以定义图像数据结构,

DATA.h

#ifndef DATA_#define DATA_#include 
#include
#include"memory.h"using namespace std;typedef unsigned char PIXUC1;typedef float PIXFC1;//单通道 类型图像template
class IMGCH1{public: IMGCH1(unsigned int HEIGHT_,unsigned int WIDTH_,unsigned char INITVALUE); IMGCH1(unsigned int HEIGHT_,unsigned int WIDTH_,PIXVALUETYPE* dataPtr_); ~IMGCH1();PIXVALUETYPE* dataPtr;unsigned int rows;unsigned int cols;};template
IMGCH1
::IMGCH1(unsigned int HEIGHT_,unsigned int WIDTH_,unsigned char INITVALUE):rows(HEIGHT_),cols(WIDTH_){ dataPtr=new PIXVALUETYPE[rows*cols]; memset(dataPtr,INITVALUE,rows*cols);}template
IMGCH1
::IMGCH1(unsigned int HEIGHT_,unsigned int WIDTH_,PIXVALUETYPE* dataPtr_):rows(HEIGHT_),cols(WIDTH_){ dataPtr=new PIXVALUETYPE[rows*cols]; long int datalength =rows*cols; //拷贝数据 PIXVALUETYPE*pt=dataPtr; PIXVALUETYPE*pt_=dataPtr_;for(int i=0;i
IMGCH1
:: ~IMGCH1(){ delete [] dataPtr; }#endif

 

 

MyCanny.h

 

#include "iostream"  #include "math.h"  #include"DATA.h"using namespace std;   class MyCanny{public:void operator()(const IMGCH1
& srcimg,IMGCH1
& CannyImg,int lowthread,int highthread,int gaussSize); //******************灰度转换函数************************* //第一个参数image输入的彩色RGB图像; //第二个参数imageGray是转换后输出的灰度图像; //************************************************************* void ToUchar(const IMGCH1
&floatImage,IMGCH1
&imageUchar);//******************高斯卷积核生成函数************************* // gaus是一个指向含有N个double类型数组的二维指针; // size是高斯卷积核的尺寸大小; // gausArray 是一个指向含有N个double类型数组的一维指针; // sigma是卷积核的标准差 //************************************************************* void GetGaussianKernel(float **gaus, float* gausArray,const int size,const float sigma); //******************高斯滤波************************* //imageSource是待滤波原始图像; //imageGaussian是滤波后输出图像; //gausArray是一个指向含有N个double类型数组的指针; //size是滤波核的尺寸 //************************************************************* void GaussianFilter(const IMGCH1
& srcimg,IMGCH1
&imageGaussian,float gausArray[],int size);//******************Sobel算子计算梯度和方向******************** //imageSourc原始灰度图像; //imageSobelXY是梯度图像; //pointDrection是梯度方向数组指针 //************************************************************* void SobelGradDirection(const IMGCH1
&imageSource,IMGCH1
&imageSobelXY,char *pointDrection); //******************局部极大值抑制************************* //imageInput输入的Sobel梯度图像;//imageOutPut是输出的局部极大值抑制图像;//pointDrection是图像上每个点的梯度方向数组指针 梯度方向角,简化为 0(水平) 45,-45,90(垂直)//************************************************************* void LocalMaxValue(const IMGCH1
&imageInput, IMGCH1
&imageOutput, char *pointDrection); //******************双阈值处理************************* //imageInput经过局部极大值抑制的梯度图 //lowThreshold是低阈值 //highThreshold是高阈值 //****************************************************** void DoubleThreshold( IMGCH1
&imageIput,int lowThreshold,int highThreshold); //******************双阈值中间像素连接处理********************* //imageInput 经过处理的局部极大值抑制的梯度图
0 >highThreshold ->255//函数执行完后是Canny边缘检测图, 边缘(255)其他(0)//lowThreshold是低阈值 //highThreshold是高阈值 //************************************************************* void DoubleThresholdLink(IMGCH1
&imageInput,IMGCH1
&CannyImg,int lowThreshold) ;//******************递归连接边缘********************* //imageInput 梯度幅值图像; // x,y 为要检测点的坐标//lowThreshold是低阈值 //************************************************************* void LinkEdge(IMGCH1
&imageInput,int x,int y,int lowThreshold );void SHOW(const IMGCH1
&imageInput);int width;int height;};

 

MyCanny.cpp

 

#include"MyCanny.h"//为了显示,可以把类里的show函数注释掉,就可以在实现部分不依赖于opencv  #include"opencv.hpp"using namespace cv;void MyCanny::operator()(const IMGCH1
& srcimg_,IMGCH1
& CannyImg_ ,int lowthread,int highthread,int size){ if(srcimg_.cols==0&&srcimg_.rows==0) { cerr<<" imageSource is empty"<
highthread) { cerr<<"Fourth parameter must large than third parameter. "<
imageGaussian_(height,width,PIXUC1(0)); GaussianFilter(srcimg_,imageGaussian_,gausArray,size); //梯度 IMGCH1
SobelGradAmpl_(height,width,PIXUC1(0)); char *pointDirection=new char[srcimg_.cols*srcimg_.rows]; //定义梯度方向角数组 SobelGradDirection(imageGaussian_,SobelGradAmpl_,pointDirection); //计算X、Y方向梯度和方向角 //局部非极大值抑制 IMGCH1
imageLocalMax_(height,width,PIXUC1(0)); LocalMaxValue(SobelGradAmpl_,imageLocalMax_,pointDirection); //双阈值处理 DoubleThreshold(imageLocalMax_,lowthread,highthread); //双阈值中间阈值滤除及连接 DoubleThresholdLink(imageLocalMax_,CannyImg_,lowthread); delete []pointDirection; for(int i=0;i
& imageSource, IMGCH1
&imageGaussian,float *gausArray,int size){ //滤波 for(int _row=0;_row
=imageSource.rows?imageSource.rows-1:row; col=col<0?0:col; col=col>=imageSource.cols?imageSource.cols-1:col; //卷积和 imageGaussian.dataPtr[_row*width+_col]+=gausArray[k]*imageSource.dataPtr[row*width+col]; k++; } } } } } //******************Sobel算子计算X、Y方向梯度和梯度方向角******************** void MyCanny::SobelGradDirection(const IMGCH1
& imageSource, IMGCH1
&SobelAmpXY, char *pointDrection){ for(int i=0;i<(imageSource.rows-1)*(imageSource.cols-1);i++) { pointDrection[i]=0; } IMGCH1
imageSobelX(height,width,PIXFC1(0)); IMGCH1
imageSobelY(height,width,PIXFC1(0)); PIXUC1 *P=imageSource.dataPtr; PIXFC1 *PX=imageSobelX.dataPtr; PIXFC1 *PY=imageSobelY.dataPtr; int k=0; for(int row=1;row<(imageSource.rows-1);row++) { for(int col=1;col<(imageSource.cols-1);col++) { pointDrection[k]=-1; //通过指针遍历图像上每一个像素 int gradY=P[(row-1)*width+col+1]+P[row*width+col+1]*2+P[(row+1)*width+col+1]-P[(row-1)*width+col-1]-P[row*width+col-1]*2-P[(row+1)*width+col-1]; PY[row*width+col]=abs(gradY); int gradX=P[(row+1)*width+col-1]+P[(row+1)*width+col]*2+P[(row+1)*width+col+1]-P[(row-1)*width+col-1]-P[(row-1)*width+col]*2-P[(row-1)*width+col+1]; PX[row*width+col]=abs(gradX); if(gradX==0) { gradX=0.01; //防止除数为0异常 } float gradDrection=atan2(gradY,gradX)*57.3;//弧度转换为度 if(gradDrection<=-67.5&&gradDrection<=-112.5||gradDrection>=67.5&&gradDrection<=-112.5) pointDrection[k]=90; else if(gradDrection>=22.5&&gradDrection<67.5||gradDrection>=-157.5&&gradDrection<-112.5) pointDrection[k]=45; else if(gradDrection>=-67.5&&gradDrection<22.5||gradDrection>=112.5&&gradDrection<157.5) pointDrection[k]=-45; else pointDrection[k]=0; k++; } } IMGCH1
imageSobelXY(height,width,PIXFC1(0)); for(int row=0;row
&imageInput, IMGCH1
&imageOutput, char *pointDrection){ for(int row=0;row
&imageIput,int lowThreshold,int highThreshold){ for(int row=0;row
highThreshold) imageIput.dataPtr[row*width+col]=255; if(imageIput.dataPtr[row*width+col]
&imageInput,IMGCH1
&CannyImg,int lowThreshold){ for(int row=1;row
&imageInput,int x,int y,int lowThreshold ){ int nextpoint_x=-1; int nextpoint_y=-1; if(x<1||x>width-1||y<1||y>height-1) return; if( imageInput.dataPtr[(y-1)*width+x-1]>=lowThreshold&& imageInput.dataPtr[(y-1)*width+x-1]!=255) { nextpoint_x=x-1; nextpoint_y=y-1; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); } else if( imageInput.dataPtr[(y-1)*width+x]>=lowThreshold&&imageInput.dataPtr[(y-1)*width+x]!=255) { nextpoint_x=x; nextpoint_y=y-1; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); } else if(imageInput.dataPtr[(y-1)*width+x+1]>=lowThreshold&&imageInput.dataPtr[(y-1)*width+x+1]!=255) { nextpoint_x=x+1; nextpoint_y=y-1; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); } else if( imageInput.dataPtr[y*width+x-1]>=lowThreshold&&imageInput.dataPtr[y*width+x-1]!=255 ) { nextpoint_x=x-1; nextpoint_y=y; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); } else if( imageInput.dataPtr[y*width+x+1]>=lowThreshold&&imageInput.dataPtr[y*width+x+1]!=255 ) { nextpoint_x=x+1; nextpoint_y=y; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); } else if( imageInput.dataPtr[(y+1)*width+x-1]>=lowThreshold&&imageInput.dataPtr[(y+1)*width+x-1]!=255 ) { nextpoint_x=x-1; nextpoint_y=y+1; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); } else if( imageInput.dataPtr[(y+1)*width+x]>=lowThreshold&& imageInput.dataPtr[(y+1)*width+x]!=255 ) { nextpoint_x=x; nextpoint_y=y+1; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); } else if(imageInput.dataPtr[(y+1)*width+x+1]>=lowThreshold&&imageInput.dataPtr[(y+1)*width+x+1]!=255) { nextpoint_x=x+1; nextpoint_y=y+1; imageInput.dataPtr[nextpoint_y*width+nextpoint_x]=255; LinkEdge(imageInput,nextpoint_x,nextpoint_y,lowThreshold); }}void MyCanny::ToUchar(const IMGCH1
&floatImage,IMGCH1
&imageUchar){ for(int row=0;row
255?255: floatImage.dataPtr[row*width+col];}void MyCanny::SHOW(const IMGCH1
&imageInput){ Mat show=Mat::zeros(imageInput.rows,imageInput.cols,CV_8UC1); for(int row=0;row
(row,col)=imageInput.dataPtr[row*imageInput.cols+col]; } imshow(" ",show); waitKey(0);}

 

 

测试

 

#include"opencv.hpp"using namespace cv;#include"MyCanny.h"using namespace std;int main(){		Mat src=imread("E:\\matchpic\\right_16488.jpg",0);		//转换数据结构	IMGCH1
src_(src.rows,src.cols,PIXUC1(0)); for(int row=0;row
(row,col); Mat Cannyedge=Mat::zeros(src.rows,src.cols,CV_8UC1); IMGCH1
Cannyedge_(src.rows,src.cols,PIXUC1(0)); MyCanny MyCanny_; MyCanny_(src_,Cannyedge_,10,100,3);//检测 //转换回Mat显示 for(int row=0;row
(row,col)=Cannyedge_.dataPtr[row*src.cols+col]; imshow("Cannyedge ",Cannyedge); waitKey(0); }

 

 

 

 

转载于:https://www.cnblogs.com/zhubaohua-bupt/p/7182786.html

你可能感兴趣的文章
HDU6203 ping ping ping
查看>>
前端小笔记
查看>>
《人人都是产品经理》书籍目录
查看>>
Netsharp系列文章目录结构
查看>>
如何在git bash中运行mysql
查看>>
OO第三阶段总结
查看>>
构建之法阅读笔记02
查看>>
初学差分约束
查看>>
HEVC编码学习(一)HM配置
查看>>
通过Spark SQL关联查询两个HDFS上的文件操作
查看>>
DataTable和 DataRow的 区别与联系
查看>>
检索COM 类工厂中CLSID 为 {00024500-0000-0000-C000-000000000046}的组件时失败
查看>>
mysql数据库中数据类型
查看>>
python-实现生产者消费者模型
查看>>
APP网络优化篇
查看>>
算法18-----判断是否存在符合条件的元素【list】
查看>>
《刑法》关于拐卖妇女儿童犯罪的规定
查看>>
Windows的本地时间(LocalTime)、系统时间(SystemTime)、格林威治时间(UTC-Time)、文件时间(FileTime)之间的转换...
查看>>
alias重启后失效了
查看>>
RestTemplate的Object与Entity的区别
查看>>