One, BMP file format (BMP file format)
BMP file format, also known as Bitmap (Bitmap) or DIB (Device-Independent Device, device-independent bitmap), is an image file format widely used in the Windows system. Notepad++ is used as an analysis tool to combine bitmap data with Windows. The structure performs an in-depth analysis of the BMP file format. The data of the BMP file is divided into four parts according to the order from the beginning of the file header: bmp file header: Provides the format, size, and other information of the file Bitmap information (bitmap information): provides the size of the image data, Bit palette, compression method, color index, etc. Color palette: Optional, such as using the index to represent the image, the color palette is the mapping table of the index and its corresponding color Ø Bitmap data: The image data is ^ _ ^ The following combination of the definition of the Windows structure, through a table to analyze these four parts.

The images we generally see are mainly 24-bit images, that is, the R, G, and B colors are each represented by 8 bits. Such an image is called true color. In this case, the palette is not needed. That is, bitmap data is immediately followed by the bitmap information header.Therefore, we often have such a statement: bitmap file offset from the beginning of the file 54 bytes is bitmap data, which in fact is the case of 24 or 32 bitmap.This also explains why the program we write in this program is useless for some bitmap files.
BMP file header data structure

Bitmap header data structure

Bitmap data
Each pixel occupies one byte. After this byte is fetched, the corresponding color is queried by the byte index and displayed on the corresponding display device. Note: Because the height of the image in the bitmap header is positive, the bitmap data is arranged in the file from the lower left corner to the upper right corner, arranged in the behavioral main order.

That is, the first pixel 60 we see is the data in the bottom left corner of the image, the second human pixel 60 is the data in the second row of the last row of the image, ... until the last column of data in the last row, followed by the countdown The data in the first column of the second row, and so on.
- If the image is a bitmap of 24-bit or 32-bit data, the bitmap data area is not an index but the actual pixel value.Explain below, at this time, the RGB color array of each pixel of the bitmap data area is arranged:
- The 24-bit RGB stores the value of each color channel of each pixel in the order of BGR. After all the color component values of a pixel are stored, the next next pixel is stored, and no interleaving is stored.
- The 32-bit data is stored in the order of the BGRA, and the rest is the same as the 24-bit bitmap. The arrangement of pixels is consistent with the foregoing.
Alignment rules After finishing the rules of pixel arrangement and the arrangement rules of the color components of each pixel, we finally talk about the alignment rules of the data.We know that the minimum unit of Windows' default scan is 4 bytes. If the data alignment satisfies this value, it will have great gain for the data acquisition speed.Therefore, the BMP image complies with this requirement and requires that the length of data for each line must be a multiple of 4, and if it is not enough to perform bit stuffing (filled with 0), this can achieve fast access by line.At this time, the size of the bitmap data area is not necessarily represented by the picture width×the number of bytes per pixel×the picture performance, because each row may also need bit stuffing. The number of bytes per line after padding is:

, where BPP (Bits Per Pixel) is the number of bits per pixel. In the program, we can say: int iLineByteCnt = (((m_iImageWidth * m_iBitsPerPixel) + 31) >> 5) << 2; Thus, the size of the bitmap data area is: m_iImageDataSize = iLineByteCnt * m_iImageHeight; After a row of data, it is also possible that the following data is not the data of the next row and may need to skip a piece of padding data: skip = 4 - ((m_iImageWidth * m_iBitsPerPixel)>> 3) & 3;
Second, Ruby BMP image analysis
According to the above description of the BMP image format, I can write the following Ruby code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
@file = File.open(file, "rb+") @bitMapFileHeader = @file.read(14).unpack('a2LS2L') @type=@bitMapFileHeader[0] #file type, BM:BMP picture If @type!="BM" Puts "Not a BMP Picture" Exit End @size=@bitMapFileHeader[1] #file size @offBits=@bitMapFileHeader[4] #offset byte of image data @bitMapInfoHeader = @file.read(40).unpack('L3S2L6') @infoSize=@bitMapInfoHeader[0] #image info field size @width=@bitMapInfoHeader[1] #image width @height=@bitMapInfoHeader[2] #image height @planes=@bitMapInfoHeader[3] #number of planes @bitCountPerPixel=@bitMapInfoHeader[4] #Number of pictures @compression=@bitMapInfoHeader[5] @imageDataSize=@bitMapInfoHeader[6] #image data segment size @xPelsPerMeter=@bitMapInfoHeader[7] @yPelsPerMeter=@bitMapInfoHeader[8] @ClrUsed=@bitMapInfoHeader[9] @ClrImportant=@bitMapInfoHeader[10] @skipByteALine = 4 - ((@width * @bitCountPerPixel)>> 3) & 3 If @bitCountPerPixel == 24 iLineByteCnt = (((@width * @bitCountPerPixel) + 31) >> 5) << 2 @file.seek @offBits @imageDataArray= @file.read(@imageDataSize).unpack("C*") End |
The read(length) in the file object reads length bytes of data starting from the file pointer. The data type is a string. Through the unpack function, we can parse the data structure of the bmp image by passing in the unpack parameter. Take @file.read(14).unpack('a2LS2L') as an example. According to the analysis of the data structure of the above BMP file, read(14) reads the first 14 bytes of the file header of the bmp file. The parameter is 'a2LS2L'. 'You can parse 14 bytes of data into two characters (1 * 2 bytes), a Long type (1 * 8 bytes), two Short type (2 * 2 bytes), respectively remove the bmp picture File Type ("BM"), File Size, Two Reserved Fields, Image Data Offset (@imageDataSize).

