先上效果图
gamma=0.5
gamma=1.5
原图知乎
废话不多说,直接上代码
#include <string.h>
#include <math.h>
#include"stdio.h"
#include"stdlib.h"
#define GrayFileName "gray.bmp"
#define EnhanceFileName "enhance.bmp"
#define Gamma 1.5
// 文件信息头结构体
typedef struct {
//unsigned short bfType; // 19778,必须是BM字符串,对应的十六进制为0x4d42,十进制为19778,否则不是bmp格式文件
unsigned int bfSize; // 文件大小 以字节为单位(2-5字节)
unsigned short bfReserved1; // 保留,必须设置为0 (6-7字节)
unsigned short bfReserved2; // 保留,必须设置为0 (8-9字节)
unsigned int bfOffBits; // 从文件头到像素数据的偏移 (10-13字节)
} BitmapFileHeader;
//图像信息头结构体
typedef struct {
unsigned int biSize; // 此结构体的大小 (14-17字节)
long biWidth; // 图像的宽 (18-21字节)
long biHeight; // 图像的高 (22-25字节)
unsigned short biPlanes; // 表示bmp图片的平面属,显然显示器只有一个平面,所以恒等于1 (26-27字节)
unsigned short biBitCount; // 一像素所占的位数,一般为24 (28-29字节)
unsigned int biCompression; // 说明图象数据压缩的类型,0为不压缩。 (30-33字节)
unsigned int biSizeImage; // 像素数据所占大小, 这个值应该等于上面文件头结构中bfSize-bfOffBits (34-37字节)
long biXPelsPerMeter; // 说明水平分辨率,用像素/米表示。一般为0 (38-41字节)
long biYPelsPerMeter; // 说明垂直分辨率,用像素/米表示。一般为0 (42-45字节)
unsigned int biClrUsed; // 说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。 (46-49字节)
unsigned int biClrImportant; // 说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。(50-53字节)
} BitmapInfoHeader;
double normImg(double pixel, int max, int min, double p_max, double p_min) {
return pixel * ((max - min) / (p_max - p_min));
}
void logTransform() {
FILE *fp;
fp = fopen(GrayFileName, "rb");
if (fp == NULL) {
printf("Failed to open the original file!");
exit(-1);
}
unsigned short fileType;//单独把文件类型提出来是因为C语言结构体的对齐原则
fread(&fileType, sizeof(unsigned short), 1, fp);
//保证读出来的是BMP文件后再做下一步的读取
BitmapFileHeader fileHeader;
BitmapInfoHeader infoHeader;
if (fileType == 0x4d42) {
fread(&fileHeader, sizeof(BitmapFileHeader), 1, fp);
fread(&infoHeader, sizeof(BitmapInfoHeader), 1, fp);
} else {
printf("Not a BMP File!");
exit(-1);
}
//单独设置变量给文件的分辨率,后面用起来更加简单直观
long fileWidth = infoHeader.biWidth;
long fileHeight = infoHeader.biHeight;
//创建增强文件
FILE *fp_new;
fp_new = fopen(EnhanceFileName, "wb");
if (fp_new == NULL) {
printf("Failed to create the new file!");
}
fwrite(&fileType, sizeof(unsigned short), 1, fp_new);
fwrite(&fileHeader, sizeof(BitmapFileHeader), 1, fp_new);
fwrite(&infoHeader, sizeof(BitmapInfoHeader), 1, fp_new);
//将24位的RGB颜色信息转换为灰度值信息,并写入数组
int bytesPerLine = (fileWidth * infoHeader.biBitCount + 31) / 32 * 4;//处理每行字节数,使之为4的倍数
int padding = bytesPerLine - fileWidth * 3;//补位数是处理后的字节数减去原本的字节数
unsigned char min = 255, max = 0;
unsigned char gray[fileHeight][fileWidth];
for (int i = 0; i < fileHeight; i++) {
for (int j = 0; j < fileWidth; j++) {
fread(&gray[i][j], sizeof(unsigned char), 1, fp);
fseek(fp, 2, SEEK_CUR);
min = gray[i][j] < min ? gray[i][j] : min;
max = gray[i][j] > max ? gray[i][j] : max;
}
for (int j = 0; j < padding; j++) {//处理补位
fseek(fp, 1, SEEK_CUR);
}
}
double p_max = pow(max, Gamma);
double p_min = pow(min, Gamma);
for (int i = 0; i < fileHeight; i++) {
for (int j = 0; j < fileWidth; j++) {
unsigned char new_gray = normImg(pow(gray[i][j], Gamma), max, min, p_max, p_min);
fwrite(&new_gray, sizeof(unsigned char), 1, fp_new);
fwrite(&new_gray, sizeof(unsigned char), 1, fp_new);
fwrite(&new_gray, sizeof(unsigned char), 1, fp_new);
}
unsigned char pad = 0;
for (int j = 0; j < padding; j++) {//处理补位
fwrite(&pad, sizeof(unsigned char), 1, fp_new);
fseek(fp, 1, SEEK_CUR);
}
}
fclose(fp);
fclose(fp_new);
}
int main(){
logTransform();
}