青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

碎片圖像無縫拼合技術的VC++實現

摘要:本文講述了在Microsoft Visual C++ 6.0下多幅碎片圖像無縫拼合技術的實現原理和過程,并給出了部分關鍵代碼以供參考。

  關鍵字:Microsoft Visual C++ 6.0、圖像、無縫拼合、位圖文件

  一、 引言

  在測繪、文博等行業(yè)經常會遇到這樣一種情況:觀測對象比較大,為保證分辨率又不能將其全部照下,只能進行局部照相,事后再將這些局部照相的重合部分去掉,拼合成一幅完整的圖像。以前多采用手工拼合,誤差較大,往往不能很好的實現無縫拼合,即使有少量的專業(yè)設備,成本也普遍較高。其實只需將照片通過掃描儀將其錄入到計算機中,通過程序處理,完全能很好的實現多幅圖像的無縫拼合,滿足實際需要,而且對于文博行業(yè)中常會遇到的破碎的、不規(guī)則對象如古舊字畫殘片等也能很好的進行無縫拼合。本文就對針對該程序的實現原理及過程做了簡要的介紹。

  二、 程序設計原理

  首先我們從實際出發(fā),我們是通過進行局部照相的手段來保存整體的全部信息,而要保證這些局部照片所含的信息之和能包括整體的全部信息就必然的使每兩幅鄰近的圖片有一部分交疊的部分,這樣才能保證在將整體對象劃分為若干局部照片而后再拼合成整體圖像的過程中不遺漏任何信息,即該劃分、拼合的整個過程是無損的。既然如此,我們只需能保證讓兩相鄰圖片的重疊部分能完全重合,那么我們也就能夠肯定在此狀態(tài)下的這兩幅圖像實現了無縫拼合。所以,問題就轉換為使相鄰圖片的重疊部分能完全重合,而判斷兩相同的圖像片段是否完全重疊可以用光柵掩碼來進行直觀的判斷,比如我們可以采用"異或"的掩碼,當相同位置上的兩幅圖片的像素相同時就為0即黑色,所以可以對兩圖片進行移動,只要重疊部分全黑,則表明此時兩圖像的重疊部分已準確的重合了,而此時也實現了圖像的無縫拼合。此后只需再采用"或"的光柵掩碼將合并后的圖像顯示出來,再通過拷屏等手段將其存盤即可。在實現拼合的全過程中主要涉及到圖像的拖放、圖像文件的讀取及顯示、光柵掩碼、拷屏以及內存位圖的保存等多種技術。接下來就對這些技術的具體應用進行介紹。

  三、 程序的具體實現

  在進行拼合之前,首先要將從掃描儀錄入的圖像從文件讀取到內存中,并顯示出來。由于在拼合時采取的光柵操作掩碼是"異或",所以為保持圖像的原始面貌,可以在消息WM_ERASEBKGND 的響應函數中用PatBlt函數將整個客戶區(qū)的初始背景設定為黑色:

……
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);

  之后我們就可以創(chuàng)建一個和當前設備環(huán)境兼容的內存設備環(huán)境hMemDC1,并將剛才讀取到內存的位圖放置到該設備環(huán)境中:

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光柵或操作。

  我們可以通過對鼠標消息響應函數的編程來實現在客戶區(qū)內的位圖拖放,按照Windows系統(tǒng)的習慣,首先在鼠標左鍵的響應函數中通過PtInRect()函數判斷鼠標在左鍵按下時是否是落在位圖上,如果是就可以在鼠標左鍵彈起之前將圖片隨鼠標拖動了,顯然這部分應在WM_MOUSEMOVE消息的響應函數內編寫代碼:

……
if(m_bCanMove1==true) //在移動之前鼠標左鍵是在圖片上點擊的
{
 int dx=m_nOldX1-m_nX1; //計算鼠標距離圖片原點的距離
 int dy=m_nOldY1-m_nY1;
 m_nX1=point.x-dx; //計算新的圖片原點的坐標(客戶區(qū)坐標)
 m_nY1=point.y-dy;
 Invalidate(); //更新視圖
}
m_nOldX1=point.x; //保存上一次的鼠標位置
m_nOldY1=point.y;
……

  到此為止,可以運行程序對多幅碎片圖像進行拼合了,用鼠標拖動一幅圖像在另一幅圖像邊緣移動,由于采用了"異或"的光柵掩碼,兩幅圖片交疊的地方顏色會發(fā)生改變,但只有完全重合時才會全黑,表明此時的拼合是無縫的,將掩碼換為"或"即可將拼合后的圖像顯示出來。但此時只是保留在內存中,還要經過進一步的處理,才能將合并后的圖像存盤保留。

  首先要對合并后的圖像所在的矩形框的位置、大小進行判斷,可以用下面的類似代碼來完成(本例同時最多能有4幅圖像進行拼合):

