AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

碎片图像无缝拼合技术的VC++实现

51自学网 2015-08-30 http://www.51zixue.net

一、 引言

在测绘、文博等行业经常会遇到这样一种情况:观测对象比较大,为保证分辨率又不能将其全部照下,只能进行局部照相,事后再将这些局部照相的重合部分去掉,拼合成一幅完整的图像。以前多采用手工拼合,误差较大,往往不能很好的实现无缝拼合,即使有少量的专业设备,成本也普遍较高。其实只需将照片通过扫描仪将其录入到计算机中,通过程序处理,完全能很好的实现多幅图像的无缝拼合,满足实际需要,而且对于文博行业中常会遇到的破碎的、不规则对象如古旧字画残片等也能很好的进行无缝拼合。本文就对针对该程序的实现原理及过程做了简要的介绍。

二、 程序设计原理

首先我们从实际出发,我们是通过进行局部照相的手段来保存整体的全部信息,而要保证这些局部照片所含的信息之和能包括整体的全部信息就必然的使每两幅邻近的图片有一部分交叠的部分,这样才能保证在将整体对象划分为若干局部照片而后再拼合成整体图像的过程中不遗漏任何信息,即该划分、拼合的整个过程是无损的。既然如此,我们只需能保证让两相邻图片的重叠部分能完全重合,那么我们也就能够肯定在此状态下的这两幅图像实现了无缝拼合。所以,问题就转换为使相邻图片的重叠部分能完全重合,而判断两相同的图像片段是否完全重叠可以用光栅掩码来进行直观的判断,比如我们可以采用"异或"的掩码,当相同位置上的两幅图片的像素相同时就为0即黑色,所以可以对两图片进行移动,只要重叠部分全黑,则表明此时两图像的重叠部分已准确的重合了,而此时也实现了图像的无缝拼合。此后只需再采用"或"的光栅掩码将合并后的图像显示出来,再通过拷屏等手段将其存盘即可。在实现拼合的全过程中主要涉及到图像的拖放、图像文件的读取及显示、光栅掩码、拷屏以及内存位图的保存等多种技术。接下来就对这些技术的具体应用进行介绍。

三、 程序的具体实现

在进行拼合之前,首先要将从扫描仪录入的图像从文件读取到内存中,并显示出来。由于在拼合时采取的光栅操作掩码是"异或",所以为保持图像的原始面貌,可以在消息WM_ERASEBKGND 的响应函数中用PatBlt函数将整个客户区的初始背景设定为黑色:

……
pDC->PatBlt(0,0,rect.Width(),rect.Height(), BLACKNESS);
return TRUE;

读取位图文件可以用LoadImage函数来实现,m_sPath1指定了文件的路径,LR_LOADFROMFILE属性指定从文件中读取位图,返回值为该位图的句柄:

……
HBITMAP hbitmap;
hbitmap=(HBITMAP)LoadImage(AfxGetInstanceHandle(),
m_sPath1,
IMAGE_BITMAP,0,0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);

之后我们就可以创建一个和当前设备环境兼容的内存设备环境hMemDC1,并将刚才读取到内存的位图放置到该设备环境中:

hMemDC1=::CreateCompatibleDC(NULL);
SelectObject(hMemDC1,hbitmap);
::DeleteObject(hbitmap); //释放掉用过的位图句柄
Invalidate();

至于位图的显示,由于需要频繁的拖动和其他处理,将其放置于OnDraw函数中较为合理,需要更新显示时只需显式地用Invalidate()函数刷新即可。OnDraw()中的显示位图部分最好用BitBlt函数来完成,该函数负责把hMemDC1中的位图放置到pDC页面中以完成内存页面的置换,其处理速度还是比较快的:

……
::BitBlt(pDC->m_hDC,m_nX1,m_nY1, m_nWidth1,m_nHeight1,hMemDC1,0,0,m_dwRop);
……

函数中的m_dwRop变量对光栅操作码进行设置,初始为SRCINVERT即光栅异或操作,当拼合成功需要显示合并后的效果时再将其设定为SRCPAINT光栅或操作。

我们可以通过对鼠标消息响应函数的编程来实现在客户区内的位图拖放,按照Windows系统的习惯,首先在鼠标左键的响应函数中通过PtInRect()函数判断鼠标在左键按下时是否是落在位图上,如果是就可以在鼠标左键弹起之前将图片随鼠标拖动了,显然这部分应在WM_MOUSEMOVE消息的响应函数内编写代码:

……
if(m_bCanMove1==true) //在移动之前鼠标左键是在图片上点击的
{
int dx=m_nOldX1-m_nX1; //计算鼠标距离图片原点的距离
int dy=m_nOldY1-m_nY1;
m_nX1=point.x-dx; //计算新的图片原点的坐标(客户区坐标)
m_nY1=point.y-dy;
Invalidate(); //更新视图
}
m_nOldX1=point.x; //保存上一次的鼠标位置
m_nOldY1=point.y;
……

到此为止,可以运行程序对多幅碎片图像进行拼合了,用鼠标拖动一幅图像在另一幅图像边缘移动,由于采用了"异或"的光栅掩码,两幅图片交叠的地方颜色会发生改变,但只有完全重合时才会全黑,表明此时的拼合是无缝的,将掩码换为"或"即可将拼合后的图像显示出来。但此时只是保留在内存中,还要经过进一步的处理,才能将合并后的图像存盘保留。

<

 

 

 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,51zixue.net不保证资料的完整性。
上一篇:直方图变换图像处理技术  下一篇:在CTreeCtrl中枚举系统中的所有窗口