转载请说明出处:
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); //转换数据结构 IMGCH1src_(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); }