……
int temp1,temp2,x0,y0,x1,y1;
temp1=m_nX1<m_nX2?m_nX1:m_nX2;
if(m_sPath3!="")//如果有3幅圖片參與拼合
{
 if(m_sPath4!="")//如果有4幅圖片參與拼合
  temp2=m_nX3<m_nX4?m_nX3:m_nX4;
 else
  temp2=m_nX3;
  x0=temp1<temp2?temp1:temp2;
}
else
 x0=temp1;
 ……
 temp1=m_nX1+m_nWidth1>m_nX2+m_nWidth2?m_nX1+m_nWidth1:m_nX2+m_nWidth2;
 if(m_sPath3!="")
 {
  if(m_sPath4!="")
   temp2=m_nX3+m_nWidth3>m_nX4+m_nWidth4?m_nX3+m_nWidth3:m_nX4+m_nWidth4;
  else
   temp2=m_nX3+m_nWidth3;
   x1=temp1>temp2?temp1:temp2;
 }
 else
  x1=temp1;

  可以用類似的代碼計算出y0和y1。在進行屏幕截圖之前必須將由x0,y0,x1,y1構成的矩形由客戶坐標轉換成屏幕坐標,可以用ClientToScreen()函數來實現。下面是將屏幕指定區(qū)域以位圖形式拷貝到內存中去的函數的主要實現代碼:

HBITMAP CImageView::CopyScreenToBitmap(LPRECT lpRect)
{
 ……
 // 確保選定區(qū)域不為空矩形
 if(IsRectEmpty(lpRect))
  return NULL;
 //為屏幕創(chuàng)建設備描述表
 hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
 //為屏幕設備描述表創(chuàng)建兼容的內存設備描述表
 hMemDC = CreateCompatibleDC(hScrDC);
 ……
 // 創(chuàng)建一個與屏幕設備描述表兼容的位圖
 hBitmap = CreateCompatibleBitmap(hScrDC, lpRect->Width(),lpRect->Height());
 // 把新位圖選到內存設備描述表中
 hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
 // 把屏幕設備描述表拷貝到內存設備描述表中
 BitBlt(hMemDC, 0, 0, lpRect->Width(),lpRect->Height, hScrDC, lpRect->left lpRect->top, SRCCOPY);
 //得到屏幕位圖的句柄
 hBitmap =(HBITMAP)SelectObject(hMemDC, hOldBitmap);
 //清除
 DeleteDC(hScrDC);
 DeleteDC(hMemDC);
 ……
 // 返回位圖句柄
 return hBitmap;
}

  當把拼合后的區(qū)域拷貝到內存,并獲取到該內存位圖的句柄后可以將其通過剪貼板傳送到其他圖形處理軟件中進行進一布的處理,也可以按照位圖的格式直接將其保存成文件,為方便計,本例采用了后者。其實現過程主要是根據剛才獲取到的內存位圖句柄按格式填充BMP文件的信息頭以及像素陣列,下面就結合實現的關鍵代碼進行介紹:
首先獲取設備描述表句柄,并用函數GetDeviceCaps()獲取到當前顯示分辨率下每個像素所占字節(jié)數,并據此計算出調色板的大小:

……
hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if (iBits <= 1)
 wBitCount = 1;
else if (iBits<= 4)
 wBitCount = 4;
else if (iBits<= 8)
 wBitCount = 8;
else if (iBits <= 24)
 wBitCount = 24; //計算調色板大小
……

  然后就可以設置位圖信息頭結構了,其中bi 是BITMAPINFOHEADER 結構的實例對象:

……
if (wBitCount <= 8)
 dwPaletteSize = (1<<wBitCount) *sizeof(RGBQUAD); //設置位圖信息頭結構
 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
 bi.biSize = sizeof(BITMAPINFOHEADER);
 bi.biWidth = Bitmap.bmWidth;
 bi.biHeight = Bitmap.bmHeight;
 bi.biPlanes = 1;
 bi.biBitCount = wBitCount;
 bi.biCompression = BI_RGB;
 bi.biSizeImage = 0;
 bi.biXPelsPerMeter = 0;
 bi.biYPelsPerMeter = 0;
 bi.biClrUsed = 0;
 bi.biClrImportant = 0;

  用GlobalAlloc()函數根據計算的結果為位圖內容分配內存,并返回分配得到的內存句柄hDib,并用GetStockObject()來設置缺省狀態(tài)下的調色板:

