由于本题需要对 BMP 格式的图像进行操作,需要先了解 BMP 格式的文件结构。BMP 格式的文件由文件头(14 字节)、位图信息头(40 字节)和像素数据组成,其中位图信息头中包含了图像的宽、高、色深等信息,像素数据则按照一定的格式存储了每个像素的 RGB 值。

在进行直方图均衡操作时,需要先读取图像的像素数据,统计每个像素 R 分量的出现次数,计算出每个 R 分量的累计分布函数,并根据累计分布函数对每个像素的 R 分量进行映射,最后将处理后的像素数据写回文件中。

下面是一份基于 C 语言的代码实现:

#include <stdio.h>
#include <stdlib.h>

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef int LONG;

#pragma pack(2) // 按照 2 字节对齐

// BMP 文件头
typedef struct tagBITMAPFILEHEADER {
    WORD bfType; // 文件类型,必须为 BM
    DWORD bfSize; // 文件大小,单位为字节
    WORD bfReserved1; // 保留字,必须为 0
    WORD bfReserved2; // 保留字,必须为 0
    DWORD bfOffBits; // 从文件头到位图数据的偏移量,单位为字节
} BITMAPFILEHEADER;

// BMP 位图信息头
typedef struct tagBITMAPINFOHEADER {
    DWORD biSize; // 信息头大小,必须为 40
    LONG biWidth; // 图像宽度,单位为像素
    LONG biHeight; // 图像高度,单位为像素
    WORD biPlanes; // 颜色平面数,必须为 1
    WORD biBitCount; // 每个像素的位数,一般为 24
    DWORD biCompression; // 压缩类型,一般为 0
    DWORD biSizeImage; // 图像数据大小,单位为字节
    LONG biXPelsPerMeter; // 水平分辨率,单位为像素/米
    LONG biYPelsPerMeter; // 垂直分辨率,单位为像素/米
    DWORD biClrUsed; // 颜色表中实际使用的颜色数,一般为 0
    DWORD biClrImportant; // 重要颜色数,一般为 0
} BITMAPINFOHEADER;

#pragma pack() // 恢复默认对齐方式

int main() {
    FILE *fp_in, *fp_out;
    BITMAPFILEHEADER file_header;
    BITMAPINFOHEADER info_header;
    BYTE *pixel_data, *new_pixel_data;
    int width, height, row_bytes, padding_bytes, i, j, r, g, b;
    int *histogram, *cdf, cdf_min, cdf_max;
    float cdf_scale;

    // 打开输入文件
    fp_in = fopen('3.bmp', 'rb');
    if (fp_in == NULL) {
        printf('Failed to open input file.\n');
        return 1;
    }

    // 读取 BMP 文件头
    fread(&file_header, sizeof(BITMAPFILEHEADER), 1, fp_in);
    if (file_header.bfType != 0x4d42) {
        printf('Invalid BMP file.\n');
        return 1;
    }

    // 读取 BMP 位图信息头
    fread(&info_header, sizeof(BITMAPINFOHEADER), 1, fp_in);
    if (info_header.biBitCount != 24) {
        printf('Unsupported color depth.\n');
        return 1;
    }

    // 计算图像宽度、高度、每行字节数和填充字节数
    width = info_header.biWidth;
    height = info_header.biHeight;
    row_bytes = ((width * 3) + 3) / 4 * 4;
    padding_bytes = row_bytes - width * 3;

    // 分配像素数据和新的像素数据
    pixel_data = (BYTE*)malloc(row_bytes * height);
    new_pixel_data = (BYTE*)malloc(row_bytes * height);

    // 读取像素数据
    fread(pixel_data, 1, row_bytes * height, fp_in);

    // 关闭输入文件
    fclose(fp_in);

    // 计算 R 分量的直方图
    histogram = (int*)calloc(256, sizeof(int));
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            b = *(pixel_data + i * row_bytes + j * 3);
            g = *(pixel_data + i * row_bytes + j * 3 + 1);
            r = *(pixel_data + i * row_bytes + j * 3 + 2);
            histogram[r]++;
        }
    }

    // 计算 R 分量的累计分布函数
    cdf = (int*)calloc(256, sizeof(int));
    cdf[0] = histogram[0];
    for (i = 1; i < 256; i++) {
        cdf[i] = cdf[i - 1] + histogram[i];
    }

    // 寻找最小和最大的累计分布函数值
    cdf_min = cdf[0];
    cdf_max = cdf[255];
    for (i = 0; i < 256; i++) {
        if (cdf[i] < cdf_min) {
            cdf_min = cdf[i];
        }
        if (cdf[i] > cdf_max) {
            cdf_max = cdf[i];
        }
    }

    // 计算累计分布函数的缩放比例
    cdf_scale = 255.0 / (cdf_max - cdf_min);

    // 对 R 分量进行直方图均衡
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            b = *(pixel_data + i * row_bytes + j * 3);
            g = *(pixel_data + i * row_bytes + j * 3 + 1);
            r = *(pixel_data + i * row_bytes + j * 3 + 2);
            r = (int)((cdf[r] - cdf_min) * cdf_scale + 0.5);
            if (r < 0) {
                r = 0;
            }
            if (r > 255) {
                r = 255;
            }
            *(new_pixel_data + i * row_bytes + j * 3) = b;
            *(new_pixel_data + i * row_bytes + j * 3 + 1) = g;
            *(new_pixel_data + i * row_bytes + j * 3 + 2) = r;
        }
    }

    // 打开输出文件
    fp_out = fopen('4.bmp', 'wb');
    if (fp_out == NULL) {
        printf('Failed to open output file.\n');
        return 1;
    }

    // 写入 BMP 文件头
    fwrite(&file_header, sizeof(BITMAPFILEHEADER), 1, fp_out);

    // 写入 BMP 位图信息头
    fwrite(&info_header, sizeof(BITMAPINFOHEADER), 1, fp_out);

    // 写入像素数据
    fwrite(new_pixel_data, 1, row_bytes * height, fp_out);

    // 关闭输出文件
    fclose(fp_out);

    // 释放内存
    free(pixel_data);
    free(new_pixel_data);
    free(histogram);
    free(cdf);

    return 0;
}

需要注意的是,在读取和写入文件时,需要使用二进制模式打开文件(即参数为 'rb' 和 'wb'),否则可能会出现文件格式错误的问题。同时,在读取像素数据时,每行的字节数需要按照 4 字节对齐,因此需要计算每行的填充字节数。在对 R 分量进行直方图均衡时,需要注意对像素值的范围进行限制,否则可能会出现超出范围的像素值。

C语言实现BMP图像直方图均衡化 - 将 3.bmp 的 R 分量进行均衡并输出为 4.bmp

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

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