Digital Image Processing (Minimalist) Chapter 3 Reading and Displaying BMP Files (docx)

Suggested prerequisites: advanced mathematics (calculus), linear algebra.
Bibliography:
1. Image Engineering (Volume 1)-Image Processing (4th Edition) Zhang Yujin Tsinghua University Press


Link: https://pan.baidu.com/s/1hEMGRUotQFL_RtGap6JaUg
Extraction code: 0000

Three BMP file reading and display

BMP file is a very simple image storage format. When learning to process images, we start with the simplest format. When dealing with other complex formats, the method of decompressing and then performing subsequent processing is often adopted. The decompressed data is often similar to uncompressed formats such as BMP (usually, compressed BMP is rare).
BMP files are mainly used on the Windows platform. Therefore, before continuing the following study, you should have some knowledge of Windows programming.

The structure of the BMP file is divided into four parts:
[1] File header.
[2] Information header.
[3] Palette (optional).
[4] Image data.

In the form definition file header <wingdi.h> are:
typedef struct {tagBITMAPFILEHEADER WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } the BITMAPFILEHEADER, LPBITMAPFILEHEADER FAR *, * PBITMAPFILEHEADER; wherein <minwindef.h>: # define far #define FAR far typedef unsigned long DWORD; typedef unsigned short WORD; The length of this structure is fixed at 14 bytes. The explanation of each member is as follows:












bfType
specifies the file type, and its value is 42 4D, which is BM. That is to say, the first two bytes of all .bmp files are "BM".

bfSize
specifies the file size (including the file header). The value is a DWORD value, which is a double word (4 bytes), so the maximum size of a BMP file is 4 GB (232 bytes).

bfReserved1 and bfReserved2 are
reserved words, which are not considered here.

bfOffBits
is the number of offset bytes from the file header to the actual bitmap data.

The format of the message header is also defined in <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 biClrUsed; ; } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; where <winnt.h>: typedef long LONG; The length of this structure is fixed at 40 bytes. The explanation of each member is as follows:















The biSize
value is the constant 40, which specifies the length of this structure.

biWidth, biHeight
specify the width and height of the image (unit: pixels).

The
value of biPlanes is fixed at 1, which is not considered here.

biBitCount
specifies the number of bits to be used when representing colors. The values ​​can be: 1 (black and white two-color image), 4 (16 color image), 8 (256 color), 24 (true color image).

biCompression
specifies whether the bitmap is compressed. Windows bitmaps can be compressed, but they are not used much. We only discuss the case of no compression, biCompression is 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


When the image is in a compressed format, biSizeImage describes the length of the bitmap data. When the image is not compressed, this value is zero.

biXPelsPerMeter, biYPelsPerMeter
specify the horizontal and vertical resolution of the target device. Unit: the number of pixels per meter.

biClrUsed
specifies the number of colors actually used in this image (determines the number of palette array elements). If the value is zero, the number of colors used is 2 to the power of biBitCount.
A standard BMP file should only set this value to zero when it is in true color.

biClrImportant
specifies the number of important colors in this image. This value is usually zero, which means that all colors are considered important.

When the image is not in true color, there is a palette after the message header. The palette is actually an array with a total of biClrUsed elements (if the value is zero, there are 2 elements to the power of biBitCount). Each element in the array is an RGBQUAD structure, occupying 4 bytes, and its definition is located in <wingdi.h>:
typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; a standard 256 gray For a degree image, the first three items rgbBlue, rgbGreen, and rgbRed of the 0th to 255th items of the palette are all 0 to 255. In the subsequent bitmap data, each byte represents 1 pixel, and the index value is exactly the gray value.





For a bitmap using a palette, the image data is the index value of the pixel color in the palette; for a true color image, the image data is the actual RGB value. The following describes the 2-color, 16-color, 256-color bitmap and true color bitmap respectively.
2-color bitmap, one bit can represent the color of the pixel (usually 0 represents black, 1 represents white), and one byte can represent 8 pixels.
16-color bitmap, 4 bits can represent the color of one pixel, so one byte can represent 2 pixels.
256-color bitmap, one byte represents one pixel.
In true color image, three bytes represent 1 pixel.

But the number of bytes in each row is not simply equal to width × space occupied by a single pixel. BMP format requirements: The number of bytes in each line must be an integral multiple of 4. If it is not, it needs to be filled after one line of bitmap data.

The data of the BMP file is from bottom to top and from left to right. In other words, the first pixel read from the file is the first pixel from the left in the bottom line of the image, then the second pixel from the left...The next is the first pixel from the left in the penultimate line, and the second pixel from the left. Pixels... and so on, the final result is the rightmost pixel in the top row.