……
dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;
hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi; // 處理調色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
 hDC = ::GetDC(NULL);
 hOldPal =SelectPalette(hDC, (HPALETTE)hPal, FALSE);
 RealizePalette(hDC);
}
// 獲取該調色板下新的像素值
GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,
(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize,
(BITMAPINFO*)lpbi, DIB_RGB_COLORS);
//恢復調色板
if (hOldPal)
{
 SelectPalette(hDC,(HPALETTE)hOldPal, TRUE);
 RealizePalette(hDC);
 ::ReleaseDC(NULL,hDC);
}
……

  最后的工作就是創(chuàng)建位圖文件了,需要把設置好的位圖文件頭和像素點陣信息依次保存到文件中,其中bmfHdr 是BITMAPFILEHEADER位圖文件頭結構的實例對象,需要按照BMP位圖的存盤格式對其進行設置:

……
fh = CreateFile(lpFileName,
GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
// 設置位圖文件頭
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER)+ dwPaletteSize;
//寫入位圖文件頭
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
// 寫入位圖文件其余內容
WriteFile(fh, (LPSTR)lpbi, dwDIBSize,&dwWritten, NULL);
……

  四、程序的實例檢測

  下面就通過一個實例--拼合一幅古代國畫殘片來對程序的拼合效果進行檢測。其中圖一到圖三是拼合前的三幅古代國畫殘片,圖四是經過本程序處理后存盤得到的經過無縫合成的圖片。經過檢測,拼合效果還是相當不錯的,在碎片圖像的銜接處根本沒有接縫的存在:

碎片圖像無縫拼合技術的VC++實現(圖一)
圖一

碎片圖像無縫拼合技術的VC++實現(圖二)
圖二

 
碎片圖像無縫拼合技術的VC++實現(圖三)
圖三

碎片圖像無縫拼合技術的VC++實現(圖四)
圖四
 

  小結

  本程序通過一個實例講述了處理圖片無縫拼合的一種實用方法,在測繪、勘察、文博等行業(yè)均有較大的應用潛力。在理解了程序的設計思路和編程思想的前提下,結合具體的實際需求,通過對本文具體代碼的改動可以設計出更適合本單位實際情況的類似軟件。另外,本文所講述的截取并保存屏幕技術在類似程序的編制上也可以提供一定的參考。本程序在Windows 2000 Professional下,由Microsoft Visual C++ 6.0編譯通過。

posted on 2008-09-10 19:27 wrh 閱讀(243) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發(fā)表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


導航

<2009年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

統(tǒng)計

常用鏈接

留言簿(19)

隨筆檔案

文章檔案

