用C语言编写一段代码对大小为256×256大小 24 位真彩的bmp格式的图像进行相应操作并且读写要求用到fread 、fwrite 函数等将图像3bmp中的色彩R G B分量 中的R分量进行直方图均衡将对G分量进行直方图均衡衡后的图像输出为名字为5bmp的图像
由于直方图均衡需要对每个像素进行操作,因此需要读取整个图像,对每个像素进行处理,然后再写入新的图像。下面是一份用C语言实现的代码,实现了对BMP图像的读取、处理和写入。
#include <stdio.h>
#include <stdlib.h>
// 定义BMP文件头结构体
typedef struct {
unsigned short bfType; // 文件类型,必须为0x4D42
unsigned int bfSize; // 文件大小,单位为字节
unsigned short bfReserved1; // 保留字段
unsigned short bfReserved2; // 保留字段
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;
// 定义像素结构体
typedef struct {
unsigned char b, g, r;
} PIXEL;
// 读取BMP文件头
void readBmpFileHeader(FILE* fp, BMPFILEHEADER* fileHeader) {
fread(&fileHeader->bfType, sizeof(fileHeader->bfType), 1, fp);
fread(&fileHeader->bfSize, sizeof(fileHeader->bfSize), 1, fp);
fread(&fileHeader->bfReserved1, sizeof(fileHeader->bfReserved1), 1, fp);
fread(&fileHeader->bfReserved2, sizeof(fileHeader->bfReserved2), 1, fp);
fread(&fileHeader->bfOffBits, sizeof(fileHeader->bfOffBits), 1, fp);
}
// 读取BMP信息头
void readBmpInfoHeader(FILE* fp, BMPINFOHEADER* infoHeader) {
fread(&infoHeader->biSize, sizeof(infoHeader->biSize), 1, fp);
fread(&infoHeader->biWidth, sizeof(infoHeader->biWidth), 1, fp);
fread(&infoHeader->biHeight, sizeof(infoHeader->biHeight), 1, fp);
fread(&infoHeader->biPlanes, sizeof(infoHeader->biPlanes), 1, fp);
fread(&infoHeader->biBitCount, sizeof(infoHeader->biBitCount), 1, fp);
fread(&infoHeader->biCompression, sizeof(infoHeader->biCompression), 1, fp);
fread(&infoHeader->biSizeImage, sizeof(infoHeader->biSizeImage), 1, fp);
fread(&infoHeader->biXPelsPerMeter, sizeof(infoHeader->biXPelsPerMeter), 1, fp);
fread(&infoHeader->biYPelsPerMeter, sizeof(infoHeader->biYPelsPerMeter), 1, fp);
fread(&infoHeader->biClrUsed, sizeof(infoHeader->biClrUsed), 1, fp);
fread(&infoHeader->biClrImportant, sizeof(infoHeader->biClrImportant), 1, fp);
}
// 读取像素数组
void readPixels(FILE* fp, PIXEL* pixels, int width, int height) {
int padding = (4 - ((width * 3) % 4)) % 4; // 计算每行的填充字节数
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
fread(&pixels[i * width + j], sizeof(PIXEL), 1, fp);
}
fseek(fp, padding, SEEK_CUR); // 跳过填充字节
}
}
// 写入BMP文件头
void writeBmpFileHeader(FILE* fp, BMPFILEHEADER* fileHeader) {
fwrite(&fileHeader->bfType, sizeof(fileHeader->bfType), 1, fp);
fwrite(&fileHeader->bfSize, sizeof(fileHeader->bfSize), 1, fp);
fwrite(&fileHeader->bfReserved1, sizeof(fileHeader->bfReserved1), 1, fp);
fwrite(&fileHeader->bfReserved2, sizeof(fileHeader->bfReserved2), 1, fp);
fwrite(&fileHeader->bfOffBits, sizeof(fileHeader->bfOffBits), 1, fp);
}
// 写入BMP信息头
void writeBmpInfoHeader(FILE* fp, BMPINFOHEADER* infoHeader) {
fwrite(&infoHeader->biSize, sizeof(infoHeader->biSize), 1, fp);
fwrite(&infoHeader->biWidth, sizeof(infoHeader->biWidth), 1, fp);
fwrite(&infoHeader->biHeight, sizeof(infoHeader->biHeight), 1, fp);
fwrite(&infoHeader->biPlanes, sizeof(infoHeader->biPlanes), 1, fp);
fwrite(&infoHeader->biBitCount, sizeof(infoHeader->biBitCount), 1, fp);
fwrite(&infoHeader->biCompression, sizeof(infoHeader->biCompression), 1, fp);
fwrite(&infoHeader->biSizeImage, sizeof(infoHeader->biSizeImage), 1, fp);
fwrite(&infoHeader->biXPelsPerMeter, sizeof(infoHeader->biXPelsPerMeter), 1, fp);
fwrite(&infoHeader->biYPelsPerMeter, sizeof(infoHeader->biYPelsPerMeter), 1, fp);
fwrite(&infoHeader->biClrUsed, sizeof(infoHeader->biClrUsed), 1, fp);
fwrite(&infoHeader->biClrImportant, sizeof(infoHeader->biClrImportant), 1, fp);
}
// 写入像素数组
void writePixels(FILE* fp, PIXEL* pixels, int width, int height) {
int padding = (4 - ((width * 3) % 4)) % 4; // 计算每行的填充字节数
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
fwrite(&pixels[i * width + j], sizeof(PIXEL), 1, fp);
}
for (int j = 0; j < padding; j++) {
fputc(0, fp); // 写入填充字节
}
}
}
// 计算直方图
void calcHistogram(PIXEL* pixels, int width, int height, int* histR, int* histG, int* histB) {
for (int i = 0; i < 256; i++) {
histR[i] = 0;
histG[i] = 0;
histB[i] = 0;
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
histR[pixels[i * width + j].r]++;
histG[pixels[i * width + j].g]++;
histB[pixels[i * width + j].b]++;
}
}
}
// 计算累积直方图
void calcCumulativeHistogram(int* hist, int* cumHist) {
cumHist[0] = hist[0];
for (int i = 1; i < 256; i++) {
cumHist[i] = cumHist[i - 1] + hist[i];
}
}
// 直方图均衡
void histogramEqualization(PIXEL* pixels, int width, int height, int* hist, int* cumHist) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int r = pixels[i * width + j].r;
pixels[i * width + j].r = 255.0 * cumHist[r] / (width * height) + 0.5;
}
}
}
int main() {
FILE* fpIn = fopen("3.bmp", "rb");
FILE* fpOut = fopen("5.bmp", "wb");
if (fpIn == NULL || fpOut == NULL) {
printf("文件打开失败\n");
return 0;
}
BMPFILEHEADER fileHeader;
BMPINFOHEADER infoHeader;
PIXEL* pixels;
// 读取BMP文件头和信息头
readBmpFileHeader(fpIn, &fileHeader);
readBmpInfoHeader(fpIn, &infoHeader);
// 分配像素数组内存
pixels = (PIXEL*)malloc(infoHeader.biWidth * infoHeader.biHeight * sizeof(PIXEL));
// 读取像素数组
readPixels(fpIn, pixels, infoHeader.biWidth, infoHeader.biHeight);
// 计算直方图
int histR[256], histG[256], histB[256];
calcHistogram(pixels, infoHeader.biWidth, infoHeader.biHeight, histR, histG, histB);
// 计算累积直方图
int cumHistR[256], cumHistG[256], cumHistB[256];
calcCumulativeHistogram(histR, cumHistR);
calcCumulativeHistogram(histG, cumHistG);
calcCumulativeHistogram(histB, cumHistB);
// 直方图均衡
histogramEqualization(pixels, infoHeader.biWidth, infoHeader.biHeight, histR, cumHistR);
histogramEqualization(pixels, infoHeader.biWidth, infoHeader.biHeight, histG, cumHistG);
histogramEqualization(pixels, infoHeader.biWidth, infoHeader.biHeight, histB, cumHistB);
// 写入BMP文件头和信息头
writeBmpFileHeader(fpOut, &fileHeader);
writeBmpInfoHeader(fpOut, &infoHeader);
// 写入像素数组
writePixels(fpOut, pixels, infoHeader.biWidth, infoHeader.biHeight);
// 释放内存
free(pixels);
// 关闭文件
fclose(fpIn);
fclose(fpOut);
return 0;
}
需要注意的是,BMP图像中每个像素的RGB分量的顺序是BGR,而不是RGB。因此在读取和写入像素数组时,要注意分别读取和写入B、G、R三个分量。
原文地址: https://www.cveoy.top/t/topic/b3iF 著作权归作者所有。请勿转载和采集!