Convert 24-bit true color bitmap to 4-bit (16-color) grayscale image (BMP)

Source: Internet
Author: User

The first thing to declare is that this 4-digit (16) color map is special, rather than a 16-color map, it's just a gray-scale map that uses 4-digit 16 colors for simulation.

What is a grayscale image?

A grayscale image is an image that only contains brightness information without color information. As we usually see, the brightness changes continuously from dark to bright. Therefore
In a grayscale image, the brightness value needs to be brightened. It is usually divided into 256 levels from 0 to 255, 0 is the lowest (all black), and is the brightest (all white ).
BMP files do not have the concept of grayscale images, but it is easy to use BMP files to represent grayscale images. The general method is to use a 256-color palette.

The RGB values of each item are the same, that is, from (255,255,255, 0), (255,255,255, 1) to (), (, 0) indicates that all black () indicates that all white

1. BMP bitmap format

The structure of the BMP file is divided into four parts. This article assumes that the reader has already understood the format of the BMP Bitmap (almost all the multimedia parts in the book that teach VC are described, and Google is also very satisfied.

This section describes the color palette and image data.

There is a palette for non-true color bitmaps. The format of the palette is as follows:

Typedef struct tagrgbquad {

Byte rgbblue; // blue weight
Byte rgbgreen; // green component
Byte rgbred; // red weight
Byte rgbreserved; // The reserved value does not need to be set to 0.

} Rgbquad;
A general color palette is a struct array consisting of the above struct to store specific color information. In a bitmap, only the subscript of the palette is stored in the image data section.

. This can greatly save space.

For example:
Rgbquad RGB [2];
RGB [0]. rgbblue = 0;
RGB [0]. rgbgreen = 0;
RGB [0]. rgbred = 0;
RGB [0]. rgbreserved = 0;
RGB [1]. rgbblue = 255;
RGB [1]. rgbgreen= 255;
RGB [1]. rgbred= 255;
RGB [1]. rgbreserving = 255;

The rgbquad array with the length of 2 is a one-bit two-color black and white color palette,
In the bitmap data part, only one bit of length is required to store 0 to indicate black, 1 to indicate white, and 1 to indicate 8 pixels of information, 3 bytes for R, G, and B

Saves 24 times the storage space

(In general, the data in the BMP file is from top to bottom, from left to right (refer to: proficient in Visual C ++ Typical Algorithm and Implementation of Digital Image Processing, 18 pages of version 2 ). note: The first read should be B, G, and R)

A true color chart is not a 24-hour bitmap. For example, a 24-hour bitmap requires a 24-hour color palette with an array size of 2. The subscript of the color palette also requires three bytes to be stored.

It is better to directly represent the color value of each pixel with the R, G, and B components. The color palette technology wastes a palette space of 256*256*256*3 bytes.

Here we need to use four digits to represent a grayscale image, so there are only 16 items in its color palette. The RGB values of each item are the same as those of a grayscale image usually composed of 256 colors.

Create this palette here

Rgbquad pa [16];
Byte C;
For (INT I = 0; I <16; I ++)
{
C = I * 17;
Pa [I]. rgbred = C;
Pa [I]. rgbgreen = C;
Pa [I]. rgbblue = C;
Pa [I]. rgbreserved = 0;
}

2. Conversion Algorithm

The current image is a 24-bit genuine color, indicating its data part. Three bytes represent a pixel, and the three bytes represent RGB respectively.
What we need to do now is to calculate the average value of the RGB value of each pixel, and then represent it with the value closest to the brightness of the color in the 16-color palette.
The 4-bit image represents two pixels in 1 byte. Special attention is needed here.

The specific Algorithm Implementation Code is as follows. pbuffer is an array for storing image data.

Ushort R, G, B;

//////////////////////////////////////// ////////////////////////
// The first Pixel
B = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
R = pbuffer [dwindex ++];

Int maxcolor = (R + G + B)/3;

Maxcolor/= 17; // calculate the subscript in the 16-color palette

// Second Pixel
B = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
R = pbuffer [dwindex ++];

Int maxcolor2 = (R + G + B)/3;

Maxcolor2/= 17;

Pnew [dwoldindex ++] = (maxcolor <4) | maxcolor2; // combine one byte to represent two pixels

 

3. Implementation Code

The complete implementation code is as follows:
Bool convert24to4 (maid, maid) // 24-> 4 grayscale
{
Bitmapfileheader bmhdr; // BMP File Header
Bitmapinfoheader bminfo; // BMP file information

Handle hfile, hnewfile;
DWORD dwbytewritten = 0;

// Open the source file handle
Hfile = createfile (lpszsrcfile,
Generic_read,
File_pai_read,
Null,
Open_existing,
File_attribute_normal,
Null );

If (hfile = invalid_handle_value)
Return false;

// Create a new file
Hnewfile = createfile (lpszdestfile,
Generic_read | generic_write,
File_pai_read | file_pai_write,
Null,
Create_always,
File_attribute_normal,
Null );
If (hnewfile = invalid_handle_value)
{
Closehandle (hfile );
Return false;
}

// Read the source file BMP header and file information
Readfile (hfile, & bmhdr, sizeof (bmhdr), & dwbytewritten, null );
Readfile (hfile, & bminfo, sizeof (bminfo), & dwbytewritten, null );

Trace ("bisize: % d, biwidth: % d, biheight: % d, bibitcount: % d, bisizeimage: % d

/N ", bminfo. bisize, bminfo. biwidth, bminfo. biheight, bminfo. bibitcount, bminfo. bisizeimage );
Trace ("Bix: % d, biy: % d, biclrused: % d, biclrimportant: % d

/N ", bminfo. bixpelspermeter, bminfo. biypelspermeter, bminfo. biclrused, bminfo. biclrimportant );

// Only 24 uncompressed images are processed
If (bminfo. bibitcount! = 24 | bminfo. bicompression! = 0)
{
Closehandle (hnewfile );
Closehandle (hfile );
Deletefile (lpszdestfile );
Return false;
}

// Calculate the image data size
DWORD dwoldsize = bminfo. bisizeimage;
If (dwoldsize = 0) // recalculate
{
Dwoldsize = bmhdr. bfsize-sizeof (bmhdr)-sizeof (bminfo );
}

Trace ("Old width: % d, old Height: % d, old size: % d Bytes/N", bminfo. biwidth, bminfo. biheight, dwoldsize );

Long WID = bminfo. biwidth % 4;

If (WID> 0)
{
WID = 4-wid;
}

WID + = bminfo. biwidth;

DWORD dwnewsize;

Dwnewsize = WID * bminfo. biheight/2; // calculate the size of the new image after conversion

Trace ("New Size: % d Bytes/N", dwnewsize );
 

// Read raw data
Uchar * pbuffer = NULL;
Pbuffer = new uchar [dwoldsize]; // apply for the original data space
If (pbuffer = NULL)
{
Closehandle (hnewfile );
Closehandle (hfile );
Deletefile (lpszdestfile );
Return false;
}
// Read data
Readfile (hfile, pbuffer, dwoldsize, & dwbytewritten, null );

Uchar * pnew = new uchar [dwnewsize];

Uchar color = 0;
DWORD dwindex = 0, dwoldindex = 0;
While (dwindex <dwoldsize) // one byte represents two pixels
{
Ushort R, G, B;

//////////////////////////////////////// ////////////////////////
// The first Pixel
B = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
R = pbuffer [dwindex ++];

Int maxcolor = (R + G + B)/3;

Maxcolor/= 17;

// Second Pixel
B = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
R = pbuffer [dwindex ++];

Int maxcolor2 = (R + G + B)/3;

Maxcolor2/= 17;

Pnew [dwoldindex ++] = (maxcolor <4) | maxcolor2; // combine one byte to represent two pixels

}

//////////////////////////////////////// ////////////////////////////////////////
// Complete. Save the result to the new file.

// Modify attributes
Bmhdr. bfsize = sizeof (bmhdr) + sizeof (bminfo) + sizeof (rgbquad) * 16 + dwnewsize;
Bmhdr. bfoffbits = bmhdr. bfsize-dwnewsize;
Bminfo. bibitcount = 4;
Bminfo. bisizeimage = dwnewsize;

// Create a color palette
Rgbquad pa [16];
Uchar C;
For (INT I = 0; I <16; I ++)
{
C = I * 17;
Pa [I]. rgbred = C;
Pa [I]. rgbgreen = C;
Pa [I]. rgbblue = C;
Pa [I]. rgbreserved = 0;
}

// BMP Header
Writefile (hnewfile, & bmhdr, sizeof (bmhdr), & dwbytewritten, null );
// File Information Header
Writefile (hnewfile, & bminfo, sizeof (bminfo), & dwbytewritten, null );
// Color palette
Writefile (hnewfile, Pa, sizeof (rgbquad) * 16, & dwbytewritten, null );
// File data
Writefile (hnewfile, pnew, dwnewsize, & dwbytewritten, null );

Delete [] pbuffer;
Delete [] pnew;

// Close the file handle
Closehandle (hnewfile );
Closehandle (hfile );

Return true;
}

4. Questions

Since a 24-digit real-food image can be converted into a 4-digit grayscale image, there must be a proper way to convert it into a 4-digit color image. The specific difference is that
The color palette is different (which colors must be represented in the color palette). The most important thing is that the original color is represented by the existing 16 colors, which indicates a more appropriate color.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.