C++实现彩色bmp图片转灰度图

简介

BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。BMP位图文件默认的文件扩展名是BMP或者bmp。

BMP图片格式

BMP文件总体上由4部分组成,分别是位图文件头、位图信息头、调色板和图像数据

位图文件头(bitmap-file header)

BMP文件头数据结构共14个字节,包含以下信息:

typedef struct{
    unsigned short bfType;                            //文件类型,具体值为0x4D42
    int bfSize;                                        //文件大小,以字节为单位
    unsigned short bfReserved1;                       //保留值,必须为0
    unsigned short bfReserved2;                       //保留值,必须为0
    int bfOffBits;                                     //从文件开头到具体图像数据的字节偏移量(具体文件头(14byte)+位图信息头(40byte)+调色板)
}BITMAPFILEHEADER;

位图信息头(bitmap-information header)

图片信息头(40字节)存储着图像的尺寸,颜色索引,位平面数等信息,其结构体包括:


typedef struct{
   unsigned int biSize;                           //位图信息头的大小,均为40字节
   int biWidth;                                    //位图宽度,单位为像素
   int biHeight;                                   //位图高度,单位为像素
   unsigned short biPlanes;                      //位图的平面数,设置为1
   unsigned short biBitCount;                    //像素位数,有1,4,8,16,24,32等
   unsigned int biCompression;                   //位图压缩类型,0为不压缩、1为BI_RLE8、2为BI_RLE4(30-33)
   unsigned int    biSizeImage;                  //图像数据部分大小,等于bfSize-bfOffBits (34-37)
   int     biXPelsPerMeter;                       // 用像素/米表示的水平分辨率
   int     biYPelsPerMeter;                       // 用像素/米表示的垂直分辨率
   unsigned int    biClrUsed;                    // 调色板中的颜色索引数,0为图片有调色板
   unsigned int    biClrImportant;               // 重要颜色索引的数目,0表示都重要(50-53)
}BITMAPINFOHEADER;

彩色表/调色板(color table)

调色板,由颜色索引数决定【可以没有该项数据结构】

typedef struct
{
    unsigned char rgbBlue;  //蓝色分量亮度
    unsigned char rgbGreen; //绿色分量亮度
    unsigned char rgbRed;   //红色分量亮度
    unsigned char rgbReserved;
}RGBQUAD;

位图数据(bitmap-data)

位图数据记录了位图的每一个像素值。
像素是从下到上、从左到右保存的
每个像素使用一个或者多个字节表示。
如果一个图像水平线的字节数不是4的倍数,这行就使用空字节补齐,通常是ASCII码0。
如果图片是24位的彩色图,则RGB的顺序为B0G0R0B1G1R1…。

代码编写

本代码实现彩色图转灰度图的功能。

#include
#pragma pack(1)
typedef struct{
    unsigned short bfType;                            //文件类型,具体值为0x4D42
    int bfSize;                                        //文件大小,以字节为单位
    unsigned short bfReserved1;                       //保留值,必须为0
    unsigned short bfReserved2;                       //保留值,必须为0
    int bfOffBits;                                     //从文件开头到具体图像数据的字节偏移量(具体文件头(14byte)+位图信息头(40byte)+调色板)
}BITMAPFILEHEADER;

typedef struct{
   unsigned int biSize;                           //位图信息头的大小,均为40字节
   int biWidth;                                    //位图宽度,单位为像素
   int biHeight;                                   //位图高度,单位为像素
   unsigned short biPlanes;                      //位图的平面数,设置为1
   unsigned short biBitCount;                    //像素位数,有1,4,8,16,24,32等
   unsigned int biCompression;                   //位图压缩类型,0为不压缩、1为BI_RLE8、2为BI_RLE4(30-33)
   unsigned int    biSizeImage;                  //图像数据部分大小,等于bfSize-bfOffBits (34-37)
   int     biXPelsPerMeter;                       // 用像素/米表示的水平分辨率
   int     biYPelsPerMeter;                       // 用像素/米表示的垂直分辨率
   unsigned int    biClrUsed;                    // 调色板中的颜色索引数,0为图片有调色板
   unsigned int    biClrImportant;               // 重要颜色索引的数目,0表示都重要(50-53)
}BITMAPINFOHEADER;

