由于直方图均衡需要对每个像素进行操作,因此需要读取整个图像,对每个像素进行处理,然后再写入新的图像。下面是一份用C语言实现的代码,实现了对BMP图像的读取、处理和写入。

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

// 定义BMP文件头结构体
typedef struct {
    unsigned short bfType;          // 文件类型,必须为0x4D42
    unsigned int bfSize;            // 文件大小,单位为字节
    unsigned short bfReserved1;     // 保留字段
    unsigned short bfReserved2;     // 保留字段
    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;

// 定义像素结构体
typedef struct {
    unsigned char b, g, r;
} PIXEL;

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

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

// 读取像素数组
void readPixels(FILE* fp, PIXEL* pixels, int width, int height) {
    int padding = (4 - ((width * 3) % 4)) % 4;  // 计算每行的填充字节数
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            fread(&pixels[i * width + j], sizeof(PIXEL), 1, fp);
        }
        fseek(fp, padding, SEEK_CUR);  // 跳过填充字节
    }
}

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

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

// 写入像素数组
void writePixels(FILE* fp, PIXEL* pixels, int width, int height) {
    int padding = (4 - ((width * 3) % 4)) % 4;  // 计算每行的填充字节数
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            fwrite(&pixels[i * width + j], sizeof(PIXEL), 1, fp);
        }
        for (int j = 0; j < padding; j++) {
            fputc(0, fp);  // 写入填充字节
        }
    }
}

// 计算直方图
void calcHistogram(PIXEL* pixels, int width, int height, int* histR, int* histG, int* histB) {
    for (int i = 0; i < 256; i++) {
        histR[i] = 0;
        histG[i] = 0;
        histB[i] = 0;
    }
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            histR[pixels[i * width + j].r]++;
            histG[pixels[i * width + j].g]++;
            histB[pixels[i * width + j].b]++;
        }
    }
}

// 计算累积直方图
void calcCumulativeHistogram(int* hist, int* cumHist) {
    cumHist[0] = hist[0];
    for (int i = 1; i < 256; i++) {
        cumHist[i] = cumHist[i - 1] + hist[i];
    }
}

// 直方图均衡
void histogramEqualization(PIXEL* pixels, int width, int height, int* hist, int* cumHist) {
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            int r = pixels[i * width + j].r;
            pixels[i * width + j].r = 255.0 * cumHist[r] / (width * height) + 0.5;
        }
    }
}

int main() {
    FILE* fpIn = fopen("3.bmp", "rb");
    FILE* fpOut = fopen("5.bmp", "wb");
    if (fpIn == NULL || fpOut == NULL) {
        printf("文件打开失败\n");
        return 0;
    }

    BMPFILEHEADER fileHeader;
    BMPINFOHEADER infoHeader;
    PIXEL* pixels;

    // 读取BMP文件头和信息头
    readBmpFileHeader(fpIn, &fileHeader);
    readBmpInfoHeader(fpIn, &infoHeader);

    // 分配像素数组内存
    pixels = (PIXEL*)malloc(infoHeader.biWidth * infoHeader.biHeight * sizeof(PIXEL));

    // 读取像素数组
    readPixels(fpIn, pixels, infoHeader.biWidth, infoHeader.biHeight);

    // 计算直方图
    int histR[256], histG[256], histB[256];
    calcHistogram(pixels, infoHeader.biWidth, infoHeader.biHeight, histR, histG, histB);

    // 计算累积直方图
    int cumHistR[256], cumHistG[256], cumHistB[256];
    calcCumulativeHistogram(histR, cumHistR);
    calcCumulativeHistogram(histG, cumHistG);
    calcCumulativeHistogram(histB, cumHistB);

    // 直方图均衡
    histogramEqualization(pixels, infoHeader.biWidth, infoHeader.biHeight, histR, cumHistR);
    histogramEqualization(pixels, infoHeader.biWidth, infoHeader.biHeight, histG, cumHistG);
    histogramEqualization(pixels, infoHeader.biWidth, infoHeader.biHeight, histB, cumHistB);

    // 写入BMP文件头和信息头
    writeBmpFileHeader(fpOut, &fileHeader);
    writeBmpInfoHeader(fpOut, &infoHeader);

    // 写入像素数组
    writePixels(fpOut, pixels, infoHeader.biWidth, infoHeader.biHeight);

    // 释放内存
    free(pixels);

    // 关闭文件
    fclose(fpIn);
    fclose(fpOut);

    return 0;
}

需要注意的是,BMP图像中每个像素的RGB分量的顺序是BGR,而不是RGB。因此在读取和写入像素数组时,要注意分别读取和写入B、G、R三个分量。

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

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

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