摘要
圖象拼接是在全景視頻系統、地理信息系統等應用中經常遇到的一個問題,本文基於網格匹配的方法對邊界部分有重疊的圖象提出了一種行之有效的對准算法,並通過平滑因子對圖象實現了無縫拼接。並應用文檔視窗模型實現了該算法,並完成了位圖文件的顯示、存儲等操作,具有一定的普遍意義。
關鍵詞:
圖象拼接,算法,重疊圖象,文檔視窗,位圖文件,圖象顯示
文章正文
一、 多文檔視窗模型概述
MFC的AppWizard可以生成三種類型的應用程序:基於對話框的應用、單文檔應用(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
文檔類型標識包括七個子串,包括窗口標題、文檔名稱、文件擴展名等。在6中curTemplate->GetDocString(str, CDocTemplate::docName);取的就是第二個子串,文檔名稱。文檔建立之後我們就可以對其進行操作了。當然文檔類和視窗類,文檔類和主窗口類,以及不同文檔類之間進行通信也是較為復雜的,並非幾句話就能說清楚,如不熟悉文檔視窗的讀者請參看其它有關資料。
二、 重疊圖象拼接技術
1.算法思想
在實現全景視頻(Panoramic Video)系統、地理信息系統(GIS)及其它一些應用的過程中,我們通常會碰到這樣的一個問題,就是要把幾幅小的圖象拼接成一幅大的圖象。為了能讓計算機自動對准圖象我們要求待拼接的圖象邊界有部分重疊,計算機正是利用這些信息進行匹配對准。匹配算法的總體思想是既要保證對准的精度,又要保證運算量不至過大。這裡算法利用了圖象的自身特性,既在一般圖象中,相鄰的象素點的灰度值相差不大。因此,可在第二幅圖象的邊界取一個網格,然後將網格在第一幅圖象上移動,計算所有網格點的兩幅圖象對應象素點的RGB值的差的平方和。記錄最小的值的網格位置,即認為是最佳匹配位置。(如圖1)為了減小運算量,我們將匹配分為兩個步驟,第一步是粗略匹配,在該階段網格每次水平或垂直移動一個網格間距。在完成粗略匹配之後,我們在當前最佳匹配點處進行精確匹配,在該階段以當前最佳匹配點為中心,網格向上下、左右各移動一個小步長。初始步長為粗略拼接時移動步長的一半,即為半個網格間距。不斷的與當前最小平方和進行比較,如果比當前值優,就替換當前最佳匹配點。循環進行這個過程每次步長減半,直到水平步長和垂直步長均為0為止。
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,對應的前後兩幅圖象為image1、image2,結果為image3,則image3=d*image1+(1-d)*imge2其中d的值由1漸變到0,它與該點距重疊邊界的距離有關。
四、 多文擋視窗模型的重疊圖象拼接程序框架
1. 程序構成
程序除應用類、主窗口類以外,還包括CFristImageDoc, CSecondImageDoc, CThirdImageDoc類用來保存第一幅、第二副以及拼接後圖象的數據。還有與其相連的文檔類和框架類。
2. 程序流程
程序的主要工作在應用類中完成,首先打開第一幅圖象,圖象的顯示等操作由CFirstImageDoc 類和與其相關的視窗類及框架類完成,並將圖象的位數組指針和圖象大小傳給應用類成員變量。再打開第二幅圖象同樣完成顯示等操作,也將位數組指針和圖象大小傳給應用類成員變量。在應用類中完成圖象的匹配對准工作,最後實現圖象的合成。將合成後的圖象傳給CThirdImageDoc類進行顯示當用戶對拼接結果基本滿意後,可以選擇平滑連接將兩幅圖象平滑的連接起來。用戶可將最後的結果保存成bmp文件。
五、 總結
圖象拼接中,圖象對准是前提和關鍵,程序基於網格匹配的方法實現了圖象對准,應用了交互技術讓用戶可以對網格點的多少,網格間距大小,均可調整,還允許用戶輸入重疊范圍使拼接過程有的放矢,缺省是較小圖象高度的1/3。該程序實現了對位圖圖象文件的各種操作,具有普遍意義,還引入了不同文檔類型的多文檔視窗模型,並在不同文檔類間實現了數據交換,具有一定的實用價值。為了使程序簡單易用,只實現了對24位位圖的拼接,也未提供垂直方向的拼接,只提供了水平方向的拼接。如要對不符合條件的圖象進行拼接我們只需在Windows提供的畫筆中將圖象轉化一下即可。