C/C++实现BMP图像直方图均衡化 - 256x256真彩色图像处理
#include <stdio.h> #include <stdlib.h>
#pragma pack(2) // 结构体按2字节对齐
// BMP文件头结构体 typedef struct { unsigned short bfType; // 文件类型,必须为0x4D42 unsigned int bfSize; // 文件大小 unsigned short bfReserved1; // 保留字段1 unsigned short bfReserved2; // 保留字段2 unsigned int bfOffBits; // 数据偏移量 } BMPFileHeader;
// BMP信息头结构体 typedef struct { unsigned int biSize; // 信息头大小 int biWidth; // 图像宽度 int biHeight; // 图像高度 unsigned short biPlanes; // 颜色平面数,必须为1 unsigned short biBitCount; // 每个像素的位数 unsigned int biCompression; // 压缩类型 unsigned int biSizeImage; // 数据大小 int biXPelsPerMeter; // 水平分辨率 int biYPelsPerMeter; // 垂直分辨率 unsigned int biClrUsed; // 使用的颜色数 unsigned int biClrImportant; // 重要的颜色数 } BMPInfoHeader;
// BMP像素结构体 typedef struct { unsigned char b; // 蓝色分量 unsigned char g; // 绿色分量 unsigned char r; // 红色分量 } BMPPixel;
// 读取BMP文件头 int readBMPFileHeader(FILE *fp, BMPFileHeader *fileHeader) { if (!fp || !fileHeader) { return -1; }
size_t size = sizeof(BMPFileHeader);
size_t count = fread(fileHeader, size, 1, fp);
if (count != 1) {
return -1;
}
return 0;
}
// 读取BMP信息头 int readBMPInfoHeader(FILE *fp, BMPInfoHeader *infoHeader) { if (!fp || !infoHeader) { return -1; }
size_t size = sizeof(BMPInfoHeader);
size_t count = fread(infoHeader, size, 1, fp);
if (count != 1) {
return -1;
}
return 0;
}
// 读取BMP像素数据 int readBMPPixels(FILE *fp, BMPPixel *pixels, int width, int height) { if (!fp || !pixels) { return -1; }
int rowSize = (width * 24 + 31) / 32 * 4; // 每行像素数据的字节数,必须为4的倍数
int paddingSize = rowSize - width * 3; // 每行填充的字节数
for (int i = height - 1; i >= 0; i--) { // BMP图像的行是从下到上存储的
for (int j = 0; j < width; j++) {
BMPPixel pixel;
size_t count = fread(&pixel, sizeof(BMPPixel), 1, fp);
if (count != 1) {
return -1;
}
pixels[i * width + j] = pixel;
}
fseek(fp, paddingSize, SEEK_CUR); // 跳过填充字节
}
return 0;
}
// 写入BMP文件头 int writeBMPFileHeader(FILE *fp, BMPFileHeader *fileHeader) { if (!fp || !fileHeader) { return -1; }
size_t size = sizeof(BMPFileHeader);
size_t count = fwrite(fileHeader, size, 1, fp);
if (count != 1) {
return -1;
}
return 0;
}
// 写入BMP信息头 int writeBMPInfoHeader(FILE *fp, BMPInfoHeader *infoHeader) { if (!fp || !infoHeader) { return -1; }
size_t size = sizeof(BMPInfoHeader);
size_t count = fwrite(infoHeader, size, 1, fp);
if (count != 1) {
return -1;
}
return 0;
}
// 写入BMP像素数据 int writeBMPPixels(FILE *fp, BMPPixel *pixels, int width, int height) { if (!fp || !pixels) { return -1; }
int rowSize = (width * 24 + 31) / 32 * 4; // 每行像素数据的字节数,必须为4的倍数
int paddingSize = rowSize - width * 3; // 每行填充的字节数
for (int i = height - 1; i >= 0; i--) { // BMP图像的行是从下到上存储的
for (int j = 0; j < width; j++) {
BMPPixel pixel = pixels[i * width + j];
size_t count = fwrite(&pixel, sizeof(BMPPixel), 1, fp);
if (count != 1) {
return -1;
}
}
for (int j = 0; j < paddingSize; j++) {
fputc(0, fp); // 填充0字节
}
}
return 0;
}
// 计算直方图 void calcHistogram(BMPPixel *pixels, int width, int height, int *histogram) { for (int i = 0; i < 256; i++) { histogram[i] = 0; }
for (int i = 0; i < width * height; i++) {
BMPPixel pixel = pixels[i];
int gray = (pixel.r * 299 + pixel.g * 587 + pixel.b * 114 + 500) / 1000; // 计算灰度值
histogram[gray]++;
}
}
// 计算累积直方图 void calcCumulativeHistogram(int *histogram, int *cumulativeHistogram) { cumulativeHistogram[0] = histogram[0]; for (int i = 1; i < 256; i++) { cumulativeHistogram[i] = cumulativeHistogram[i - 1] + histogram[i]; } }
// 直方图均衡 void histogramEqualization(BMPPixel *pixels, int width, int height) { int histogram[256]; int cumulativeHistogram[256]; int total = width * height;
calcHistogram(pixels, width, height, histogram);
calcCumulativeHistogram(histogram, cumulativeHistogram);
for (int i = 0; i < width * height; i++) {
BMPPixel pixel = pixels[i];
int gray = (pixel.r * 299 + pixel.g * 587 + pixel.b * 114 + 500) / 1000; // 计算灰度值
int newGray = cumulativeHistogram[gray] * 255 / total;
pixels[i].r = newGray;
pixels[i].g = newGray;
pixels[i].b = newGray;
}
}
int main() { FILE *fpIn, *fpOut; BMPFileHeader fileHeader; BMPInfoHeader infoHeader; BMPPixel *pixels;
// 打开输入文件
fpIn = fopen('2.bmp', 'rb');
if (!fpIn) {
printf('Error: cannot open input file.\n');
return -1;
}
// 读取文件头和信息头
if (readBMPFileHeader(fpIn, &fileHeader) < 0 || readBMPInfoHeader(fpIn, &infoHeader) < 0) {
printf('Error: invalid input file.\n');
fclose(fpIn);
return -1;
}
// 检查文件类型和位数
if (fileHeader.bfType != 0x4D42 || infoHeader.biBitCount != 24) {
printf('Error: unsupported file type or bit count.\n');
fclose(fpIn);
return -1;
}
// 分配像素数组
pixels = (BMPPixel *)malloc(infoHeader.biWidth * infoHeader.biHeight * sizeof(BMPPixel));
if (!pixels) {
printf('Error: out of memory.\n');
fclose(fpIn);
return -1;
}
// 读取像素数据
if (readBMPPixels(fpIn, pixels, infoHeader.biWidth, infoHeader.biHeight) < 0) {
printf('Error: invalid input file.\n');
free(pixels);
fclose(fpIn);
return -1;
}
// 关闭输入文件
fclose(fpIn);
// 直方图均衡
histogramEqualization(pixels, infoHeader.biWidth, infoHeader.biHeight);
// 打开输出文件
fpOut = fopen('3.bmp', 'wb');
if (!fpOut) {
printf('Error: cannot open output file.\n');
free(pixels);
return -1;
}
// 写入文件头和信息头
if (writeBMPFileHeader(fpOut, &fileHeader) < 0 || writeBMPInfoHeader(fpOut, &infoHeader) < 0) {
printf('Error: cannot write output file.\n');
free(pixels);
fclose(fpOut);
return -1;
}
// 写入像素数据
if (writeBMPPixels(fpOut, pixels, infoHeader.biWidth, infoHeader.biHeight) < 0) {
printf('Error: cannot write output file.\n');
free(pixels);
fclose(fpOut);
return -1;
}
// 关闭输出文件
fclose(fpOut);
// 释放像素数组
free(pixels);
return 0;
原文地址: https://www.cveoy.top/t/topic/jCUA 著作权归作者所有。请勿转载和采集!