基于纹理边缘抑制的轮廓和边界检测(Contour and Boundary Detection)
基于纹理边缘抑制的轮廓和边界检测(Contour and Boundary Detection)
一幅复杂的自然场景图像中包含丰富的信息,视觉不可能对空间中的每一点赋予相同的关注程度。对人类视觉系统的实验表明:图像中的轮廓特征特别重要,它们在保留关于物体的边界有用的结构信息的同时,极大地降低了数据量,从而简化了信息的表达形式,使视觉能对各种瞬息万变的输入可以及时有效地处理。在很多情况下,根据画出了的物体轮廓就可以识别出物体。
轮廓在计算机视觉中属于中层视觉,它是基于形状目标识别的一个重要特征。形状与结构的视觉分析在人类的视觉感知中起着重要的作用,物体往往是通过它的形状大小、颜色信息和几何结构等特征来描述的。在许多视觉任务中,由于形状具有很强的鲁棒性,因此一般物体的识别主要是根据形状特征。轮廓检测的一个首要问题是如何处理通过简单边缘检测机制产生的大量的候选成分。由于许多的边缘仅仅是一种对比度的突变,它们可能不属于任何有意思的和相关物理轮廓。通过来自周边环境上下文的信息影响 边缘检测器的响应来增强对相关边缘的敏感性,并根据上下文的信息将孤立的边缘点连接起来,构成某一个物体在图像上形成的一个区域的完整边界线,去除那些不具有实际物理意义的背景纹理边缘。
本文根据Cosmin Grigorescu等人的论文“Contour and boundary detection improved by surround suppression of texture edges"的内容和自己的理解而成,如果对其中的细节感兴趣,敬请参考原文。 在Cosmin Grigorescu的论文中,提出了一个重要的计算环节(Computational Step),叫做环境抑制(Surround Suppression)来提高自然场景中图像的目标轮廓和区域边界的检测。该灵感主要是受到人的初级视皮层(Primary Visual Cortex)中的那些具有方向选择性的神经元(Orientation Selective Neurons)激发,这些细胞对周围的非经典感受野区域具有抑制作用,并且影响对边缘和线条的聚集的感知能力(Perception of Group of Edges or Lines)。接下来,本文将详细的介绍下这篇论文的基本内容。
(1)计算梯度(Gradient Computation)
这里的操作类似Canny算子的第一步,也即首先将原图与一个高斯函数进行卷积,对图像进行平滑滤波,然后对滤波后的图像进行有限差分运算,求梯度。在Canny中,其计算公式如下:
然而,通过学者的研究得出,采用上面的公式来计算是病态的(ill-posed),因此,在该文中,采用如下的公式来计算梯度:
其中,是高斯函数的一阶微分。接着,进一步来计算X、Y方向的梯度,计算公式如下:
计算完梯度,那么就可以进一步得到幅值和方向,公式如下:
接着,沿着梯度方向采用非极大值抑制来对图像中的边缘像素进行定位,非极大值抑制可以参考博文:Canny算子中的非极大值抑制(Non-Maximum Suppression)分析。
(2)环境抑制(Surround Suppression)
通过第一步的计算,可以得到边缘图像,在这一步,需要对检测到的边缘图像进行非轮廓边缘的抑制,非轮廓边缘包括背景纹理以及噪声等。在该文中,通过高斯差分来模拟人的初级视皮层细胞对环境抑制机制,DOG的表达式如下:
权重函数的定义如下:
对图像中的每一个点,采用上面的权重函数进行处理。根据处理方式的不同,可以分为各向同性抑制和各向异性抑制。下面来简单介绍下这两种抑制。
(3)各向同性抑制(Isotropic Surround Suppression)
通过前面的两步计算,各向同性抑制的准备工作已经就绪了。该种方式的抑制作用只考虑距离因素,因此其表达公式如下:
最后,可以得到轮廓检测算子,用公式表达如下:
其中,alpha是一个控制因子(control factor),H(*)是一个操作算子,类似于Canny算子的后处理部分,包括轮廓的细化、滞后阈值化以及轮廓连接等,具体的可以参考Canny算子。
(4)各向异性抑制(Anisotropic Surround Suppression)
各向异性抑制与各向同性抑制相比,增加了一个抑制因素,也即方向因素。对于两个点(x,y)和(x-u,y-v),其方向因素表示如下:
通过上式可知,如果这两个点的方向一致,那么抑制最用最大,因为cos(0)=1,随着夹角的增大,抑制作用逐渐减少,当两个点相互垂直时,抑制作用最小(cos(90)=0)。
增加了方向的环境抑制因素后,抑制作用表示如下:
公式中的符号与前面相同,不再介绍。
下面给出两段代码:
(1)非极大值抑制
// non-maximum suppression
void NonMaxSuppress(float*pMag, float* pGradX, float*pGradY, Size sz, unsigned char* pNSRst)
{
long x,y;
int nPos;
// the component of the gradient
float gx,gy;
// the temp varialbe
float g1,g2,g3,g4;
float weight;
float dTemp,dTemp1,dTemp2;
//设置图像边缘为不可能的分界点
for(x=0;x<sz.width;x++)
{
pNSRst[x] = 0;
pNSRst[(sz.height-1)*sz.width+x] = 0;
}
for(y=0;y<sz.height;y++)
{
pNSRst[y*sz.width] = 0;
pNSRst[y*sz.width + sz.width-1] = 0;
} for (y=1;y<sz.height-1;y++)
{
for (x=1;x<sz.width-1;x++)
{
nPos=y*sz.width+x;
// if pMag[nPos]==0, then nPos is not the edge point
if (pMag[nPos]==0)
{
pNSRst[nPos]=0;
}
else
{
// the gradient of current point
dTemp=pMag[nPos];
// x,y 方向导数
gx=pGradX[nPos];
gy=pGradY[nPos];
//如果方向导数y分量比x分量大,说明导数方向趋向于y分量
if (fabs(gy)>fabs(gx))
{
// calculate the factor of interplation
weight=fabs(gx)/fabs(gy);
g2 = pMag[nPos-sz.width]; // 上一行
g4 = pMag[nPos+sz.width]; // 下一行
//如果x,y两个方向导数的符号相同
//C 为当前像素,与g1-g4 的位置关系为:
//g1 g2
// C
// g4 g3
if(gx*gy>0)
{
g1 = pMag[nPos-sz.width-1];
g3 = pMag[nPos+sz.width+1];
}
//如果x,y两个方向的方向导数方向相反
//C是当前像素,与g1-g4的关系为:
// g2 g1
// C
// g3 g4
else
{
g1 = pMag[nPos-sz.width+1];
g3 = pMag[nPos+sz.width-1];
}
}
else
{
//插值比例
weight = fabs(gy)/fabs(gx);
g2 = pMag[nPos+1]; //后一列
g4 = pMag[nPos-1]; // 前一列
//如果x,y两个方向的方向导数符号相同
//当前像素C与 g1-g4的关系为
// g3
// g4 C g2
// g1
if(gx * gy > 0)
{
g1 = pMag[nPos+sz.width+1];
g3 = pMag[nPos-sz.width-1];
} //如果x,y两个方向导数的方向相反
// C与g1-g4的关系为
// g1
// g4 C g2
// g3
else
{
g1 = pMag[nPos-sz.width+1];
g3 = pMag[nPos+sz.width-1];
}
}
dTemp1 = weight*g1 + (1-weight)*g2;
dTemp2 = weight*g3 + (1-weight)*g4;
//当前像素的梯度是局部的最大值
//该点可能是边界点
if(dTemp>=dTemp1 && dTemp>=dTemp2)
pNSRst[nPos] = 128;
else
//不可能是边界点
pNSRst[nPos] = 0;
}
}
}
}
(2)高斯差分DoG
// sigma2 = 4*sigma1
void getDoGKernel( Mat& kernel, int kSize, double sigma1, double sigma2)
{
double sigma1x = sigma1*sigma1;
double sigma2x = sigma2*sigma2;
Mat mkernel (kSize, kSize, CV_64F);
int center = (kSize-1)/2;
int i,j;
double dsum = 0; for ( i=0; i<kSize; ++i )
{
double* data = (double*)(mkernel.data+ mkernel.step[0]*i);
int di = (i-center);
for ( j=0; j<kSize; ++j )
{
int dj = (j-center);
double d1 = (1.0/sigma1x)*exp(-(di*di+dj*dj)/(2*sigma1x));
double d2 = (1.0/sigma2x)*exp(-(di*di+dj*dj)/(2*sigma2x));
double dis = d2 - d1;
if ( dis>0.0)
data[j] = dis;
else
data[j]=0.0;
dsum += fabs(dis);
}
}
// 归一化
mkernel = mkernel/dsum;
mkernel.copyTo( kernel);
return;
}
最后,再附上一小节代码:
Sobel( gray, sobelX, CV_32F, 1, 0, 3);
Sobel( gray, sobelY, CV_32F, 0, 1, 3);
magnitude( sobelX, sobelY, mag);
//cartToPolar( sobelX, sobelY, mag, dir, true);
// 非极大值值抑制
filter2D( mag, mag, mag.depth(), kernel); // 环境抑制 surround suppression
另外,推荐几篇相关论文:
1、Cosmin Grigorescu. contour detection based on nonclassical receptive field inhibition(2003 TIP).
2、唐奇伶. 基于初级视皮层感知机制的轮廓与边界检测(2007华中科技大学博士论文)
作者:kezunhai出处:http://blog.csdn.net/kezunhai欢迎转载或分享,但请务必声明文章出处。
基于纹理边缘抑制的轮廓和边界检测(Contour and Boundary Detection)的更多相关文章
- 基于纹理的图片检索及demo(未启动)
基于纹理的图片检索及demo(未启动)
- opencv::轮廓发现(find contour in your image)
轮廓发现(find contour) 轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法. 所以边缘提取的阈值选定会影响最终轮廓发现结果 //发现轮廓 cv::findContours( InputO ...
- Halcon编程-基于纹理的mara检测
表面瑕疵检测是机器视觉领域非常重要的一个应用.机器视觉是集光学.机电和计算机三个领域的一门不算新的技术.但目前表面瑕疵检测在学界主要是计算机专业或者控制专业瞄准图像处理方向在做,而视觉光学系统这一块主 ...
- 每天进步一点点------Sobel算子(3)基于彩色图像边缘差分的运动目标检测算法
摘 要: 针对目前常用的运动目标提取易受到噪声影响.易出现阴影和误检漏检等情况,提出了一种基于Sobel算子的彩色边缘图像检测和帧差分相结合的检测方法.首先用Sobel算子提取视频流中连续4帧图像的 ...
- 基于纹理内存的CUDA热传导模拟
原文链接 项目中有三个,第一个是全局内存,其余两个分别是基于1d和2d纹理内存.项目打包下载. 纹理内存是只读内存,与常量内存相同的是,纹理内存也缓存在芯片中,因此某些情况下,它能减少对内存的请求并提 ...
- 基于Qt的FreeType字体轮廓解析
一.本文目的 以前的文档中.详细的介绍了FreeType开源字体引擎库的基础知识.基本用法.但并未详细的阐明在TurboCG中.是如何解析出一个文字的轮廓的,本文集中阐述.怎么样使用FreeType开 ...
- 基于图像二维熵的视频信号丢失检测(Signal Loss Detection)
1 图像二维熵 图像二维熵作为一种特征评价尺度能够反映出整个图像所含平均信息量的高低,熵值(H)越大则代表图像所包含的信息越多,反之熵值(H)越小,则图像包含的信息越少.对于图像信息量,可以简单地认 ...
- Image Processing and Analysis_8_Edge Detection:Edge and line oriented contour detection State of the art ——2011
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- Canny边缘检測算法原理及其VC实现具体解释(一)
图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般能够看作是一个阶跃,既从一个灰度值在非常小的缓冲区域内急剧变化到还有一个灰度相差较大的灰度值.图象的边缘部分集中了图象的大部分信息,图 ...
随机推荐
- Bootstrap在线编辑器简单分享
Bootstrap 已经使响应式网站开发变得简单很多. 但是如果你不必手动写全部代码,事情会如何呢? 如果你可以自由地选择你想要使用的Bootstrap 组件.并可以把它们拖拽到画布中,事情会如何呢? ...
- 精通CSS+DIV基础总结(二)
上一篇我们已经总结了部分CSS+DIV相关知识,这篇我们接着总结,从下边几个方面学习一下: 一,我们看如何设置网页的背景,顾名思义背景可以通过颜色和图片来设置,下边我们看一下如何设置: 颜色的设置非常 ...
- uva 11210 Chinese Mahjong(暴力搜索)
Chinese Mahjong Mahjong () is a game of Chinese origin usually played by four persons with tiles res ...
- CSDN 正整数异或值问题
题目详情: http://student.csdn.net/mcs/programming_challenges?page=4 给你n个正整数,请你计算出有多少对数的异或值小于等于k. 输入描写叙述: ...
- 多线程程序 怎样查看每个线程的cpu占用
可以用下面的命令将 cpu 占用率高的线程找出来: ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu 这个命令首先指定参数'H',显示线程相关的 ...
- E514:write error(file system full?)
vi编辑某文件,保存时报错,提示:E514: write error (file system full?)---写入错误,磁盘满了? 查看磁盘空间:df -h根目录磁盘空间已满,used%100. ...
- Javascript进阶篇——( JavaScript内置对象---下)--Array数组对象---笔记整理
Array 数组对象数组对象是一个对象的集合,里边的对象可以是不同类型的.数组的每一个成员对象都有一个“下标”,用来表示它在数组中的位置,是从零开始的数组定义的方法: 1. 定义了一个空数组: var ...
- 在VS中如何用C++连接Mysql
在如鹏网上看到的如何用C连接Mysql,解决了大二时的一直困惑,大喜! 第一步下载 安装的数据库是如鹏网的Mysql :http://pan.baidu.com/s/1c0m3xIw 提取码:m9sn ...
- (原) c++ 杂
Declaration of variables C++ is a strongly-typed language, and requires every variable to be decla ...
- js各种验证文本框输入格式
不能为空 <input onblur="if(this.value.replace(/^ +| +$/g,'')=='')alert('不能为空!')"> 只能输入英文 ...