C/C++ BMP (24-bit true color) image processing (5) - - image linear transformation

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:

  1. /*******************Image Processing Section********************************/  
  2. /*******************Linear Transform of Images ******************************/  
  3. /*Grayscale*/  
  4. for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)  
  5. for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)  
  6. {  
  7.     int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels  
  8.     pColorData[pixel_point] = pColorData[pixel_point + 1] = pColorData[pixel_point + 2] =  
  9.         (pColorData[pixel_point] + pColorData[pixel_point + 1] + pColorData[pixel_point + 2]) / 3;    
  10. }  
  11. /*Grayscale*/  
  12.   
  13. /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/  
  14. BYTE min = 255;//minimum value  
  15. BYTE max = 0;//Maximum  
  16. for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)  
  17. for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)  
  18. {  
  19.     int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels  
  20.     if (pColorData[pixel_point]>max)  
  21.     {  
  22.         max = pColorData[pixel_point];  
  23.     }  
  24.     if (pColorData[pixel_point]<min)  
  25.     {  
  26.         min = pColorData[pixel_point];  
  27.     }  
  28. }  
  29. printf("Maximum gray value:%d,Minimum gray value:%d\n", max, min);  
  30. /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/  
  31.   
  32. /*linear transformation*/  
  33. double k = (255 - 0) / (double)(max - min);  
  34. double b = -k*min;  
  35. for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)  
  36. for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)  
  37. {  
  38.     int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels  
  39.     pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] =  
  40.     k*pColorData[pixel_point] + b;  
  41. }  
  42. /*linear transformation*/  
  43. /*******************Linear Transform of Images ******************************/  
  44. /*******************Image Processing Section********************************/  
