c语言32位变为灰度图,C++ C语言 读取32位BMP图片转为8位灰度图

BMP格式详细介绍链接:

BMP格式详解

BMP格式总结:

① 前14字节描述文件类型,大小,数据偏移

② 接着的40字节描述图片的大小,宽度,高度,位深度,分辨率等等

③ 位深度常见的是1,4,8,24,32。其中1表示只有黑白两种颜色,4是16色,8是256色,24是RGB形式表示的,32是在24的基础上加上透明度的RGBA表示。

④ 目前常见的彩色图片位24位或32位,8位一般为灰度图

⑤ 如果是8位图(256色),40字节的图片描述后面会有颜色表,描述图片上256种颜色的RGBA值。灰度图的第 i 种颜色的RGB值均为 i ,A值为0。

⑥由于windows默认的扫描最小单位是4字节,所以BMP格式为了能够更快地按行读取,如果每行的字节数不是4的倍数,会在后面补0直到长度为4的倍数。可以简单地得知,32位图不需要对齐。(对齐规则)

PS:如果用fread整体读入BMP文件信息和图片信息,可能由于 内存对齐 的原因,读入的信息可能存放不到内存里预期的地方,下面的代码实现种用#pragma pack(1)解决由于内存对齐产生的问题

简单的实现代码:

#include #include #include #include using namespace std;

//设置内存对齐

#pragma pack(1)

typedef struct tag_color_32{

BYTE Red;

BYTE Green;

BYTE Blue;

BYTE Alpha;

} color_32;

int main(int argc,char** argv){

FILE *fp,*out; // 定义一个文件指针

BITMAPFILEHEADER bmpFileHeader; // 定义一个 BMP 文件头的结构体

BITMAPINFOHEADER bmpInfo; // 定义一个 BMP 文件信息结构体

string s(argv[1]);

s = s + "tmp.bmp";

FILE *out = fopen(s.c_str(),"wb");

if((fp = fopen(argv[1], "rb")) == NULL)

{

printf("Cann't open the file!\n");

return 0;

}

fseek(fp, 0, SEEK_SET);

fread(&bmpFileHeader,14,1,fp);

fread(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, fp);

// 输出BMP文件的位图文件头的所有信息

printf("位图文件头主要是对位图文件的一些描述:BMPFileHeader\n\n");

printf("文件标识符 = 0X%X\n", bmpFileHeader.bfType);

printf("BMP 文件大小 = %d 字节\n", bmpFileHeader.bfSize);

printf("保留值1 = %d \n", bmpFileHeader.bfReserved1);

printf("保留值2 = %d \n", bmpFileHeader.bfReserved2);

printf("文件头到图像数据位开始的偏移量 = %d 字节\n", bmpFileHeader.bfOffBits);

// 输出BMP文件的位图信息头的所有信息

printf("\n\n位图信息头主要是对位图图像方面信息的描述:BMPInfo\n\n");

printf("信息头的大小 = %d 字节\n", bmpInfo.biSize);

printf("位图的高度 = %d \n", bmpInfo.biHeight);

printf("位图的宽度 = %d \n", bmpInfo.biWidth);

printf("图像的位面数(位面数是调色板的数量,默认为1个调色板) = %d \n", bmpInfo.biPlanes);

printf("每个像素的位数 = %d 位\n", bmpInfo.biBitCount);

printf("压缩类型 = %d \n", bmpInfo.biCompression);

printf("图像的大小 = %d 字节\n", bmpInfo.biSizeImage);

printf("水平分辨率 = %d \n", bmpInfo.biXPelsPerMeter);

printf("垂直分辨率 = %d \n", bmpInfo.biYPelsPerMeter);

printf("使用的色彩数 = %d \n", bmpInfo.biClrUsed);

printf("重要的色彩数 = %d \n", bmpInfo.biClrImportant);

printf("\n\n\n压缩说明:有0(不压缩),1(RLE 8,8位RLE压缩),2(RLE 4,4位RLE压缩,3(Bitfields,位域存放)");

//32位色图

if(bmpInfo.biBitCount == 32){

int Height = bmpInfo.biHeight;

int Width = bmpInfo.biWidth;

bool reverse = false;

if(Height < 0){

reverse = true;

Height *= -1;

}

color_32 *pixels;

pixels = new color_32[Height*Width];

//fseek(fp,bmpFileHeader.bfOffBits,SEEK_SET);

for(int i = 0;i < Height * Width;i++)

fread(pixels+i,4,1,fp);

//设置文件头

bmpInfo.biBitCount = 8;

bmpInfo.biClrUsed = 256;

//灰度图颜色表

RGBQUAD pRGB[256];

for(int i = 0;i < 256;i++){

pRGB[i].rgbRed = i;

pRGB[i].rgbGreen = i;

pRGB[i].rgbBlue = i;

pRGB[i].rgbReserved = 0;

}

bmpFileHeader.bfOffBits = 54 + 4 * 256;

//考虑对齐规则 计算每一行的字节数

int LineByte = ((bmpInfo.biBitCount / 8 * Width + 3) / 4) * 4;

bmpFileHeader.bfSize = 54 + 4 * 256 + Height * LineByte;

//写入新的文件

fseek(out,0,SEEK_SET);

fwrite(&bmpFileHeader,14,1,out);

fwrite(&bmpInfo,40,1,out);

fwrite(&pRGB,4*256,1,out);

for(int i = 0;i < Height;i++){

for(int j = 0;j < Width;j++){

float pr = pixels[i*Width + j].Red;

float pg = pixels[i*Width + j].Green;

float pb = pixels[i*Width + j].Blue;

//提取灰度低的黑色部分

BYTE data = pr * 0.299 + pg * 0.587 + pb * 0.114;

if((pr - pg) > 5 || (pr - pb) > 5) data = 255;

data = data < 25 ? 0 : 255;

fwrite(&data,1,1,out);

}

for(int j = Width;j < LineByte;j++){

BYTE data = 0;

fwrite(&data,1,1,out);

}

}

}

fclose(out);

fclose(fp);

while(1);

return 0;

}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值