用C或C++编程 对大小为256×256大小 24 位真彩的bmp格式的图像进行相应操作并且读写要求用到fread 、fwrite 函数等将图像3bmp中的色彩R G B分量 中的R分量进行直方图均衡将对R分量进行直方图均衡后的图像输出为4bmp
由于本题需要对BMP格式进行读写操作,需要先了解BMP文件格式的结构。BMP文件由文件头、位图信息头和像素数据三部分组成,其中像素数据部分存储着图像的RGB值。具体可以参考以下链接:https://blog.csdn.net/u010019717/article/details/53883891
下面给出实现代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
// 定义BMP文件头结构体
#pragma pack(push, 1)
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType; // 文件类型,必须为0x4d42
unsigned int bfSize; // 文件大小,单位为字节
unsigned short bfReserved1; // 保留字段
unsigned short bfReserved2; // 保留字段
unsigned int bfOffBits; // 位图数据的起始位置,单位为字节
} BITMAPFILEHEADER;
#pragma pack(pop)
// 定义BMP位图信息头结构体
#pragma pack(push, 1)
typedef struct tagBITMAPINFOHEADER {
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
} BITMAPINFOHEADER;
#pragma pack(pop)
// 定义RGB颜色结构体
typedef struct tagRGBQUAD {
unsigned char rgbBlue; // 蓝色分量
unsigned char rgbGreen; // 绿色分量
unsigned char rgbRed; // 红色分量
unsigned char rgbReserved; // 保留字段
} RGBQUAD;
// 读取BMP文件头
void readBmpHeader(FILE* fp, BITMAPFILEHEADER& bmpFileHeader, BITMAPINFOHEADER& bmpInfoHeader) {
fread(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
fread(&bmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
}
// 写入BMP文件头
void writeBmpHeader(FILE* fp, BITMAPFILEHEADER bmpFileHeader, BITMAPINFOHEADER bmpInfoHeader) {
fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
fwrite(&bmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
}
// 读取BMP像素数据
void readBmpData(FILE* fp, RGBQUAD** bmpData, int width, int height) {
*bmpData = new RGBQUAD[width * height];
fseek(fp, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), SEEK_SET);
fread(*bmpData, sizeof(RGBQUAD), width * height, fp);
}
// 写入BMP像素数据
void writeBmpData(FILE* fp, RGBQUAD* bmpData, int width, int height) {
fseek(fp, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), SEEK_SET);
fwrite(bmpData, sizeof(RGBQUAD), width * height, fp);
}
// 计算RGB直方图
void computeHistogram(RGBQUAD* bmpData, int width, int height, int* histogram) {
memset(histogram, 0, sizeof(int) * 256);
for (int i = 0; i < width * height; i++) {
histogram[bmpData[i].rgbRed]++;
}
}
// 计算RGB累积分布函数
void computeCDF(int* histogram, int* cdf) {
cdf[0] = histogram[0];
for (int i = 1; i < 256; i++) {
cdf[i] = cdf[i - 1] + histogram[i];
}
}
// 计算RGB均衡化后的映射表
void computeEqualizationMap(int* cdf, int totalPixels, unsigned char* equalizationMap) {
for (int i = 0; i < 256; i++) {
equalizationMap[i] = (unsigned char)(cdf[i] * 255.0 / totalPixels + 0.5);
}
}
// 对RGB图像进行直方图均衡
void histogramEqualization(RGBQUAD* bmpData, int width, int height) {
// 计算RGB直方图
int histogram[256];
computeHistogram(bmpData, width, height, histogram);
// 计算RGB累积分布函数
int cdf[256];
computeCDF(histogram, cdf);
// 计算RGB均衡化后的映射表
unsigned char equalizationMap[256];
computeEqualizationMap(cdf, width * height, equalizationMap);
// 对R分量进行直方图均衡
for (int i = 0; i < width * height; i++) {
bmpData[i].rgbRed = equalizationMap[bmpData[i].rgbRed];
}
}
int main() {
// 读取原始BMP文件
FILE* fp = fopen("3.bmp", "rb");
if (fp == NULL) {
cout << "Failed to open file!" << endl;
return 0;
}
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFOHEADER bmpInfoHeader;
readBmpHeader(fp, bmpFileHeader, bmpInfoHeader);
RGBQUAD* bmpData;
readBmpData(fp, &bmpData, bmpInfoHeader.biWidth, bmpInfoHeader.biHeight);
fclose(fp);
// 对R分量进行直方图均衡
histogramEqualization(bmpData, bmpInfoHeader.biWidth, bmpInfoHeader.biHeight);
// 写入均衡化后的BMP文件
fp = fopen("4.bmp", "wb");
if (fp == NULL) {
cout << "Failed to open file!" << endl;
return 0;
}
writeBmpHeader(fp, bmpFileHeader, bmpInfoHeader);
writeBmpData(fp, bmpData, bmpInfoHeader.biWidth, bmpInfoHeader.biHeight);
fclose(fp);
// 释放内存
delete[] bmpData;
return 0;
}
注意,本题中要求使用fread()和fwrite()函数进行BMP文件的读写操作,因此需要注意以下几点:
- 读取BMP文件头和像素数据时,需要使用
fseek()函数将文件指针定位到相应位置,否则会读取到无效数据。 - 写入BMP文件头和像素数据时,也需要使用
fseek()函数将文件指针定位到相应位置,否则会覆盖掉文件头信息。 - 由于BMP文件中的像素数据是按行存储的,每行的字节数需要根据图像宽度和每个像素的位数计算得出,因此在读取和写入像素数据时,需要注意字节数的计算。
完整代码已上传至GitHub:https://github.com/linyacool/Programming-Exercises/tree/main/C%2B%2B/BMPHistogramEqualization
原文地址: https://www.cveoy.top/t/topic/b3c6 著作权归作者所有。请勿转载和采集!