南宫上天 2023-03-04 17:11 采纳率: 33.3%
浏览 38
已结题

BMP图像直方图均衡化算法程序为什么出来的图片无法显示呀

BMP图像直方图均衡化算法程序为什么出来的图片无法显示呀


#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <stdint.h>
typedef unsigned char BYTE;  // 定义BYTE为一个字节的类型
typedef unsigned short WORD; // 定义WORD为两个字节的类型
typedef unsigned int DWORD;  // 定义DWORD为四个字节的类型
typedef struct PerPixelgbr
{
    BYTE b;
    BYTE g;
    BYTE r;
}BGR;
//14 Bytes 文件头信息块
typedef struct tBITMAPFILEHEADER
{
    DWORD    bfSize;            //图片大小
    DWORD        bfReserved;    //保留字;    
    DWORD    bfOffBits;        //文件头到像素数据偏移量
}TBH;
//40 Bytes 图像描述信息块
typedef struct tBITMAPINFOHEADER
{
    DWORD    biSize;    //此结构体大小,换成kb除以1024
    DWORD    biWidth;            //宽          
    DWORD    biHeight;            //高
    WORD        biPlanes;        //平面显示属,一般显示器只有一个平面所以为1
    WORD        biBitCount;        //一个像素所占的位数,一般为24,带A通道的有32
    DWORD    biCompression;    //图像数据压缩的类,0为不压缩
    DWORD    biSizeImage;    //像素数据所占的大小 =bfSize-bfOffBits
    DWORD    biXPelsPerMeter;//水平分辨率
    DWORD    biYPelsPerMeter;//垂直分辨率
    DWORD    biClrUsed;        //位图实际使用的彩表的彩色索引数,为0证明全部使用
    DWORD    biClrImportant;    //说明对图象显示有重要影响的颜色索引数,如果是0,表示无差别
}TBI;
int main()
{
    FILE* in;
    FILE* out;
    TBH* BITMAPFILEHEADER;
    TBI* BITMAPINFOHEADER;
    BGR* duqu;
    BITMAPFILEHEADER = (TBH*)malloc(sizeof(TBH));
    BITMAPINFOHEADER = (TBI*)malloc(sizeof(TBI));
    duqu = (BGR*)malloc(sizeof(BGR));
    fopen_s(&in, "E:\\121.bmp", "rb");
    WORD  fileType;
    fread(&fileType, sizeof(unsigned short), 1, in);
    if(fileType == 0x4d42)
    {
        printf("文件类型标识正确\n");
    }//判断是不是bmp文件
    else{}
    fread(BITMAPFILEHEADER, sizeof(TBH), 1, in);//读取 14 Bytes 文件头信息块
    fread(BITMAPINFOHEADER, sizeof(TBI), 1, in);//读取 40 Bytes 图像描述信息块
    int W, H;
    W = (BITMAPINFOHEADER->biWidth);//得到宽度
    H = (BITMAPINFOHEADER->biHeight);//得到长度
    uint32_t B_ZFT[256] = { 0 }, G_ZFT[256] = { 0 }, R_ZFT[256] = { 0 };
    uint32_t B_CS[256], G_CS[256], R_CS[256];
    double B_GL[256], G_GL[256], R_GL[256];
    double gailvhe = 0;
    //fseek(in, 18, SEEK_SET);
    //fread(&W, 4, 1, in);
    //fseek(in, 22, SEEK_SET);
    //fread(&H, 4, 1, in);
    //fseek(in, 54, SEEK_SET);
    for (int i = W * H; i > 0; i--)
    {
        fread(duqu,  sizeof(BGR), 1, in);
        B_ZFT[(duqu->b)]++;
        G_ZFT[(duqu->g)]++;
        R_ZFT[(duqu->r)]++;
    }
    free(duqu);
    for (int i = 0; i < 256; i++)
    {
        gailvhe += (double)B_ZFT[i] / ((double)W * (double)H);
        B_GL[i] = gailvhe;
    }
    printf("%lf", gailvhe);
    gailvhe = 0;
    for (int i = 0; i < 256; i++)
    {
        gailvhe += (double)G_ZFT[i] / ((double)W * (double)H);
        G_GL[i] = gailvhe;
    }
    printf("%lf", gailvhe);
    gailvhe = 0;
    for (int i = 0; i < 256; i++)
    {
        gailvhe += (double)R_ZFT[i] / ((double)W * (double)H);
        R_GL[i] = gailvhe;
    }
    printf("%lf", gailvhe);
    for (int i = 0; i < 256; i++)
    {
        B_CS[i] = (uint32_t)(B_GL[i] * 255);
        G_CS[i] = (uint32_t)(G_GL[i] * 255);
        R_CS[i] = (uint32_t)(R_GL[i] * 255);
    }
    BGR* xielu = (BGR*)malloc(sizeof(BGR));
    duqu = (BGR*)malloc(sizeof(BGR));
    fseek(in, 54, SEEK_SET);
    fopen_s(&out, "E:\\12121.bmp", "wb");
    fwrite(&fileType, 2, 1, out);
    fwrite(&BITMAPFILEHEADER, sizeof(TBH), 1, out);
    fwrite(&BITMAPINFOHEADER, sizeof(TBI), 1, out);
    //fseek(out, 54, SEEK_SET);
    for (int i = W * H; i > 0; i--)
    {
        fread(duqu, sizeof(BGR), 1, in);
        (xielu->b) = B_CS[(duqu->b)];
        (xielu->g) = G_CS[(duqu->g)];
        (xielu->r) = R_CS[(duqu->r)];
        fwrite(&xielu, sizeof(BGR), 1, out);
    }
    free(duqu);
    free(xielu);
    fclose(in);
    fclose(out);
    return 0;
}
  • 写回答

