资源描述
毕业设计
题 目 彩色颗粒显微图像识别系统
---颗粒图像识别模块
学 院 机械工程学院
专 业 机械工程及其自动化
班 级 机自0706
学 生 姚孔
学 号 20070403244
指导教师 王玉增
二〇一一年五月三十日
1 前言
1.1 选题的背景
图像识别技术已经应用到了人类社会的各个领域,从指纹的识别、车辆的检测、医学研究到军事的影像目标识别、匹配及典型目标打击效果评估,深深地影响着人类的生活。图像识别技术逐渐向高智能、非人工干预的方向发展。
图像的识别与图像的分割是图像处理领域研究最多的课题之一,但它们依然是大多数研究人员的研究重心, 因为己经取得的成果远没有待解决问题多。图像识别的发展大致经历了三个阶段:文字识别阶段、数字图像处理阶段与识别、物体识别阶段。文字识别阶段的研究是从1950年开始的,一般是用来识别字母、数字和符号的,从印刷文字识别再到手写文字识别,应用非常广泛,并且已经研制成功了好多专用设备。数字图像的处理和数字图像的识别的研究开始于1965年。数字图像与模拟图像相比具有存储、传送方便可压缩、传输过程中不容易失真、处理方便等巨大优势,这些都为图像的识别技术的发展提供了强大的动力。物体的识别主要指对三维世界的客体及环境的感知和认识,属于高级计算机视觉范畴。它是以数字图像的处理与识别为基础的并结合人工智能、系统学等学科的研究方向,其研究的成果被广泛应用于各种工业及探测机器人上。现代图像识别技术的一个不足之处就是自适应性能较差,一旦目标图像被较强的噪声感染或是目标图像有较大的残缺往往就得不到理想的结果。
图像识别问题的数学实质是属于模式空间到类别空间的映射问题。目前,在图像识别的发展过程中,主要有以下三种识别方法:统计模式识别、结构模式识别、模糊模式识别。图像分割是图像处理中的一项非常关键的技术,自20世纪70年代,其研究已经经历几十年的历史,一直都受到人们的高度重视,至今借助于各种理论提出了数以千计的图像分割算法,并且这方面的研究仍旧在积极地进行着。现有的图像分割的方法有好多种,有阈值分割方法,边缘检测方法,区域提取方法,以及结合特定理论工具的分割方法等。从图像的类型来分有:灰度图像的分割、彩色图像的分割和纹理图像的分割等。早在1965年就有人提出了边缘检测算子,使得边缘检测产生了许多经典算法。但在近二十多年间,随着基于直方图图像分割和小波变换的图像分割方法的研究计算技术、以及VLSI技术的迅速发展,有关图像处理方面的研究取得了相当大的进展。图像分割方法结合了一些特定理论、原理、方法和工具,如基于数学形态学的图像分割、基于小波变换的图像分割、基于遗传算法的图像分割等。
目前,国内、国外已经把图像的识别技术应用到很多领域,其中最典型的应用领域有:①在光学信息处理上如光学文字识别、光学标记识别、光学图形的识别、光谱能量的分析等。②在医疗仪器上的样本检查分析、眼球运动的检测、X射线的摄像、胃镜、肠镜的摄像等。③自动化的仪器如自动售货机、自动搬运机、监视装置等。④工业自动检测上如零件尺寸的动态检查、产品质量、包装、形状识别,表面缺陷的检测等。⑤军事上有卫星的侦察、航空遥感、微光夜视、导弹制导、目标的跟踪、军事图像的通信等,例如一些国际组织发射了资源遥感卫星和天空实验室(如SKYLAB)。⑥在人工智能方面有机器人的视觉、无人自动的驾驶、邮件自动的分检、指纹识别、人脸识别等,如中科院计算所自主研制的“面像检测与识别的核心技术”。
1.2 国内外研究现状
战略目标无论是在军事方面还是民用方面,都有着非常重大的意义,但是令人遗憾的是,经过这么些年,各类有关文献中关于遥感图像的战略目标识别的部分仍然少之又少。相对比而言,道路目标识别的部分较多,但很少作用于军事用途,而是用于GIS(地理信息系统的导航)或者其它测绘的需求。像桥梁这样的大型地面的目标识别也是以水上的桥梁居多,然而陆地桥梁方面的研究则是较为少见。机场识别的大部分也仅能够检测出直线特征明显的主副跑道,而对于机场的其它附属设施的识别则是很少涉及到的。很多战略目标都没有固定的模型,例如不同分辨率图像中的港口、道路、桥梁、机场和交通枢纽等等,模型都是不相同的。这些目标不像那些战术目标(飞机、舰船、车辆等)可以提取很多不变特征,如Hu矩和小波矩的特征等,所以大型战略目标的分割与检测都需要先验知识的指导。可以预期,在21世纪初期,图像技术将经历一个飞跃式发展的成熟阶段,为深入人民生活创造了新的文化环境,成为提高生产自动化、智能化水平的基础学科之一。图像技术的基础性研究,尤其是结合人工智能和视觉处理的新算法,从更高水平获取图像信息的丰富内涵,成为人类运算量最大、直观性也最强,并与现实世界直接联系的视觉和“形象思维”这一智能的模拟和复现,是一个很艰难并且非常重要的任务。
1.3 选题目的与意义
图像处理是信号与信息处理科学的一个部分,也是在计算机领域中最为活跃的领域之一。图像的识别是对处理后的图像进行分类处理,确定所属类别。图像的处理技术和图像的模式识别技术都是计算机应用与研究领域的重要分支,将两者有机地并和谐地结合起来,能够进一步地发挥原来单一技术的作用。利用图像的处理技术处理包含数字字符的图像, 模式识别是进一步地识别处理后的图像, 从而使两者很好地结合起来; 实际应用这一技术会有很好的收益效果。数字图像的处理技术在航空航天、工业生产、医疗的诊断、资源环境、气象以及交通的监测、文化教育等领域有着非常广泛的应用,创造了巨额的社会价值;但同时还远远不能满足社会的需求,自身也在不断的完善和发展,有很多新的方面需要探索。它必将先向更深入的更完善的方向发展:向处理算法更优化,处理速度加快,实现图形的智能化生成、处理、识别以及理解。尽管计算机图像识别面临着非常巨大的困难,然而这一技术还是得到了很大的发展。综观图像识别技术近几十年来的发展和变化,不难看出一些优越特点:图像识别技术将经历一个飞速发展的阶段,立体视觉和人工智能仍旧是计算机图像识别今后的发展方向;短期内实现全自动化通用性计算机视觉系统可能性不大,今后应当结合各种实际应用以开发各种计算机图像目标识别系统。可以预期,图像的识别技术为人类生活创造了新的文化环境,成为提高生产的自动化水平、智能化水平的基础科学之一。图像识别的基础性研究,尤其是结合人工智能与视觉处理的新算法,从更高水平获取图像信息的丰富内涵。本文主要介绍了图像的轮廓识别,通过图像轮廓的各种算法,例如:边缘检测、轮廓提取、种子填充、Hough变换、轮廓跟踪等,结合微软公司提供的VS2010编程软件,利用CxImage图像处理类库和C++编程基础知识,对计算机采集到的图像进行轮廓识别。通过对图像轮廓识别的研究达到人类对图像识别的经一步研究。
2 图像识别
2.1 图像识别介绍
图像识别,是运用计算机对图像进行处理、分析和理解,以识别各种不相同模式的目标和对像的技术。地理学中是指将遥感图像进行分类的技术。
图像识别可能是以图像的主要特征为识别基础的。每个图像都有它的特征,例如字母A有个尖,P有个圈、而Y的中心有个锐角等。对图像识别时眼动的研究表明,视线总是集中在图像的主要特征上,也就是集中在图像的轮廓曲度最大或者轮廓方向突然改变的地方,这些地方的信息量是最大的。并且眼睛的扫描路线也总是依次从一个特征转到另外一个特征上。由此可见,在图像的识别过程中,知觉机制必须排除输入的其他多余信息,抽出关键的信息。于此同时,在大脑里必有一个负责整合信息的机制,它能把分阶段获得的信息量整理成一个比较完整的知觉映像。
在人类图像的识别系统中,对比较复杂图像的识别往往要通过不同层次的信息加工才能得以实现。对于熟悉的图形,由于掌握了它的基本特征,就会把它当作一个单元来识别,而不再注意它的细节问题了。这种由孤立的单元材料所组成的整体单位叫做组块,每一个组块都是同时被感知的。在文字材料的识别中,人们不但可以一个汉字的笔划或者偏旁等单元组成一个组块,而且能够把经常在一起出现的字或者词组成组块单位来加以识别。
2.2 CxImage图像操作类库介绍
CxImage类库是一个非常优秀的图像操作类库。它可以方便快捷地存取、显示、转换各种图像。有些读者可能说,有那么多优秀的图像操作类库如OpenIL,FreeImage,PaintLib等等,它们可所谓是功能强大,齐全,没有必要使用其它的类库。但我要说,这些类库基本上是没有免费的,使用这些类库,你要被这样或者那样的许可协议所要束缚。在这点上,CxImage类库是完全免费的。另外,在使用上述类库时,你会遇到很多麻烦。因为它们大部分是与平台无关的,且用C语言写成,有的还甚至夹杂着基本的C++ wrapper与成堆的编译选项的声明需要我们去处理。而CxImage类库在这方面做得是相当好的。还有让我最看好的是作者完全公开了源代码。与那些封装好的图形库和GDI+来说相比较,这一点使我们可以进一步的学习各种编解码技术,而不再浮于各种技术的表面。
如图1 CxImage Structure
一个CxImage对象是一个扩展了的位图。作者只是在位图结构上添加了一些起存储信息作用的成员变量。一个CxImage对象(同时)也是一组层。每个层只有在需要时才会分配相应的缓冲区。CxImage::pDib代表着背景图像,CxImage::pAlpha代表着透明层,CxImage::pSelection代表着被选中的层,被用来创建图像处理时让用户感兴趣的区域。在这三个特殊层面的基础上,你可以增加一些额外的层,这些层可以存储在CxImage::pLayers中。一般说来,层是一个完整的CxImage对象。因此,你可以构造很复杂的嵌套层。
下面是CxImage的一些成员变量:
class CxImage
{
...
protected:
void* pDib; //包含文件头,调色板等等
BITMAPINFOHEADER head; //标准的文件头(位图)
CXIMAGEINFO info; //扩展了的信息
BYTE* pSelection; //用户选中的区域
BYTE* pAlpha; //alpha通道
CxImage** pLayers; //通用层
}
typedef struct tagCxImageInfo {
DWORD dwEffWidth; //DWORD 扫描线宽
BYTE* pImage; //图像位数
void* pGhost; //if this is a ghost, pGhost point to the body
DWORD dwType; //原图像的格式
char szLastError[256]; //出错信息
long nProgress; //监视循环的次数
long nEscape; //跳出标志
long nBkgndIndex; //GIF, PNG, MNG格式使用
RGBQUAD nBkgndColor; //RGB三原色透明度
BYTE nQuality; //JPEG格式使用
long nFrame; //TIF, GIF, MNG使用 :实际的帧数
long nNumFrames; //TIF, GIF, MNG使用 :帧总数
DWORD dwFrameDelay; //GIF, MNG使用
long xDPI; //水平分辨率
long yDPI; //垂直分辨率
RECT rSelectionBox; //选中的矩形区
BYTE nAlphaMax; //阴影的最大不透明度
bool bAlphaPaletteEnabled; //如果调色板中有Alpha通道则为真
bool bEnabled; //打开绘图函数
long xOffset;
long yOffset;
DWORD dwEncodeOption; //一些编码选项
RGBQUAD last_c; //一些优化选项
BYTE last_c_index;
bool last_c_isvalid;
long nNumLayers;
DWORD dwFlags;
} CXIMAGEINFO;
3图像轮廓识别
3.1图像轮廓识别的方法
1.图像边缘检测:(1)Robert算子、(2)Sobel算子、(3)Prewitt算子、(4)Laplacian算子、(5)Kirsch算子;
2.图像Hough变换;
3.图像轮廓提取;
4.图像种子填充:(1)种子填充一、(2)种子填充二;
5.图像轮廓跟踪。
3.2图像边缘检测
利用计算机进行图像处理有两个目的:一是产生更适合人们观察和识别的图像;二是希望能够由计算机自动识别和理解图像。无论是为了哪一种目的,图像处理中最主要的一步就是对包含有大量各式各样景物的信息的图像进行分解,最终的显示结果是图像被分解成一些具有某种特征的最小的分量,称为图像的基元。
特征是指图像场中可用来作为标志的属性。它可分为图像的统计特性与图像的视觉特征两大类。图像的统计特征是指一些认为所定义的特征,通过变换才能得到的,如直方图、矩、频谱等等;图像的视觉特征是指人的视觉可以直接感觉到的自然特征,如区域的亮度、纹理或轮廓等等。利用这两类特征把图像分解成一系列目标或区域的过程称为图像的分割。
边缘是图像的最基本的特征。所谓边缘(或边沿)是指其周围像素灰度有阶跃变化的那些像素的集合。边缘广泛存在于物体和背景之间、物体和物体之间、基元和基元之间,它是图像分割所依赖的很重要的特征。边缘是由灰度的不连续性所反映的。比较经典的边缘提取方法是考察图像的每个像素在某个邻域内灰度值的变化,也可以是描述为亮度的变化,运用边缘邻近一阶或二阶方向导数变化规律,用简单的方法进行边缘检测。这种方法称为边缘检测局部算子法。类别可以分为两种:一种称为阶跃性边缘,它两边的像素的灰度值有着非常显著的不同;即不连续性,比如图像的边缘;另一种称为屋顶状边缘,它是位于灰度值从增加到减少的变化转折点,可以根据事先制订的准则将图像分割为相似的区域,比如门限处理、区域生长、区域分离和聚合等等;像素落在图像中某一个物体的边界上,那么它的邻域将成为一个灰度级的变化带。对这种变化最为有用的两个特征是灰度的变化率与方向,它们分别以梯度向量的幅度和方向来表示。检测算子检查每个像素的邻域并对灰度变化率进行量化,也包括方向的确定。大多数使用基于方向导数掩模求卷积的方法。
3.3图像的灰度变换
(1)图像灰度变换VC代码
int CVidCapDlg::MobanEdge3(int mm[3][3])
{
int w,h;
w=image->GetWidth();
h=image->GetHeight();
CxImage *Img = new CxImage(w,h,8);
Img->SetGrayPalette();
for(int i =0;i<h;i++)
for(int j=0;j<w;j++)
{
if(i<1||i>h-2||j<1||j>w-2)
continue;
int temp = 0;
for(int ii =0;ii<3;ii++)
for(int jj=0;jj<3;jj++)
temp += image->GetPixelIndex(j+jj-1,i+ii-1) * mm[ii][jj];
int yuzhi = 100;
int b = abs(temp) > 100?255:0;
Img->SetPixelIndex(j,i,(BYTE)b);
}
image->Destroy();
image = Img;
ReDraw();
return 100;
}
(2)未处理的图像
(3)处理后的图像
3.3.1Robert算子
(1)Robert算法介绍
Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后的结果边缘不是很平滑的。经分析,由于Robert算子通常都会在图像边缘附近的区域内产生较为宽的响应,故采用上述算子检测的边缘图像常常需要做细化处理,边缘定位的精度不是很高的。
.NET代码如下:
private void menuItem23_Click(object sender, System.EventArgs e)
{
if(this.pictureBox1.Image!=null)
{
this.pictureBox2.Visible=true;
int height=this.pictureBox1.Image.Height;
int width=this.pictureBox1.Image.Width;
Bitmap temp=new Bitmap(width,height);
Bitmap process=(Bitmap)this.pictureBox1.Image;
int i,j,p0,p1,p2,p3;
Color [] pixel=new Color[4];
int result;
for(j=height-2;j>0;j--)
{
for(i=0;i<width-2;i++)
{
pixel[0]=process.GetPixel(i,j);
pixel[1]=process.GetPixel(i,j+1);
pixel[2]=process.GetPixel(i+1,j);
pixel[3]=process.GetPixel(i+1,j+1);
p0=(int)(0.3*pixel[0].R+0.59*pixel[0].G+0.11*pixel[0].B);
p1=(int)(0.3*pixel[1].R+0.59*pixel[1].G+0.11*pixel[1].B);
p2=(int)(0.3*pixel[2].R+0.59*pixel[2].G+0.11*pixel[2].B);
p3=(int)(0.3*pixel[3].R+0.59*pixel[3].G+0.11*pixel[3].B);
result=(int)Math.Sqrt((p0-p3)*(p0-p3)+(p1-p2)*(p1-p2));
if (result>255)
result=255;
if (result<0)
result=0;
temp.SetPixel(i,j,Color.FromArgb(result,result,result));
}
}
this.pictureBox2.Image=temp;
}
}
(2)RobertVC算法
void CVidCapDlg::OnBnClickedButton3()
{
int mm[3][3];
for(int ii =0;ii<3;ii++)
for(int jj=0;jj<3;jj++)
mm[ii][jj] = 0;
mm[0][0] = -1;
mm[0][2] = 1;
mm[1][0] = -2;
mm[1][2] = 2;
mm[2][0] = -1;
mm[2][2] = 1;
MobanEdge3(mm);
// TODO: 再次添加控件通知处理程序代码
}
(3)RobertVC算法未处理图像
(4)RobertVC算法处理后图像
3.3.2Sobel算子
(1)SobelVC算法
索贝尔算子(Sobel operator)是图像处理中的基本算子之一,主要是用作边缘检测。在技术上,它是一离散性差分的算子,用来运算图像亮度函数的梯度的近似值。在图像的任何一点使用此算子,将会产生相对应的梯度矢量或者是其法矢量,其公式如下:
图像的每一个像素的横向以及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。
然后可用以下公式计算梯度的方向。
在以上例子中,如果以上的角度Θ是等于零的,即代表图像该处拥有纵向边缘,左方较右方暗。
在边沿检测中,常常使用的一种模板是Sobel 算子。Sobel 算子有两种,一种是检测水平边沿的 ;另一种是检测垂直边沿的 。与其他算子相比,Sobel算子对于象素位置的影响做了加权,因此效果更加好。
Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两种,一种是检测水平边沿的 ,另一种是检测垂直平边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为精确,在检测不同方向的边沿时梯度的幅度是一致的。由于建筑物图像的特殊性,我们可以发现,处理该类型图像的轮廓时,并不需要对梯度的方向进行运算,所以程序并没有给出各向同性Sobel算子的处理方法。
由于Sobel算子是滤波算子的形式,用于边缘的提取,可以利用快速卷积函数,简单有效,因此应用广泛。美中不足的是,Sobel算子并没有将图像的主体和背景严格地区分开来,换句话说就是Sobel算子没有基于图像的灰度进行处理,由于Sobel算子并没有严格地模拟人的视觉生理特性,所以提取的图像轮廓有时并不能令人满意。 在观测一幅图像的时候,我们往往首先要注意的是图像与背景不相同的部分,正是这个部分将主体突出显示出来,基于该理论,我们给出了下面阈值化轮廓提取算法,该算法已在数学上证明当像素点满足正态分布时所求解的是最优的。
.NET代码如下
for(Times=0;Times<128&&iThreshold!=iNewThreshold;Times++)
{
iThreshold=iNewThreshold;
lP1=0;
lP2=0;
lS1=0;
lS2=0;
for(i=iMinGray;i<iThreshold;i++)
{
lP1+=Histogram*i;
lS1+=Histogram;
}
iMean1Gray=lP1/lS1;
for(i=iThreshold;i<iMaxGray;i++)
{
lP2+=Histogram*i;
lS2+=Histogram;
}
iMean2Gray=lP2/lS2;
iNewThreshold=(iMean1Gray+iMean2Gray)/2;
}
补充Sobel算子的矩阵表达式:
Sobel1=[-1 -2 -1; %检测水平边沿的Sobel算子
0 0 0;
1 2 1];
Sobel2=[1 0 -1; %检测垂直平边沿的Sobel算子
2 0 -2;
1 0 -1];
void CVidCapDlg::OnBnClickedButton5()
{
int mm[3][3];
for(int ii =0;ii<3;ii++)
for(int jj=0;jj<3;jj++)
mm[ii][jj] = 0;
mm[0][0] = -1;
mm[0][2] = 1;
mm[1][0] = -2;
mm[1][2] = 2;
mm[2][0] = -1;
mm[2][2] = 1;
MobanEdge3(mm);
// TODO: 再次添加控件通知处理程序代码
}
(3)SobelVC算法未处理图像
(4)SobelVC算法处理后图像
3.3.3Prewitt算子
(1)Prewitt算法介绍
Prewitt算子指的是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差值,在边缘处达到极值检测边缘,去掉部分伪边缘,并对噪声具有平滑作用 。其原理是在图像空间利用两个方向上的模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。
对数字图像f(x,y),Prewitt算子的定义如下:
G(i)=|[f(i-1,j-1)+f(i-1,j)+f(i-1,j+1)]-[f(i+1,j-1)+f(i+1j)+f(i+1,j+1)]|
G(j)=|[f(i-1,j+1)+f(i,j+1)+f(i+1,j+1)]-[f(i-1,j-1)+f(i,j-1)+f(i+1,j-1)]|
则 P(i,j)=max[G(i),G(j)]或 P(i,j)=G(i)+G(j)
经典Prewitt算子认为:凡灰度值大于或者等于阈值的像素点都是边缘点。即是选择适当的阈值T,若P(i,j)≥T,则(i,j)为边缘点,P(i,j)为边缘图像。这种判定是不太合理的,会造成边缘点的错误判断,因为许多噪声点的灰度值也很大,而且对于幅值较小的边缘点,其边缘反而丢失了。
(2)PrewittVC算法
void CVidCapDlg::OnBnClickedButton6()
{
int mm[3][3];
for(int i =0;i<3;i++)
for(int j=0;j<3;j++)
mm[i][j] = 0;
mm[0][0] = -1;
mm[0][1] = -1;
mm[0][2] = -1;
mm[2][0] = 1;
mm[2][1] = 1;
mm[2][2] = 1;
MobanEdge3(mm);
// TODO: 再次添加控件通知处理程序代码
}
(3)PrewittVC算法未处理图像
(4)PrewittVC算法处理后的图像
3.3.4Laplacian算子
(1)Laplacian算法介绍
Laplacian 算子指的是n维欧几里德空间里的一个二阶微分算子,定义为梯度()的散度()。因此如果f是二阶可微的实函数,则f的拉普拉斯算子定义如下:
(1) f的拉普拉斯算子是笛卡儿坐标系xi中的所有非混合二阶偏导数;
(2) 作为一个二阶微分算子,拉普拉斯算子把C函数映射到C函数,对于k ≥ 2。表达式(1)(或(2))定义了一个算子Δ : C(R) → C(R),或更一般地,定义了一个算子Δ : C(Ω) → C(Ω),对于任何开集Ω。
对于阶跃状的边缘,导数在边缘点出现零交叉,即边缘点两旁二阶导数取异号。据此,对数字图像{f(i,j)}的每个像素,取它关于x轴方向和y轴方向的二阶差分之和,表示为
运算模板
函数的拉普拉斯算子也是该函数的黑塞矩阵的轨迹,可以证明,它具有各向同性,即与坐标轴方向是无关的,坐标轴旋转后梯度结果不变。如果邻域系统是4 邻域,Laplacian 算子的模板为:
0
1
0
1
-4
1
0
1
0
如果邻域系统是8 邻域,Laplacian 算子的模板为:
1
1
1
1
-8
1
1
1
1
前面提过,Laplacian 算子对噪声是比较敏感的,所以图像一般首先是经过平滑处理的,因为平滑处理也是运用模板进行的,所以,通常的分割算法都是把Laplacian 算子和平滑算子结合起来生成一个新的模板。
(2)LaplacianVC算法
void CVidCapDlg::OnBnClickedButton7()
{
int mm[3][3];
for(int i =0;i<3;i++)
for(int j=0;j<3;j++)
mm[i][j] = 0;
mm[0][0] = -1;
mm[0][1] = -1;
mm[0][2] = -1;
mm[2][0] = 1;
mm[2][1] = 1;
mm[2][2] = 1;
MobanEdge3(mm);
// TODO: 再次添加控件通知处理程序代码
}
(3)LaplacianVC未处理的图像
(4)LaplacianVC处理后的图像
3.3.5Kirsch算子
(1)Kirsch算法介绍
利用经典图像边缘检测模板的算子在8个方向模板之间的内在联系,提出了一种新的快速Kirsch算法。实验证明采用快速Kirsch算法可将对图像处理的速度提高到采用经典Kirsch算法所达到的运算速度的三倍以上。
(2)KirschVC算法
void CVidCapDlg::OnBnClickedButton8()
{
int mm[3][3];
for(int i =0;i<3;i++)
for(int j=0;j<3;j++)
mm[i][j] = -3;
mm[0][0] = 5;
mm[0][1] = 5;
mm[0][2] = 5;
mm[1][1] = 0;
MobanEdge3(mm);
// TODO: 再次添加控件通知处理程序代码
}
(3)KirschVC未处理的图像
(4)KirschVC处理后的图像
3.4图像的Hough变换
Hough变换利用图像空间与Hough参数空间的点与线的对偶性,把图像空间中的检测问题转换到参数空间中。通过在参数空间里进行简单的累加统计,接着在Hough参数空间寻找累加器峰值的方法检测直线。即也就是把检测整体特性转化为检测局部特性。比如直线、椭圆、圆、弧线等。
Hough变换的基本思想为:在原始图像坐标系中的一个点对应参数坐标系中的一条直线,同样参数坐标系中的一条直线对应了原始坐标系中的一个点,接下来,原始坐标系下显示直线上的所有点,他们的斜率和节距都是相同的,即在参数坐标系下对应着同一个点。将原始坐标系下的各个点投影到参数坐标系下以后,观察参数坐标系下有没有聚焦点,这样的聚焦点就对应了原始坐标下的直线。
3.4.1图像的Hough变换VC代码
* 函数名称:
* HoughDIB()
* 参数:
* LPSTR lpDIBBits - 指向源DIB图像指针
* LONG lWidth - 源图像宽度(象素数,必须是4的倍数)
* LONG lHeight - 源图像高度(象素数)
* 返回值:
* BOOL - 运算成功返回TRUE,否则返回FALSE。
* 说明:
* 该函数用于对检测图像中的平行直线。如果图像中有两条平行的直线,则将这两条平行直线
* 提取出来。
* 要求目标图像为只有0和255两个灰度值的灰度图像。
************************************************************************
BOOL WINAPI HoughDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
// 指向源图像的指针
LPSTR lpSrc;
// 指向缓存图像的指针
LPSTR lpDst;
// 指向变换域的指针
LPSTR lpTrans;
// 图像每行的字节数
LONG lLineBytes;
// 指向缓存DIB图像的指针
LPSTR lpNewDIBBits;
HLOCAL hNewDIBBits;
//指向变换域的指针
LPSTR lpTransArea;
HLOCAL hTransArea;
//变换域的尺寸
int iMaxDist;
int iMaxAngleNumber;
//变换域的坐标
int iDist;
int iAngleNumber;
//循环变量
long i;
long j;
//像素值
unsigned char pixel;
//存储变换域中的两个最大值
MaxValue MaxValue1;
MaxValue MaxValue2;
// 暂时分配内存,以保存新图像
hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);
if (hNewDIBBits == NULL)
{
// 分配内存失败
return FALSE;
}
// 锁定内存
lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
// 初始化新分配的内存,设定初始值为255
lpDst = (char *)lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight);
//计算变换域的尺寸
//最大距离
iMaxDist = (int) sqrt(lWidth*lWidth + lHeight*lHeight);
//角度从0-180,每格2度
iMaxAngleNumber = 90;
//为变换域分配内存
hTransArea = LocalAlloc(LHND, lWidth * lHeight * sizeof(int));
if (hNewDIBBits == NULL)
{
// 分配内存失败
Return FALSE;
}
// 锁定内存
lpTransArea = (char * )LocalLock(hTransArea);
// 初始化新分配的内存,设定初始值为0
lpTrans = (char *)lpTransArea;
memset(lpTrans, 0, lWidth * lHeight * sizeof(int));
// 计算图像每行的字节数
lLineBytes = WIDTHBYTES(lWidth * 8);
for(j = 0; j <lHeight; j++)
{
for(i = 0;i <lWidth; i++)
{
// 指向源图像倒数第j行,第i个象素的指针
lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
//取得当前指针处的像素值,注意要转换为unsigned char型
pixel = (unsigned char)*lpSrc;
//目标图像中含有0和255外的其它灰度值
if(pixel != 255 && *lpSrc != 0)
return FALSE;
//如果是黑点,则在变换域的对应各点上加1
if(pixel == 0)
{
//注意步长是2度
for(iAngleNumber=0; iAngleNu
展开阅读全文