C语言实现BMP图像直方图均衡化:完整代码解析与优化
C语言实现BMP图像直方图均衡化:完整代码解析与优化
本文提供了一段使用C语言编写的完整代码,用于对256×256大小的24位真彩BMP格式图像进行直方图均衡化处理。代码详细解释了BMP文件格式、直方图均衡算法,并利用fread()和fwrite()函数进行高效的读写操作。
1. 算法原理
直方图均衡化是一种图像增强技术,它通过调整图像的灰度级分布来提高图像的对比度。基本思想是将原图像的灰度级分布变换为近似均匀分布,从而使图像的细节更加明显。
2. 代码实现
由于直方图均衡需要对每个像素点进行计算,所以需要先将BMP图像读入内存中,进行操作后再写回文件。以下是实现直方图均衡化的完整代码:
#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; // 信息头大小,必须为40
int biWidth; // 图像宽度,像素为单位
int biHeight; // 图像高度,像素为单位
unsigned short biPlanes; // 必须为1
unsigned short biBitCount; // 每个像素的位数,一般为24
unsigned int biCompression; // 压缩类型,一般为0
unsigned int biSizeImage; // 图像数据大小,字节为单位
int biXPelsPerMeter; // 水平分辨率,像素为单位
int biYPelsPerMeter; // 垂直分辨率,像素为单位
unsigned int biClrUsed; // 颜色表中实际使用的颜色数,0表示使用所有颜色
unsigned int biClrImportant; // 重要的颜色数,0表示所有颜色都重要
} BMPINFOHEADER;
// bmp像素数据
typedef struct {
unsigned char b; // 蓝色分量
unsigned char g; // 绿色分量
unsigned char r; // 红色分量
} BMPPIXEL;
// 直方图均衡
void histogram_equalization(BMPPIXEL *pixels, int width, int height) {
int i, j, k;
int hist[256] = {0}; // 像素值直方图
int cdf[256] = {0}; // 累积分布函数
int min_cdf = width * height; // 最小累积分布函数
int max_cdf = 0; // 最大累积分布函数
int new_val[256]; // 新像素值
// 计算像素值直方图
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
hist[pixels[i * width + j].r]++;
}
}
// 计算累积分布函数
for (i = 0; i < 256; i++) {
if (i == 0) {
cdf[i] = hist[i];
} else {
cdf[i] = cdf[i - 1] + hist[i];
}
if (cdf[i] < min_cdf) {
min_cdf = cdf[i];
}
if (cdf[i] > max_cdf) {
max_cdf = cdf[i];
}
}
// 计算新像素值
for (i = 0; i < 256; i++) {
new_val[i] = (cdf[i] - min_cdf) * 255 / (max_cdf - min_cdf);
}
// 更新像素值
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
pixels[i * width + j].r = new_val[pixels[i * width + j].r];
pixels[i * width + j].g = new_val[pixels[i * width + j].g];
pixels[i * width + j].b = new_val[pixels[i * width + j].b];
}
}
}
int main() {
FILE *fp_in, *fp_out;
BMPFILEHEADER file_header;
BMPINFOHEADER info_header;
BMPPIXEL *pixels;
int i, j;
// 打开文件
if ((fp_in = fopen("2.bmp", "rb")) == NULL) {
printf("Error: cannot open file!\n");
return 1;
}
if ((fp_out = fopen("3.bmp", "wb")) == NULL) {
printf("Error: cannot create file!\n");
fclose(fp_in);
return 1;
}
// 读取文件头和信息头
fread(&file_header, sizeof(BMPFILEHEADER), 1, fp_in);
fread(&info_header, sizeof(BMPINFOHEADER), 1, fp_in);
// 分配像素数据内存
pixels = (BMPPIXEL*) malloc(info_header.biWidth * info_header.biHeight * sizeof(BMPPIXEL));
// 读取像素数据
for (i = 0; i < info_header.biHeight; i++) {
for (j = 0; j < info_header.biWidth; j++) {
fread(&pixels[i * info_header.biWidth + j], sizeof(BMPPIXEL), 1, fp_in);
}
}
// 直方图均衡
histogram_equalization(pixels, info_header.biWidth, info_header.biHeight);
// 更新文件头和信息头
info_header.biSizeImage = info_header.biWidth * info_header.biHeight * sizeof(BMPPIXEL);
file_header.bfSize = file_header.bfOffBits + info_header.biSizeImage;
// 写入文件头和信息头
fwrite(&file_header, sizeof(BMPFILEHEADER), 1, fp_out);
fwrite(&info_header, sizeof(BMPINFOHEADER), 1, fp_out);
// 写入像素数据
for (i = 0; i < info_header.biHeight; i++) {
for (j = 0; j < info_header.biWidth; j++) {
fwrite(&pixels[i * info_header.biWidth + j], sizeof(BMPPIXEL), 1, fp_out);
}
}
// 释放内存
free(pixels);
// 关闭文件
fclose(fp_in);
fclose(fp_out);
return 0;
}
3. 代码解析
- BMP文件格式: 代码定义了BMP文件头结构体
BMPFILEHEADER和信息头结构体BMPINFOHEADER,以及像素数据结构体BMPPIXEL,用于解析BMP文件。 - 直方图均衡函数:
histogram_equalization()函数实现直方图均衡算法,主要步骤包括:- 计算像素值直方图;
- 计算累积分布函数;
- 计算新的像素值;
- 更新像素值。
- 主函数:
main()函数负责打开输入文件和输出文件,读取文件头和信息头,分配像素数据内存,调用histogram_equalization()函数进行直方图均衡处理,最后写入处理后的图像数据到输出文件。
4. 注意事项
- BMP文件头和信息头中的一些字段必须按照一定的格式填写,否则会导致图片无法正常显示。在本代码中,使用了
#pragma pack(2)来指定结构体按2字节对齐,这是因为BMP文件头和信息头中有一些字段需要按照2字节对齐,否则会导致文件大小计算错误。 - BMP图像的像素数据是按照从下到上、从左到右的顺序存储的,所以在读取和写入像素数据时需要注意顺序。
5. 优化建议
- 为了提高代码效率,可以考虑使用更高效的算法来计算直方图和累积分布函数,例如使用查找表或并行计算。
- 可以使用内存映射文件来避免将整个图像读入内存,减少内存消耗。
- 可以使用多线程来加速图像处理过程。
6. 总结
本文提供了使用C语言实现BMP图像直方图均衡化的完整代码,并详细解析了代码逻辑和实现细节。通过对代码的优化,可以提高图像处理效率和性能。
7. 代码使用说明
- 将代码保存为
histogram_equalization.c文件; - 编译并运行代码:
gcc histogram_equalization.c -o histogram_equalization; - 将需要处理的BMP图像文件命名为
2.bmp,程序会将处理后的图像文件保存为3.bmp。
希望本文能够帮助读者理解BMP图像直方图均衡化的实现原理和代码编写方法。
原文地址: https://www.cveoy.top/t/topic/jCUZ 著作权归作者所有。请勿转载和采集!