/*******************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:

Original image

 

Image after Linear Transform

The whole project code is as follows:

  1. #include <string.h>   
  2. #include <math.h>     
  3. #include <stdio.h>     
  4. #include <stdlib.h>     
  5. #include <malloc.h>  
  6.   
  7. #Include < time.h >// time-related header file, where functions can be used to calculate image processing speed  
  8.   
  9. #WIDTHBYTES(bits) (((bits)+31)/32*4)// Used to multiply the byte number of image width by 4 bytes  
  10.   
  11. #define MYDRAW_WIDTH 375// Target Image Width  
  12. #define MYDRAW_HEIGHT 300// Target Image Height  
  13.   
  14.   
  15. typedef unsigned char  BYTE;  
  16. typedef unsigned short WORD;  
  17. typedef unsigned long  DWORD;  
  18. typedef long LONG;  
  19.   
  20. //Definition of Bitmap File Header Information Structure  
  21. //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)  
  22.   
  23. typedef struct tagBITMAPFILEHEADER {  
  24.     DWORD  bfSize;          //file size  
  25.     WORD   bfReserved1;     //Retain words without consideration  
  26.     WORD   bfReserved2;     //Retained words, ibid.  
  27.     DWORD  bfOffBits;       //The number of offset bytes of actual bitmap data, i.e. the sum of the first three Parts'lengths  
  28. } BITMAPFILEHEADER;  
  29.   
  30. //The information header BITMAPINFOHEADER is also a structure, which is defined as follows:  
  31.   
  32. typedef struct tagBITMAPINFOHEADER{  
  33.     //public:  
  34.     DWORD   biSize;             //Specify the length of this structure to be 40  
  35.     LONG    biWidth;            //Bitmap width  
  36.     LONG    biHeight;           //Bitmap height  
  37.     WORD    biPlanes;           //Plane number, 1  
  38.     WORD    biBitCount;         //The number of color bits can be 1, 2, 4, 8, 16, 24, and the new number can be 32.  
  39.     DWORD   biCompression;      //Compression, which can be 0, 1, 2, where 0 means uncompressed  
  40.     DWORD   biSizeImage;        //Number of bytes occupied by actual bitmap data  
  41.     LONG    biXPelsPerMeter;    //X-Direction Resolution  
  42.     LONG    biYPelsPerMeter;    //Y-Direction Resolution  
  43.     DWORD   biClrUsed;          //The number of colors used, if 0, represents the default value (2 ^ color bits)  
  44.     DWORD   biClrImportant;     //The number of important colors, if 0, means that all colors are important  
  45. } BITMAPINFOHEADER;  
  46.   
  47. void main()  
  48. {  
  49.     long now = 0;  
  50.     now = clock();//Storage image processing start time  
  51.   
  52.     BITMAPFILEHEADER bitHead, writebitHead;  
  53.     BITMAPINFOHEADER bitInfoHead, writebitInfoHead;  
  54.     FILE* pfile;//input file  
  55.     FILE* wfile;//output file  
  56.   
  57.     char strFile[50] = "linear transformation.bmp";//To open the image path, the BMP image must be in 24-bit true color format  
  58.     char strFilesave[50] = "Transform results.bmp";//Image Storage Path after Processing  
  59.     fopen_s(&pfile, strFile, "rb");//File Open Image  
  60.     fopen_s(&wfile, strFilesave, "wb");//Open the file to prepare for storing the modified image  
  61.     //Read Bitmap File Header Information  
  62.     WORD fileType;  
  63.     fread(&fileType, 1, sizeof(WORD), pfile);  
  64.     fwrite(&fileType, 1, sizeof(WORD), wfile);  
  65.     if (fileType != 0x4d42)  
  66.     {  
  67.         printf("file is not .bmp file!");  
  68.         return;  
  69.     }  
  70.     //Read Bitmap File Header Information  
  71.     fread(&bitHead, 1, sizeof(tagBITMAPFILEHEADER), pfile);  
  72.     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.  
  73.     //Read bitmap header information  
  74.     fread(&bitInfoHead, 1, sizeof(BITMAPINFOHEADER), pfile);  
  75.     writebitInfoHead = bitInfoHead;//Bitmap file headers are similar  
  76.   
  77.     writebitInfoHead.biHeight = MYDRAW_HEIGHT;//Rewriting bitmap height for intercepting files  
  78.     writebitInfoHead.biWidth = MYDRAW_WIDTH;//Rewrite bitmap width for intercepting files  
  79.     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.  
  80.     writebitInfoHead.biSizeImage = mywritewidth*writebitInfoHead.biHeight;//Calculating the actual data area size of bitmap  
  81.   
  82.     writebitHead.bfSize = 54 + writebitInfoHead.biSizeImage;//Bitmap file header size is bitmap data area size plus 54 byte  
  83.     fwrite(&writebitHead, 1, sizeof(tagBITMAPFILEHEADER), wfile);//Write back bitmap file header information to output file  
  84.     fwrite(&writebitInfoHead, 1, sizeof(BITMAPINFOHEADER), wfile);//Write back bitmap header information to output file  
  85.   
  86.     int width = bitInfoHead.biWidth;  
  87.     int height = bitInfoHead.biHeight;  
  88.     //Allocate memory space to store source diagrams in memory.  
  89.     int l_width = WIDTHBYTES(width*bitInfoHead.biBitCount);//Calculate the actual width of the bitmap and ensure that it is a multiple of 4 byte  
  90.     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  
  91.   
  92.     BYTE    *pColorData = (BYTE *)malloc(height*l_width);//Open up memory space to store image data  
  93.     memset(pColorData, 0, height*l_width);  
  94.   
  95.     BYTE    *pColorDataMid = (BYTE *)malloc(mywritewidth*MYDRAW_HEIGHT);//Open up memory space to store data after image processing  
  96.     memset(pColorDataMid, 0, mywritewidth*MYDRAW_HEIGHT);  
  97.   
  98.     long nData = height*l_width;  
  99.     long write_nData = mywritewidth*MYDRAW_HEIGHT;//Length Definition of Intercepted Bitmap Data Area  
  100.   
  101.     //Read bitmap data information into an array.  
  102.     fread(pColorData, 1, nData, pfile);//Image processing can be realized by manipulating this part of data.  
  103.   
  104.     /*******************Image Processing Section********************************/  
  105.     /*******************Linear Transform of Images ******************************/  
  106.     /*Grayscale*/  
  107.     for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)  
  108.     for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)  
  109.     {  
  110.         int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels  
  111.         pColorData[pixel_point] = pColorData[pixel_point + 1] = pColorData[pixel_point + 2] =  
  112.             (pColorData[pixel_point] + pColorData[pixel_point + 1] + pColorData[pixel_point + 2]) / 3;    
  113.     }  
  114.     /*Grayscale*/  
  115.   
  116.     /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/  
  117.     BYTE min = 255;//minimum value  
  118.     BYTE max = 0;//Maximum  
  119.     for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)  
  120.     for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)  
  121.     {  
  122.         int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels  
  123.         if (pColorData[pixel_point]>max)  
  124.         {  
  125.             max = pColorData[pixel_point];  
  126.         }  
  127.         if (pColorData[pixel_point]<min)  
  128.         {  
  129.             min = pColorData[pixel_point];  
  130.         }  
  131.     }  
  132.     printf("Maximum gray value:%d,Minimum gray value:%d\n", max, min);  
  133.     /*Computing the Maximum and Minimum Gray Value of Pixel Points in Image*/  
  134.   
  135.     /*linear transformation*/  
  136.     double k = (255 - 0) / (double)(max - min);  
  137.     double b = -k*min;  
  138.     for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)  
  139.     for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)  
  140.     {  
  141.         int pixel_point = hnum*write_width + wnum * 3;//Point to image pixels  
  142.         pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] =  
  143.             k*pColorData[pixel_point] + b;  
  144.     }  
  145.     /*linear transformation*/  
  146.     /*******************Linear Transform of Images ******************************/  
  147.     /*******************Image Processing Section********************************/  
  148.   
  149.     fwrite(pColorDataMid, 1, write_nData, wfile);   //Write back the processed image data area to the file  
  150.     fclose(pfile);  
  151.     fclose(wfile);  
  152.   
  153.     printf("Image Processing Completion\n");  
  154.     printf("The running time is:%dms\n"int(((double)(clock() - now)) / CLOCKS_PER_SEC * 1000));//Output image processing time-consuming information  
  155. }  
#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
}



 

Added by bastienvans on Fri, 21 Jun 2019 03:24:27 +0300