从传统到如今深度学习稍微列举下:
canny
步骤:
1,用高斯滤波器平滑图像
2,用一阶偏导有限差分计算梯度和幅值和方向
3,对梯度幅值进行非极大抑制
4,用双阙值算法检测和连接边缘
细节:
边缘检测是基于对图像灰度差异运算而实现的,如果输入的是RGB,则需要先进行灰度图变换。RGB转灰度图的一个常用公式为:
Gray = R*0.299 + G*0.587 + B*0.114
//******************灰度转换函数*************************
//第一个参数image输入的彩色RGB图像;
//第二个参数imageGray是转换后输出的灰度图像;
//*************************************************************
void ConvertRGB2GRAY(const Mat &image,Mat &imageGray)
{
if(!image.data||image.channels()!=3)
{
return ;
}
imageGray=Mat::zeros(image.size(),CV_8UC1);
uchar *pointImage=image.data;
uchar *pointImageGray=imageGray.data;
int stepImage=image.step;
int stepImageGray=imageGray.step;
for(int i=0;i
生成高斯滤波卷积核:
高斯滤波的过程是将灰度图像与高斯卷积核进行卷积,所以第一步是根据给定尺寸和sigma的高斯卷积核参数。
一维高斯卷积核:
二维高斯函数:
其中k+1为size/2
//******************高斯卷积核生成函数*************************
//第一个参数gaus是一个指向含有N个double类型数组的指针;
//第二个参数size是高斯卷积核的尺寸大小;
//第三个参数sigma是卷积核的标准差
//*************************************************************
void GetGaussianKernel(double **gaus, const int size,const double sigma)
{
const double PI=4.0*atan(1.0); //圆周率π赋值
int center=size/2;
double sum=0;
for(int i=0;i
将生成的高斯卷积核与图像卷积,得到灰度图像的高斯滤波后的图像,抑制噪声
//******************高斯滤波*************************
//第一个参数imageSource是待滤波原始图像;
//第二个参数imageGaussian是滤波后输出图像;
//第三个参数gaus是一个指向含有N个double类型数组的指针;
//第四个参数size是滤波核的尺寸
//*************************************************************
void GaussianFilter(const Mat imageSource,Mat &imageGaussian,double **gaus,int size)
{
imageGaussian=Mat::zeros(imageSource.size(),CV_8UC1);
if(!imageSource.data||imageSource.channels()!=1)
{
return ;
}
double gausArray[100];
for(int i=0;i=imageSource.rows?imageSource.rows-1:row;
col=col<0?0:col;
col=col>=imageSource.cols?imageSource.cols-1:col;
//卷积和
imageGaussian.at(i,j)+=gausArray[k]*imageSource.at(row,col);
k++;
}
}
}
}
}
利用sobel梯度算子计算梯度幅值与方向。图像的灰度值的梯度可以使用最简单的一阶有限差分来近似,若为下面的矩阵:
则计算公式为:
其中f为图像灰度值,p代表x方向梯度幅值,Q代表Y方向梯度幅值,M点位该点幅值,thea为梯度方向也就是角度。
一般常常采用的为sobel算子,sobel算子卷积核为:
使用sobel算子计算x,y方向梯度和梯度方向角代码实现:
//******************Sobel卷积因子计算X、Y方向梯度和梯度方向角********************
//第一个参数imageSourc原始灰度图像;
//第二个参数imageSobelX是X方向梯度图像;
//第三个参数imageSobelY是Y方向梯度图像;
//第四个参数pointDrection是梯度方向角数组指针
//*************************************************************
void SobelGradDirction(const Mat imageSource,Mat &imageSobelX,Mat &imageSobelY,double *&pointDrection)
{
pointDrection=new double[(imageSource.rows-1)*(imageSource.cols-1)];
for(int i=0;i<(imageSource.rows-1)*(imageSource.cols-1);i++)
{
pointDrection[i]=0;
}
imageSobelX=Mat::zeros(imageSource.size(),CV_32SC1);
imageSobelY=Mat::zeros(imageSource.size(),CV_32SC1);
uchar *P=imageSource.data;
uchar *PX=imageSobelX.data;
uchar *PY=imageSobelY.data;
int step=imageSource.step;
int stepXY=imageSobelX.step;
int k=0;
int m=0;
int n=0;
for(int i=1;i<(imageSource.rows-1);i++)
{
for(int j=1;j<(imageSource.cols-1);j++)
{
//通过指针遍历图像上每一个像素
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];
PY[i*stepXY+j*(stepXY/step)]=abs(gradY);
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];
PX[i*stepXY+j*(stepXY/step)]=abs(gradX);
if(gradX==0)
{
gradX=0.00000000000000001; //防止除数为0异常
}
pointDrection[k]=atan(gradY/gradX)*57.3;//弧度转换为度
pointDrection[k]+=90;
k++;
}
}
convertScaleAbs(imageSobelX,imageSobelX);
convertScaleAbs(imageSobelY,imageSobelY);
}
求梯度图的幅值
为了使得x,y方向的梯度和梯度角之后来计算x和y方向融合的梯度幅值,计算公式为:
//******************计算Sobel的X和Y方向梯度幅值*************************
//第一个参数imageGradX是X方向梯度图像;
//第二个参数imageGradY是Y方向梯度图像;
//第三个参数SobelAmpXY是输出的X、Y方向梯度图像幅值
//*************************************************************
void SobelAmplitude(const Mat imageGradX,const Mat imageGradY,Mat &SobelAmpXY)
{
SobelAmpXY=Mat::zeros(imageGradX.size(),CV_32FC1);
for(int i=0;i(i,j)=sqrt(imageGradX.at(i,j)*imageGradX.at(i,j)+imageGradY.at(i,j)*imageGradY.at(i,j));
}
}
convertScaleAbs(SobelAmpXY,SobelAmpXY);
}
对梯度进行非极大抑制
对幅值图像进行非极大抑制,可以进一步消除非边缘的噪点,更重要的是,可以细化边缘。
抑制逻辑:沿着该点梯度方向,比较前后两个点的幅值大小,若该点大于前后两点,则保留,若该点小于则置为0.
双阈值处理:指定一个低阈值A,一个高阈值B,一般取B为图像整体灰度级分布的70%,灰度值大于B,置为255,灰度值小于A,置于0.
灰度值置于A和B之间的,考察该像素点邻近的8像素点是否有灰度值为255的,若没有255的,表示这是一个孤立的局部极大值点,可以排除,否则为0.若有255的,表示邻近,依次重复。
指标:
1,好的信噪比,非边缘点判定为边缘点的概率要低,将边缘点判为非边缘点的概率要低
2,高的定位性能,检测出的边缘点要尽可能在实际边缘点的中心
3,对单一边缘仅有唯一的响应,单个边缘产生多个响应的概率要低。
在提高对景物边缘的敏感性的同时,又能抑制噪声的方法才能更加好的提取。
参考:
https://blog.csdn.net/dcrmg/article/details/52344902
http://www.cnblogs.com/techyan1990/p/7291771.html
我只罗列了三大会的一些文章:
Holistically-Nested Edge Detection(ICCV 2015)
Richer Convolutional Features for Edge Detection(CVPR 2017)
CASENet: Deep Category-Aware Semantic Edge Detection(CVPR 2017)
Learning Relaxed Deep Supervision for Better Edge Detection.(CVPR 2016)
深度学习在边缘检测好像不那么热,所以文章都比较少。