Then read from the file @ imageDataSize bytes of data, parsed into a character array, which in addition to some of the alignment rules outside the data are image data;
1 |
@imageDataArray= @file.read(@imageDataSize).unpack("C*") |
If it is a 24-bit BMP picture, each pixel occupies three bytes, which are the B, G, and R values in RGB, respectively. Taking a picture with height=2, width=2 as an example, the image data part is converted into a single-byte array as follows:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
124 | 254 | 258 | 123 | 212 | twenty one | 221 | 56 | 107 | 204 | 251 | 100 | 52 | 100 | 111 | 59 |
Invalid data for each row: skipByteALine = 4 - ((2 * 24)>> 3) & 3=2 In order to more visually represent the correspondence between image pixels and RGB data, here I present the above in a two-dimensional matrix. One-dimensional array:

Due to the alignment principle, the 15th and 16th elements of the first row of 7, 8 and the second row will be discarded. Based on the above considerations, the RGB value of the specified pixel position can be obtained by the following Ruby code
1 2 3 4 5 |
# RGB of the picture (i,j) position, mapping of two-dimensional coordinates to one-dimensional coordinates, taking into account the number of bits and the amount of skipping of one pixel Def getRGB(i, j) linearIndex = (@width*i+j)*(@bitCountPerPixel>>3)+i*@skipByteALine RGB.new(@imageDataArray[linearIndex+2], @imageDataArray[linearIndex+1], @imageDataArray[linearIndex]) End |
Sets the RGB value of the specified pixel position by the following Ruby code
1 2 3 4 5 |
Def setRGB(i, j, rgb) linearIndex = (@width*i+j)*(@bitCountPerPixel>>3)+i*@skipByteALine @imageDataArray[linearIndex+2] = rgb.r @imageDataArray[linearIndex+1] = rgb.g @imageDataArray[linearIndex] = rgb.b End |
Third, Ruby processing pictures
Through the setRGB and getRGB methods described above to modify the bmp image data byte array, we can operate on the specified pixel bmp, the following describes the image graying:
1 2 3 4 5 6 7 8 9 10 11 12 |
# Grayscale image, take RGB three-color average # Grayscale pictures # Take RGB three-color average Def self.grey(bmp) For i in 0 .. Bmp.height - 1 For j in 0 .. Bmp.width - 1 Rgb = bmp.getRGB(i, j) Grey = rgb.getGreyLevel bmp.setRGB(i, j, RGB.new(grey, grey, grey)) End End End |
The above code I get RGB of all pixels, and then find the average of R, G, B values, RGB values are the same when the three pixels are grayed. The above operation will only modify the image data byte array, modify the need to save to Disk, save as follows:
1 2 3 4 5 6 7 |
Def save(file) @saveFile = File.open(file, "wb") @saveFile.write(@bitMapFileHeader.pack('a2LS2L')) @saveFile.write(@bitMapInfoHeader.pack('L3S2L6')) @saveFile.write(@imageDataArray.pack('C*')) @file.close @saveFile.close End |
Original image:

Processing effect:

In the next article, I will introduce image processing algorithms such as binarization, embossing filters, and film filters. Preview:
Paste_Image.png
Project home page
Geekeren/RubyImageProcess
Reference article
Http://blog.csdn.net/hzqnju/article/details/5927825 http://www.jianshu.com/p/30fbaab6d0a6 http://blog.csdn.net/hxker/article/details/50013303 http:/ /blog.csdn.net/o_sun_o/article/details/8351037
This article has been printed on copyright and is protected by copyright laws. It must not be reproduced without permission.If you need to reprint, please contact the author or visit the copyright to obtain the authorization. If you feel that this article is useful to you, you can click the "Sponsoring Author" below to call the author!
Reprinted Note Source: Baiyuan's Blog>>https://wangbaiyuan.cn/en/ruby-parser-bmp-file-image-processing-algorithm-on-2.html
No Comment