#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; // 信息头大小,单位为字节
    int biWidth; // 图像宽度,单位为像素
    int biHeight; // 图像高度,单位为像素
    unsigned short biPlanes; // 位平面数,必须为1
    unsigned short biBitCount; // 每像素位数,必须为24
    unsigned int biCompression; // 压缩类型,0表示不压缩
    unsigned int biSizeImage; // 像素数据大小,单位为字节
    int biXPelsPerMeter; // 水平分辨率,单位为像素/m
    int biYPelsPerMeter; // 垂直分辨率,单位为像素/m
    unsigned int biClrUsed; // 调色板颜色数,为0表示使用所有颜色
    unsigned int biClrImportant; // 重要颜色数,为0表示所有颜色都重要
} BMPInfoHeader;

// 像素结构体
typedef struct {
    unsigned char b; // 蓝色分量
    unsigned char g; // 绿色分量
    unsigned char r; // 红色分量
} Pixel;

// 直方图结构体
typedef struct {
    int count[256]; // 每个像素值的数量
    float prob[256]; // 每个像素值的概率
    int cumCount[256]; // 累计像素值的数量
    int cumProb[256]; // 累计像素值的概率
    int map[256]; // 映射表
} Histogram;

// 读取BMP文件头
void readBMPFileHeader(FILE* fp, BMPFileHeader* header) {
    fread(&header->bfType, sizeof(header->bfType), 1, fp);
    fread(&header->bfSize, sizeof(header->bfSize), 1, fp);
    fread(&header->bfReserved1, sizeof(header->bfReserved1), 1, fp);
    fread(&header->bfReserved2, sizeof(header->bfReserved2), 1, fp);
    fread(&header->bfOffBits, sizeof(header->bfOffBits), 1, fp);
}

// 读取BMP信息头
void readBMPInfoHeader(FILE* fp, BMPInfoHeader* header) {
    fread(&header->biSize, sizeof(header->biSize), 1, fp);
    fread(&header->biWidth, sizeof(header->biWidth), 1, fp);
    fread(&header->biHeight, sizeof(header->biHeight), 1, fp);
    fread(&header->biPlanes, sizeof(header->biPlanes), 1, fp);
    fread(&header->biBitCount, sizeof(header->biBitCount), 1, fp);
    fread(&header->biCompression, sizeof(header->biCompression), 1, fp);
    fread(&header->biSizeImage, sizeof(header->biSizeImage), 1, fp);
    fread(&header->biXPelsPerMeter, sizeof(header->biXPelsPerMeter), 1, fp);
    fread(&header->biYPelsPerMeter, sizeof(header->biYPelsPerMeter), 1, fp);
    fread(&header->biClrUsed, sizeof(header->biClrUsed), 1, fp);
    fread(&header->biClrImportant, sizeof(header->biClrImportant), 1, fp);
}

// 读取像素数据
void readPixels(FILE* fp, int width, int height, Pixel* pixels) {
    int rowSize = (width * 3 + 3) / 4 * 4; // 每行像素数据大小,必须为4的倍数
    int paddingSize = rowSize - width * 3; // 每行填充字节数
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            fread(&pixels[y * width + x], sizeof(Pixel), 1, fp);
        }
        fseek(fp, paddingSize, SEEK_CUR); // 跳过填充字节
    }
}

// 写入BMP文件头
void writeBMPFileHeader(FILE* fp, BMPFileHeader* header) {
    fwrite(&header->bfType, sizeof(header->bfType), 1, fp);
    fwrite(&header->bfSize, sizeof(header->bfSize), 1, fp);
    fwrite(&header->bfReserved1, sizeof(header->bfReserved1), 1, fp);
    fwrite(&header->bfReserved2, sizeof(header->bfReserved2), 1, fp);
    fwrite(&header->bfOffBits, sizeof(header->bfOffBits), 1, fp);
}

