canny算子的OpenCV实现

  1. <span style="font-size:18px;">#include "core/core.hpp"      
  2. #include "highgui/highgui.hpp"      
  3. #include "imgproc/imgproc.hpp"      
  4. #include "iostream"    
  5. #include "math.h"    
  6.     
  7. using namespace std;     
  8. using namespace cv;      
  9.     
  10. //******************灰度转换函数*************************    
  11. //第一个参数image输入的彩色RGB图像;    
  12. //第二个参数imageGray是转换后输出的灰度图像;    
  13. //*************************************************************    
  14. void ConvertRGB2GRAY(const Mat &image,Mat &imageGray);    
  15.     
  16.     
  17. //******************高斯卷积核生成函数*************************    
  18. //第一个参数gaus是一个指向含有N个double类型数组的指针;    
  19. //第二个参数size是高斯卷积核的尺寸大小;    
  20. //第三个参数sigma是卷积核的标准差    
  21. //*************************************************************    
  22. void GetGaussianKernel(double **gaus, const int size,const double sigma);    
  23.     
  24. //******************高斯滤波*************************    
  25. //第一个参数imageSource是待滤波原始图像;    
  26. //第二个参数imageGaussian是滤波后输出图像;    
  27. //第三个参数gaus是一个指向含有N个double类型数组的指针;    
  28. //第四个参数size是滤波核的尺寸    
  29. //*************************************************************    
  30. void GaussianFilter(const Mat imageSource,Mat &imageGaussian,double **gaus,int size);    
  31.     
  32. //******************Sobel算子计算梯度和方向********************    
  33. //第一个参数imageSourc原始灰度图像;    
  34. //第二个参数imageSobelX是X方向梯度图像;    
  35. //第三个参数imageSobelY是Y方向梯度图像;    
  36. //第四个参数pointDrection是梯度方向数组指针    
  37. //*************************************************************    
  38. void SobelGradDirction(const Mat imageSource,Mat &imageSobelX,Mat &imageSobelY,double *&pointDrection);    
  39.     
  40. //******************计算Sobel的X和Y方向梯度幅值*************************    
  41. //第一个参数imageGradX是X方向梯度图像;    
  42. //第二个参数imageGradY是Y方向梯度图像;    
  43. //第三个参数SobelAmpXY是输出的X、Y方向梯度图像幅值    
  44. //*************************************************************    
  45. void SobelAmplitude(const Mat imageGradX,const Mat imageGradY,Mat &SobelAmpXY);    
  46.     
  47. //******************局部极大值抑制*************************    
  48. //第一个参数imageInput输入的Sobel梯度图像;    
  49. //第二个参数imageOutPut是输出的局部极大值抑制图像;    
  50. //第三个参数pointDrection是图像上每个点的梯度方向数组指针    
  51. //*************************************************************    
  52. void LocalMaxValue(const Mat imageInput,Mat &imageOutput,double *pointDrection);    
  53.     
  54. //******************双阈值处理*************************    
  55. //第一个参数imageInput输入和输出的的Sobel梯度幅值图像;    
  56. //第二个参数lowThreshold是低阈值    
  57. //第三个参数highThreshold是高阈值    
  58. //******************************************************    
  59. void DoubleThreshold(Mat &imageIput,double lowThreshold,double highThreshold);    
  60.     
  61. //******************双阈值中间像素连接处理*********************    
  62. //第一个参数imageInput输入和输出的的Sobel梯度幅值图像;    
  63. //第二个参数lowThreshold是低阈值    
  64. //第三个参数highThreshold是高阈值    
  65. //*************************************************************    
  66. void DoubleThresholdLink(Mat &imageInput,double lowThreshold,double highThreshold);    
  67.     
  68. Mat imageSource;    
  69. Mat imageGray;    
  70. Mat imageGaussian;    
  71.     
  72. int main(int argc,char *argv[])      
  73. {    
  74.     imageSource=imread(argv[1]);  //读入RGB图像    
  75.     imshow("RGB Image",imageSource);    
  76.     ConvertRGB2GRAY(imageSource,imageGray); //RGB转换为灰度图    
  77.     imshow("Gray Image",imageGray);    
  78.     int size=5; //定义卷积核大小    
  79.     double **gaus=new double *[size];  //卷积核数组    
  80.     for(int i=0;i<size;i++)    
  81.     {    
  82.         gaus[i]=new double[size];  //动态生成矩阵    
  83.     }       
  84.     GetGaussianKernel(gaus,5,1); //生成5*5 大小高斯卷积核,Sigma=1;    
  85.     imageGaussian=Mat::zeros(imageGray.size(),CV_8UC1);    
  86.     GaussianFilter(imageGray,imageGaussian,gaus,5);  //高斯滤波    
  87.     imshow("Gaussian Image",imageGaussian);    
  88.     Mat imageSobelY;    
  89.     Mat imageSobelX;    
  90.     double *pointDirection=new double[(imageSobelX.cols-1)*(imageSobelX.rows-1)];  //定义梯度方向角数组    
  91.     SobelGradDirction(imageGaussian,imageSobelX,imageSobelY,pointDirection);  //计算X、Y方向梯度和方向角    
  92.     imshow("Sobel Y",imageSobelY);    
  93.     imshow("Sobel X",imageSobelX);    
  94.     Mat SobelGradAmpl;    
  95.     SobelAmplitude(imageSobelX,imageSobelY,SobelGradAmpl);   //计算X、Y方向梯度融合幅值    
  96.     imshow("Soble XYRange",SobelGradAmpl);    
  97.     Mat imageLocalMax;    
  98.     LocalMaxValue(SobelGradAmpl,imageLocalMax,pointDirection);  //局部非极大值抑制    
  99.     imshow("Non-Maximum Image",imageLocalMax);    
  100.     Mat cannyImage;    
  101.     cannyImage=Mat::zeros(imageLocalMax.size(),CV_8UC1);    
  102.     DoubleThreshold(imageLocalMax,90,160);        //双阈值处理    
  103.     imshow("Double Threshold Image",imageLocalMax);    
  104.     DoubleThresholdLink(imageLocalMax,90,160);   //双阈值中间阈值滤除及连接    
  105.     imshow("Canny Image",imageLocalMax);    
  106.     waitKey();    
  107.     system("pause");    
  108.     return 0;    
  109. }    
  110.     
  111. //******************高斯卷积核生成函数*************************    
  112. //第一个参数gaus是一个指向含有N个double类型数组的指针;    
  113. //第二个参数size是高斯卷积核的尺寸大小;    
  114. //第三个参数sigma是卷积核的标准差    
  115. //*************************************************************    
  116. void GetGaussianKernel(double **gaus, const int size,const double sigma)    
  117. {    
  118.     const double PI=4.0*atan(1.0); //圆周率π赋值    
  119.     int center=size/2;    
  120.     double sum=0;    
  121.     for(int i=0;i<size;i++)    
  122.     {    
  123.         for(int j=0;j<size;j++)    
  124.         {    
  125.             gaus[i][j]=(1/(2*PI*sigma*sigma))*exp(-((i-center)*(i-center)+(j-center)*(j-center))/(2*sigma*sigma));    
  126.             sum+=gaus[i][j];    
  127.         }    
  128.     }    
  129.     for(int i=0;i<size;i++)    
  130.     {    
  131.         for(int j=0;j<size;j++)    
  132.         {    
  133.             gaus[i][j]/=sum;    
  134.             cout<<gaus[i][j]<<"  ";    
  135.         }    
  136.         cout<<endl<<endl;    
  137.     }    
  138.     return ;    
  139. }    
  140.     
  141. //******************灰度转换函数*************************    
  142. //第一个参数image输入的彩色RGB图像;    
  143. //第二个参数imageGray是转换后输出的灰度图像;    
  144. //*************************************************************    
  145. void ConvertRGB2GRAY(const Mat &image,Mat &imageGray)    
  146. {    
  147.     if(!image.data||image.channels()!=3)    
  148.     {    
  149.         return ;    
  150.     }    
  151.     imageGray=Mat::zeros(image.size(),CV_8UC1);    
  152.     uchar *pointImage=image.data;    
  153.     uchar *pointImageGray=imageGray.data;    
  154.     int stepImage=image.step;    
  155.     int stepImageGray=imageGray.step;    
  156.     for(int i=0;i<imageGray.rows;i++)    
  157.     {    
  158.         for(int j=0;j<imageGray.cols;j++)    
  159.         {    
  160.             pointImageGray[i*stepImageGray+j]=0.114*pointImage[i*stepImage+3*j]+0.587*pointImage[i*stepImage+3*j+1]+0.299*pointImage[i*stepImage+3*j+2];    
  161.         }    
  162.     }    
  163. }    
  164.     
  165. //******************高斯滤波*************************    
  166. //第一个参数imageSource是待滤波原始图像;    
  167. //第二个参数imageGaussian是滤波后输出图像;    
  168. //第三个参数gaus是一个指向含有N个double类型数组的指针;    
  169. //第四个参数size是滤波核的尺寸    
  170. //*************************************************************    
  171. void GaussianFilter(const Mat imageSource,Mat &imageGaussian,double **gaus,int size)    
  172. {    
  173.     imageGaussian=Mat::zeros(imageSource.size(),CV_8UC1);    
  174.     if(!imageSource.data||imageSource.channels()!=1)    
  175.     {    
  176.         return ;    
  177.     }    
  178.     double gausArray[100];     
  179.     for(int i=0;i<size*size;i++)    
  180.     {    
  181.         gausArray[i]=0;  //赋初值,空间分配    
  182.     }    
  183.     int array=0;    
  184.     for(int i=0;i<size;i++)    
  185.     {    
  186.         for(int j=0;j<size;j++)    
  187.     
  188.         {    
  189.             gausArray[array]=gaus[i][j];//二维数组到一维 方便计算    
  190.             array++;    
  191.         }    
  192.     }    
  193.     //滤波    
  194.     for(int i=0;i<imageSource.rows;i++)    
  195.     {    
  196.         for(int j=0;j<imageSource.cols;j++)    
  197.         {    
  198.             int k=0;    
  199.             for(int l=-size/2;l<=size/2;l++)    
  200.             {    
  201.                 for(int g=-size/2;g<=size/2;g++)    
  202.                 {    
  203.                     //以下处理针对滤波后图像边界处理,为超出边界的值赋值为边界值    
  204.                     int row=i+l;    
  205.                     int col=j+g;    
  206.                     row=row<0?0:row;    
  207.                     row=row>=imageSource.rows?imageSource.rows-1:row;    
  208.                     col=col<0?0:col;    
  209.                     col=col>=imageSource.cols?imageSource.cols-1:col;    
  210.                     //卷积和    
  211.                     imageGaussian.at<uchar>(i,j)+=gausArray[k]*imageSource.at<uchar>(row,col);    
  212.                     k++;    
  213.                 }    
  214.             }    
  215.         }    
  216.     }    
  217. }    
  218. //******************Sobel算子计算X、Y方向梯度和梯度方向角********************    
  219. //第一个参数imageSourc原始灰度图像;    
  220. //第二个参数imageSobelX是X方向梯度图像;    
  221. //第三个参数imageSobelY是Y方向梯度图像;    
  222. //第四个参数pointDrection是梯度方向角数组指针    
  223. //*************************************************************    
  224. void SobelGradDirction(const Mat imageSource,Mat &imageSobelX,Mat &imageSobelY,double *&pointDrection)    
  225. {    
  226.     pointDrection=new double[(imageSource.rows-1)*(imageSource.cols-1)];    
  227.     for(int i=0;i<(imageSource.rows-1)*(imageSource.cols-1);i++)    
  228.     {    
  229.         pointDrection[i]=0;    
  230.     }    
  231.     imageSobelX=Mat::zeros(imageSource.size(),CV_32SC1);    
  232.     imageSobelY=Mat::zeros(imageSource.size(),CV_32SC1);    
  233.     uchar *P=imageSource.data;      
  234.     uchar *PX=imageSobelX.data;      
  235.     uchar *PY=imageSobelY.data;      
  236.     
  237.     int step=imageSource.step;      
  238.     int stepXY=imageSobelX.step;     
  239.     int k=0;    
  240.     int m=0;    
  241.     int n=0;    
  242.     for(int i=1;i<(imageSource.rows-1);i++)      
  243.     {      
  244.         for(int j=1;j<(imageSource.cols-1);j++)      
  245.         {      
  246.             //通过指针遍历图像上每一个像素     
  247.             double gradY=P[(i-1)*step+j+1]+P[i*step+j+1]*2+P[(i+1)*step+j+1]-P[(i-1)*step+j-1]-P[i*step+j-1]*2-P[(i+1)*step+j-1];    
  248.             PY[i*stepXY+j*(stepXY/step)]=abs(gradY);    
  249.             double gradX=P[(i+1)*step+j-1]+P[(i+1)*step+j]*2+P[(i+1)*step+j+1]-P[(i-1)*step+j-1]-P[(i-1)*step+j]*2-P[(i-1)*step+j+1];    
  250.             PX[i*stepXY+j*(stepXY/step)]=abs(gradX);    
  251.             if(gradX==0)    
  252.             {    
  253.                 gradX=0.00000000000000001;  //防止除数为0异常    
  254.             }    
  255.             pointDrection[k]=atan(gradY/gradX)*57.3;//弧度转换为度    
  256.             pointDrection[k]+=90;    
  257.             k++;    
  258.         }      
  259.     }     
  260.     convertScaleAbs(imageSobelX,imageSobelX);    
  261.     convertScaleAbs(imageSobelY,imageSobelY);    
  262. }    
  263. //******************计算Sobel的X和Y方向梯度幅值*************************    
  264. //第一个参数imageGradX是X方向梯度图像;    
  265. //第二个参数imageGradY是Y方向梯度图像;    
  266. //第三个参数SobelAmpXY是输出的X、Y方向梯度图像幅值    
  267. //*************************************************************    
  268. void SobelAmplitude(const Mat imageGradX,const Mat imageGradY,Mat &SobelAmpXY)    
  269. {    
  270.     SobelAmpXY=Mat::zeros(imageGradX.size(),CV_32FC1);    
  271.     for(int i=0;i<SobelAmpXY.rows;i++)    
  272.     {    
  273.         for(int j=0;j<SobelAmpXY.cols;j++)    
  274.         {    
  275.             SobelAmpXY.at<float>(i,j)=sqrt(imageGradX.at<uchar>(i,j)*imageGradX.at<uchar>(i,j)+imageGradY.at<uchar>(i,j)*imageGradY.at<uchar>(i,j));    
  276.         }    
  277.     }    
  278.     convertScaleAbs(SobelAmpXY,SobelAmpXY);    
  279. }    
  280. //******************局部极大值抑制*************************    
  281. //第一个参数imageInput输入的Sobel梯度图像;    
  282. //第二个参数imageOutPut是输出的局部极大值抑制图像;    
  283. //第三个参数pointDrection是图像上每个点的梯度方向数组指针    
  284. //*************************************************************    
  285. void LocalMaxValue(const Mat imageInput,Mat &imageOutput,double *pointDrection)    
  286. {    
  287.     //imageInput.copyTo(imageOutput);    
  288.     imageOutput=imageInput.clone();    
  289.     int k=0;    
  290.     for(int i=1;i<imageInput.rows-1;i++)    
  291.     {    
  292.         for(int j=1;j<imageInput.cols-1;j++)    
  293.         {    
  294.             int value00=imageInput.at<uchar>((i-1),j-1);    
  295.             int value01=imageInput.at<uchar>((i-1),j);    
  296.             int value02=imageInput.at<uchar>((i-1),j+1);    
  297.             int value10=imageInput.at<uchar>((i),j-1);    
  298.             int value11=imageInput.at<uchar>((i),j);    
  299.             int value12=imageInput.at<uchar>((i),j+1);    
  300.             int value20=imageInput.at<uchar>((i+1),j-1);    
  301.             int value21=imageInput.at<uchar>((i+1),j);    
  302.             int value22=imageInput.at<uchar>((i+1),j+1);    
  303.     
  304.             if(pointDrection[k]>0&&pointDrection[k]<=45)    
  305.             {    
  306.                 if(value11<=(value12+(value02-value12)*tan(pointDrection[i*imageOutput.rows+j]))||(value11<=(value10+(value20-value10)*tan(pointDrection[i*imageOutput.rows+j]))))    
  307.                 {    
  308.                     imageOutput.at<uchar>(i,j)=0;    
  309.                 }    
  310.             }       
  311.             if(pointDrection[k]>45&&pointDrection[k]<=90)    
  312.     
  313.             {    
  314.                 if(value11<=(value01+(value02-value01)/tan(pointDrection[i*imageOutput.cols+j]))||value11<=(value21+(value20-value21)/tan(pointDrection[i*imageOutput.cols+j])))    
  315.                 {    
  316.                     imageOutput.at<uchar>(i,j)=0;    
  317.     
  318.                 }    
  319.             }    
  320.             if(pointDrection[k]>90&&pointDrection[k]<=135)    
  321.             {    
  322.                 if(value11<=(value01+(value00-value01)/tan(180-pointDrection[i*imageOutput.cols+j]))||value11<=(value21+(value22-value21)/tan(180-pointDrection[i*imageOutput.cols+j])))    
  323.                 {    
  324.                     imageOutput.at<uchar>(i,j)=0;    
  325.                 }    
  326.             }    
  327.             if(pointDrection[k]>135&&pointDrection[k]<=180)    
  328.             {    
  329.                 if(value11<=(value10+(value00-value10)*tan(180-pointDrection[i*imageOutput.cols+j]))||value11<=(value12+(value22-value11)*tan(180-pointDrection[i*imageOutput.cols+j])))    
  330.                 {    
  331.                     imageOutput.at<uchar>(i,j)=0;    
  332.                 }    
  333.             }    
  334.             k++;    
  335.         }    
  336.     }    
  337. }    
  338.     
  339. //******************双阈值处理*************************    
  340. //第一个参数imageInput输入和输出的的Sobel梯度幅值图像;    
  341. //第二个参数lowThreshold是低阈值    
  342. //第三个参数highThreshold是高阈值    
  343. //******************************************************    
  344. void DoubleThreshold(Mat &imageIput,double lowThreshold,double highThreshold)    
  345. {    
  346.     for(int i=0;i<imageIput.rows;i++)    
  347.     {    
  348.         for(int j=0;j<imageIput.cols;j++)    
  349.         {    
  350.             if(imageIput.at<uchar>(i,j)>highThreshold)    
  351.             {    
  352.                 imageIput.at<uchar>(i,j)=255;    
  353.             }       
  354.             if(imageIput.at<uchar>(i,j)<lowThreshold)    
  355.             {    
  356.                 imageIput.at<uchar>(i,j)=0;    
  357.             }       
  358.         }    
  359.     }    
  360. }    
  361. //******************双阈值中间像素连接处理*********************    
  362. //第一个参数imageInput输入和输出的的Sobel梯度幅值图像;    
  363. //第二个参数lowThreshold是低阈值    
  364. //第三个参数highThreshold是高阈值    
  365. //*************************************************************    
  366. void DoubleThresholdLink(Mat &imageInput,double lowThreshold,double highThreshold)    
  367. {    
  368.     for(int i=1;i<imageInput.rows-1;i++)    
  369.     {    
  370.         for(int j=1;j<imageInput.cols-1;j++)    
  371.         {    
  372.             if(imageInput.at<uchar>(i,j)>lowThreshold&&imageInput.at<uchar>(i,j)<255)    
  373.             {    
  374.                 if(imageInput.at<uchar>(i-1,j-1)==255||imageInput.at<uchar>(i-1,j)==255||imageInput.at<uchar>(i-1,j+1)==255||    
  375.                     imageInput.at<uchar>(i,j-1)==255||imageInput.at<uchar>(i,j)==255||imageInput.at<uchar>(i,j+1)==255||    
  376.                     imageInput.at<uchar>(i+1,j-1)==255||imageInput.at<uchar>(i+1,j)==255||imageInput.at<uchar>(i+1,j+1)==255)    
  377.                 {    
  378.                     imageInput.at<uchar>(i,j)=255;    
  379.                     DoubleThresholdLink(imageInput,lowThreshold,highThreshold); //递归调用    
  380.                 }       
  381.                 else    
  382.             {    
  383.                     imageInput.at<uchar>(i,j)=0;    
  384.             }                   
  385.             }                   
  386.         }    
  387.     }    
  388. }  </span>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值