【数字图像处理】一.MFC详解显示BMP格式图片
本文主要是講述《數(shù)字圖像處理》系列欄目中的第一篇文章.主要詳細(xì)介紹了BMP圖片格式,同時(shí)使用C++和MFC顯示BMP格式,主要結(jié)合自己的《數(shù)字圖像處理》課程和以前的項(xiàng)目敘述講解.
一.BMP圖片格式定義
BMP文件格式是Windows操作系統(tǒng)推薦和支持的標(biāo)準(zhǔn)圖像文件格式,是一種將內(nèi)存或顯示器的圖像數(shù)據(jù)不經(jīng)過(guò)壓縮而直接按位存盤(pán)的文件格式,故稱位圖(bitmap),其擴(kuò)展名為BMP.BMP圖像通常有4個(gè)部分組成:位圖文件頭、位圖信息頭、顏色表、位圖數(shù)據(jù).如下圖所示:
第一部分為位圖文件頭BITMAPFILEHEADER.位圖文件頭結(jié)構(gòu)長(zhǎng)度固定為14個(gè)字節(jié),包含文件的類型、大小、位圖文件保留字、位圖數(shù)據(jù)距文件頭的偏移量.其中WORD為無(wú)符號(hào)16位整數(shù)(2byte),DWORD為無(wú)符號(hào)32位整數(shù)(4byte).具體結(jié)構(gòu)體定義如下:
//位圖文件頭 typedef struct tagBITMAPFILEHEADER {WORD bfType; //位圖文件的類型,必須為BM 0x424d 表示.bmp DWORD bfSize; //位圖文件的大小,以字節(jié)為單位 包括該14字節(jié) WORD bfReserved1; //位圖文件保留字,必須為0 WORD bfReserved2; //位圖文件保留字,必須為0 DWORD bfOffBits; //位圖數(shù)據(jù)距文件頭的偏移量,以字節(jié)為單位 即前三部分和 } BITMAPFILEHEADER;第二部分為位圖信息頭BITMAPINFOHEADER,該結(jié)構(gòu)也固定為40個(gè)字節(jié),用于說(shuō)明位圖的尺寸、寬高、像素、分辨率、顏色表等信息.具體結(jié)構(gòu)定義如下:
//位圖信息頭 typedef struct tagBITMAPINFOHEADER {DWORD biSize; //本結(jié)構(gòu)所占用字節(jié)數(shù) 40字節(jié)LONG biWidth; //位圖的寬度,以像素為單位LONG biHeight; //位圖的高度,以像素為單位WORD biPlanes; //目標(biāo)設(shè)備的級(jí)別,必須為1WORD biBitCount; //每個(gè)像素所需的位數(shù),必須是1(雙色)、//4(16色)、8(256色)或24(真彩色)之一DWORD biCompression; //位圖壓縮類型,必須是 0(BI_RGB不壓縮)、//1(BI_RLE8壓縮類型)或2(BI_RLE壓縮類型)之一DWORD biSizeImage; //位圖的大小,以字節(jié)為單位LONG biXPelsPerMeter; //位圖水平分辨率,每米像素?cái)?shù)LONG biYPelsPerMeter; //位圖垂直分辨率,每米像素?cái)?shù)DWORD biClrUsed; //位圖實(shí)際使用的顏色表中的顏色數(shù)DWORD biClrImportant; //位圖顯示過(guò)程中重要的顏色數(shù) } BITMAPINFOHEADER;第三部分為顏色表或調(diào)色板(Palette).有些位圖需要調(diào)色板,有些位圖如真彩色圖(biBitCount=24)不需要調(diào)色板,它們的BITMAPINFOHEADER后面直接是位圖數(shù)據(jù).調(diào)色板實(shí)際是一個(gè)數(shù)組,共有biClrUsed個(gè)元素(如果該值為零,則有2的biBitCount次冪個(gè)元素).數(shù)組中每個(gè)元素的類型是一個(gè)RGBQUAD結(jié)構(gòu),占4字節(jié).定義如下:
//位圖顏色表 typedef struct tagRGBQUAD {BYTE rgbBlue; //藍(lán)色的亮度(值范圍為0~255)BYTE rgbGreen; //綠色的亮度(值范圍為0~255)BYTE rgbRed; //紅色的亮度(值范圍為0~255)BYTE rgbReserved; //保留,必須為0 } RGBQUAD;第四部分就是實(shí)際的圖像數(shù)據(jù).對(duì)于真彩色圖(24位位圖 biBitCount=24),圖像數(shù)據(jù)就是實(shí)際的RGB值;對(duì)于用到調(diào)色板的位圖,圖像數(shù)據(jù)就是該像素顏色在調(diào)色板中的索引值.下面對(duì)2色、16色、256色和真彩色位圖分別介紹:
(1).2色位圖:當(dāng)biBitCount=1時(shí),用1位就可以表示該像素的顏色(0表示黑,1表示白),所以8個(gè)像素占1個(gè)字節(jié);
(2).16色位圖:當(dāng)biBitCount=4時(shí),用4為可以表示一個(gè)像素的顏色,所以2個(gè)像素占1個(gè)字節(jié);
(3).256色位圖:當(dāng)biBitCount=8時(shí),用1個(gè)字節(jié)表示1個(gè)像素,1個(gè)像素占1個(gè)字節(jié);
(4).真彩色圖:當(dāng)biBitCount=24時(shí),此時(shí)用3個(gè)字節(jié)表示1個(gè)像素,其中RGB各占1字節(jié),由于沒(méi)有顏色表,位圖信息頭后面是位圖數(shù)據(jù).
同時(shí),注意以下幾點(diǎn):
1.由于Windows規(guī)定一個(gè)掃描所占的字節(jié)數(shù)必須是4的倍數(shù)(即以long為單位),不足的以0填充.同時(shí)注意下面公式,計(jì)算只含位圖數(shù)據(jù)的大小:biSizeImage=(((bi.biWidth*bi.biBitCount)+31)/(32*4))*bi.Height
在后面講述獲取文件的信息時(shí)會(huì)通過(guò)UE軟件結(jié)合16進(jìn)制數(shù)據(jù)進(jìn)行詳細(xì)講解上面各個(gè)數(shù)據(jù)的具體含義.
2.BMP圖片格式的數(shù)據(jù)是從下到上、從左到右讀.即文件中最先讀到的圖像是最下面一行的左邊第一個(gè)元素,即從左下角開(kāi)始存儲(chǔ)(0,0)點(diǎn),從左下角到右上角存儲(chǔ)數(shù)據(jù).尤其是在圖像幾何變換平移、旋轉(zhuǎn)時(shí),我就犯過(guò)這樣的錯(cuò)誤,本想讓圖像從左下角向右上移動(dòng),結(jié)果剛好相反,后面也會(huì)通過(guò)實(shí)例加深大家的印象.
3.如果想使用C語(yǔ)言\C++顯示圖片,建議自定義個(gè)ImageStruct.h的頭文件.包含BMP位圖的位圖文件頭結(jié)構(gòu)、位圖信息頭結(jié)構(gòu)、位圖顏色表3個(gè)結(jié)構(gòu),在實(shí)例變量操作.而使用MFC,因?yàn)樵趙ingdi.h文件中系統(tǒng)已經(jīng)定義了BMP圖像的結(jié)構(gòu)BITMAPFILEHEADER、BITMAPINFOHEADER,直接在View.h中用他倆實(shí)例定義即可.
?
二.顯示BMP圖片的基本步驟
在MFC工程XXXView.h類中添加成員函數(shù)void ShowBitmap(CDC* pDC,CString BmpName);通過(guò)自定義函數(shù)實(shí)現(xiàn)顯示BMP格式圖像,其中*pDC是CDC句柄,BmpName是圖像文件名.具體步驟如下:
1.創(chuàng)建位圖并調(diào)用函數(shù)LoadImage裝載圖標(biāo)、光標(biāo)或位圖.
? HBITMAP m_hBitmap;?
? m_hBitmap=(HBITMAP)LoadImage(HINSTANCE hinst,LPCTSTR lpszName,UINT uType,int cxDesired,int cyDesired,UINT fuLoad)
2.定義并創(chuàng)建一個(gè)內(nèi)存設(shè)備環(huán)境DC,調(diào)用函數(shù)CreateCompatibleDC創(chuàng)建兼容的DC.
? CDC dcBmp; dcBmp.CreateCompatibleDC(pDC) ;
3.定義BITMAP變量,調(diào)用函數(shù)GetBitmap將圖片載入位圖中,該定義是為后去圖像的長(zhǎng)寬等信息.
? BITMAP m_bmp; m_bitmap.GetBitmap(&m_bmp);
4.調(diào)用函數(shù)SelectObject將位圖選入兼容內(nèi)存設(shè)備環(huán)境DC中.
? dcBmp.SelectObject(&m_bitmap);
5.將兼容的DC中的位圖填到當(dāng)前DC中,調(diào)用函數(shù)BitBlt或strechBlt顯示圖像.
(1).BitBlt()該函數(shù)對(duì)指定的源設(shè)備環(huán)境區(qū)域中的像素進(jìn)行位塊(bit_block)轉(zhuǎn)換,以傳送到目標(biāo)設(shè)備環(huán)境.
? pDC->BitBlt(0,0,m_bmp.bmWidth,m_bmp.bmHeight,&dcBmp,0,0,SRCCOPY);
(2).stretchBlt()該函數(shù)從源矩形中復(fù)制位圖到目標(biāo)矩形,必要是按目標(biāo)設(shè)備設(shè)置的模式進(jìn)行圖像拉伸或壓縮.
? pDC->StretchBlt(0,0,m_nDrawWidth,m_nDrawHeight,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY);
6.恢復(fù)臨時(shí)DC的位圖,刪除CreateCompatibleDC得到的圖片DC,刪除內(nèi)存中的位圖及釋放系統(tǒng)資源.
? dcBmp.SelectObject(pbmpOld); DeleteObject(&m_bitmap);? dcBmp.DeleteDC();
具體函數(shù)代碼如下:
補(bǔ)充:MFC中DC指device context,設(shè)備環(huán)境或設(shè)備描述表,它其實(shí)是GDI內(nèi)部保存數(shù)據(jù)的一種數(shù)據(jù)結(jié)構(gòu).此結(jié)構(gòu)中屬性內(nèi)容與特定輸出設(shè)備相關(guān),屬性定義了GDI函數(shù)的工作細(xì)節(jié).總之,使用GDI繪圖函數(shù),就需要一個(gè)DC句柄,MFC中把和DC相關(guān)的封裝成類.其中CDC是一個(gè)抽象基類,可以訪問(wèn)整個(gè)顯示器和打印機(jī).其中下面鏈接中的文章詳細(xì)描述了CBitmap、HBitmap、Bitmap三者的區(qū)別與聯(lián)系.http://blog.csdn.net/ivan_ljf/article/details/8569130
?
三.MFC顯示BMP圖片
下面將詳細(xì)講解使用VS2012 MFC創(chuàng)建工程的具體步驟:
第一步:新建項(xiàng)目"MFC應(yīng)用程序",項(xiàng)目名為ShowBMP,在應(yīng)用程序類型中選擇"單個(gè)文檔",點(diǎn)擊"確定".在右欄的"資源視圖"中,點(diǎn)擊"Menu->IDR_MAINFRAM"可以查看并修改菜單視圖.
第二步:向CShowBMPView類添加成員變量和成員函數(shù).在右欄的"類視圖"右鍵CShowBMPView添加函數(shù)或直接在ShowBMPView.h中直接添加public成員變量和成員函數(shù).添加代碼如下:
第三步:設(shè)置打開(kāi)BMP圖片函數(shù)."項(xiàng)目"->"類向?qū)?#34;->選擇"類名"CShowBMPView->在命令對(duì)象ID中雙擊"ID_FILE_OPEN"->自動(dòng)生成默認(rèn)成員函數(shù)OnFileOpen,消息為COMMAND.雙擊成員函數(shù)(Member Functions)進(jìn)入函數(shù)編輯.(VC++ 6.0中Ctrl+W可以實(shí)現(xiàn)建立類向?qū)?
向添加成員函數(shù)CShowBMPView::OnFileOpen()添加如下代碼,主要是生成打開(kāi)圖片的對(duì)話框,并獲取圖片路徑及后綴.自定義四種格式為bmp gif jpg tiff,但目前只能打開(kāi)bmp格式圖片.
//**************文件打開(kāi)****************// void CShowBMPView::OnFileOpen() {//四種格式的文件:bmp gif jpg tiffCString filter;filter="所有文件(*.bmp,*.jpg,*.gif,*tiff)|*.bmp;*.jpg;*.gif;*.tiff| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg| GIF(*.gif)|*.gif| TIFF(*.tiff)|*.tiff||";CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,filter,NULL); //按下確定按鈕 dlg.DoModal() 函數(shù)顯示對(duì)話框if( dlg.DoModal() == IDOK ){BmpName = dlg.GetPathName(); //獲取文件路徑名 如D:\pic\abc.bmpEntName = dlg.GetFileExt(); //獲取文件擴(kuò)展名EntName.MakeLower(); //將文件擴(kuò)展名轉(zhuǎn)換為一個(gè)小寫(xiě)字符Invalidate(); //調(diào)用該函數(shù)就會(huì)調(diào)用OnDraw重繪畫(huà)圖} }第四步:在ShowBMPView.cpp中編寫(xiě)void CShowBMPView::ShowBitmap(CDC *pDC, CString BmpName)函數(shù),即“二.顯示BMP圖片基本步驟”.同時(shí)通過(guò)OnDraw()函數(shù)調(diào)用ShowBitmap()函數(shù)顯示圖片.代碼如下:
//在OnDraw函數(shù)中調(diào)用ShowBitmap()實(shí)現(xiàn)圖片的顯示功能 void CShowBMPView::OnDraw(CDC* pDC) {CShowBMPDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;// TODO: 在此處為本機(jī)數(shù)據(jù)添加繪制代碼if( EntName.Compare(_T("bmp")) == 0 ) //bmp格式{ShowBitmap(pDC,BmpName); //顯示圖片} }四.運(yùn)行結(jié)果及總結(jié)
運(yùn)行程序后,顯示如下所示:其中可以看到自定義的打開(kāi)對(duì)話框和顯示圖片.
??
最后,該文章主要是數(shù)字圖像處理的基礎(chǔ)知識(shí),詳細(xì)介紹了BMP圖片格式和使用MFC如何讀取BMP圖片的相關(guān)知識(shí).僅以此篇紀(jì)念自己的考研結(jié)束,新的開(kāi)始.同時(shí)推薦大家閱讀一位叫煙雨江南的作者的文章,個(gè)人感覺(jué)幫組很大.http://blog.csdn.net/xiajun07061225/article/details/6633938?同時(shí)該項(xiàng)目免費(fèi)下載網(wǎng)址:
http://download.csdn.net/detail/eastmount/6848841
希望該文章能夠?qū)Υ蠹矣兴鶐椭?同時(shí)如果文章中有錯(cuò)誤或不足之處,還請(qǐng)大家海涵.
(By:Eastmount 2014-1-14 夜8點(diǎn)http://blog.csdn.net/eastmount)
總結(jié)
以上是生活随笔為你收集整理的【数字图像处理】一.MFC详解显示BMP格式图片的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 算法知识之最长公共子序列问题(动态规划)
- 下一篇: C# 系统应用之清空回收站操作