數字影像處理(極簡) 第三章 BMP檔案的讀取與顯示(docx)
建議先修課程:高等數學(微積分)、線性代數。
參考書目:
1、影像工程(上冊)——影像處理(第4版) 章毓晉 清華大學出版社
連結:https://pan.baidu.com/s/1hEMGRUotQFL_RtGap6JaUg
提取碼:0000
三 BMP檔案的讀取與顯示
BMP檔案是一個非常簡單的影像儲存格式。學習處理影像時,我們先從最簡單的格式入手。處理其它複雜的格式時,往往採用先解壓縮再進行後續處理的方法。解壓縮後的資料往往與BMP等非壓縮格式(通常是,壓縮的BMP很少見)相仿。
BMP檔案主要應用於Windows平臺。因此,繼續下面的學習之前,你應當具備一些Windows程式設計的知識。
BMP檔案的結構分為四部分:
【1】檔案頭。
【2】資訊頭。
【3】調色盤(可選)。
【4】影像資料。
檔案頭的格式定義在<wingdi.h>中:
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
其中
<minwindef.h>:
#define far
#define FAR far
typedef unsigned long DWORD;
typedef unsigned short WORD;
這個結構的長度固定為14位元組。各個成員的解釋如下:
bfType
指定檔案型別,其值為42 4D,即BM。也就是說所有.bmp檔案的頭兩個位元組都是“BM”。
bfSize
指定檔案大小(包括檔案頭)。該值為DWORD值,即雙字(4位元組),因此BMP檔案的大小最大為4 GB(232位元組)。
bfReserved1,bfReserved2
保留字,這裡不考慮。
bfOffBits
為從檔案頭到實際的點陣圖資料的偏移位元組數。
資訊頭的格式也定義在<wingdi.h>中:
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
其中
<winnt.h>:
typedef long LONG;
這個結構的長度固定為40位元組。各個成員的解釋如下:
biSize
值為常量40,指定此結構的長度。
biWidth,biHeight
指定影像的寬和高(單位:畫素)。
biPlanes
值固定為1,這裡不考慮。
biBitCount
指定表示顏色時要用到的位數,取值可以為:1(黑白二色圖)、4(16色圖)、8(256色)、24(真彩色圖)。
biCompression
指定點陣圖是否壓縮。Windows點陣圖可以採用壓縮格式,但用得不多。我們只討論不壓縮的情況,biCompression為BI_RGB。
<wingdi.h>:
#define BI_RGB 0L
#define BI_RLE8 1L
#define BI_RLE4 2L
#define BI_BITFIELDS 3L
#define BI_JPEG 4L
#define BI_PNG 5L
biSizeImage
在影像為壓縮格式時,刻畫點陣圖資料的長度。影像未壓縮時,此值為零。
biXPelsPerMeter,biYPelsPerMeter
指定目標裝置的水平和垂直解析度。單位:每米的畫素個數。
biClrUsed
指定本影像實際用到的顏色數(決定調色盤陣列元素的個數),如果該值為零,則用到的顏色數為2的biBitCount次方。
一個規範的BMP檔案應當只有在真彩色時才將該值置為零。
biClrImportant
指定本影像中重要的顏色數量。該值通常為零,即認為所有的顏色都是重要的。
當影像不是真彩色時,在資訊頭之後還有調色盤。調色盤實際上是一個陣列,共有biClrUsed個元素(如果該值為零,則有2的biBitCount次方個元素)。陣列中每個元素的是一個RGBQUAD結構,佔4個位元組,其定義位於<wingdi.h>:
typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
一個標準的256灰度影像,其調色盤的第0到255項的前三項rgbBlue、rgbGreen、rgbRed均分別為0到255。後續的點陣圖資料中,每1個位元組代表1個畫素,索引值正好就是灰度值。
對於用到調色盤的點陣圖,影像資料就是該畫素顏色在調色盤中的索引值;對於真彩色圖,影像資料就是實際的RGB值。下面就2色、16色、256色點陣圖和真彩色點陣圖分別介紹。
2色點陣圖,用1位就可以表示該畫素的顏色(一般0表示黑,1表示白),一個位元組可以表示8個畫素。
16色點陣圖,用4位可以表示一個畫素的顏色,所以一個位元組可以表示2個畫素。
256色點陣圖,一個位元組表示1個畫素。
真彩色圖,三個位元組表示1個畫素。
但是每一行的位元組數並不簡單等於寬度×單個畫素佔用的空間。BMP格式要求:每一行的位元組數必須是4的整數倍。如果不是,則需要在一行的點陣圖資料後補齊。
BMP檔案的資料是從下到上,從左到右的。也就是說,從檔案中最先讀到的是影像最下面一行的左邊第一個畫素,然後是左邊第二個畫素……接下來是倒數第二行左邊第一個畫素,左邊第二個畫素……依次類推,最後得到的是最上面一行的最右一個畫素。
在應用程式的GUI中顯示點陣圖,需要用到<wingdi.h>中的Windows API函式StretchDIBits:
StretchDIBits函式將DIB,JPEG或PNG影像中畫素矩形的顏色資料複製到指定的目標矩形。如果目標矩形大於源矩形,則此函式會拉伸顏色資料的行和列以適合目標矩形。如果目標矩形小於源矩形,則此函式使用指定的柵格操作壓縮行和列。
其語法如下:
int StretchDIBits(
HDC hdc,
int xDest,
int yDest,
int DestWidth,
int DestHeight,
int xSrc,
int ySrc,
int SrcWidth,
int SrcHeight,
const VOID * lpBits,
const BITMAPINFO* lpbmi,
UINT iUsage,
DWORD rop
);
其中
<winnt.h>:
#define VOID void
<minwindef.h>:
typedef unsigned int UINT;
每個引數的解釋如下:
hdc
目標裝置上下文的控制程式碼。
裝置上下文也稱裝置描述表,是一種Windows資料結構,其中包含有關裝置(例如顯示器或印表機)的繪圖屬性的資訊。 所有繪圖呼叫都通過裝置上下文物件進行,該物件封裝用於繪製線條、形狀和文字的Windows API。裝置上下文允許Windows中與裝置無關的繪圖。裝置上下文可用於繪製到螢幕、印表機或元檔案(metafile)。
xDest
目標矩形左上角的x座標(以邏輯單位表示)。
yDest
目標矩形左上角的y座標(以邏輯單位表示)。
DestWidth
目標矩形的寬度,以邏輯單位為單位。
DestHeight
目標矩形的高度,以邏輯單位為單位。
xSrc
影像中源矩形的x座標(以畫素為單位)。
ySrc
影像中源矩形的y座標(以畫素為單位)。
SrcWidth
影像中源矩形的寬度(以畫素為單位)。
SrcHeight
影像中源矩形的高度(以畫素為單位)。
lpBits
指向影像位的指標,影像位儲存為位元組陣列。
lpbmi
指向包含有關DIB資訊的BITMAPINFO結構的指標。
iUsage
指定是否提供了BITMAPINFO結構的bmiColors成員。如果提供,則指定bmiColors是否包含顯式的紅色,綠色,藍色(RGB)值或索引。iUsage引數必須是以下值之一:
DIB_PAL_COLORS
該陣列包含進入源裝置上下文的邏輯調色盤的16位索引。
DIB_RGB_COLORS
顏色表包含文字RGB值。
rop
光柵操作程式碼,指定如何將源畫素,目標裝置上下文的當前畫筆和目標畫素組合在一起以形成新影像。
以MFC(提示:MFC已經被市場淘汰,這裡只做演示用。除非維護老專案,否則不應選用MFC。)為例,在檢視類(負責前臺響應)的OnDraw函式中,使用StretchDIBits顯示點陣圖,則每次視窗被重繪時就會顯示指定的點陣圖:
void CTestView::OnDraw(CDC* pDC) {
CTESTDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc) return;
// TODO: add draw code for native data here
if (nullptr == lpBitsInfo) return;
LPVOID lpBits = (LPVOID)&lpBitsInfo->bmiColors[lpBitsInfo->bmiHeader.biClrUsed];
StretchDIBits(pDC->GetSafeHdc(),
0, 0, lpBitsInfo->bmiHeader.biWidth, lpBitsInfo->bmiHeader.biHeight,
0, 0, lpBitsInfo->bmiHeader.biWidth, lpBitsInfo->bmiHeader.biHeight,
lpBits, lpBitsInfo, DIB_RGB_COLORS, SRCCOPY);
}
其中
<minwindef.h>:
typedef void far LPVOID;
<wingdi.h>:
#define DIB_RGB_COLORS 0 / color table in RGBs /
#define DIB_PAL_COLORS 1 / color table in palette indices /
#define SRCCOPY (DWORD)0x00CC0020 / dest = source */
此程式碼中,原影像與目標顯示區域是按照1:1的比例來顯示的,無放縮。
lpbmi引數這裡為lpBitsInfo,它是一個BITMAPINFO結構的指標,此結構定義於<wingdi.h>:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;
第一個成員bmiHeader便是BMP檔案的資訊頭;第二個成員的長度通常遠遠大於1,包含調色盤(如果有的話)和點陣圖資料。
lpBits引數這裡為lpBits,是一個void型指標。這裡指向調色盤(如果有)之後的點陣圖資料的首個位元組。
處理影像內容時要注意:如要訪問畫素點<i,j>的資料,則其在記憶體中的位置應當為:
S+L_LINE (h-1-i)+j
其中S為點陣圖資料實際的開始位置,即上文的lpBits;L_LINE為一行的位元組數:
L_LINE=(wb+31)/32×4
w為影像的寬度,b為點陣圖的位數(1、4、8、24)。
可見,L_LINE是對齊之後的長度。wb是一整行畫素佔用的位數。而當32 | wb時,上式也可寫為
L_LINE=(wb+31)/32×4=wb/32×4=8wb
此時一行的長度已經按4位元組對齊。多出來的31會被整除運算截斷。容易看出:已對齊的情況下,一旦一行的資料再多出1位,那麼就要多佔用4個位元組。
如果需要遍歷一個BMP影像的每一個畫素點<i,j>,那麼迴圈應當這樣寫:
for (LONG i = 0; i < h; ++i)
for (LONG j = 0; j < w; ++j) {
…
}
i對應行編號,j對應列編號。
注意:一幅w×h的影像,其水平畫素(列數)和垂直畫素(行數)的取值範圍分別是[0, w-1]和[0, h-1]之間的整數。
相關文章
- 第三章 載入並顯示BMP影像
- python讀取docx檔案,就是如此簡單Python
- 使用IPicture介面讀取和顯示BMP,GIF,JPG,ICO,EMF,WMF影像 (轉)
- PlY檔案讀取顯示
- 數字影像處理-取樣量化(Matlab)Matlab
- 讓emacs完美顯示BMP檔案的辦法Mac
- Word圖示未顯示在.doc和.docx文件檔案
- Python 影像處理 OpenCV (2):畫素處理與 Numpy 操作以及 Matplotlib 顯示影像PythonOpenCV
- java讀取大檔案並處理Java
- 數字影像處理day_12 影像分割
- Maui 讀取外部檔案顯示到Blazor中UIBlazor
- 數字影像處理實驗(四)影像銳化
- 【傳統影像處理】1 數字影像基礎
- 數字影像處理--認識影像各種概念
- Java讀取本地檔案,並顯示在JSP檔案中JavaJS
- 極簡 Node.js 入門 - 3.2 檔案讀取Node.js
- 數字影像處理讀書筆記(三)直方圖匹配筆記直方圖
- 讀取檔案迴圈處理的兩種方法
- [00]數字影像處理-matlab速成Matlab
- 數字影像處理相關練習
- 不能顯示隱藏檔案的終極方法
- visual C++數字影像處理類C++
- 使用POI讀寫word docx檔案
- Shell 引數的讀取和處理
- Golang 快速讀取處理大日誌檔案工具Golang
- 個人實驗程式碼記錄 | 數字影像處理實驗3·影像直方圖與均衡化處理直方圖
- 數字影像處理學習筆記(1)——傅立葉變換在影像處理中的應用筆記
- JavaScript檔案處理第二部分:檔案讀取JavaScript
- [Python影像處理] 三十.影像量化及取樣處理萬字詳細總結(推薦)Python
- win10怎麼顯示檔案字尾_window10如何顯示檔案字尾副檔名Win10
- Win8 Metro(C#)數字影像處理--2.62影像對數增強C#
- 電腦檔案字尾名怎麼顯示?電腦中顯示檔案字尾(副檔名)的設定方法
- FPGA影像採集與顯示專案(一)帶LOGO的VGA顯示模組FPGAGo
- 自定義bmp影像縮放及在lcd螢幕任意位置顯示
- MATLAB批量儲存影像和顯示演算法處理的影像不留空白Matlab演算法
- bmp to jpg(32位bmp也可處理)
- nodeJS根據檔案字尾名讀取檔案並返回符合檔案總數NodeJS
- 數字影像處理實驗之對比度拉伸