Visual C++中基于多文档视窗模型的重叠图象拼接技术

Visual C++中基于多文档视窗模型的重叠图象拼接技术

辽宁省抚顺石油学院计算机科学与技术系    李志刚 

摘要:

       图象拼接是在全景视频系统、地理信息系统等应用中经常遇到的一个问题,本文基于网格匹配的方法对边界部分有重叠的图象提出了一种行之有效的对准算法,并通过平滑因子对图象实现了无缝拼接。并应用文档视窗模型实现了该算法,并完成了位图文件的显示、存储等操作,具有一定的普遍意义。

关键词:

       图象拼接,算法,重叠图象,文档视窗,位图文件,图象显示

一、           多文档视窗模型概述

MFCAppWizard可以生成三种类型的应用程序:基于对话框的应用、单文档应用(SDI)和多文档应用(MDI)。三种应用中,以多文档应用(MDI)最为复杂,其功能也最强大。当我们用AppWizard生成一个多文档应用时,系统由CMultiDocTemplate自动生成了一个从Cdocument类继承的文档类,一个从Cview类继承的视窗类,一个从CMDIChildWnd类继承的框架类。当我们每次建立一个新的文档时,程序根据文档模板生成一个新实例,这些我们均可不用关心AppWizard已经自动生成了代码。但如果我们要在程序中使用多个不同的文档类时,则需自己建立文档模板并控制文档实例的建立。假设我们要向一基于多文档的工程MDI中增加一Test的文档。具体步骤如下:

1、ClassWizard建立一个框架类CTestFrame基类选CMDIChildWnd

2、ClassWizard建立一个文档类CTestDoc基类选CDocument

3、ClassWizard建立一个文档类CTestView基类选CView

4、将三个类的头文件加入应用类CMDIApp中。

5、创建新文档模板,在CMDIApp::InitInstance()函数中加入如下代码

      CMultiDocTemplate* pDocTemplate;

       pDocTemplate = new CMultiDocTemplate(

              IDR_TESTTYPE,

              RUNTIME_CLASS(CTestDoc),

              RUNTIME_CLASS(CTestFrame),

              RUNTIME_CLASS(CTestView));

       AddDocTemplate(pDocTemplate);

6、定义一菜单项ID号为ID_NEWTEST,利用ClassWizard将其处理函数加入应用类(或主框架类),在其处理函数CMDIApp::OnNewtest()函数中加入如下代码

       POSITION curTemplatePos = GetFirstDocTemplatePosition();

       while(curTemplatePos != NULL)

       {

              //取下一个文档模板指针

              CDocTemplate* curTemplate =GetNextDocTemplate(curTemplatePos);

              CString str;

              curTemplate->GetDocString(str, CDocTemplate::docName);     //取文档名称

              if(str == _T("Test"))      //判断当前文档文档是否Test

              {

                     curTemplate->OpenDocumentFile(NULL); //创建新的文档实例

                     return;

}

              }

       这样我们就建立了一个新的文档类。注意在5中创建文档模板时我们用到了一文档类型资源IDR_TESTTYPE,该资源ID在资源文件中定义如下(未包括图标和菜单的定义)

STRINGTABLE PRELOAD DISCARDABLE

BEGIN

       ……….

       IDR_TESTTYPE           "/nTest/nTest/n/n/nMDI.Document/nTest Document"

END

    文档类型标识包括七个子串,包括窗口标题、文档名称、文件扩展名等。在6curTemplate->GetDocString(str, CDocTemplate::docName);取的就是第二个子串,文档名称。文档建立之后我们就可以对其进行操作了。当然文档类和视窗类,文档类和主窗口类,以及不同文档类之间进行通信也是较为复杂的,并非几句话就能说清楚,如不熟悉文档视窗的读者请参看其它有关资料。

二、           重叠图象拼接技术

1.算法思想

