Principle of Converting color BMP into Grayscale Images

Source: Internet
Author: User
Tags color representation readfile
In image processing, most of the processing methods need to convert a color image into a grayscale image in advance for calculation and recognition.
The principle of converting a grayscale image from a color chart is as follows:
We know that the color bitmap consists of three components: R/G/B, and its file storage format is
Bitmapfileheader + bitmapinfoheader:
If it is a 24-bit true color chart, each point is represented by three bytes respectively R/G/B, so here we follow the color information of the image directly;
For an 8-bit (256-color), 4-bit (16-color), and 1-bit (monochrome) graph, the following is the color palette data, an array of the rgbquad type, its length is determined by bitmapinfoheader. this parameter is determined by biclrused.
Then the image data is followed closely by the image data (24 bitmap is the real image data, and others are the index data of the palette ).
A grayscale image is an image that only contains brightness information and does not contain color information. It is like a black-and-white image we usually see: The brightness changes continuously from dark to bright. Therefore, to represent a grayscale image, you need to quantify the brightness value. Usually divided into 0 to 255, a total of 256 levels, of which 0 is the lowest (black), 255 is the brightest (white ). In addition to RGB, YUV is also used to represent colors. TV signals use a color representation method similar to YUV. In this representation method, the physical meaning of the Y component is the brightness. The Y component contains all the information of the grayscale image and can represent a grayscale image with only the y fraction.
The y conversion formula from RGB to YUV space is as follows:
Y = 0.299r + 0.587G + 0.114b
In Windows, a 16-bit or higher graph is a little different from the following graph. A 16-bit or lower graph uses a color palette to select a specific color, each cell in the palette contains four bytes, one of which is transparency. The specific pixel values store indexes, which are 1, 2, 4, and 8 bits. A 16-bit or more image uses pixels to represent the color.
How can we convert a color image to a grayscale image?
There is a palette in a grayscale image. First, you must determine the specific color values of the palette. As we mentioned earlier, the three components of the grayscale image are equal.
When converted to 8 bits, the color palette contains 256 colors, each of which ranges from 0 to 255, and the three components are equal.
When it is converted to 4 bits, the color palette contains 16 colors, and 255 color values are evenly divided at an equal interval. All three components are equal.
When the color is converted to 2 bits, the four colors in the color palette are evenly divided into 255 colors at an equal interval, and the three components are equal.
When the color is converted to one digit, the two colors in the color palette are 0 and 255, indicating black and white.
When the color is converted to a gray scale, the corresponding value is calculated according to the formula. The value is actually the brightness level. The brightness ranges from 0 to 255. Because different bits have different brightness levels, the specific values of Y are as follows:
Y = y/(1 <(8-number of digits converted ));
Therefore, to convert the image into a grayscale image and store it as a visible image, you need to convert it as follows:
For an image with more than 16 digits without a color palette, you only need to convert the image data to the same gray value based on the digits of each vertex.
For images with less than 16 bits, you need to modify the value of the color palette and modify the gray index based on the number of digits occupied by each vertex.

 

The following is the sample code for converting a 256 color image to a grayscale image:

/*************************************** * *********************** <Br/> * Function Name: <br/> * convert256togray () <br/> * parameter: <br/> * hdib-image handle <br/> * return value: <br/> * None <br/> * function: <br/> * convert a 256-color bitmap to a grayscale image <br/> * <br/> ******************* **************************************** * ***/</P> <p> void convert256togray (hdib) <br/>{< br/> lpstrlpdib; </P> <p> // obtain the dib pointer from the dib handle and lock Dib. <br/> lpdib = (lpstr ):: globallock (hglobal) hdib); </P> <p> // pointer to the dib pixel data zone <br/> lpstr lpdibbits; </P> <p> // pointer to the dib pixel <br/> byte * lpsrc; </P> <p> // image width <br/> longlwidth; <br/> // image height <br/> long lheight; </P> <p> // number of bytes per line of the image <br/> longllinebytes; </P> <p> // pointer to the bitmapinfo structure (win3.0) <br/> lpbitmapinfo lpbmi; </P> <p> // pointer to the bitmapcoreinfo structure <br/> lpbitmapcoreinfo lpmn; </P> <p> // obtain the pointer to the bitmapinfo structure (win3.0) <br/> lpbmi = (lpbitmapinfo) lpdib; </P> <p> // obtain the pointer to the bitmapcoreinfo structure <br/> lpbitmapcoreinfo (lpbitmapcoreinfo) lpdib; </P> <p> // grayscale ing table <br/> byte bmap [256]; </P> <p> // calculate the gray scale ing table (Save the gray scale values of each color), and update the dib palette <br/> Inti, J; <br/> for (I = 0; I <256; I ++) <br/>{< br/> // calculate the gray value corresponding to the color <br/> bmap [I] = (byte) (0.299 * lpbmi-> bmicolors [I]. rgbred + </P> <p> 0.587 * lpbmi-> bmicolors [I]. rgbgreen + </P> <p> 0.114 * lpbmi-> bmicolors [I]. rgbblue + 0.5); <br/> // update the red weight of the dib palette <br/> lpbmi-> bmicolors [I]. rgbred = I; </P> <p> // update the dib color palette green component <br/> lpbmi-> bmicolors [I]. rgbgreen = I; </P> <p> // update the blue component of the dib palette <br/> lpbmi-> bmicolors [I]. rgbblue = I; </P> <p> // update the reserved position of the dib palette <br/> lpbmi-> bmicolors [I]. rgbreserved = 0; </P> <p >}< br/> // locate the starting position of the DIB image pixel <br/> lpdibbits =: finddibbits (lpdib ); </P> <p> // obtain the image width <br/> lwidth =: dibwidth (lpdib ); </P> <p> // obtain the image height <br/> lheight =: dibheight (lpdib ); </P> <p> // calculate the number of bytes per line of the image <br/> llinebytes = widthbytes (lwidth * 8 ); </P> <p> // change the color index of each pixel (that is, change the color index to the gray value according to the grayscale ing table) </P> <p> // scan row by row <br/> for (I = 0; I <lheight; I ++) <br/>{</P> <p> // scan by column <br/> for (j = 0; j <lwidth; j ++) <br/> {<br/> // point to row I of Dib, pointer to pixel j <br/> lpsrc = (unsigned char *) lpdibbits + llinebytes * (lheight-1-I) + J; </P> <p> // transformation <br/> * lpsrc = bmap [* lpsrc]; <br/>}</P> <p> // unlock <br/>: globalunlock (hglobal) hdib); <br/>}

 

Convert a 24-bit color image to a 4-bit grayscale image

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

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
R = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
B = pbuffer [dwindex ++];

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

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

// Second Pixel
R = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
B = 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
R = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
B = pbuffer [dwindex ++];

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

Maxcolor/= 17;

// Second Pixel
R = pbuffer [dwindex ++];
G = pbuffer [dwindex ++];
B = 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.