To display the bitmap in the GUI of the application, you need to use the Windows API function StretchDIBits in <wingdi.h>: The
StretchDIBits function copies the color data of the pixel rectangle in the DIB, JPEG or PNG image to the specified target rectangle. If the target rectangle is larger than the source rectangle, this function stretches the rows and columns of the color data to fit the target rectangle. If the target rectangle is smaller than the source rectangle, this function uses the specified raster operation to compress rows and columns.
The syntax is:
int StretchDIBits (
the HDC HDC,
int xDest,
int yDest,
int DestWidth,
int DestHeight,
int xSrc,
int ySrc,
int srcWidth,
int srcHeight,
const VOID * lpBits,
const the BITMAPINFO * lpbmi,
UINT iUsage,
DWORD ROP
) ;
Among them
<winnt.h>:
#define VOID void
<minwindef.h>:
typedef unsigned int UINT;

The explanation of each parameter is as follows:

The hdc
target device context handle.
The device context, also known as the device description table, is a Windows data structure that contains information about the drawing properties of the device (such as a monitor or printer). All drawing calls are made through the device context object, which encapsulates the Windows API for drawing lines, shapes, and text. The device context allows device-independent drawing in Windows. The device context can be used to draw to the screen, printer, or metafile.

xDest
The x coordinate (in logical units) of the upper left corner of the target rectangle.

yDest
The y coordinate (in logical units) of the upper left corner of the target rectangle.

DestWidth
The width of the target rectangle, in logical units.

DestHeight
The height of the target rectangle, in logical units.


The x coordinate (in pixels) of the source rectangle in the xSrc image.


The y coordinate (in pixels) of the source rectangle in the ySrc image.

SrcWidth
The width (in pixels) of the source rectangle in the image.

SrcHeight
The height (in pixels) of the source rectangle in the image.

lpBits
points to a pointer to the image bit, and the image bit is stored as a byte array.

lpbmi
points to a pointer to the BITMAPINFO structure that contains information about the DIB.

iUsage
specifies whether the bmiColors member of the BITMAPINFO structure is provided. If provided, specify whether bmiColors contains explicit red, green, and blue (RGB) values ​​or indexes. The iUsage parameter must be one of the following values:
DIB_PAL_COLORS
This array contains the 16-bit index into the logical palette of the source device context.
The DIB_RGB_COLORS
color table contains text RGB values.

The rop
raster operation code specifies how to combine the source pixel, the current brush of the target device context, and the target pixel to form a new image.

Take MFC (Hint: MFC has been eliminated by the market, here is only for demonstration purposes. Unless you maintain an old project, you should not choose MFC.) As an example, in the OnDraw function of the view class (responsible for foreground response), use StretchDIBits to display bitmap , The specified bitmap will be displayed every time the window is redrawn:
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 */

In this code, the original image and the target display area are displayed in a ratio of 1:1 without scaling.

The lpbmi parameter here is lpBitsInfo, which is a pointer to a BITMAPINFO structure, which is defined in <wingdi.h>:
typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO; the first The member bmiHeader is the information header of the BMP file; the length of the second member is usually much greater than 1, including the palette (if any) and bitmap data.



The lpBits parameter here is lpBits, which is a void pointer. This points to the first byte of the bitmap data after the palette (if any).

When processing image content, pay attention: if you want to access the data of pixel <i,j>, its location in the memory should be:
S+L_LINE (h-1-i)+j
where S is the actual bitmap data The starting position is the lpBits above; L_LINE is the number of bytes in a line:
L_LINE=(wb+31)/32×4
w is the width of the image, b is the number of bits of the bitmap (1, 4 , 8, 24) .
It can be seen that L_LINE is the length after alignment. wb is the number of bits occupied by a whole row of pixels. When 32 | wb, the above formula can also be written as
L_LINE=(wb+31)/32×4=wb/32×4=8wb.
At this time, the length of a line has been aligned by 4 bytes. The extra 31 will be truncated by the division operation. It is easy to see: in the case of alignment, once a row of data has one more bit, it will take up 4 more bytes.

If you need to traverse each pixel <i,j> of a BMP image, then the loop should be written like this:
for (LONG i = 0; i <h; ++i)
for (LONG j = 0; j <w; + +j) { } i corresponds to the row number, j corresponds to the column number. Note: For a w×h image, the value ranges of horizontal pixels (number of columns) and vertical pixels (number of rows) are integers between [0, w-1] and [0, h-1] respectively.



Guess you like

Origin blog.csdn.net/COFACTOR/article/details/109854282