// 写入BMP信息头
void writeBMPInfoHeader(FILE* fp, BMPInfoHeader* header) {
    fwrite(&header->biSize, sizeof(header->biSize), 1, fp);
    fwrite(&header->biWidth, sizeof(header->biWidth), 1, fp);
    fwrite(&header->biHeight, sizeof(header->biHeight), 1, fp);
    fwrite(&header->biPlanes, sizeof(header->biPlanes), 1, fp);
    fwrite(&header->biBitCount, sizeof(header->biBitCount), 1, fp);
    fwrite(&header->biCompression, sizeof(header->biCompression), 1, fp);
    fwrite(&header->biSizeImage, sizeof(header->biSizeImage), 1, fp);
    fwrite(&header->biXPelsPerMeter, sizeof(header->biXPelsPerMeter), 1, fp);
    fwrite(&header->biYPelsPerMeter, sizeof(header->biYPelsPerMeter), 1, fp);
    fwrite(&header->biClrUsed, sizeof(header->biClrUsed), 1, fp);
    fwrite(&header->biClrImportant, sizeof(header->biClrImportant), 1, fp);
}

// 写入像素数据
void writePixels(FILE* fp, int width, int height, Pixel* pixels) {
    int rowSize = (width * 3 + 3) / 4 * 4; // 每行像素数据大小,必须为4的倍数
    int paddingSize = rowSize - width * 3; // 每行填充字节数
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            fwrite(&pixels[y * width + x], sizeof(Pixel), 1, fp);
        }
        for (int i = 0; i < paddingSize; i++) {
            fputc(0, fp); // 填充0
        }
    }
}

// 计算直方图
void calcHistogram(int width, int height, Pixel* pixels, Histogram* hist) {
    // 初始化直方图
    for (int i = 0; i < 256; i++) {
        hist->count[i] = 0;
        hist->prob[i] = 0;
        hist->cumCount[i] = 0;
        hist->cumProb[i] = 0;
        hist->map[i] = 0;
    }
    // 统计像素值的数量
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            hist->count[pixels[y * width + x].r]++;
        }
    }
    // 计算像素值的概率
    int pixelCount = width * height;
    for (int i = 0; i < 256; i++) {
        hist->prob[i] = (float)hist->count[i] / pixelCount;
    }
    // 计算累计像素值的数量和概率
    hist->cumCount[0] = hist->count[0];
    hist->cumProb[0] = hist->prob[0] * 255;
    for (int i = 1; i < 256; i++) {
        hist->cumCount[i] = hist->cumCount[i - 1] + hist->count[i];
        hist->cumProb[i] = hist->cumProb[i - 1] + hist->prob[i] * 255;
    }
    // 计算映射表
    for (int i = 0; i < 256; i++) {
        hist->map[i] = hist->cumProb[i];
    }
}

// 直方图均衡
void equalizeHistogram(int width, int height, Pixel* pixels) {
    Histogram hist;
    calcHistogram(width, height, pixels, &hist);
    // 映射像素值
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            pixels[y * width + x].r = hist.map[pixels[y * width + x].r];
        }
    }
}

int main() {
    FILE* fpIn = fopen("3.bmp", "rb");
    FILE* fpOut = fopen("4.bmp", "wb");
    if (fpIn == NULL || fpOut == NULL) {
        printf("Failed to open file.\n");
        return 1;
    }
    BMPFileHeader fileHeader;
    BMPInfoHeader infoHeader;
    readBMPFileHeader(fpIn, &fileHeader);
    readBMPInfoHeader(fpIn, &infoHeader);
    if (fileHeader.bfType != 0x4D42 || infoHeader.biBitCount != 24) {
        printf("Invalid BMP file.\n");
        return 1;
    }
    Pixel* pixels = (Pixel*)malloc(infoHeader.biWidth * infoHeader.biHeight * sizeof(Pixel));
    readPixels(fpIn, infoHeader.biWidth, infoHeader.biHeight, pixels);
    equalizeHistogram(infoHeader.biWidth, infoHeader.biHeight, pixels);
    fileHeader.bfSize = fileHeader.bfOffBits + infoHeader.biWidth * infoHeader.biHeight * 3;
    infoHeader.biSizeImage = infoHeader.biWidth * infoHeader.biHeight * 3;
    writeBMPFileHeader(fpOut, &fileHeader);
    writeBMPInfoHeader(fpOut, &infoHeader);
    writePixels(fpOut, infoHeader.biWidth, infoHeader.biHeight, pixels);
    free(pixels);
    fclose(fpIn);
    fclose(fpOut);
    return 0;
}
用C语言编写一段代码对大小为256×256大小 24 位真彩的bmp格式的图像进行相应操作并且读写要求用到fread 、fwrite 函数等将图像3bmp中的色彩R G B分量 中的R分量进行直方图均衡将对R分量进行直方图均衡后的图像输出为4bmp 代码尽量简洁

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

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