南宫上天 2023-03-04 09: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 09: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;
    }
    
    
    

    展开全部

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
    南宫上天 2023-03-04 09:43

    谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢 谢谢谢谢

    回复
    南宫上天 回复 南宫上天 2023-03-04 09:53

    不过这个只能处理长宽相等的,能改进下吗

    回复
    南宫上天 2023-03-04 09:54

    不过这个只能处理长宽相等的,能改进下吗

    回复
    展开全部6条评论
查看更多回答(2条)
编辑
预览

报告相同问题?

问题事件

  • 系统已结题 3月11日
  • 已采纳回答 3月4日
  • 创建了问题 3月4日
手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部