收藏夾

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美激情精品久久久久久| 久久亚洲风情| 伊人久久噜噜噜躁狠狠躁| 欧美一区日本一区韩国一区| 欧美亚洲免费电影| 国模私拍一区二区三区| 久久午夜精品| 国产精品v欧美精品v日韩| 午夜视频在线观看一区| 欧美在线一级va免费观看| 国产在线精品自拍| 亚洲欧洲精品一区二区三区不卡 | 欧美.www| 欧美精品999| 亚洲男人天堂2024| 久久久久久日产精品| 在线激情影院一区| 久久国产免费看| 久久久亚洲国产天美传媒修理工| 亚洲毛片一区二区| 国产日韩欧美一区在线| 亚洲国产成人91精品| 国产在线精品成人一区二区三区 | 久久久久久伊人| 欧美激情第五页| 国外成人在线视频| 亚洲一区二区三区色| 亚洲美女在线观看| 久久阴道视频| 久久亚洲综合色一区二区三区| 欧美日本亚洲韩国国产| 欧美国产日韩精品免费观看| 国产一区二区高清| 久久精品国产77777蜜臀| 午夜激情久久久| 国产精品久久久久久久久久直播| 最新日韩在线视频| 亚洲免费电影在线| 欧美中文字幕久久| 国产欧美婷婷中文| 小黄鸭精品aⅴ导航网站入口| 亚洲欧美另类中文字幕| 国产精品日韩欧美大师| 国产精品99久久久久久白浆小说| 亚洲视频观看| 国产噜噜噜噜噜久久久久久久久| 亚洲性感激情| 欧美福利视频| 亚洲精品日韩激情在线电影| 开心色5月久久精品| 欧美国产精品va在线观看| 伊人精品成人久久综合软件| 欧美国产日韩精品免费观看| 亚洲一品av免费观看| 国产精品亚洲网站| 免费观看一级特黄欧美大片| 亚洲免费成人| 欧美激情国产高清| 欧美中文在线免费| 一本大道久久a久久精二百| 国语对白精品一区二区| 欧美日韩ab| 欧美xx视频| 欧美一区二区高清| 亚洲精品自在久久| 在线精品福利| 国产乱码精品1区2区3区| 欧美精品一区二区三区蜜桃| 久久精品国产91精品亚洲| 亚洲女女女同性video| 一区二区三区精品视频| 亚洲精品国精品久久99热| 欧美一区二区三区在线视频| 亚洲伊人一本大道中文字幕| 亚洲黄色天堂| 91久久精品国产91久久性色| 久久久久国产精品www| 久久国产精品毛片| 欧美资源在线| 欧美在线亚洲综合一区| 欧美影片第一页| 久久亚洲综合色一区二区三区| 午夜国产一区| 久久精品免费电影| 久久久精品国产免大香伊| 久久九九热免费视频| 久久影院午夜论| 久久阴道视频| 日韩视频三区| 欧美一区二区三区免费视| 久久久久久噜噜噜久久久精品 | 久久久久国产精品一区| 先锋影院在线亚洲| 美腿丝袜亚洲色图| 欧美日韩一区二区三区在线观看免 | 午夜欧美精品久久久久久久| 欧美一级大片在线免费观看| 欧美专区第一页| 亚洲国产黄色| 亚洲欧美日韩一区二区在线| 久久精品中文字幕一区| 亚洲精品国产视频| 久久久91精品国产| 国产精品红桃| 日韩亚洲欧美一区| 久久深夜福利| 中文欧美在线视频| 欧美精品久久久久久| 国内成人精品2018免费看| 亚洲网友自拍| 亚洲免费激情| 欧美日韩在线免费| 亚洲乱码久久| 亚洲大黄网站| 久久综合电影| 精品二区视频| 久久三级视频| 欧美亚洲色图校园春色| 国产日韩欧美一区二区三区在线观看 | 久久综合导航| 久久精品视频亚洲| 韩国三级电影久久久久久| 亚洲一区二区三区在线播放| 亚洲精品极品| 欧美成人一品| 欧美成人有码| 亚洲精品综合精品自拍| 亚洲精品久久久久久久久久久久久 | 亚洲一区欧美| 国产香蕉97碰碰久久人人| 久久久精品2019中文字幕神马| 欧美一区二区播放| 一区一区视频| 亚洲精品久久久久久久久久久 | 欧美日韩精品欧美日韩精品| 亚洲欧美日韩一区二区三区在线观看| 亚洲免费中文字幕| 亚洲第一在线视频| 夜夜夜久久久| 亚洲国产日韩精品| 亚洲欧美变态国产另类| 亚洲免费电影在线| 久久国产精品久久精品国产| 亚洲国产清纯| 欧美在线一二三四区| 亚洲一区二区三区午夜| 另类激情亚洲| 欧美中文字幕视频| 欧美性jizz18性欧美| 免费一级欧美在线大片| 国产精品无码永久免费888| 亚洲第一综合天堂另类专| 国产精品分类| 欧美激情一区二区在线| 国内外成人在线视频| 欧美亚洲一区二区三区| 亚洲欧美日韩专区| 欧美日韩天天操| 99国产精品国产精品久久 | 亚洲精品一区二区三区av| 午夜久久久久久久久久一区二区| 亚洲视频一区在线| 欧美色大人视频| 午夜激情亚洲| 欧美一区二区视频免费观看| 国产啪精品视频| 免费在线欧美黄色| 久久―日本道色综合久久| 韩国精品一区二区三区| 久久人人九九| 欧美激情国产日韩精品一区18| 亚洲激情成人网| 欧美日韩在线免费观看| 亚洲一区二区三区免费在线观看| 亚洲视频在线观看一区| 黄色日韩在线| 久久日韩粉嫩一区二区三区| 亚洲高清资源| 久久av一区二区三区| 亚洲第一精品夜夜躁人人爽| 欧美国产在线电影| 亚洲一区二区三区免费视频| 久久久久久精| 夜夜嗨一区二区| 亚洲国产综合在线| 国产欧美精品在线观看| 欧美91大片| 久久精品国产清自在天天线| 亚洲免费高清| 亚洲国产成人久久综合| 欧美伊人久久久久久久久影院| 亚洲国产成人精品女人久久久 | 国产精品久久91| 免费黄网站欧美| 久久人人97超碰人人澡爱香蕉| 日韩一级免费| 亚洲精品美女在线| 亚洲国产精选| 亚洲激情在线播放| 亚洲激情一区二区三区|