【转】BMP真彩图转化为灰度图处理方法

      感谢大神无私分享 https://blog.csdn.net/oier_xcj/article/details/77511342

BMP图像文件信息

BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式。
典型的BMP图像文件由四部分组成:
1:BMP文件头(14字节)
  BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

typedef struct tagBITMAPFILEHEADER
{
    WORD bfType;//位图文件的类型,必须为BM(1-2字节)
    DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)
    WORD bfReserved1;//位图文件保留字,必须为0(7-8字节)
    WORD bfReserved2;//位图文件保留字,必须为0(9-10字节)
    DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前)
    //文件头的偏移量表示,以字节为单位
}__attribute__((packed)) BITMAPFILEHEADER;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2:位图信息头(40字节)
  BMP位图信息头数据用于说明位图的尺寸等信息。

typedef struct tagBITMAPINFOHEADER
{
    DWORD biSize;//本结构所占用字节数(15-18字节)
    LONG biWidth;//位图的宽度,以像素为单位(19-22字节)
    LONG biHeight;//位图的高度,以像素为单位(23-26字节)
    WORD biPlanes;//目标设备的级别,必须为1(27-28字节)
    WORD biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节)
    //4(16色),8(256色)16(高彩色)或24(真彩色)之一
    DWORD biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节)
    //1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
    DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)
    LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)
    LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
    DWORD biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节)
    DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节)
}__attribute__((packed)) BITMAPINFOHEADER;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3:颜色表
  颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD
{
    BYTE rgbBlue;//蓝色的亮度(值范围为0-255)
    BYTE rgbGreen;//绿色的亮度(值范围为0-255)
    BYTE rgbRed;//红色的亮度(值范围为0-255)
    BYTE rgbReserved;//保留,必须为0
}__attribute__((packed)) RGBQUAD;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
  当biBitCount=1,4,8时,分别有2,16,256个表项;
  当biBitCount=24时,没有颜色表项。

4:位图数据
  位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
  当biBitCount=1时,8个像素占1个字节;
  当biBitCount=4时,2个像素占1个字节;
  当biBitCount=8时,1个像素占1个字节;
  当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;
  Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充。

BMP图像灰度化处理程序

#include
#include
#include

/*
位图头结构
*/
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER
{
    unsigned char bfType[2];//文件格式
    unsigned long bfSize;//文件大小
    unsigned short bfReserved1;//保留
    unsigned short bfReserved2;
    unsigned long bfOffBits; //DIB数据在文件中的偏移量
}fileHeader;
#pragma pack()

/*
位图数据信息结构
*/
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER
{
    unsigned long biSize;//该结构的大小
    long biWidth;//文件宽度
    long biHeight;//文件高度
    unsigned short biPlanes;//平面数
    unsigned short biBitCount;//颜色位数
    unsigned long biCompression;//压缩类型
    unsigned long biSizeImage;//DIB数据区大小
    long biXPixPerMeter;
    long biYPixPerMeter;
    unsigned long biClrUsed;//多少颜色索引表
    unsigned long biClrImporant;//多少重要颜色
}fileInfo;
#pragma pack()

/*
调色板结构
*/
#pragma pack(1)
typedef struct tagRGBQUAD
{
    unsigned char rgbBlue; //蓝色分量亮度
    unsigned char rgbGreen;//绿色分量亮度
    unsigned char rgbRed;//红色分量亮度
    unsigned char rgbReserved;
}rgbq;
#pragma pack()

int main()
{
    /*存储RGB图像的一行像素点*/
    unsigned char ImgData[3000][3];
    /*将灰度图的像素存到一个一维数组中*/
    unsigned char ImgData2[3000];
    int i,j,k;
    FILE * fpBMP,* fpGray;
    fileHeader * fh;
    fileInfo * fi;
    rgbq * fq;
    char filename1[20],filename2[20];

    printf("输入图像文件名:");
    scanf("%s",filename1);
    if((fpBMP=fopen(filename1,"rb"))==NULL)
    {
        printf("打开文件失败");
        exit(0);
    }
    printf("输出图像文件名:");
    scanf("%s",filename2);
    if((fpGray=fopen(filename2,"wb"))==NULL)
    {
        printf("创建文件失败");
        exit(0);
    }

    fh=(fileHeader *)malloc(sizeof(fileHeader));
    fi=(fileInfo *)malloc(sizeof(fileInfo));
    //读取位图头结构和信息头
    fread(fh,sizeof(fileHeader),1,fpBMP);
    fread(fi,sizeof(fileInfo),1,fpBMP);
    //修改头信息
    fi->biBitCount=8;
    fi->biSizeImage=( (fi->biWidth*3+3)/4 ) * 4*fi->biHeight;
    //fi->biClrUsed=256;

    fh->bfOffBits = sizeof(fileHeader)+sizeof(fileInfo)+256*sizeof(rgbq);
    fh->bfSize = fh->bfOffBits + fi->biSizeImage;

    //创建调色版
    fq=(rgbq *)malloc(256*sizeof(rgbq));
    for(i=0;i<256;i++)
    {
        fq[i].rgbBlue=fq[i].rgbGreen=fq[i].rgbRed=i;
        //fq[i].rgbReserved=0;
    }
    //将头信息写入
    fwrite(fh,sizeof(fileHeader),1,fpGray);
    fwrite(fi,sizeof(fileInfo),1,fpGray);
    fwrite(fq,sizeof(rgbq),256,fpGray);
    //读取RGB图像素并转换为灰度值
    for ( i=0;ibiHeight;i++ )
    {
        for(j=0;j<(fi->biWidth+3)/4*4;j++)
        {
            for(k=0;k<3;k++)
                fread(&ImgData[j][k],1,1,fpBMP);
        }
        for(j=0;j<(fi->biWidth+3)/4*4;j++)
        {
            ImgData2[j]=int( (float)ImgData[j][0] * 0.114 +
                        (float)ImgData[j][1] * 0.587 +
                        (float)ImgData[j][2] * 0.299 );
        }
        //将灰度图信息写入
        fwrite(ImgData2,j,1,fpGray);
    }

        free(fh);
        free(fi);
        free(fq);
        fclose(fpBMP);
        fclose(fpGray);
        printf("success\n");
        return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129

测试结果

原图
【转】BMP真彩图转化为灰度图处理方法_第1张图片
灰度处理图像
【转】BMP真彩图转化为灰度图处理方法_第2张图片

你可能感兴趣的:(【转】BMP真彩图转化为灰度图处理方法)