学习DIP第49天
转载请标明本文出处:http://blog.csdn.net/tonyshengtan ,出于尊重文章作者的劳动,转载请标明出处!文章代码已托管,欢迎共同开发: https://github.com/Tony-Tan/DIPpro
今天介绍二阶微分算子,二阶微分算子典型的是Laplace算子,LoG可以看成是一个高斯模板的拉普拉斯变换,但是也可以从根源上推导出LoG算子,而后面要介绍的DoG则是为了纯粹的减少计算,模拟LoG的一种方法。
LoG最底层的原理是二阶微分算子,也就是对原始图像求二次微分的边缘定位算法,前面的边缘模型中可以得知,当使用二阶微分算子的时候,其对边缘的响应是一个零交叉,而且能够判断出高灰度方向,但二阶微分对噪声的敏感度过高,需要平滑预处理。
Marr和Hildreth【Marr和Hildreth,1980】证明了以下两个观点:
(1)灰度变化与图像尺寸没有关系,因此检测需要不同尺度的算子
(2)灰度的突然变化会在一阶导数中引起波峰和波谷,或者二阶导数中一起零交叉
所以可以提出一种能变换尺寸的(当时用的是标准Sobel等那些,固定尺寸的,当时Sobel还没有扩展),在各种大小的图像上都能起作用的,可以检测模糊的相对较大的边缘,也可以检测细小的锐度集中的精细细节,当然这种算子也必须对全图所有像素点其作用。Marr和Hildreth证明LoG算子是满足上述条件的最满意的算子。
LoG算子:
其中标准高斯函数,
对一个标准高斯函数(未归一化)进行二次偏微分:
最终表达式:
LoG零交叉出现在
下面全方位无死角观察下,说明,上面公式给出的是倒置的草帽,我们这里给他加了个负号,让它正过来。。。
剖面图,沿着直径切开:
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
//3x3的邻域内,如果中心像素大于阈值,切周围存在负像素值,则此点为0交叉点
void findCross(double *src,double *dst,int width,int height,double threshold){
double *dsttemp=(double *)malloc(sizeof(double)*width*height);
Zero(dst, width, height);
double c_value=0.0;
int flag=1;
Zero(dsttemp, width, height);
for(int j=1;j<height-1;j++){
for(int i=1;i<width-1;i++){
c_value=src[j*width+i];
flag=1;
for(int m=-1;m<=1&&flag;m++)
for(int n=-1;n<=1;n++){
if(c_value>threshold&&src[(j+m)*width+i+n]<-0.1){
flag=0;
dsttemp[j*width+i]=255.0;
break;
}
}
}
}
matrixCopy(dsttemp, dst,width, height);
free(dsttemp);
}
//得到LoG模板,根据公式得出double型模板,然后调整整体位置,使模板内系数和为0
void getLoGMask(double *mask,int width,int height,double delta){
int center_x=width/2;
int center_y=height/2;
double x,y;
for(int j=0;j<height;j++){
for(int i=0;i<width;i++){
x=i-center_x;
y=j-center_y;
mask[j*width+i]=-((x*x+y*y-2*delta*delta)/pow(delta,4))*(exp(-(x*x+y*y)/(2*delta*delta)));
}
}
double sum=0.0;
for(int i=0;i<width*height;i++){
sum+=mask[i];
}
double di=sum/(double)(width*height);
for(int i=0;i<width*height;i++){
mask[i]-=di;
}
}
//LoG边缘检测完整过程,
//生成模板
//与图像卷积
//寻找0交叉
double LoG(double *src,double *dst,int width,int height,int m_width,int m_height,double delta,double threshold){
double *dsttemp=(double *)malloc(sizeof(double)*width*height);
double * mask=(double *)malloc(sizeof(double)*m_width*m_height);
getLoGMask(mask, m_width,m_height,delta);
RealConvolution(src, dsttemp, mask, width, height, m_width, m_height);
findCross(dsttemp,dst,width,height,threshold);
free(dsttemp);
free(mask);
return findMatrixMax(dst,width,height);
}
以下为算子对图像操作的结果
原图:
观察上述结果阈值为0的结果,或出现意大利通心粉效应–所有边缘会形成一个闭环,典型的是那些圈圈,这是一个严重的缺陷,所以不使用0阈值,而是使用超过0的阈值来解决这个问题,LoG的边缘检测效果还是不错的,当选择
待续。。。
灰度图像--图像分割 Marr-Hildreth算子(LoG算子)
原文地址:http://blog.csdn.net/tonyshengtan/article/details/43794359