typedef struct
{
    unsigned char rgbBlue;  //蓝色分量亮度
    unsigned char rgbGreen; //绿色分量亮度
    unsigned char rgbRed;   //红色分量亮度
    unsigned char rgbReserved;
}RGBQUAD;

void showbmp(BITMAPFILEHEADER bmp){
   printf("****************************************文件头信息打印*******************************************************\n");
   printf("文件类型:%x\n",bmp.bfType);
   printf("文件大小=%d\n",bmp.bfSize);
   printf("文件保留值1=%d\n",bmp.bfReserved1);
   printf("文件保留值2=%d\n",bmp.bfReserved2);
   printf("文件信息区的大小=%d\n",bmp.bfOffBits);
}

void showbmpinfo(BITMAPINFOHEADER info){
   printf("结构体大小=%d\n",info.biSize);
   printf("图像宽=%d\n",info.biWidth);
   printf("图像高=%d\n",info.biHeight);
   printf("图像位面数=%d\n",info.biPlanes);
   printf("像素位数=%d\n",info.biBitCount);
   printf("位图压缩类型:%d\n",info.biCompression);
   printf("图像数据部分大小:%d\n",info.biSizeImage);
   printf("水平分辨率:%d\n",info.biXPelsPerMeter);
   printf("垂直分辨率:%d\n",info.biYPelsPerMeter);
   printf("位图颜色表中的颜色数:%d\n",info.biClrUsed);
   printf("重要颜色索引的数目:%d\n",info.biClrImportant);
}

int main(){
    BITMAPFILEHEADER bmp;
    BITMAPINFOHEADER bmp_info;
    //
    FILE* fp1;
    FILE* fp2;
    fp1=fopen("C:\\Users\\qjm\\Desktop\\test.bmp","rb");
    fread(&bmp,14,1,fp1);
    fread(&bmp_info,40,1,fp1);
    //show infomation
    showbmp(bmp);
    showbmpinfo(bmp_info);
    //
    int lineByte=(bmp_info.biWidth*3+3)/4*4;                 //4字节对齐后一行的字节数,单位字节
    int lineByte_gray=(bmp_info.biWidth+3)/4*4;
    printf("lineByte=%d\n",lineByte);
    printf("lineByte_gray=%d\n",lineByte_gray);
    //
    unsigned char* src_img=new unsigned char[bmp_info.biSizeImage];
    unsigned char* dest_img=new unsigned char[bmp_info.biSizeImage/3];
    fread(src_img,1,bmp_info.biSizeImage,fp1);
    for(int i=0;i<bmp_info.biHeight;i++)
        for(int j=0;j<bmp_info.biWidth;j++){
            unsigned char b=src_img[i*lineByte+j*3+0];
            unsigned char g=src_img[i*lineByte+j*3+1];
            unsigned char r=src_img[i*lineByte+j*3+2];
            unsigned char gray=((unsigned int)r+(unsigned int)g+(unsigned int)b)/3;
            dest_img[i*lineByte_gray+j]=gray;
    }
    fclose(fp1);
    //
    printf("****************************************************************\n");
    RGBQUAD* pRgbQuards=new RGBQUAD[256];
	for(int i=0;i<256;i++)
	{
		pRgbQuards[i].rgbBlue=i;
		pRgbQuards[i].rgbRed=i;
		pRgbQuards[i].rgbGreen=i;

	}
    fp2=fopen("C:\\Users\\qjm\\Desktop\\test_out.bmp","wb");
    bmp_info.biBitCount=24/3;
    bmp_info.biSizeImage=bmp_info.biSizeImage/3;
    bmp.bfOffBits=14+40+256*sizeof(RGBQUAD);                         //增加了颜色表
    bmp.bfSize=bmp.bfOffBits+bmp_info.biSizeImage;
    //
    showbmp(bmp);
    showbmpinfo(bmp_info);
    //
    fwrite(&bmp,1,14,fp2);
    fwrite(&bmp_info,1,40,fp2);
    fwrite(pRgbQuards,1,256*sizeof(RGBQUAD),fp2);
    fwrite(dest_img,1,bmp_info.biSizeImage,fp2);
    fclose(fp2);
    return 0;
}

待测试图片:
在这里插入图片描述
转灰度图后的效果:
在这里插入图片描述

你可能感兴趣的:(算法,c/c++,c++,开发语言)