When the gray value of the pixels in the image is basically concentrated in a paragraph, the difference between the object and the object in the image is very insignificant (that is, the contrast of the image is relatively low). In this case, "linear transformation" can be used to process the image.
Linear transformation of image is easy to understand. From the linear transformation formula y=kx+b, it can be imagined that assuming the gray value of the image pixel is x, the output is y through the linear transformation, then replacing the gray value x of the original pixel with y realizes the linear mapping. Its function is that when the gray value of the image pixel is concentrated in a certain range such as [a,b], it can be mapped to a new range [c,d] by linear transformation formula. If C is 0 and D is 255, then the image is mapped to the whole gray level, that is to say, the contrast of the image is increased as much as possible. After the above analysis, we know from the mathematical solution of the equation that as long as the four values a,b, C and D are determined, the linear transformation formula can be obtained, and then the linear transformation formula can be used to transform the image.
From the above analysis, we can roughly know that the application of linear transformation is to achieve good results in some images with relatively concentrated gray values. Because before linear transformation, we first search the minimum and maximum gray level of the image as a, b, if a is close to 0 and B is close to 255, the effect is conceivable. Therefore, in the process of applying linear transformation, special attention should be paid to how to eliminate the interference of individual points.
ok, no more nonsense, the main implementation code is as follows:
- /*******************Image Processing Section********************************/
- /*******************Linear Transform of Images ******************************/
- /*Grayscale*/
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels
- pColorData[pixel_point] = pColorData[pixel_point + 1] = pColorData[pixel_point + 2] =
- (pColorData[pixel_point] + pColorData[pixel_point + 1] + pColorData[pixel_point + 2]) / 3;
- }
- /*Grayscale*/
- /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/
- BYTE min = 255;//minimum value
- BYTE max = 0;//Maximum
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels
- if (pColorData[pixel_point]>max)
- {
- max = pColorData[pixel_point];
- }
- if (pColorData[pixel_point]<min)
- {
- min = pColorData[pixel_point];
- }
- }
- printf("Maximum gray value:%d,Minimum gray value:%d\n", max, min);
- /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/
- /*linear transformation*/
- double k = (255 - 0) / (double)(max - min);
- double b = -k*min;
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels
- pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] =
- k*pColorData[pixel_point] + b;
- }
- /*linear transformation*/
- /*******************Linear Transform of Images ******************************/
- /*******************Image Processing Section********************************/
The results are as follows:/*******************Image Processing Section********************************/ /*******************Linear Transform of Images ******************************/ /*Grayscale*/ for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++) for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++) { int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels pColorData[pixel_point] = pColorData[pixel_point + 1] = pColorData[pixel_point + 2] = (pColorData[pixel_point] + pColorData[pixel_point + 1] + pColorData[pixel_point + 2]) / 3; } /*Grayscale*/ /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/ BYTE min = 255;//minimum value BYTE max = 0;//Maximum for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++) for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++) { int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels if (pColorData[pixel_point]>max) { max = pColorData[pixel_point]; } if (pColorData[pixel_point]<min) { min = pColorData[pixel_point]; } } printf("Maximum gray value:%d,Minimum gray value:%d\n", max, min); /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/ /*linear transformation*/ double k = (255 - 0) / (double)(max - min); double b = -k*min; for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++) for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++) { int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] = k*pColorData[pixel_point] + b; } /*linear transformation*/ /*******************Linear Transform of Images ******************************/ /*******************Image Processing Section********************************/
Original image
Image after Linear Transform
The whole project code is as follows:
- #include <string.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <malloc.h>
- #Include < time.h >// time-related header file, where functions can be used to calculate image processing speed
- #WIDTHBYTES(bits) (((bits)+31)/32*4)// Used to multiply the byte number of image width by 4 bytes
- #define MYDRAW_WIDTH 375// Target Image Width
- #define MYDRAW_HEIGHT 300// Target Image Height
- typedef unsigned char BYTE;
- typedef unsigned short WORD;
- typedef unsigned long DWORD;
- typedef long LONG;
- //Definition of Bitmap File Header Information Structure
- //It does not contain file type information (due to the memory structure of the structure, if added, the file information will not be read correctly)
- typedef struct tagBITMAPFILEHEADER {
- DWORD bfSize; //file size
- WORD bfReserved1; //Retain words without consideration
- WORD bfReserved2; //Retained words, ibid.
- DWORD bfOffBits; //The number of offset bytes of actual bitmap data, i.e. the sum of the first three Parts'lengths
- } BITMAPFILEHEADER;
- //The information header BITMAPINFOHEADER is also a structure, which is defined as follows:
- typedef struct tagBITMAPINFOHEADER{
- //public:
- DWORD biSize; //Specify the length of this structure to be 40
- LONG biWidth; //Bitmap width
- LONG biHeight; //Bitmap height
- WORD biPlanes; //Plane number, 1
- WORD biBitCount; //The number of color bits can be 1, 2, 4, 8, 16, 24, and the new number can be 32.
- DWORD biCompression; //Compression, which can be 0, 1, 2, where 0 means uncompressed
- DWORD biSizeImage; //Number of bytes occupied by actual bitmap data
- LONG biXPelsPerMeter; //X-Direction Resolution
- LONG biYPelsPerMeter; //Y-Direction Resolution
- DWORD biClrUsed; //The number of colors used, if 0, represents the default value (2 ^ color bits)
- DWORD biClrImportant; //The number of important colors, if 0, means that all colors are important
- } BITMAPINFOHEADER;
- void main()
- {
- long now = 0;
- now = clock();//Storage image processing start time
- BITMAPFILEHEADER bitHead, writebitHead;
- BITMAPINFOHEADER bitInfoHead, writebitInfoHead;
- FILE* pfile;//input file
- FILE* wfile;//output file
- char strFile[50] = "linear transformation.bmp";//To open the image path, the BMP image must be in 24-bit true color format
- char strFilesave[50] = "Transform results.bmp";//Image Storage Path after Processing
- fopen_s(&pfile, strFile, "rb");//File Open Image
- fopen_s(&wfile, strFilesave, "wb");//Open the file to prepare for storing the modified image
- //Read Bitmap File Header Information
- WORD fileType;
- fread(&fileType, 1, sizeof(WORD), pfile);
- fwrite(&fileType, 1, sizeof(WORD), wfile);
- if (fileType != 0x4d42)
- {
- printf("file is not .bmp file!");
- return;
- }
- //Read Bitmap File Header Information
- fread(&bitHead, 1, sizeof(tagBITMAPFILEHEADER), pfile);
- writebitHead = bitHead;//Because the intercepted image header is similar to the source file header, the source file header data is assigned to the intercepted file header first.
- //Read bitmap header information
- fread(&bitInfoHead, 1, sizeof(BITMAPINFOHEADER), pfile);
- writebitInfoHead = bitInfoHead;//Bitmap file headers are similar
- writebitInfoHead.biHeight = MYDRAW_HEIGHT;//Rewriting bitmap height for intercepting files
- writebitInfoHead.biWidth = MYDRAW_WIDTH;//Rewrite bitmap width for intercepting files
- int mywritewidth = WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//The width of the actual bitmap data area of BMP image is a multiple of 4 byte, and the width of the actual data area is calculated here.
- writebitInfoHead.biSizeImage = mywritewidth*writebitInfoHead.biHeight;//Calculating the actual data area size of bitmap
- writebitHead.bfSize = 54 + writebitInfoHead.biSizeImage;//Bitmap file header size is bitmap data area size plus 54 byte
- fwrite(&writebitHead, 1, sizeof(tagBITMAPFILEHEADER), wfile);//Write back bitmap file header information to output file
- fwrite(&writebitInfoHead, 1, sizeof(BITMAPINFOHEADER), wfile);//Write back bitmap header information to output file
- int width = bitInfoHead.biWidth;
- int height = bitInfoHead.biHeight;
- //Allocate memory space to store source diagrams in memory.
- int l_width = WIDTHBYTES(width*bitInfoHead.biBitCount);//Calculate the actual width of the bitmap and ensure that it is a multiple of 4 byte
- int write_width = WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//Calculate the actual width of the bitmap and ensure that it is a multiple of 4 byte
- BYTE *pColorData = (BYTE *)malloc(height*l_width);//Open up memory space to store image data
- memset(pColorData, 0, height*l_width);
- BYTE *pColorDataMid = (BYTE *)malloc(mywritewidth*MYDRAW_HEIGHT);//Open up memory space to store data after image processing
- memset(pColorDataMid, 0, mywritewidth*MYDRAW_HEIGHT);
- long nData = height*l_width;
- long write_nData = mywritewidth*MYDRAW_HEIGHT;//Length Definition of Intercepted Bitmap Data Area
- //Read bitmap data information into an array.
- fread(pColorData, 1, nData, pfile);//Image processing can be realized by manipulating this part of data.
- /*******************Image Processing Section********************************/
- /*******************Linear Transform of Images ******************************/
- /*Grayscale*/
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels
- pColorData[pixel_point] = pColorData[pixel_point + 1] = pColorData[pixel_point + 2] =
- (pColorData[pixel_point] + pColorData[pixel_point + 1] + pColorData[pixel_point + 2]) / 3;
- }
- /*Grayscale*/
- /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/
- BYTE min = 255;//minimum value
- BYTE max = 0;//Maximum
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels
- if (pColorData[pixel_point]>max)
- {
- max = pColorData[pixel_point];
- }
- if (pColorData[pixel_point]<min)
- {
- min = pColorData[pixel_point];
- }
- }
- printf("Maximum gray value:%d,Minimum gray value:%d\n", max, min);
- /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/
- /*linear transformation*/
- double k = (255 - 0) / (double)(max - min);
- double b = -k*min;
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels
- pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] =
- k*pColorData[pixel_point] + b;
- }
- /*linear transformation*/
- /*******************Linear Transform of Images ******************************/
- /*******************Image Processing Section********************************/
- fwrite(pColorDataMid, 1, write_nData, wfile); //Write back the processed image data area to the file
- fclose(pfile);
- fclose(wfile);
- printf("Image Processing Completion\n");
- printf("The running time is:%dms\n", int(((double)(clock() - now)) / CLOCKS_PER_SEC * 1000));//Output image processing time-consuming information
- }
#include <string.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> #Include < time.h >// time-related header file, where functions can be used to calculate image processing speed #Define WIDTHBYTES (bits) (((bits) +31)/32*4)// Used to multiply the byte number of image width by 4 bytes #Define MYDRAW_WIDTH 375//Target Image Width #define MYDRAW_HEIGHT 300//Target Image Height typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef long LONG; //Definition of Bitmap File Header Information Structure //It does not contain file type information (due to the memory structure of the structure, if added, the file information will not be read correctly) typedef struct tagBITMAPFILEHEADER { DWORD bfSize; //file size WORD bfReserved1; //Retain words without consideration WORD bfReserved2; //Retained words, ibid. DWORD bfOffBits; //The number of offset bytes of actual bitmap data, i.e. the sum of the first three Parts'lengths } BITMAPFILEHEADER; //The information header BITMAPINFOHEADER is also a structure, which is defined as follows: typedef struct tagBITMAPINFOHEADER{ //public: DWORD biSize; //Specify the length of this structure to be 40 LONG biWidth; //Bitmap width LONG biHeight; //Bitmap height WORD biPlanes; //Plane number, 1 WORD biBitCount; //The number of color bits can be 1, 2, 4, 8, 16, 24, and the new number can be 32. DWORD biCompression; //Compression, which can be 0, 1, 2, where 0 means uncompressed DWORD biSizeImage; //Number of bytes occupied by actual bitmap data LONG biXPelsPerMeter; //X-Direction Resolution LONG biYPelsPerMeter; //Y-Direction Resolution DWORD biClrUsed; //The number of colors used, if 0, represents the default value (2 ^ color bits) DWORD biClrImportant; //The number of important colors, if 0, means that all colors are important } BITMAPINFOHEADER; void main() { long now = 0; now = clock();//Storage image processing start time BITMAPFILEHEADER bitHead, writebitHead; BITMAPINFOHEADER bitInfoHead, writebitInfoHead; FILE* pfile;//input file FILE* wfile;//output file char strFile[50] = "linear transformation.bmp";//To open the image path, the BMP image must be in 24-bit true color format char strFilesave[50] = "Transform results.bmp";//Image Storage Path after Processing fopen_s(&pfile, strFile, "rb");//File Open Image fopen_s(&wfile, strFilesave, "wb");//Open the file to prepare for storing the modified image //Read Bitmap File Header Information WORD fileType; fread(&fileType, 1, sizeof(WORD), pfile); fwrite(&fileType, 1, sizeof(WORD), wfile); if (fileType != 0x4d42) { printf("file is not .bmp file!"); return; } //Read Bitmap File Header Information fread(&bitHead, 1, sizeof(tagBITMAPFILEHEADER), pfile); writebitHead = bitHead;//Because the intercepted image header is similar to the source file header, the source file header data is assigned to the intercepted file header first. //Read bitmap header information fread(&bitInfoHead, 1, sizeof(BITMAPINFOHEADER), pfile); writebitInfoHead = bitInfoHead;//Bitmap file headers are similar writebitInfoHead.biHeight = MYDRAW_HEIGHT;//Rewriting bitmap height for intercepting files writebitInfoHead.biWidth = MYDRAW_WIDTH;//Rewrite bitmap width for intercepting files int mywritewidth = WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//The width of the actual bitmap data area of BMP image is a multiple of 4 byte, and the width of the actual data area is calculated here. writebitInfoHead.biSizeImage = mywritewidth*writebitInfoHead.biHeight;//Calculating the actual data area size of bitmap writebitHead.bfSize = 54 + writebitInfoHead.biSizeImage;//Bitmap file header size is bitmap data area size plus 54 byte fwrite(&writebitHead, 1, sizeof(tagBITMAPFILEHEADER), wfile);//Write back bitmap file header information to output file fwrite(&writebitInfoHead, 1, sizeof(BITMAPINFOHEADER), wfile);//Write back bitmap header information to output file int width = bitInfoHead.biWidth; int height = bitInfoHead.biHeight; //Allocate memory space to store source graphs in memory int l_width = WIDTHBYTES(width*bitInfoHead.biBitCount);//Calculate the actual width of the bitmap and ensure that it is a multiple of 4 byte int write_width = WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//Calculate the actual width of the bitmap and ensure that it is a multiple of 4 byte BYTE *pColorData = (BYTE *)malloc(height*l_width);//Open up memory space to store image data memset(pColorData, 0, height*l_width); BYTE *pColorDataMid = (BYTE *)malloc(mywritewidth*MYDRAW_HEIGHT);//Open up memory space to store data after image processing memset(pColorDataMid, 0, mywritewidth*MYDRAW_HEIGHT); long nData = height*l_width; long write_nData = mywritewidth*MYDRAW_HEIGHT;//Length Definition of Intercepted Bitmap Data Area //Read bitmap data information into an array fread(pColorData, 1, nData, pfile);//Image processing can be realized by manipulating this part of data. /*******************Image Processing Section********************************/ /*******************Linear Transform of Images ******************************/ /*Grayscale*/ for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++) for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++) { int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels pColorData[pixel_point] = pColorData[pixel_point + 1] = pColorData[pixel_point + 2] = (pColorData[pixel_point] + pColorData[pixel_point + 1] + pColorData[pixel_point + 2]) / 3; } /*Grayscale*/ /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/ BYTE min = 255;//minimum value BYTE max = 0;//Maximum for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++) for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++) { int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels if (pColorData[pixel_point]>max) { max = pColorData[pixel_point]; } if (pColorData[pixel_point]<min) { min = pColorData[pixel_point]; } } printf("Maximum gray value:%d,Minimum gray value:%d\n", max, min); /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/ /*linear transformation*/ double k = (255 - 0) / (double)(max - min); double b = -k*min; for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++) for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++) { int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] = k*pColorData[pixel_point] + b; } /*linear transformation*/ /*******************Linear Transform of Images ******************************/ /*******************Image Processing Section********************************/ fwrite(pColorDataMid, 1, write_nData, wfile); //Write back the processed image data area to the file fclose(pfile); fclose(wfile); printf("Image Processing Completion\n"); printf("The running time is:%dms\n", int(((double)(clock() - now)) / CLOCKS_PER_SEC * 1000));//Output image processing time-consuming information }