C language removes the background of bmp picture
I. Preface
In image processing, most of the processing methods need to convert color image into gray image in advance to carry out relevant calculation and recognition.
The principle of color image conversion to gray image is as follows:
We know that the color bitmap is composed of three components of R/G/B, and its file storage format is
BITMAPFILEHEADER+BITMAPINFOHEADER, followed by:
- If it is a 24 bit true color image, each point is represented by three bytes R/G/B respectively, so the color information of the image is directly followed here;
- If it is an 8-bit (256 colors), 4-bit (16 colors) and 1-bit (monochrome) graph, the palette data is immediately followed. An array of RGBQUAD type, whose length is determined by BITMAPINFOHEADER.biClrUsed.
Then the image data is followed (24 bitmaps are real image data, others are index data of palette).
Gray scale image refers to an image with only brightness information and no color information, just like the black-and-white photos we usually see: the brightness changes continuously from dark to light. Therefore, in order to represent the gray-scale image, it is necessary to quantify the brightness value. It is usually divided into 256 levels from 0 to 255, of which 0 is the darkest (all black) and 255 is the brightest (all white). In the method of representing color, in addition to RGB, there is also a method called YUV, which has many applications. In TV signal, we use a kind of color representation similar to YUV. In this representation method, the physical meaning of Y component is brightness. Y component contains all the information of gray-scale image. Only Y component can represent a gray-scale image.
The Gray conversion formula from RGB to YUV space is:
Gray = R0.299 + G0.587 + B*0.114
In WINDOWS, the graph that represents more than 16 bits is a little different from the graph that represents less than 16 bits; the graph that represents less than 16 bits uses a palette to select a specific color, each unit of the palette is 4 bytes, one of which is transparent; the specific pixel value stores an index, which is 1, 2, 4, 8 bits respectively. 16 bit or more images use pixels to represent colors directly.
So how to convert color image to gray image?
There is a palette in the gray-scale image. First, we need to determine the specific color value of the palette. As we mentioned earlier, the three components of a grayscale image are equal.
When converted to 8 bits, there are 256 colors in the palette, each from exactly 0 to 255, with three equal components.
When it is converted to 4 bits, 16 colors in the palette are equally divided into 255 color values at equal intervals, and all three components are equal.
When it is converted to 2 bits, there are 4 colors in the palette, with equal interval of 255 colors, and the three components are equal.
When converted to 1 bit, two colors in the palette, 0 and 255, represent black and white.
When the color is converted to grayscale, the corresponding value is calculated according to the formula, which is actually the brightness level; the brightness is from 0 to 255; because different bits have different brightness levels, the specific value of Y is as follows: y = Y / (1 < (8-converted digits));
Therefore, we need to convert it into gray-scale image and store it into a visible image as follows:
Images with more than 16 bits do not have color palette, only need to convert image data into the same gray value according to the number of bits of each point
For images below 16 bits, you need to modify the value of the palette, and modify the gray value index according to the number of bits occupied by each point.
What? I don't understand after saying so much???
- 24 bit true color picture file header + picture header + bitmap data (the kind of picture you usually see)
- 8-bit grayscale file information header + picture information header + palette + bitmap data (that is, the image with the effect found by the black-and-white camera)
Binary image (also known as single value image) has one bit per pixel, i.e. black and white image. The value of each pixel is not 0 or 1.
Each pixel of gray image is 8 bit, ranging from 0 to 255. It has color palette, and the pixel value is the entry of table item.
The pseudo color image has 8 bits per pixel, ranging from 0-255. It has a palette, and the pixel value is the entry of the table item.
Each pixel of true color image is 24bit, and each pixel is composed of independent R, G and B components, each of which accounts for 8bit.
What we need to do now is to convert a 24 bit bitmap into an 8-bit gray-scale image.
2, Grayscale
Header file
# ifndef BMP_H # define BMP_H /*bitmap-file header */ #pragma pack(1)//Single byte alignment typedef struct tagBITMAPFILEHEADER { unsigned char bfType[2];//file format unsigned int bfSize; // File size in bytes (2-5 bytes) unsigned short bfReserved1; // Reserved, must be set to 0 (6-7 bytes) unsigned short bfReserved2; // Reserved, must be set to 0 (8-9 bytes) unsigned int bfOffBits; // Offset from file header to pixel data (10-13 bytes) }BITMAPFILEHEADER; #pragma pack() /*Bitmap header*/ #pragma pack(1) typedef struct tagBITMAPINFOHEADER { unsigned int biSize; // Size of this structure (14-17 bytes) long biWidth; // Image width (18-21 bytes) long biHeight; // Image height (22-25 bytes) unsigned short biPlanes; // Represents the plane genus of bmp picture, obviously the display has only one plane, so it is equal to 1 (26-27 bytes) unsigned short biBitCount; // The number of bits occupied by a pixel, (28-29 bytes) when biBitCount=24, the BMP image is a 24Bit true color image without palette items. unsigned int biCompression; // Describes the type of image data compression. 0 is not compressed. (30-33 bytes) unsigned int biSizeImage; // The size of pixel data, which should be equal to bfsize bfoffbits (34-37 bytes) in the file header structure above long biXPelsPerMeter; // Indicates the horizontal resolution in pixels per meter. Generally 0 (38-41 bytes) long biYPelsPerMeter; // Indicates the vertical resolution in pixels per meter. Generally 0 (42-45 bytes) unsigned int biClrUsed; // Describes the number of color indexes in the color table that the bitmap actually uses (if set to 0, all palette items are used). (46-49 bytes) unsigned int biClrImportant; // Indicates the number of color indexes that have important influence on image display. If it is 0, it means that they are all important. (50-53 bytes) }BITMAPINFOHEADER; #pragma pack() /*Palette structure*/ #pragma pack(1) typedef struct tagRGBQUAD { unsigned char rgbBlue; //Blue component of the color (value range 0-255) unsigned char rgbGreen; //Green component of the color (value range 0-255) unsigned char rgbRed; //Red component of the color (value range 0-255) unsigned char rgbReserved;// Reserved, must be 0 }RGBQUAD; #pragma pack() #endif
Here you see the "pragma pack (1)" and "pragma pack(). Haven't you seen this? I haven't seen it before. Let's see: Structure alignment details
C file
#include<stdio.h> #include<malloc.h> #include<stdlib.h> #include"bmp.h" int main() { unsigned char ImgData[3000][3];//Convert bitmap information into a row of pixels of RGB image stored in grayscale unsigned char ImgData2[3000];//Save the pixels of the gray-scale image into a one-dimensional array int i, j, k; FILE * fpBMP, *fpGray; BITMAPFILEHEADER *fileHeader; BITMAPINFOHEADER *infoHeader; RGBQUAD * ipRGB; char filename1[20], filename2[20]; printf("Enter image file name:"); scanf("%s", filename1); if ((fpBMP = fopen(filename1, "rb")) == NULL) { printf("Failed to open picture"); exit(0); } printf("Output image filename:"); scanf("%s", filename2); if ((fpGray = fopen(filename2, "wb")) == NULL) { printf("Failed to create picture"); exit(0); } //Request the memory space of this structure size for the defined structure variable fileHeader = (BITMAPFILEHEADER *)malloc(sizeof(BITMAPFILEHEADER)); infoHeader = (BITMAPINFOHEADER *)malloc(sizeof(BITMAPINFOHEADER)); //Read data block to file information header and picture information header from bmp file fread(fileHeader, sizeof(BITMAPFILEHEADER), 1, fpBMP); fread(infoHeader, sizeof(BITMAPINFOHEADER), 1, fpBMP); //Through these two programs, the information header and file header of BMP image are assigned to fileHeader and infoHeader variables, and various attributes of image can be obtained according to fileHeader and infoHeader. printf("The number of bits per pixel of the original picture:%d\n" ,infoHeader->biBitCount); printf("Pixel data offset of each pixel of the original picture:%d\n" ,fileHeader->bfOffBits); //Modify header //There are 11 parts in the header, and two parts need to be modified when graying infoHeader->biBitCount = 8;//Convert 24 bit true color image to 8-bit gray-scale image infoHeader->biSizeImage = ((infoHeader->biWidth * 3 + 3) / 4) * 4 * infoHeader->biHeight;//The actual number of bytes occupied by each line of 24Bit true color picture //Modify file header //There are 5 parts in the file header, two parts need to be modified when graying fileHeader->bfOffBits = sizeof( BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD); fileHeader->bfSize = fileHeader->bfOffBits + infoHeader->biSizeImage; printf("The number of bits per pixel of the modified picture:%d\n" ,infoHeader->biBitCount); printf("Each pixel data offset of the modified picture:%d\n" ,fileHeader->bfOffBits); //The palette of gray image is R=G=B. the three values of true color image are not equal ipRGB = (RGBQUAD *)malloc(256 * sizeof(RGBQUAD)); for (i = 0; i < 256; i++) { ipRGB[i].rgbBlue = ipRGB[i].rgbGreen = ipRGB[i].rgbRed = i; } //Read the information header, file header, BMP palette of BMP image to the new image fwrite(fileHeader, sizeof(BITMAPFILEHEADER), 1, fpGray); fwrite(infoHeader, sizeof(BITMAPINFOHEADER), 1, fpGray); fwrite(ipRGB , sizeof(RGBQUAD) , 256, fpGray); //Read RGB image pixels and convert them to grayscale values for (i = 0; i < infoHeader->biHeight; i++)//Line by line scanning { //The actual number of bytes occupied by each line of a 24Bit true color picture is [(biWidth*3+3)/4*4] so each line of biHeight is scanned [(biWidth*3+3)/4*4] times for (j = 0; j < (infoHeader->biWidth + 3) / 4 * 4; j++)//Write bitmap data part of BMP image { for (k = 0; k < 3; k++) fread(&ImgData[j][k], 1, 1, fpBMP);////Read only one byte at a time and store in the array } //The part of modifying bitmap data is mainly from the rgbRed, rgbGreen and rgbBlue components of the original color image to the gray value Y of the gray image, which can be obtained by the following formula: for (j = 0; j < (infoHeader->biWidth + 3) / 4 * 4; j++) { ImgData2[j] = (int)((float)ImgData[j][0] * 0.114 + (float)ImgData[j][1] * 0.587 + (float)ImgData[j][2] * 0.299 ); } //Write grayscale information fwrite(ImgData2, j, 1, fpGray);//Write parts of BMP image in order } free(fileHeader); free(infoHeader); free(ipRGB); fclose(fpBMP); fclose(fpGray); printf("bmp Background removal completed\n"); return 0; }
At this point, 24 bitmaps are converted to 8-bit gray-scale images.
Take a look at the effect.
To enter the path of the picture here, it is recommended to put it directly into the project directory. It's OK to put it in other places, just fill in the path of the picture. I can also type D:\c_test\bmp-cleancover .bmp. Because my picture 1.bmp is placed in the BMP cleancover folder of the c'u test on disk D.
Compare the results:
How do you feel different?
I thought what I wanted to accomplish was this effect. Consult others and tell me to binarize. It's just grayscale. Binarization means that the picture is not black or white.
3, Binarization
#include<stdio.h> #include<malloc.h> #include<stdlib.h> #include"bmp.h" int main() { /*Variable declaration*/ FILE *fpBMP,*fpTwoValue;//Source file fpBMP, target file fpTwoValue char filename1[20], filename2[20]; BITMAPFILEHEADER *fileHeader;//bitmap-file header BITMAPINFOHEADER *infoHeader;//Bitmap header RGBQUAD *ipRGB;//palette int i,j,k=0; unsigned char *a;//Store pixel values of each line of source map unsigned char b;//Store gray value or binary value of each pixel unsigned char *c;//Stores the binary value of each row of pixels printf("Enter image file name:"); scanf("%s", filename1); if ((fpBMP = fopen(filename1, "rb")) == NULL) { printf("Failed to open picture"); exit(0); } printf("Output image filename:"); scanf("%s", filename2); if ((fpTwoValue = fopen(filename2, "wb")) == NULL) { printf("Failed to create picture"); exit(0); } /********************************************************************/ /*Create bitmap file header, information header, palette*/ fileHeader=(BITMAPFILEHEADER *)malloc(sizeof(BITMAPFILEHEADER)); infoHeader=(BITMAPINFOHEADER *)malloc(sizeof(BITMAPINFOHEADER)); ipRGB=(RGBQUAD *)malloc(2*sizeof(RGBQUAD)); /*Read in source bitmap file header and information header*/ fread(fileHeader,sizeof(BITMAPFILEHEADER),1,fpBMP); fread(infoHeader,sizeof(BITMAPINFOHEADER),1,fpBMP); //Through these two programs, the information header and file header of BMP image are assigned to fileHeader and infoHeader variables, and various attributes of image can be obtained according to fileHeader and infoHeader. printf("The number of bits per pixel of the original picture:%d\n" ,infoHeader->biBitCount); printf("Pixel data offset of each pixel of the original picture:%d\n" ,fileHeader->bfOffBits); //Modify header //There are 11 parts in the header, and 4 parts need to be modified when graying infoHeader->biBitCount=8;//After conversion to binary graph, the color depth changes from 24 bits to 8 bits infoHeader->biSizeImage=((infoHeader->biWidth+3)/4)*4*infoHeader->biHeight;//Each pixel is changed from three bytes to a single byte, and each row of pixels is aligned with four bytes infoHeader->biClrUsed=2;//Number of color index table, 2-value chart infoHeader->biClrImportant=0;//The important color index is 0, indicating that all are important //Modify file header //There are 5 parts in the document header, and two parts need to be modified when graying fileHeader->bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+2*sizeof(RGBQUAD);//Data area offset equal to the sum of file header, information header and index table sizes fileHeader->bfSize=fileHeader->bfOffBits+infoHeader->biSizeImage;//File size, equal to offset plus data area size ipRGB[1].rgbBlue=ipRGB[1].rgbGreen=ipRGB[1].rgbRed=ipRGB[1].rgbReserved=0;//Palette color is black with index 0 ipRGB[0].rgbBlue=ipRGB[0].rgbGreen=ipRGB[0].rgbRed=190;//The index corresponding to white is 150-255 ipRGB[1].rgbReserved=0; printf("The number of bits per pixel of the modified picture:%d\n" ,infoHeader->biBitCount); printf("Each pixel data offset of the modified picture:%d\n" ,fileHeader->bfOffBits); /********************************************************************/ //Read the information header, file header, BMP palette of BMP image to the new image fwrite(fileHeader,sizeof(BITMAPFILEHEADER),1,fpTwoValue); fwrite(infoHeader,sizeof(BITMAPINFOHEADER),1,fpTwoValue); fwrite(ipRGB,2*sizeof(RGBQUAD),1,fpTwoValue); /*Convert color map to binary map*/ a=(unsigned char *)malloc((infoHeader->biWidth*3+3)/4*4);//Apply the space occupied by each row of pixels in the source graph for variable a, and consider the four byte alignment problem c=(unsigned char *)malloc((infoHeader->biWidth+3)/4*4);//Apply the space occupied by each row of pixels in the target graph for variable c, and align the same four bytes for(i=0;i<infoHeader->biHeight;i++)//Loop through each line of the image { for(j=0;j<((infoHeader->biWidth*3+3)/4*4);j++)//Loop through each byte in each line { fread(a+j,1,1,fpBMP);//Read each byte of each line of the source graph into the memory space pointed to by variable a } for(j=0;j<infoHeader->biWidth;j++)//Cycle the pixel width times, and the four byte padding bit read in will not be calculated { b=(int)(0.114*(float)a[k]+0.587*(float)a[k+1]+0.299*(float)a[k+2]);//Every three bytes in a represent BGR component respectively, multiplying different weights and converting them into gray value if(160<=(int)b) //The gray value is converted to binary value, and the threshold value selected here is 160-190 b=1; else b=0; c[j]=b; //Store the binary value of each line k+=3; } fwrite(c,(infoHeader->biWidth+3)/4*4,1,fpTwoValue);//Write the binary pixel four byte fill to the file, the fill bit is not initialized, it is a random value k=0; } /*Free up memory, close files*/ free(fileHeader); free(infoHeader); free(ipRGB); free(a); free(c); fclose(fpBMP); fclose(fpTwoValue); printf("bmp Background removal completed\n"); return 0; }
Just commission the C file to the above one. The header file does not need to be changed. Because the structural member variables of bmp images are fixed, you only need to change the parameters.
This time we can see the effect. It is obvious that the background has been removed.
Just copy the C file and H file to your program. We need to understand the principle of the program in detail. If you encounter problems, you can search on the Internet, involving the structure and file pointer. I also read a lot of information.
Alas, it's not easy to code. If passing by is helpful to you, please click "like".