在实现全景视频(Panoramic Video)系统、地理信息系统(GIS)及其它一些应用的过程中,我们通常会碰到这样的一个问题,就是要把几幅小的图象拼接成一幅大的图象。为了能让计算机自动对准图象我们要求待拼接的图象边界有部分重叠,计算机正是利用这些信息进行匹配对准。匹配算法的总体思想是既要保证对准的精度,又要保证运算量不至过大。这里算法利用了图象的自身特性,既在一般图象中,相邻的象素点的灰度值相差不大。因此,可在第二幅图象的边界取一个网格,然后将网格在第一幅图象上移动,计算所有网格点的两幅图象对应象素点的RGB值的差的平方和。记录最小的值的网格位置,即认为是最佳匹配位置。(如图 1)为了减小运算量,我们将匹配分为两个步骤,第一步是粗略匹配,在该阶段网格每次水平或垂直移动一个网格间距。在完成粗略匹配之后,我们在当前最佳匹配点处进行精确匹配,在该阶段以当前最佳匹配点为中心,网格向上下、左右各移动一个小步长。初始步长为粗略拼接时移动步长的一半,即为半个网格间距。不断的与当前最小平方和进行比较,如果比当前值优,就替换当前最佳匹配点。循环进行这个过程每次步长减半,直到水平步长和垂直步长均为0为止。


 


       (a) 拼接前两幅图象                                                      b)拼接后合成的图象

1     网格匹配拼接示意图

2.算法描述

procedure ImageMatching

{

       输入FirstImage;

       输入SecondImage;

       //获得两幅图象的大小

       Height1=GetImageHeight(FirstImage);

       Height2=GetImageHeight(SecondImage);

       Width1=GetImageWidth(FirstImage);

       Width2=GetImageWidth(SecondImage);

// 从第二幅图象取网格匹配模板

       SecondImageGrid = GetSecondImageGrid(SecondImage);

// 粗略匹配,网格在第一幅图象中先从左向右移动,再从下到上移动,每次移动一个网格间距,Step_Width Step_Height,当网格移出重叠区域后结束

y=Heitht1-GridHeight;

MinValue = MaxInteger;

While ( y<Height1-OverlapNumber)//当网格移出重叠部分后结束

{

              x=Grid_Width/2; //当网格位于第一幅图象的最左边时,A点的横坐标。

              While ( x<(Width1-Grid_Width/2) )

{

                     FirstImageGrid=GetImgaeGrid(FirstImgaeGrid, x, y);

                differ=CaculateDiff(FirstImgaeGrid, SecondImageGrid);//计算象素值差的平

                                                              //方和

                     if (differ<MinValue)

                     {

                            BestMatch_x=x;

                            BestMatch_y=y;

                            MinValue = differ;

                     }

              x= x+Step_width;

              }

              y=y-Step_Height;

}           

//精确匹配

Step_Width= Step_Width/2;

Step_Height= Step_Height/2;

While ( Step_Height>0 & Step_Width>0)//当水平步长和垂直步长均减为零时结束

{

       if(Step_Height==0) //当仅有垂直步长减为零时,将其置为1

              Step_Height=1;

       If(Step_Width==0) //当仅有水平步长减为零时,将其置为1

              Step_Width=1;

temp_x = BestMatch_x;

temp_y = BestMatch_y;

       for ( i= -1; i<1; i++)

              for( j= -1; j<1; j++)

              {

                     if ((i=0&j!=0)|(i!=0&j=0))

                     {

                           FirstImageGrid=GetImgaeGrid(FirstImgaeGrid,

temp_x+i*Step_Width, temp_y +j*Step_Height);

                     differ=CaculateDiff(FirstImgaeGrid, SecondImageGrid);

              if (differ<MinValue)

                            {

                                   BestMatch_x=x;

                                   BestMatch_y=y;

                                   MinValue = differ;

                     }

                     }

                    }

              Step_Height = Step_Height /2;

              Step_Width = Step_Width/2;

       }

}    

 

三、           基于多文挡视窗模型的重叠图象拼接技术

程序在Visual C++实现过程中有如下一些技术问题需要注意。

1、  位图文件的读取和显示

