由于直方图均衡需要对每个像素点进行计算,所以需要先将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图像的像素数据是按照从下到上、从左到右的顺序存储的,所以在读取和写入像素数据时需要注意顺序。

用C语言编程写一段完整代码 对大小为256×256大小 24 位真彩的bmp格式的图像进行相应操作并且读写要求用到fread 、fwrite 函数等要求如下:对2bmp图像进行直方图均衡输出结果图像为3bmp

原文地址: https://www.cveoy.top/t/topic/b3ae 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录