由于本题需要对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文件的读写操作,因此需要注意以下几点:

  1. 读取BMP文件头和像素数据时,需要使用fseek()函数将文件指针定位到相应位置,否则会读取到无效数据。
  2. 写入BMP文件头和像素数据时,也需要使用fseek()函数将文件指针定位到相应位置,否则会覆盖掉文件头信息。
  3. 由于BMP文件中的像素数据是按行存储的,每行的字节数需要根据图像宽度和每个像素的位数计算得出,因此在读取和写入像素数据时,需要注意字节数的计算。

完整代码已上传至GitHub:https://github.com/linyacool/Programming-Exercises/tree/main/C%2B%2B/BMPHistogramEqualization

用C或C++编程 对大小为256×256大小 24 位真彩的bmp格式的图像进行相应操作并且读写要求用到fread 、fwrite 函数等将图像3bmp中的色彩R G B分量 中的R分量进行直方图均衡将对R分量进行直方图均衡后的图像输出为4bmp

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

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