用C语言编写一段代码对大小为256×256大小 24 位真彩的bmp格式的图像进行相应操作并且读写要求用到fread 、fwrite 函数等将图像3bmp中的色彩R G B分量 中的R分量进行直方图均衡将对R分量进行直方图均衡后的图像输出为4bmp 代码尽量简洁
#include <stdio.h>
#include <stdlib.h>
#pragma pack(2) // 设置结构体按2字节对齐
// BMP文件头结构体
typedef struct {
unsigned short bfType; // 文件类型,必须为0x4D42
unsigned int bfSize; // 文件大小,单位为字节
unsigned short bfReserved1; // 保留,必须为0
unsigned short bfReserved2; // 保留,必须为0
unsigned int bfOffBits; // 从文件头到像素数据的偏移量,单位为字节
} BMPFileHeader;
// BMP信息头结构体
typedef struct {
unsigned int biSize; // 信息头大小,单位为字节
int biWidth; // 图像宽度,单位为像素
int biHeight; // 图像高度,单位为像素
unsigned short biPlanes; // 位平面数,必须为1
unsigned short biBitCount; // 每像素位数,必须为24
unsigned int biCompression; // 压缩类型,0表示不压缩
unsigned int biSizeImage; // 像素数据大小,单位为字节
int biXPelsPerMeter; // 水平分辨率,单位为像素/m
int biYPelsPerMeter; // 垂直分辨率,单位为像素/m
unsigned int biClrUsed; // 调色板颜色数,为0表示使用所有颜色
unsigned int biClrImportant; // 重要颜色数,为0表示所有颜色都重要
} BMPInfoHeader;
// 像素结构体
typedef struct {
unsigned char b; // 蓝色分量
unsigned char g; // 绿色分量
unsigned char r; // 红色分量
} Pixel;
// 直方图结构体
typedef struct {
int count[256]; // 每个像素值的数量
float prob[256]; // 每个像素值的概率
int cumCount[256]; // 累计像素值的数量
int cumProb[256]; // 累计像素值的概率
int map[256]; // 映射表
} Histogram;
// 读取BMP文件头
void readBMPFileHeader(FILE* fp, BMPFileHeader* header) {
fread(&header->bfType, sizeof(header->bfType), 1, fp);
fread(&header->bfSize, sizeof(header->bfSize), 1, fp);
fread(&header->bfReserved1, sizeof(header->bfReserved1), 1, fp);
fread(&header->bfReserved2, sizeof(header->bfReserved2), 1, fp);
fread(&header->bfOffBits, sizeof(header->bfOffBits), 1, fp);
}
// 读取BMP信息头
void readBMPInfoHeader(FILE* fp, BMPInfoHeader* header) {
fread(&header->biSize, sizeof(header->biSize), 1, fp);
fread(&header->biWidth, sizeof(header->biWidth), 1, fp);
fread(&header->biHeight, sizeof(header->biHeight), 1, fp);
fread(&header->biPlanes, sizeof(header->biPlanes), 1, fp);
fread(&header->biBitCount, sizeof(header->biBitCount), 1, fp);
fread(&header->biCompression, sizeof(header->biCompression), 1, fp);
fread(&header->biSizeImage, sizeof(header->biSizeImage), 1, fp);
fread(&header->biXPelsPerMeter, sizeof(header->biXPelsPerMeter), 1, fp);
fread(&header->biYPelsPerMeter, sizeof(header->biYPelsPerMeter), 1, fp);
fread(&header->biClrUsed, sizeof(header->biClrUsed), 1, fp);
fread(&header->biClrImportant, sizeof(header->biClrImportant), 1, fp);
}
// 读取像素数据
void readPixels(FILE* fp, int width, int height, Pixel* pixels) {
int rowSize = (width * 3 + 3) / 4 * 4; // 每行像素数据大小,必须为4的倍数
int paddingSize = rowSize - width * 3; // 每行填充字节数
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
fread(&pixels[y * width + x], sizeof(Pixel), 1, fp);
}
fseek(fp, paddingSize, SEEK_CUR); // 跳过填充字节
}
}
// 写入BMP文件头
void writeBMPFileHeader(FILE* fp, BMPFileHeader* header) {
fwrite(&header->bfType, sizeof(header->bfType), 1, fp);
fwrite(&header->bfSize, sizeof(header->bfSize), 1, fp);
fwrite(&header->bfReserved1, sizeof(header->bfReserved1), 1, fp);
fwrite(&header->bfReserved2, sizeof(header->bfReserved2), 1, fp);
fwrite(&header->bfOffBits, sizeof(header->bfOffBits), 1, fp);
}
// 写入BMP信息头
void writeBMPInfoHeader(FILE* fp, BMPInfoHeader* header) {
fwrite(&header->biSize, sizeof(header->biSize), 1, fp);
fwrite(&header->biWidth, sizeof(header->biWidth), 1, fp);
fwrite(&header->biHeight, sizeof(header->biHeight), 1, fp);
fwrite(&header->biPlanes, sizeof(header->biPlanes), 1, fp);
fwrite(&header->biBitCount, sizeof(header->biBitCount), 1, fp);
fwrite(&header->biCompression, sizeof(header->biCompression), 1, fp);
fwrite(&header->biSizeImage, sizeof(header->biSizeImage), 1, fp);
fwrite(&header->biXPelsPerMeter, sizeof(header->biXPelsPerMeter), 1, fp);
fwrite(&header->biYPelsPerMeter, sizeof(header->biYPelsPerMeter), 1, fp);
fwrite(&header->biClrUsed, sizeof(header->biClrUsed), 1, fp);
fwrite(&header->biClrImportant, sizeof(header->biClrImportant), 1, fp);
}
// 写入像素数据
void writePixels(FILE* fp, int width, int height, Pixel* pixels) {
int rowSize = (width * 3 + 3) / 4 * 4; // 每行像素数据大小,必须为4的倍数
int paddingSize = rowSize - width * 3; // 每行填充字节数
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
fwrite(&pixels[y * width + x], sizeof(Pixel), 1, fp);
}
for (int i = 0; i < paddingSize; i++) {
fputc(0, fp); // 填充0
}
}
}
// 计算直方图
void calcHistogram(int width, int height, Pixel* pixels, Histogram* hist) {
// 初始化直方图
for (int i = 0; i < 256; i++) {
hist->count[i] = 0;
hist->prob[i] = 0;
hist->cumCount[i] = 0;
hist->cumProb[i] = 0;
hist->map[i] = 0;
}
// 统计像素值的数量
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
hist->count[pixels[y * width + x].r]++;
}
}
// 计算像素值的概率
int pixelCount = width * height;
for (int i = 0; i < 256; i++) {
hist->prob[i] = (float)hist->count[i] / pixelCount;
}
// 计算累计像素值的数量和概率
hist->cumCount[0] = hist->count[0];
hist->cumProb[0] = hist->prob[0] * 255;
for (int i = 1; i < 256; i++) {
hist->cumCount[i] = hist->cumCount[i - 1] + hist->count[i];
hist->cumProb[i] = hist->cumProb[i - 1] + hist->prob[i] * 255;
}
// 计算映射表
for (int i = 0; i < 256; i++) {
hist->map[i] = hist->cumProb[i];
}
}
// 直方图均衡
void equalizeHistogram(int width, int height, Pixel* pixels) {
Histogram hist;
calcHistogram(width, height, pixels, &hist);
// 映射像素值
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[y * width + x].r = hist.map[pixels[y * width + x].r];
}
}
}
int main() {
FILE* fpIn = fopen("3.bmp", "rb");
FILE* fpOut = fopen("4.bmp", "wb");
if (fpIn == NULL || fpOut == NULL) {
printf("Failed to open file.\n");
return 1;
}
BMPFileHeader fileHeader;
BMPInfoHeader infoHeader;
readBMPFileHeader(fpIn, &fileHeader);
readBMPInfoHeader(fpIn, &infoHeader);
if (fileHeader.bfType != 0x4D42 || infoHeader.biBitCount != 24) {
printf("Invalid BMP file.\n");
return 1;
}
Pixel* pixels = (Pixel*)malloc(infoHeader.biWidth * infoHeader.biHeight * sizeof(Pixel));
readPixels(fpIn, infoHeader.biWidth, infoHeader.biHeight, pixels);
equalizeHistogram(infoHeader.biWidth, infoHeader.biHeight, pixels);
fileHeader.bfSize = fileHeader.bfOffBits + infoHeader.biWidth * infoHeader.biHeight * 3;
infoHeader.biSizeImage = infoHeader.biWidth * infoHeader.biHeight * 3;
writeBMPFileHeader(fpOut, &fileHeader);
writeBMPInfoHeader(fpOut, &infoHeader);
writePixels(fpOut, infoHeader.biWidth, infoHeader.biHeight, pixels);
free(pixels);
fclose(fpIn);
fclose(fpOut);
return 0;
}
原文地址: https://www.cveoy.top/t/topic/b3e5 著作权归作者所有。请勿转载和采集!