数字摄影测量作业报告
提取影像特征点
2010 年 12 月 15 日
- 1 -
1 作业任务 ------------------------------------------------------------------------------------ 2 作业思想 --------------------------------------------------------------------------------------- 3 设计原理与思路-------------------------------------------------------------------- 4 作业过程 --------------------------------------------------------------------------- 5 源程序 -----------------------------------------------------------------------------
6 作业成果 --------------------------------------------------------------------------- 7作业自我评点 ----------------------------------------------------------------------------- 8心得体会与建议-----------------------------------------------------------------------------
3 3 3 4 5
9 10 10
- 2 -
1 作业任务
提取一幅数字影像中的特征点:根据Moravec算子,编制程序,从一幅数字影像中自动提取50个以上的点特征(特征点)
2作业思想
理论上,特征是影像灰度曲面的不连续点。在实际影像中,由于点扩散函数的作用,特征表现为在一个微小邻域中灰度的急剧变化,或灰度分布的均匀性,也就是在局部区域中具有较大的信息量。
若不考虑噪声,实际影像是理想灰度函数与点扩散函数的卷积,则点特征与边缘特征如图2—3—2和图2—3—3所示,其灰度的分布均表现为从小到大或从大到小的明显变化,因而除了用局部信息量来检测特征之外,还可以利用各种梯度或差分算于提取特征。本次作业便采用Moravec算子,从影像中提取感兴趣的特征点。
3设计原理与思路
点特征主要是指明显点,如角点、圆点等。提取点特征的算子称为兴趣算子,即用某种算法从影像中提取感兴趣的特征点。本次作业采用Moravec算子的算法,提取特征点。
Moravec算子的计算原理与步骤如下:
(1). 计算各像素的兴趣值IV。在以像素(c , r)为中心的n* n(如5* 5)的窗口中, 如图3-1所示,计算四个方向相邻像素灰度差的平方和,则
k12V1(gci,rgci1,r)ikk12V2(gci,rigci1,ri1) ik (31)k1V3(gc,rigc,ri1)2ikk1V4(gci,rigci1,ri1)2ik
- 3 -
图 3-1 Morabec算子
式中:k=int(n/2)。取其中最小者作为该像素(c , r)的兴趣值,即
IVc,rmin{V1,V2,V3,V4}
(2). 给定一阈值,将兴趣值大于该阈值的点(窗口中心)作为候选点。
(3). 选取候选点中的极值点作为特征点。在一定大小的窗口内(窗口大小可不同于兴趣值计算窗口),选择候选点中兴趣值最大的点作为特征点。
根据以上Moravec算子的计算原理与步骤,运用visual studio新建项目,制作一个简单的小程序,包括打开图像,提取特征点,并且将特征点行列号列表显示等功能。
4作业过程
4.1 窗体设计
如图4-1-1,添加picturebox控件,相当于图像显示区;添加4个Button控件,分别为“打开图像”,“保存图像”,“提取特征点”,“关闭”事件按钮;添加textbox控件,输入阈值;添加listview控件用于列表显示所提取特征点的相关信息。
图 4-1-1 窗体设计
- 4 -
4.2 编写代码:
根据所设计的窗体,为各控件添加事件代码。 “打开图像”,“保存图像”以及“关闭”控件代码参考《C#数字图像处理算法典型事例》编写;“提取特征点”代码根据Moravec算子的计算原理与步骤编写,并标记特征点;添加listview控件中的列(序号、行号、列号、兴趣值)并设置属性,于listview控件中列表显示特征点的行列号和兴趣值。
4.3 调试程序:
准备一张特征明显的图像(在同学建议下,采用八卦图),编写完代码后启用调试,根据错误提示找原因,一个一个解决问题。观察提取点的图像位置和数据有无异常,不断调试程序,直至程序运行正常。
5 源程序
using System;
using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text;
using System.Windows.Forms;
namespace 提取影像特征点 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent(); }
private string curFileName;
private System.Drawing.Bitmap curBitmap;
//打开图像至picturebox控件窗口
private void open_Click(object sender, EventArgs e) {
OpenFileDialog opnDlg = new OpenFileDialog();
opnDlg.Filter = \"所有图像文件 | *.bmp; *.pcx; *.png; *.jpg; *.gif;\" + \"*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf|\" +
\"位图( *.bmp; *.jpg; *.png;...) | *.bmp; *.pcx; *.png; *.jpg; *.gif; *.tif; *.ico|\" +
\"矢量图( *.wmf; *.eps; *.emf;...) | *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf\"; opnDlg.Title = \"打开图像文件\";
- 5 -
opnDlg.ShowHelp = true;
if (opnDlg.ShowDialog() == DialogResult.OK) {
curFileName = opnDlg.FileName; try {
curBitmap = (Bitmap)Image.FromFile(curFileName); pictureBox1.Image = curBitmap; }
catch (Exception exp) {
MessageBox.Show(exp.Message); } }
Invalidate(); }
//提取特征点
private void extraction_Click(object sender, EventArgs e) {
double V1, V2, V3, V4; int t = 0; int w, h, s; w = curBitmap.Width; h = curBitmap.Height; s = w * h;
double f = int.Parse(textBox1.Text);//获取阈值
double[,] Gray = new double[w, h];//存储所有像素点灰度值 double[,] IV = new double[w, h];//存储所有像素点兴趣值 double[] V = new double[s];//存储特征点兴趣值 double[] I = new double[s];//存储特征点列号 double[] J = new double[s];//存储特征点行号 Color curColor;
Color c = Color.FromArgb(255, 0, 0);//设置标注特征点的颜色:红色
//计算并存储所有像素点灰度值 for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
curColor = curBitmap.GetPixel(i, j);
Gray[i, j] = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
} }
- 6 -
//计算并存储所有像素点兴趣值 for (int i = 2; i < w - 2; i++) {
for (int j = 2; j < h - 2; j++) {
V1 = Math.Pow((Gray[i - 2, j] - Gray[i - 1, j]), 2) + Math.Pow((Gray[i - 1, j]- Gray[i, j]), 2) + Math.Pow((Gray[i, j] - Gray[i + 1, j]), 2) + Math.Pow((Gray[i + 1, j] - Gray[i + 2, j]), 2);
V2 = Math.Pow((Gray[i - 2, j - 2]- Gray[i - 1, j - 1]), 2) + Math.Pow((Gray[i - 1, j - 1] - Gray[i, j]), 2) + Math.Pow((Gray[i, j] - Gray[i + 1, j + 1]), 2) + Math.Pow((Gray[i + 1, j + 1] - Gray[i + 2, j + 2]), 2);
V3 = Math.Pow((Gray[i, j - 2] - Gray[i, j - 1]), 2) + Math.Pow((Gray[i, j - 1] - Gray[i, j]), 2) + Math.Pow((Gray[i, j] - Gray[i, j + 1]), 2) + Math.Pow((Gray[i, j + 1] - Gray[i, j + 2]), 2);
V4 = Math.Pow((Gray[i - 2, j + 2] - Gray[i - 1, j + 1]), 2) + Math.Pow((Gray[i - 1, j + 1] - Gray[i, j]), 2) + Math.Pow((Gray[i, j] - Gray[i + 1, j - 1]), 2) + Math.Pow((Gray[i + 1, j - 1] - Gray[i + 2, j - 2]), 2);
double IV1 = Math.Min(V1, V2); double IV2 = Math.Min(IV1, V3); double IV3 = Math.Min(IV2, V4); IV[i, j] = IV3; } }
//提取兴趣值大于阈值的点并标记 for (int i = 2; i < w - 2; i++) {
for (int j = 2; j < h - 2; j++) {
if (IV[i, j] > f) {
V[t] = IV[i, j]; I[t] = i; J[t] = j; t++;
curBitmap.SetPixel(i, j, c); for (int n = 1; n < 4; n++) {
if (i + n < w && j + n < h && i - n >= 0 && j - n >= 0) {
curBitmap.SetPixel(i - n, j, c); curBitmap.SetPixel(i + n, j, c); curBitmap.SetPixel(i, j - n, c); curBitmap.SetPixel(i, j + n, c);
- 7 -
} } }
} }
//列表显示提取点的行列号和兴趣值 for (int k = 0; k < t; k++) {
int xh = k + 1;
ListViewItem li = new ListViewItem(); li.Text = xh.ToString();
li.SubItems.Add(I[k].ToString()); li.SubItems.Add(J[k].ToString()); li.SubItems.Add(V[k].ToString()); listView1.Items.Add(li); }
}
//保存图像
private void save_Click(object sender, EventArgs e) {
if (curBitmap == null) {
return; }
SaveFileDialog saveDlg = new SaveFileDialog(); saveDlg.Title = \"保存为\"; saveDlg.OverwritePrompt = true; saveDlg.Filter =
\"BMP文件 (*.bmp) | *.bmp|\" + \"Gif文件 (*.gif) | *.gif|\" + \"JPEG文件 (*.jpg) | *.jpg|\" + \"PNG文件 (*.png) | *.png\"; saveDlg.ShowHelp = true;
if (saveDlg.ShowDialog() == DialogResult.OK) {
string fileName = saveDlg.FileName;
string strFilExtn = fileName.Remove(0, fileName.Length - 3); switch (strFilExtn) {
case \"bmp\":
- 8 -
curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Bmp); break; case \"jpg\":
curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg); break; case \"gif\":
curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Gif); break; case \"tif\":
curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Tiff); break; case \"png\":
curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); break; default: break; } }
}
//关闭窗口
private void close_Click(object sender, EventArgs e) {
this.Close();
} } }
- 9 -
6 作业成果
阈值取26000时,提取55个特征点:
阈值取20000时,提取423个特征点:
- 10 -
7作业自我评点
7.1 优点:
窗体设计简洁大方,虽然舍去了常规菜单栏的设计,但按钮功能更突出作业目的。 提取特征点程序运算过程的编写无迭代和函数循环调用,运算速度快。
特征点的标记采用以特征点为中心,改变周围像素点颜色使其成“+”的红色标记,定位准确,避免了直接使用DrawString方法绘制符号,造成符号中心与特征点不重合的定位错误。
7.2 缺点:
窗体设计过于简单,程序功能不够完整全面,图像大小有上限,不能自动调整适应
大图。
程序运行并提取特征点后,要将程序最小化,再打开,才能看到特征点的标记。(原
因尚在研究中)
出现同一区域重复提取特征点,或是特征点靠太近的现象 7.3 自我评点:
此次作业总体来说完成了预定的任务,达到目的,但仍存在一些问题。在作业过程中,通过查阅资料,自主学习以及与同学交流,发现了不少问题并及时改进,仍然存在的问题实属时间和现阶段自己的编程技术,相信在以后的学习和提高之后能够解决好这些问题。
8 心得体会与建议
终于写到这一部分了,从开始准备做这次作业,到现在快要完成报告,不仅经历了很长时间,这个过程中自己也是感慨颇多,恨不得赶紧来写心得体会,抒发一下自己的感想。
这一个作业可能是历时最长的一次作业吧,开始的时候属于无从下手什么都不懂的阶段,所以进展很慢,积极性也不高,自己也不自觉,导致时间拖得很长。一开始由于受“数字图像处理”这门课程影响,想用matlab来实现这次作业,不过后来考虑matlab的可视化和使用方面不如visual studio编程,果断放弃了。转投visual studio程序设计后,又发现很多东西都忘了,于是又图书馆借书回来自己琢磨,温习大一暑假程序设计实习,然后一点一点开始了这次作业的编写。
在程序设计的过程中,《C#数字图像处理算法典型事例》这本书给了我很大的帮助和影响,窗口的设计和“打开图像”“保存图像”等的设计理念和代码大部分都源于这本书,慢慢地自己也学习了不少图像处理方面的知识。在调试程序的过程中也很头疼,因为对C#语言还不是非常熟悉,所以有些错误让人有些束手无策,不过事实证明,耐心和细心地去寻找原因并解决问题是可行的,也是以后的学习过程中自己需要培养的好习惯。当我的程序调试运行之后,各方面都挺顺利,不过让人郁闷的是特征点老是出现在了不是“特征”的位置上,为了解决这个问题,我自己一直研究了很久,感觉遇到了瓶颈。后来去请教了班上已经完成这个作业的同学,他们给我了很大的帮助,我才发现原来是直接使用DrawString方法绘制“+”符号而引起的,这个方法是直接用笔刷的方式绘制“+”符号,可能是取符号左上角对准位置,不能使符号中心与特征点很好地重合,导致定位错误。后来改用特征点的标记采用以特征点为中心,改变周围像素点颜色使其成“+”的红色标记,才使得定位准确。
对比当初第一次完成的未修改的程序和今天经过多次调试和修改之后的程序,发现真是变化很大。开始时自己的风格还总是局限于c++式,编写了很多子函数,如计算灰度值的子函数,计算兴趣值的子函数,在特定大小的窗口中提取特征点的子程序等,然后再一一调用,这样下来程序运行非常慢,同学看了之后都笑称我的程序提取点就像一个动态FLASH,确实,
- 11 -
每找到一个特征点标记一次,而非先全部找到后记录下来再标记这样非常耗费时间。不过改进之后,用3个数组存储找到的特征点信息,然后再全部标记,这样速递大大提高。还有一开始的时候我还不知道用listview控件,也是按照C++的思想,将特征点的行列号输出到了文本。后来在与同学交流中惊喜地发现这个控件可以使用,又改进了自己的程序。不过程序很多地方仍然存在不足,感觉专业知识方面的原理都很清楚了,就是程序设计和代码编写方面的技术不够,经验不足,加上时间也没法短时间内让自己称为一个编程高手,故还请老师原谅,我的程序确实比较简单。
这次作业又让我想起了上学期刚后方交会课程作业的情况,也是一开始觉得无从下手,自己把自己吓倒了,最后完成之后才恍然发现其实也并不难,其实也不是作业很简单,是自己在这个过程中又不断地学习和提高,使自己更加有实力来完成作业。作业过程中的经验和体会相信会给以后的学习带来莫大的帮助。感谢老师,感谢这样一次作业的机会又让我提高了不少。
谢谢老师辛苦地审阅此次作业!
- 12 -
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 7swz.com 版权所有 赣ICP备2024042798号-8
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务