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

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

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

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

  一、 引言

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

  二、 程序設計原理

  首先我們從實際出發,我們是通過進行局部照相的手段來保存整體的全部信息,而要保證這些局部照片所含的信息之和能包括整體的全部信息就必然的使每兩幅鄰近的圖片有一部分交疊的部分,這樣才能保證在將整體對象劃分為若干局部照片而后再拼合成整體圖像的過程中不遺漏任何信息,即該劃分、拼合的整個過程是無損的。既然如此,我們只需能保證讓兩相鄰圖片的重疊部分能完全重合,那么我們也就能夠肯定在此狀態下的這兩幅圖像實現了無縫拼合。所以,問題就轉換為使相鄰圖片的重疊部分能完全重合,而判斷兩相同的圖像片段是否完全重疊可以用光柵掩碼來進行直觀的判斷,比如我們可以采用"異或"的掩碼,當相同位置上的兩幅圖片的像素相同時就為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;
……

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

  首先要對合并后的圖像所在的矩形框的位置、大小進行判斷,可以用下面的類似代碼來完成(本例同時最多能有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()函數來實現。下面是將屏幕指定區域以位圖形式拷貝到內存中去的函數的主要實現代碼:

HBITMAP CImageView::CopyScreenToBitmap(LPRECT lpRect)
{
 ……
 // 確保選定區域不為空矩形
 if(IsRectEmpty(lpRect))
  return NULL;
 //為屏幕創建設備描述表
 hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
 //為屏幕設備描述表創建兼容的內存設備描述表
 hMemDC = CreateCompatibleDC(hScrDC);
 ……
 // 創建一個與屏幕設備描述表兼容的位圖
 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;
}

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

……
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()來設置缺省狀態下的調色板:

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

  最后的工作就是創建位圖文件了,需要把設置好的位圖文件頭和像素點陣信息依次保存到文件中,其中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++實現(圖四)
圖四
 

  小結

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

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


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


導航

<2008年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

統計

常用鏈接

留言簿(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>
            亚洲一区二区视频在线观看| 亚洲毛片播放| 亚洲免费一在线| 亚洲毛片网站| 欧美国产日韩视频| 欧美激情 亚洲a∨综合| 久久九九全国免费精品观看| 亚洲一区二区三区中文字幕 | 久久久久国产精品一区三寸| 亚洲制服欧美中文字幕中文字幕| 亚洲精品视频免费观看| 亚洲国产三级网| 免费人成网站在线观看欧美高清| 亚洲一区尤物| 久久九九精品99国产精品| 国内精品久久久久影院优| 国产精品美女久久| 国产精品亚洲欧美| 欧美国产一区二区| 国产精品影片在线观看| 日韩网站在线观看| 日韩午夜电影av| 午夜视频久久久| 久久久久久久高潮| 欧美日韩国产精品一卡| 欧美婷婷在线| 国外成人在线| 亚洲区在线播放| 亚洲在线日韩| 久久久国产精彩视频美女艺术照福利| 久久国产色av| 狂野欧美性猛交xxxx巴西| 欧美成人精品一区二区三区| 亚洲欧洲中文日韩久久av乱码| 欧美国产日韩精品免费观看| 一区二区三区精品久久久| 亚洲综合国产激情另类一区| 久久成人综合视频| 欧美成人精品h版在线观看| 欧美日韩岛国| 国产精品美女主播在线观看纯欲| 欧美日韩精品福利| 国产欧美亚洲精品| 伊人久久婷婷| 伊人精品视频| 亚洲国产婷婷香蕉久久久久久99| 欲香欲色天天天综合和网| 一区二区电影免费观看| 久久久免费精品| 亚洲精品一区二区三区不| 亚洲国产合集| 最新国产精品拍自在线播放| 日韩视频一区二区在线观看| 久久综合五月| 国产精品一区二区在线| 亚洲国产精品va在线观看黑人| 一本色道久久88综合日韩精品| 久久亚洲国产精品日日av夜夜| 欧美午夜电影在线| 亚洲高清三级视频| 欧美在线国产精品| 亚洲国产精品va在线观看黑人| 亚洲综合激情| 欧美日本国产精品| 1024精品一区二区三区| 欧美在线一级视频| 亚洲人成在线观看网站高清| 久久精品2019中文字幕| 亚洲日产国产精品| 久久精品一二三区| 欧美性色视频在线| 一区二区三区四区五区在线 | 久久久噜噜噜久久中文字免| 一区二区国产日产| 美女任你摸久久| 国产亚洲女人久久久久毛片| 亚洲综合色自拍一区| 亚洲国产天堂网精品网站| 久久久久久黄| 韩日视频一区| 久久久成人网| 久久久久久999| 国产一区二区主播在线| 午夜精品福利电影| 野花国产精品入口| 欧美日本韩国| 99视频精品全部免费在线| 亚洲欧美电影院| 一区二区三区欧美在线| 欧美午夜视频在线观看| 一区二区欧美精品| 亚洲精品影院在线观看| 欧美风情在线观看| 亚洲日韩欧美视频| 欧美激情aaaa| 欧美激情麻豆| 一区二区三区产品免费精品久久75 | aa级大片欧美三级| 久久久水蜜桃| aa成人免费视频| 亚洲精品中文字幕有码专区| 欧美日韩精品综合在线| 亚洲欧美资源在线| 欧美在线不卡| 91久久久亚洲精品| 亚洲精品在线视频| 国产精品久久久久久久一区探花 | 亚洲视频免费看| 国产精品久久久久久久久久久久久久 | 午夜视频在线观看一区| 在线看一区二区| 亚洲图片欧洲图片av| 99成人在线| 久久九九99| 欧美午夜精品久久久久久久| 欧美大片在线观看一区二区| 国产伦精品一区二区三区照片91 | 一区二区欧美在线观看| 久久亚洲一区二区| 欧美与欧洲交xxxx免费观看| 欧美日韩国产成人在线观看| 欧美成人资源网| 国内外成人免费激情在线视频| 99re6这里只有精品| 亚洲剧情一区二区| 久热精品视频在线| 老司机精品导航| 红桃视频一区| 久久riav二区三区| 久久久久久久波多野高潮日日| 国产精品亚洲一区二区三区在线| 亚洲免费成人av| 日韩视频中文字幕| 欧美成人一二三| 亚洲国产岛国毛片在线| 亚洲精品中文字幕在线| 欧美激情女人20p| 亚洲黄色在线| 在线亚洲观看| 欧美午夜一区二区| 亚洲午夜一级| 久久激情视频久久| 悠悠资源网亚洲青| 牛人盗摄一区二区三区视频| 欧美成人xxx| 亚洲精选成人| 国产精品成av人在线视午夜片| 亚洲天堂成人在线视频| 欧美在线短视频| 黄色欧美日韩| 欧美—级在线免费片| 亚洲毛片在线| 性感少妇一区| 一区在线电影| 欧美久久久久| 亚洲一级在线观看| 久久精品夜色噜噜亚洲aⅴ| 国产一区二区三区成人欧美日韩在线观看 | 欧美精品高清视频| 日韩亚洲欧美在线观看| 欧美在线视频二区| 在线电影国产精品| 欧美国产综合一区二区| 亚洲天天影视| 久久夜色精品国产欧美乱| 亚洲国产一区二区三区a毛片| 欧美日韩亚洲高清一区二区| 午夜在线精品偷拍| 亚洲第一二三四五区| 亚洲综合色丁香婷婷六月图片| 韩国三级电影一区二区| 欧美极品色图| 欧美资源在线| 久久久国产精品一区| 国内精品视频在线播放| 亚洲一区二区视频在线| 国语对白精品一区二区| 亚洲三级免费观看| 国产精品日日摸夜夜添夜夜av| 亚洲欧美国产一区二区三区| 国产日韩欧美日韩大片| 亚洲第一精品久久忘忧草社区| 一区二区三区四区五区视频| 韩国av一区二区三区| 欧美日韩在线一区二区| 欧美在线亚洲| 在线亚洲电影| 亚洲第一精品夜夜躁人人爽| 欧美亚洲一区| 99视频有精品| 亚洲国产另类精品专区| 国产偷国产偷亚洲高清97cao| 欧美精品一区视频| 久久人人97超碰人人澡爱香蕉| 亚洲一区二区三区精品在线观看| 亚洲国产天堂久久国产91| 美国成人毛片| 久久精品一二三区| 欧美一区二区三区在线播放| 亚洲中字在线|