3条回答 默认 最新

  • CodeBytes 2023-03-04 17:33
    关注

    该回答引用ChatGPT

    您的程序存在一些问题,导致输出的 BMP 文件无法正确显示。以下是我发现的几个问题:

    1、文件头信息块(BITMAPFILEHEADER)和图像描述信息块(BITMAPINFOHEADER)中的成员应该按照 BMP 文件格式的要求进行对齐。对于结构体成员变量,编译器会默认进行字节对齐,但是结构体中不同成员之间的空隙大小需要手动计算。具体而言,BITMAPFILEHEADER 和 BITMAPINFOHEADER 结构体中的成员变量应该按照如下方式进行定义:

    typedef struct tBITMAPFILEHEADER
    {
        WORD bfType; // 文件类型,应该为 0x4d42
        DWORD bfSize; // BMP 文件大小,单位是字节
        WORD bfReserved1; // 保留,必须设置为 0
        WORD bfReserved2; // 保留,必须设置为 0
        DWORD bfOffBits; // 位图数据的起始位置,单位是字节
    } TBH;
    
    typedef struct tBITMAPINFOHEADER
    {
        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
    } TBI;
    
    
    

    2、BMP 文件中的像素数据的存储方式有点复杂。一般而言,像素数据按照行顺序存储,每一行的像素从左到右依次存储,每个像素按照 BGR 顺序依次存储。每一行的像素数应该满足 4 字节对齐(也就是说,每行像素的字节数应该是 4 的倍数),如果不足 4 字节,则需要用 0 填充。在读取像素数据时,需要先计算每行像素占用的字节数(即 biWidth 像素实际像素占用的字节数,如果不足 4 的倍数则需要补齐),然后按照行顺序读取每个像素的 BGR 值。在写入像素数据时,需要按照行顺序写入每个像素的 BGR 值,注意写入时的字节顺序应该是 BGR。

    3、在计算像素灰度直方图时,需要根据像素的 BGR 值进行统计,然后计算各个灰度级别的像素占比。您在代码中使用了浮点数数组来记录灰度级别占比,但是没有将像素灰度值进行归一化,导致计算结果不正确。具体而言,您需要先计算像素总数,然后统计各个灰度级别像素的数量,最后将像素数量除以像素总数即可得到对应的像素占比。

    4、最后一个问题是,您的程序没有对 BMP 文件的读取位置进行正确的设置。在读取 BMP 文件时,需要先读取文件头信息块和图像描述信息块,然后才能读取像素数据。在写入 BMP 文件时,需要先将文件头信息块和图像描述信息块写入文件,然后才能写入像素数据。因此,在读取和写入文件时需要使用 fseek 函数来设置读取/写入位置。

    修改后的代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    typedef unsigned char BYTE;  // 定义BYTE为一个字节的类型
    typedef unsigned short WORD; // 定义WORD为两个字节的类型
    typedef unsigned int DWORD;  // 定义DWORD为四个字节的类型
    
    #pragma pack(push, 1) // 取消对齐
    
    //14 Bytes 文件头信息块
    typedef struct tBITMAPFILEHEADER
    {
        WORD bfType;        // 文件类型,应该为 0x4d42
        DWORD bfSize;       // BMP 文件大小,单位是字节
        WORD bfReserved1;   // 保留,必须设置为 0
        WORD bfReserved2;   // 保留,必须设置为 0
        DWORD bfOffBits;    // 位图数据的起始位置,单位是字节
    } TBH;
    
    //40 Bytes 图像描述信息块
    typedef struct tBITMAPINFOHEADER
    {
        DWORD biSize;            // 信息头大小,一般为 40 字节
        int32_t biWidth;         // 图像宽度,单位是像素
        int32_t biHeight;        // 图像高度,单位是像素,如果是正数,表示图像自下向上排列;如果是负数,表示图像自上向下排列
        WORD biPlanes;           // 图像数据平面数,一般设置为 1
        WORD biBitCount;         // 图像数据位数,一般设置为 24
        DWORD biCompression;     // 图像压缩类型,一般设置为 0
        DWORD biSizeImage;       // 图像数据大小,单位是字节
        int32_t biXPelsPerMeter; // 水平分辨率,单位是像素/米
        int32_t biYPelsPerMeter; // 垂直分辨率,单位是像素/米
        DWORD biClrUsed;         // 颜色表中实际使用的颜色数,一般为 0
        DWORD biClrImportant;    // 颜色表中重要的颜色数,一般为 0
    } TBI;
    
    typedef struct PerPixelgbr
    {
        BYTE b;
        BYTE g;
        BYTE r;
    } BGR;
    
    int main()
    {
        FILE* in;
        FILE* out;
        TBH BITMAPFILEHEADER;
        TBI BITMAPINFOHEADER;
        BGR* pixels;
    
        fopen_s(&in, "input.bmp", "rb");
        if (!in) {
            printf("Error opening input file!\n");
            return 1;
        }
    
        // 读取文件头信息块
        fread(&BITMAPFILEHEADER, sizeof(TBH), 1, in);
        if (BITMAPFILEHEADER.bfType != 0x4d42) {
            printf("Error: Not a BMP file!\n");
            fclose(in);
            return 1;
        }
    
        // 读取图像描述信息块
        fread(&BITMAPINFOHEADER, sizeof(TBI), 1, in);
    
        // 计算像素数据大小
        uint32_t imageSize = BITMAPINFOHEADER.biWidth * BITMAPINFOHEADER.biHeight * 3;
        // 计算每行字节对齐所需的填充字节数
    uint32_t paddingSize = (4 - (imageSize % 4)) % 4;
    
    // 分配像素数据缓存区
    pixels = (BGR*)malloc(imageSize);
    
    // 读取像素数据
    fread(pixels, 1, imageSize, in);
    
    fclose(in);
    
    // 对每个通道进行直方图均衡化
    uint32_t B_ZFT[256] = { 0 }, G_ZFT[256] = { 0 }, R_ZFT[256] = { 0 };
    double B_GL[256], G_GL[256], R_GL[256];
    
    for (int i = 0; i < BITMAPINFOHEADER.biWidth * BITMAPINFOHEADER.biHeight; i++)
    {
        B_ZFT[pixels[i].b]++;
        G_ZFT[pixels[i].g]++;
        R_ZFT[pixels[i].r]++;
    }
    
    double gailvhe = 0;
    for (int i = 0; i < 256; i++)
    {
        gailvhe += (double)B_ZFT[i] / ((double)BITMAPINFOHEADER.biWidth * (double)BITMAPINFOHEADER.biHeight);
        B_GL[i] = gailvhe;
    }
    gailvhe = 0;
    for (int i = 0; i < 256; i++)
    {
        gailvhe += (double)G_ZFT[i] / ((double)BITMAPINFOHEADER.biWidth * (double)BITMAPINFOHEADER.biHeight);
        G_GL[i] = gailvhe;
    }
    gailvhe = 0;
    for (int i = 0; i < 256; i++)
    {
        gailvhe += (double)R_ZFT[i] / ((double)BITMAPINFOHEADER.biWidth * (double)BITMAPINFOHEADER.biHeight);
        R_GL[i] = gailvhe;
    }
    
    uint32_t B_CS[256], G_CS[256], R_CS[256];
    for (int i = 0; i < 256; i++)
    {
        B_CS[i] = (uint32_t)(B_GL[i] * 255);
        G_CS[i] = (uint32_t)(G_GL[i] * 255);
        R_CS[i] = (uint32_t)(R_GL[i] * 255);
    }
    
    // 创建输出文件
    fopen_s(&out, "output.bmp", "wb");
    if (!out) {
        printf("Error creating output file!\n");
        free(pixels);
        return 1;
    }
    
    // 写入文件头信息块
    fwrite(&BITMAPFILEHEADER, sizeof(TBH), 1, out);
    
    // 写入图像描述信息块
    fwrite(&BITMAPINFOHEADER, sizeof(TBI), 1, out);
    
    // 写入像素数据
    for (int i = 0; i < BITMAPINFOHEADER.biWidth * BITMAPINFOHEADER.biHeight; i++)
    {
        pixels[i].b = B_CS[pixels[i].b];
        pixels[i].g = G_CS[pixels[i].g];
        pixels[i].r = R_CS[pixels[i].r];
    }
    
    fwrite(pixels, 1, imageSize, out);
    
    // 写入填充字节
    BYTE padding[3] = { 0 };
    for (int i = 0; i < paddingSize; i++) {
        fwrite(padding, 1, 1, out);
    }
    
    fclose(out);
    free(pixels);
    
    printf("Done!\n");
    return 0;
    }
    
    
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 3月12日
  • 已采纳回答 3月4日
  • 创建了问题 3月4日

悬赏问题

  • ¥15 ansys fluent计算闪退
  • ¥15 有关wireshark抓包的问题
  • ¥15 需要写计算过程,不要写代码,求解答,数据都在图上
  • ¥15 向数据表用newid方式插入GUID问题
  • ¥15 multisim电路设计
  • ¥20 用keil,写代码解决两个问题,用库函数
  • ¥50 ID中开关量采样信号通道、以及程序流程的设计
  • ¥15 U-Mamba/nnunetv2固定随机数种子
  • ¥15 vba使用jmail发送邮件正文里面怎么加图片
  • ¥15 vb6.0如何向数据库中添加自动生成的字段数据。