位图文件是一种最简单的图象文件,屏幕图象的每一点对应位图文件的几位数据。现有的标准有1位、4位、8位、24位。24位位图不含颜色表,每个象素用3个字节表示,依次表示RGB空间里的蓝、绿、红的灰度值。每种位图文件都由两部分组成,一部分是文件头和位图信息头,另一部分是图象的位数组。因此要想显示一个位图文件首先要声明一个CFile类实例将文件读入内存,然后根据文件头和位图信息头获得图象的相关信息和位数组的起始地址。调用SetDIBitsToDevice()函数即可把图象显示在屏幕上。

2、  位图文件中任意象素点颜色值的获取

要实现图象的处理,访问任意象素点的象素值是必需的操作。在访问位图文件时有两点需要注意,一是图象位数组的存储是按从下到上进行的。也就是说,图象的最底行的数据存在位数组的最开始位置。另一个特点是,图象的每行象素所占的空间是双字的整数倍,不足的用零填充。每行象素的实际存储大小可由以下公式加以计算。

    WidthBytes=(((biWidth*biBitCount)+31)&~31)>>3                       1

    假设位数组的起始指针为lpStartBits屏幕坐标(x,y)在的象素值的指针可用下式计算。

lpBits=lpStartBits + (WidthBytes*(Height-y-1) + x*biBitCount);                       (2)

    其中WidthBytes为(1)式计算的值,Height为图象的高度。

3、  不同文档类之间的数据交换的实现

不同文档类之间的数据交换我们可以通过应用程序类或主窗口类作为媒介进行。在文档类或视窗类可通过AfxGetApp()AfxGetMainWnd()获得应用类和主窗口类的指针,在应用类和主窗口类则可以通过获得文档模板来获得文档类的指针来访问文档类的数据。这样我们可以通过应用类或主窗口类的成员变量进行数据交换了。

4、  图象的平滑连接

当找到最佳匹配点后,随后的工作将是把两幅图象合成一幅图象。对于重叠部分,我们如果只是简单的取第一幅图象或第二幅图象的数据,会造成图象的模糊和明显的边界,这是不能容忍的。即使取两幅图象的平均值,效果也不能令人满意。为了能使拼接区域平滑,保证图象质量,我们采用了渐入渐出的方法,即在重叠部分由第一幅图象慢慢过渡到第二幅图象,很自然我们可以想到设一渐变因子为0<d<1,对应的前后两幅图象为image1image2,结果为image3,则image3=d*image1+(1-d)*imge2其中d的值由1渐变到0,它与该点距重叠边界的距离有关。

 

四、           多文挡视窗模型的重叠图象拼接程序框架

1.  程序构成

程序除应用类、主窗口类以外,还包括CFristImageDoc, CSecondImageDoc, CThirdImageDoc类用来保存第一幅、第二副以及拼接后图象的数据。还有与其相连的文档类和框架类。

2.  程序流程

程序的主要工作在应用类中完成,首先打开第一幅图象,图象的显示等操作由CFirstImageDoc 类和与其相关的视窗类及框架类完成,并将图象的位数组指针和图象大小传给应用类成员变量。再打开第二幅图象同样完成显示等操作,也将位数组指针和图象大小传给应用类成员变量。在应用类中完成图象的匹配对准工作,最后实现图象的合成。将合成后的图象传给CThirdImageDoc类进行显示当用户对拼接结果基本满意后,可以选择平滑连接将两幅图象平滑的连接起来。用户可将最后的结果保存成bmp文件。

五、           总结

图象拼接中,图象对准是前提和关键,程序基于网格匹配的方法实现了图象对准,应用了交互技术让用户可以对网格点的多少,网格间距大小,均可调整,还允许用户输入重叠范围使拼接过程有的放矢,缺省是较小图象高度的1/3。该程序实现了对位图图象文件的各种操作,具有普遍意义,还引入了不同文档类型的多文档视窗模型,并在不同文档类间实现了数据交换,具有一定的实用价值。为了使程序简单易用,只实现了对24位位图的拼接,也未提供垂直方向的拼接,只提供了水平方向的拼接。如要对不符合条件的图象进行拼接我们只需在Windows提供的画笔中将图象转化一下即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值