使用canny算子对图像进行边缘分割,程序代码:
#include"ImageProcess.h"
#include<math.h>
int get_value(float*ptr,int rows,int cols);
void binarization(Mat img2,int T1,int T2,int rows,int cols); //对图像二值化
void connect_edge(uchar*temp,int cols); //利用双阈值连接图像
int main()
{
int i,j;
//int rows,cols;
Mat img=imread("4.jpg",CV_LOAD_IMAGE_GRAYSCALE);
if (img.empty())
{
fprintf(stderr,"Error:load image failed.");
waitKey();
return -1;
}
else
{
//计算梯度和方向
int rows=img.rows;
int cols=img.cols;
float * p=new float[rows*cols];
float * q=new float[rows*cols];
float * Canny=new float[rows*cols]; //用canny数组来存放像素点的梯度值
float *angle=new float[rows*cols]; //用angle数组来存放像素点的方向
GaussianBlur(img,img,Size(7,7),2,2); //高斯滤波函数
for(j=0;j<rows;j++) //canny算子对每个像素计算梯度和方向
{
for(i=0;i<cols;i++)
{
p[j*cols+i]=(float)(img.data[j*cols+i+1]-img.data[j*cols+i]+img.data[(j+1)*cols+i+1]-img.data[(j+1)*cols+i]);
q[j*cols+i]=(float)(img.data[j*cols+i]-img.data[(j+1)*cols+i]+img.data[j*cols+i+1]-img.data[(j+1)*cols+i+1]);
Canny[j*cols+i]=sqrt( p[j*cols+i]* p[j*cols+i]+ q[j*cols+i]* q[j*cols+i]);
angle[j*cols+i]=atan2(q[j*cols+i],p[j*cols+i])*180/3.141592654;
if(angle[j*cols+i]<0)
angle[j*cols+i]+=180;
}
}
//非极大值抑制 img2是一个新图像,将img图像的点,如C
点,和交叉的dTmp1和dTmp2比较,若c 的梯度
值比任意一个都小,说明C不是那个方向上的极
大值,就把img2灰度值赋为0,否则就是极大值,将
它的梯度值赋给img2的灰度值
Mat img2=img.clone();
for(j=1;j<rows-1;j++)
{
for(i=1;i<cols-1;i++)
{
if(Canny[j*cols+i]==0)
img2.data[j*cols+i]=0;
else if((angle[j*cols+i]<=22.5)||(angle[j*cols+i]>157.5))
{
if((Canny[j*cols+i]<Canny[j*cols+i-1])||(Canny[j*cols+i]<Canny[j*cols+i+1]))
{
img2.data[j*cols+i]=0;
}
else
{
img2.data[j*cols+i]=(uchar)Canny[j*cols+i];
}
}
else if(angle[j*cols+i]>22.5&&angle[j*cols+i]<=67.5)
{
if((Canny[j*cols+i]<Canny[(j-1)*cols+i+1])||(Canny[j*cols+i]<Canny[(j+1)*cols+i-1]))
{
img2.data[j*cols+i]=0;
}
else
{
img2.data[j*cols+i]=(uchar)Canny[j*cols+i];
}
}
else if(angle[j*cols+i]>67.5&&angle[j*cols+i]<=112.5)
{
if((Canny[j*cols+i]<Canny[(j-1)*cols+i])||(Canny[j*cols+i]<Canny[(j+1)*cols+i]))
{
img2.data[j*cols+i]=0;
}
else
{
img2.data[j*cols+i]=(uchar)Canny[j*cols+i];
}
}
else if(angle[j*cols+i]>112.5&&angle[j*cols+i]<=157.5)
{
if((Canny[j*cols+i]<Canny[(j-1)*cols+i-1])||(Canny[j*cols+i]<Canny[(j+1)*cols+i+1]))
{
img2.data[j*cols+i]=0;
}
else
{
img2.data[j*cols+i]=(uchar)Canny[j*cols+i];
}
}
}
}
imshow("image3",img2);
int T_high,T_low; //设两个阈值,一大一小
T_high=get_value(Canny,rows,cols)+1;
printf("大阈值为%d ",T_high);
T_low=T_high/2;
printf("小阈值为%d ",T_low);
binarization(img2,T_high,T_low,rows,cols); //调用二值化函数
imshow("image4",img2);
for(int i=0;i<cols;i++) //将边界赋为其他值
{
img2.data[i]=0;
img2.data[(rows-1)*cols+i]=0;
}
for(int j=0;j<rows;j++)
{
img2.data[j*cols]=0;
img2.data[j*cols+cols-1]=0;
}
for(j=0;j<rows;j++)
{
for(i=0;i<cols;i++)
{
if(img2.data[j*cols+i]==254) connect_edge(img2.data+j*cols+i,cols); //先判断是否是亮点,是,再调用
connect_edge函数
}
}
for(j=0;j<rows;j++)
{
for(i=0;i<cols;i++)
{
if(img2.data[j*cols+i]<254)
img2.data[j*cols+i]=0;
}
, }
delete [] p;
delete [] q;
delete [] Canny,angle;
namedWindow("image2",CV_WINDOW_AUTOSIZE);
imshow("image2",img2);
namedWindow("image",CV_WINDOW_AUTOSIZE);
imshow("image",img);
waitKey();
return 0;
}
}
//自适应阈值
int get_value(float*ptr,int rows,int cols)
{
int T;
double max_variance=0.0;
int max_T=0;
for(int m=0;m<=255;m++)
{
T=m;
float foreground_gray=0;//前景总灰度值
float background_gray=0;//背景总灰度值
int fore_num=0,back_num=0;//计算个数
double fore_aver=0;
double back_aver=0;
for(int j=1;j<rows-1;j++)
{
for(int i=1;i<cols-1;i++)
{
if(ptr[j*cols+i]>T)
{
foreground_gray=ptr[j*cols+i]+foreground_gray;
fore_num++;
}
else
{
background_gray+=ptr[j*cols+i];
back_num++;
}
}
}
if(fore_num!=0)
{
fore_aver=((double)foreground_gray)/((double)fore_num);
}
if(back_num!=0)
{
back_aver=(double)background_gray/(double)back_num;
}
double fore_proportion=(double)fore_num/(double)(rows*cols);
double back_proportion=(double)back_num/(double)(rows*cols);
double total_aver=fore_proportion*fore_aver+back_proportion*back_aver;
double variance=(fore_aver-total_aver)*(fore_aver-total_aver)*fore_proportion+(back_aver-total_aver)*(back_aver-total_aver)*back_proportion;
if(variance>max_variance)
{
max_variance=variance;
max_T=T;
}
}
return max_T;
}
//二值化
void binarization(Mat img2,int T1,int T2,int rows,int cols)
{
for(int j=0;j<(rows);j++)
{
for(int i=0;i<(cols);i++)
{
if(img2.data[j*cols+i]<T1) //先和大阈值比,小于阈值的赋为0,大于的
赋为254.
{
img2.data[j*cols+i]=0;
}
else
{
img2.data[j*cols+i]=254;
}
}
}
for(int j=0;j<rows;j++) //再和小阈值比,小于的赋为0,大于的且又不是
254的,就是潜在的亮点,赋为128
{
for(int i=0;i<cols;i++)
{
if(img2.data[j*cols+i]<T2)
{
img2.data[j*cols+i]=0;
}
else
{
if(img2.data[j*cols+i]<254)
img2.data[j*cols+i]=128;
}
}
}
}
void connect_edge(uchar* temp,int cols){ //根据一个灰度值为255的点寻找它的八连通区域有没有128的点,即大于小阈值的点,若有将该点赋为255,继续递归,这样就进行了连接
* temp=255;
if(*(temp-cols-1)==128)
connect_edge(temp-cols-1,cols);
if(*(temp-cols)==128)
connect_edge(temp-cols,cols);
if(*(temp-cols+1)==128)
connect_edge(temp-cols+1,cols);
if(*(temp-1)==128)
connect_edge(temp-1,cols);
if(*(temp+1)==128)
connect_edge(temp+1,cols);
if(*(temp+cols-1)==128)
connect_edge(temp+cols-1,cols);
if(*(temp+cols)==128)
connect_edge(temp+cols,cols);
if(*(temp+cols+1)==128)
connect_edge(temp+cols+1,cols);
}