C语言实现BMP图像G分量直方图均衡
C语言实现BMP图像G分量直方图均衡
本文将介绍如何使用C语言编写程序,对256×256大小的24位真彩BMP格式图像进行G分量直方图均衡处理,并使用fread()和fwrite()函数进行文件读写操作。
1. BMP格式概述
BMP格式的文件由文件头和图像数据两部分组成,其中文件头包含了文件类型、文件大小、图像宽度、图像高度等信息,图像数据则包含了像素点的颜色信息。具体的文件格式可以参考相关资料进行了解。
2. 直方图均衡原理
直方图均衡是一种图像增强技术,它通过调整图像的灰度级分布,使得图像的对比度得到提高。其原理是将原始图像的灰度级映射到一个新的灰度级,使得新的灰度级分布更加均匀。
3. 代码实现
以下是使用C语言实现BMP图像G分量直方图均衡的代码:
#include <stdio.h>
#include <stdlib.h>
#pragma pack(2) // 按2字节对齐
// BMP文件头结构体
typedef struct {
short bfType; // 文件类型,必须为0x4D42(即BM)
int bfSize; // 文件大小,单位为字节
short bfReserved1; // 保留字段
short bfReserved2; // 保留字段
int bfOffBits; // 从文件头到实际图像数据的偏移量,单位为字节
} BMPFILEHEADER;
// BMP信息头结构体
typedef struct {
int biSize; // 信息头大小,单位为字节
int biWidth; // 图像宽度,单位为像素
int biHeight; // 图像高度,单位为像素
short biPlanes; // 颜色平面数,必须为1
short biBitCount; // 每个像素的位数
int biCompression; // 压缩类型,0为不压缩
int biSizeImage; // 图像数据大小,单位为字节
int biXPelsPerMeter; // 水平分辨率,单位为像素/米
int biYPelsPerMeter; // 垂直分辨率,单位为像素/米
int biClrUsed; // 使用的颜色数,0表示使用所有颜色
int biClrImportant; // 重要的颜色数,0表示所有颜色都重要
} BMPINFOHEADER;
// RGB颜色结构体
typedef struct {
unsigned char b;
unsigned char g;
unsigned char r;
} RGB;
// 直方图结构体
typedef struct {
int count[256]; // 每个像素值出现的次数
float prob[256]; // 每个像素值出现的概率
int map[256]; // 均衡后的像素值映射表
} HISTOGRAM;
// 读取BMP文件头信息
void readBmpFileHeader(FILE *fp, BMPFILEHEADER *fileHeader) {
fread(&fileHeader->bfType, sizeof(short), 1, fp);
fread(&fileHeader->bfSize, sizeof(int), 1, fp);
fread(&fileHeader->bfReserved1, sizeof(short), 1, fp);
fread(&fileHeader->bfReserved2, sizeof(short), 1, fp);
fread(&fileHeader->bfOffBits, sizeof(int), 1, fp);
}
// 读取BMP信息头信息
void readBmpInfoHeader(FILE *fp, BMPINFOHEADER *infoHeader) {
fread(&infoHeader->biSize, sizeof(int), 1, fp);
fread(&infoHeader->biWidth, sizeof(int), 1, fp);
fread(&infoHeader->biHeight, sizeof(int), 1, fp);
fread(&infoHeader->biPlanes, sizeof(short), 1, fp);
fread(&infoHeader->biBitCount, sizeof(short), 1, fp);
fread(&infoHeader->biCompression, sizeof(int), 1, fp);
fread(&infoHeader->biSizeImage, sizeof(int), 1, fp);
fread(&infoHeader->biXPelsPerMeter, sizeof(int), 1, fp);
fread(&infoHeader->biYPelsPerMeter, sizeof(int), 1, fp);
fread(&infoHeader->biClrUsed, sizeof(int), 1, fp);
fread(&infoHeader->biClrImportant, sizeof(int), 1, fp);
}
// 读取BMP图像数据
void readBmpData(FILE *fp, RGB *data, int width, int height) {
int i, j;
for (i = height - 1; i >= 0; i--) { // BMP图像数据是从下往上存储的
for (j = 0; j < width; j++) {
fread(&data[i * width + j], sizeof(RGB), 1, fp);
}
}
}
// 写入BMP文件头信息
void writeBmpFileHeader(FILE *fp, BMPFILEHEADER fileHeader) {
fwrite(&fileHeader.bfType, sizeof(short), 1, fp);
fwrite(&fileHeader.bfSize, sizeof(int), 1, fp);
fwrite(&fileHeader.bfReserved1, sizeof(short), 1, fp);
fwrite(&fileHeader.bfReserved2, sizeof(short), 1, fp);
fwrite(&fileHeader.bfOffBits, sizeof(int), 1, fp);
}
// 写入BMP信息头信息
void writeBmpInfoHeader(FILE *fp, BMPINFOHEADER infoHeader) {
fwrite(&infoHeader.biSize, sizeof(int), 1, fp);
fwrite(&infoHeader.biWidth, sizeof(int), 1, fp);
fwrite(&infoHeader.biHeight, sizeof(int), 1, fp);
fwrite(&infoHeader.biPlanes, sizeof(short), 1, fp);
fwrite(&infoHeader.biBitCount, sizeof(short), 1, fp);
fwrite(&infoHeader.biCompression, sizeof(int), 1, fp);
fwrite(&infoHeader.biSizeImage, sizeof(int), 1, fp);
fwrite(&infoHeader.biXPelsPerMeter, sizeof(int), 1, fp);
fwrite(&infoHeader.biYPelsPerMeter, sizeof(int), 1, fp);
fwrite(&infoHeader.biClrUsed, sizeof(int), 1, fp);
fwrite(&infoHeader.biClrImportant, sizeof(int), 1, fp);
}
// 写入BMP图像数据
void writeBmpData(FILE *fp, RGB *data, int width, int height) {
int i, j;
for (i = height - 1; i >= 0; i--) { // BMP图像数据是从下往上存储的
for (j = 0; j < width; j++) {
fwrite(&data[i * width + j], sizeof(RGB), 1, fp);
}
}
}
// 计算直方图
void calcHistogram(RGB *data, int width, int height, HISTOGRAM *hist) {
int i, j;
int pixelCount = width * height;
for (i = 0; i < 256; i++) {
hist->count[i] = 0;
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
int g = data[i * width + j].g;
hist->count[g]++;
}
}
for (i = 0; i < 256; i++) {
hist->prob[i] = (float)hist->count[i] / pixelCount;
}
hist->map[0] = (int)(hist->prob[0] * 255 + 0.5);
for (i = 1; i < 256; i++) {
hist->map[i] = hist->map[i - 1] + (int)(hist->prob[i] * 255 + 0.5);
}
}
// 直方图均衡
void histogramEqualization(RGB *data, int width, int height) {
HISTOGRAM hist;
calcHistogram(data, width, height, &hist);
int i, j;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
int g = data[i * width + j].g;
int newG = hist.map[g];
data[i * width + j].g = (unsigned char)newG;
}
}
}
int main() {
FILE *fpIn, *fpOut;
BMPFILEHEADER fileHeader;
BMPINFOHEADER infoHeader;
RGB *data;
int width, height;
// 读取输入文件
fpIn = fopen('3.bmp', 'rb');
if (fpIn == NULL) {
printf('Error: cannot open input file.\n');
return -1;
}
readBmpFileHeader(fpIn, &fileHeader);
readBmpInfoHeader(fpIn, &infoHeader);
width = infoHeader.biWidth;
height = infoHeader.biHeight;
data = (RGB *)malloc(sizeof(RGB) * width * height);
readBmpData(fpIn, data, width, height);
fclose(fpIn);
// 对G分量进行直方图均衡
histogramEqualization(data, width, height);
// 写入输出文件
fpOut = fopen('5.bmp', 'wb');
if (fpOut == NULL) {
printf('Error: cannot open output file.\n');
return -1;
}
writeBmpFileHeader(fpOut, fileHeader);
writeBmpInfoHeader(fpOut, infoHeader);
writeBmpData(fpOut, data, width, height);
fclose(fpOut);
free(data);
return 0;
}
代码说明:
- 文件头和信息头结构体: 定义了BMP文件头和信息头的结构体,方便存储文件信息。
- RGB颜色结构体: 定义了RGB颜色结构体,用于存储像素点的颜色信息。
- 直方图结构体: 定义了直方图结构体,用于存储每个灰度级出现的次数、概率和均衡后的映射表。
- 读取BMP文件信息: 使用
fread()函数读取BMP文件头和信息头,获取图像的宽度和高度信息。 - 读取BMP图像数据: 使用
fread()函数读取BMP图像数据,并存储到一个RGB类型的数组中。 - 计算直方图: 统计每个灰度级出现的次数,并计算每个灰度级的概率。
- 直方图均衡: 根据计算得到的概率,生成一个映射表,将每个灰度级映射到一个新的灰度级,实现直方图均衡。
- 写入BMP文件信息: 使用
fwrite()函数将更新后的文件头信息和图像数据写入到新的BMP文件中。
注意:
- 本代码仅供参考,需要根据实际情况进行调整。
- 为了方便理解,代码中使用了大量的注释。
- 建议在运行代码之前,将输入文件和输出文件命名为“3.bmp”和“5.bmp”。
4. 运行结果
运行代码后,将在当前目录下生成一个名为“5.bmp”的图像文件,该文件为对“3.bmp”图像的G分量进行直方图均衡后的结果。
5. 总结
本文介绍了使用C语言实现BMP图像G分量直方图均衡的方法,并给出了完整的代码实现。直方图均衡是一种常用的图像增强技术,可以有效提高图像的对比度,改善图像的视觉效果。
原文地址: https://www.cveoy.top/t/topic/jCYm 著作权归作者所有。请勿转载和采集!