C语言实现BMP图像G分量直方图均衡

本文将介绍如何使用C语言编写程序,对256×256大小的24位真彩BMP格式图像进行G分量直方图均衡处理,并使用fread()fwrite()函数进行文件读写操作。

1. BMP格式概述

BMP格式的文件由文件头和图像数据两部分组成,其中文件头包含了文件类型、文件大小、图像宽度、图像高度等信息,图像数据则包含了像素点的颜色信息。具体的文件格式可以参考相关资料进行了解。

2. 直方图均衡原理

直方图均衡是一种图像增强技术,它通过调整图像的灰度级分布,使得图像的对比度得到提高。其原理是将原始图像的灰度级映射到一个新的灰度级,使得新的灰度级分布更加均匀。

3. 代码实现

以下是使用C语言实现BMP图像G分量直方图均衡的代码:

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

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

// BMP文件头结构体
typedef struct {
    short bfType; // 文件类型,必须为0x4D42(即BM)
    int bfSize; // 文件大小,单位为字节
    short bfReserved1; // 保留字段
    short bfReserved2; // 保留字段
    int bfOffBits; // 从文件头到实际图像数据的偏移量,单位为字节
} BMPFILEHEADER;

// BMP信息头结构体
typedef struct {
    int biSize; // 信息头大小,单位为字节
    int biWidth; // 图像宽度,单位为像素
    int biHeight; // 图像高度,单位为像素
    short biPlanes; // 颜色平面数,必须为1
    short biBitCount; // 每个像素的位数
    int biCompression; // 压缩类型,0为不压缩
    int biSizeImage; // 图像数据大小,单位为字节
    int biXPelsPerMeter; // 水平分辨率,单位为像素/米
    int biYPelsPerMeter; // 垂直分辨率,单位为像素/米
    int biClrUsed; // 使用的颜色数,0表示使用所有颜色
    int biClrImportant; // 重要的颜色数,0表示所有颜色都重要
} BMPINFOHEADER;

// RGB颜色结构体
typedef struct {
    unsigned char b;
    unsigned char g;
    unsigned char r;
} RGB;

// 直方图结构体
typedef struct {
    int count[256]; // 每个像素值出现的次数
    float prob[256]; // 每个像素值出现的概率
    int map[256]; // 均衡后的像素值映射表
} HISTOGRAM;

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

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

// 读取BMP图像数据
void readBmpData(FILE *fp, RGB *data, int width, int height) {
    int i, j;
    for (i = height - 1; i >= 0; i--) { // BMP图像数据是从下往上存储的
        for (j = 0; j < width; j++) {
            fread(&data[i * width + j], sizeof(RGB), 1, fp);
        }
    }
}

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

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

// 写入BMP图像数据
void writeBmpData(FILE *fp, RGB *data, int width, int height) {
    int i, j;
    for (i = height - 1; i >= 0; i--) { // BMP图像数据是从下往上存储的
        for (j = 0; j < width; j++) {
            fwrite(&data[i * width + j], sizeof(RGB), 1, fp);
        }
    }
}

// 计算直方图
void calcHistogram(RGB *data, int width, int height, HISTOGRAM *hist) {
    int i, j;
    int pixelCount = width * height;
    for (i = 0; i < 256; i++) {
        hist->count[i] = 0;
    }
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            int g = data[i * width + j].g;
            hist->count[g]++;
        }
    }
    for (i = 0; i < 256; i++) {
        hist->prob[i] = (float)hist->count[i] / pixelCount;
    }
    hist->map[0] = (int)(hist->prob[0] * 255 + 0.5);
    for (i = 1; i < 256; i++) {
        hist->map[i] = hist->map[i - 1] + (int)(hist->prob[i] * 255 + 0.5);
    }
}

// 直方图均衡
void histogramEqualization(RGB *data, int width, int height) {
    HISTOGRAM hist;
    calcHistogram(data, width, height, &hist);
    int i, j;
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            int g = data[i * width + j].g;
            int newG = hist.map[g];
            data[i * width + j].g = (unsigned char)newG;
        }
    }
}

int main() {
    FILE *fpIn, *fpOut;
    BMPFILEHEADER fileHeader;
    BMPINFOHEADER infoHeader;
    RGB *data;
    int width, height;

    // 读取输入文件
    fpIn = fopen('3.bmp', 'rb');
    if (fpIn == NULL) {
        printf('Error: cannot open input file.\n');
        return -1;
    }
    readBmpFileHeader(fpIn, &fileHeader);
    readBmpInfoHeader(fpIn, &infoHeader);
    width = infoHeader.biWidth;
    height = infoHeader.biHeight;
    data = (RGB *)malloc(sizeof(RGB) * width * height);
    readBmpData(fpIn, data, width, height);
    fclose(fpIn);

    // 对G分量进行直方图均衡
    histogramEqualization(data, width, height);

    // 写入输出文件
    fpOut = fopen('5.bmp', 'wb');
    if (fpOut == NULL) {
        printf('Error: cannot open output file.\n');
        return -1;
    }
    writeBmpFileHeader(fpOut, fileHeader);
    writeBmpInfoHeader(fpOut, infoHeader);
    writeBmpData(fpOut, data, width, height);
    fclose(fpOut);

    free(data);

    return 0;
}

代码说明:

  1. 文件头和信息头结构体: 定义了BMP文件头和信息头的结构体,方便存储文件信息。
  2. RGB颜色结构体: 定义了RGB颜色结构体,用于存储像素点的颜色信息。
  3. 直方图结构体: 定义了直方图结构体,用于存储每个灰度级出现的次数、概率和均衡后的映射表。
  4. 读取BMP文件信息: 使用fread()函数读取BMP文件头和信息头,获取图像的宽度和高度信息。
  5. 读取BMP图像数据: 使用fread()函数读取BMP图像数据,并存储到一个RGB类型的数组中。
  6. 计算直方图: 统计每个灰度级出现的次数,并计算每个灰度级的概率。
  7. 直方图均衡: 根据计算得到的概率,生成一个映射表,将每个灰度级映射到一个新的灰度级,实现直方图均衡。
  8. 写入BMP文件信息: 使用fwrite()函数将更新后的文件头信息和图像数据写入到新的BMP文件中。

注意:

  • 本代码仅供参考,需要根据实际情况进行调整。
  • 为了方便理解,代码中使用了大量的注释。
  • 建议在运行代码之前,将输入文件和输出文件命名为“3.bmp”和“5.bmp”。

4. 运行结果

运行代码后,将在当前目录下生成一个名为“5.bmp”的图像文件,该文件为对“3.bmp”图像的G分量进行直方图均衡后的结果。

5. 总结

本文介绍了使用C语言实现BMP图像G分量直方图均衡的方法,并给出了完整的代码实现。直方图均衡是一种常用的图像增强技术,可以有效提高图像的对比度,改善图像的视觉效果。

C语言实现BMP图像G分量直方图均衡

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

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