用C语言编程写一段完整代码 对大小为256×256大小 24 位真彩的bmp格式的图像进行相应操作并且读写要求用到fread 、fwrite 函数等要求如下:对2bmp图像进行直方图均衡输出结果图像为3bmp
由于直方图均衡需要对每个像素点进行计算,所以需要先将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;
}
需要注意的是,bmp文件头和信息头中的一些字段必须按照一定的格式填写,否则会导致图片无法正常显示。在本代码中,使用了#pragma pack(2)来指定结构体按2字节对齐,这是因为bmp文件头和信息头中有一些字段需要按照2字节对齐,否则会导致文件大小计算错误。另外,bmp图像的像素数据是按照从下到上、从左到右的顺序存储的,所以在读取和写入像素数据时需要注意顺序。
原文地址: https://www.cveoy.top/t/topic/b3ae 著作权归作者所有。请勿转载和采集!