C语言实现BMP图像处理(彩色图转灰度图)

我们知道真彩图不带调色板,每个象素用 3 个字节,表示 R、G、B 三个分量。所以处理很简单,根据 R、G、B 的值求出 Y 值后,将 R、G、B 值都赋值成 Y,写入新图即可。 在YUV 的颜色表示方法中,Y 分量的物理含义就是亮度,它含了灰度图(grayscale)的所有信息,只用 Y 分量就完全能够表示出一幅灰度图来。YUV 和RGB 之间有着如下的对应关系:

                                                                     

再来看看带调色板的彩色图,我们知道位图中的数据只是对应调色板中的一个索引值,我们只需要将调色板中的彩色变成灰度,形成新调色板,而位图数据不用动,就可以了。

以上解释来自于:《数字图像处理编程入门》,代码参考:https://blog.csdn.net/u011450295/article/details/37350011


#include<stdio.h>
#include<windows.h>

int main(int argc, char* argv[])
{
	int bmpHeight;
	int bmpWidth;
	unsigned char *pBmpBuf;
	RGBQUAD *pColorTable;
	int biBitCount;

	//读取bmp文件
	FILE *fp = fopen("./02.bmp", "rb");
	if (fp == 0)
		return 0;
	fseek(fp, sizeof(BITMAPFILEHEADER), 0);

	BITMAPINFOHEADER head;
	fread(&head, 40, 1, fp);
	bmpHeight = head.biHeight;
	bmpWidth = head.biWidth;
	biBitCount = head.biBitCount;

	fseek(fp, sizeof(RGBQUAD), 1);

	int LineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;//保证每一行字节数都为4的整数倍
	pBmpBuf = new unsigned char[LineByte*bmpHeight];
	fread(pBmpBuf, LineByte*bmpHeight, 1, fp);
	fclose(fp);

	//将24位真彩图灰度化并保存
	FILE *fp1 = fopen("gray.bmp", "wb");
	if (fp1 == 0)
		return 0;
	int LineByte1 = (bmpWidth * 8 / 8 + 3) / 4 * 4;

	//修改文件头,其中有两项需要修改,分别为bfSize和bfOffBits
	BITMAPFILEHEADER bfhead;
	bfhead.bfType = 0x4D42;
	bfhead.bfSize = 14 + 40 + 256 * sizeof(RGBQUAD)+LineByte1*bmpHeight;//修改文件大小
	bfhead.bfReserved1 = 0;
	bfhead.bfReserved2 = 0;
	bfhead.bfOffBits = 14 + 40 + 256 * sizeof(RGBQUAD);//修改偏移字节数
	fwrite(&bfhead, 14, 1, fp1);    //将修改后的文件头存入fp1;

	//修改信息头,其中有两项需要修改,1个位biBitCount:真彩图为24 ,应改成8;另一个是biSizeImage:由于每像素所占位数的变化,所以位图数据的大小发生变化
	BITMAPINFOHEADER head1;
	head1.biBitCount = 8;    //将每像素的位数改为8
	head1.biClrImportant = 0;
	head1.biCompression = 0;
	head1.biClrUsed = 0;
	head1.biHeight = bmpHeight;
	head1.biWidth = bmpWidth;
	head1.biPlanes = 1;
	head1.biSize = 40;
	head1.biSizeImage = LineByte1*bmpHeight;//修改位图数据的大小
	head1.biXPelsPerMeter = 0;
	head1.biYPelsPerMeter = 0;
	fwrite(&head1, 40, 1, fp1);  //将修改后的信息头存入fp1;

	pColorTable = new RGBQUAD[256];
	for (int i = 0; i < 256; i++){
		pColorTable[i].rgbRed = i;
		pColorTable[i].rgbGreen = i;
		pColorTable[i].rgbBlue = i; //是颜色表里的B、G、R分量都相等,且等于索引值
	}
	fwrite(pColorTable, sizeof(RGBQUAD), 256, fp1); //将颜色表写入fp1;

	//写位图数据
	unsigned char *pBmpBuf1;
	pBmpBuf1 = new unsigned char[LineByte1*bmpHeight];
	for (int i = 0; i < bmpHeight; i++){
		for (int j = 0; j<bmpWidth; j++){
			unsigned char *pb1, *pb2;
			pb1 = pBmpBuf + i*LineByte + j * 3;
			int y = *(pb1)*0.299 + *(pb1 + 1)*0.587 + *(pb1 + 2)*0.114;   //将每一个像素都按公式y=B*0.299+G*0.587+R*0.114进行转化
			pb2 = pBmpBuf1 + i*LineByte1 + j;
			*pb2 = y;
		}
	}
	fwrite(pBmpBuf1, LineByte1*bmpHeight, 1, fp1);

	fclose(fp1);

	system("pause");
	return 0;
}

实验结果分析:

                               原图                                                                                                 灰度图

                         

实验结果分析:真彩色图不带调色板,而灰度图的调色板为256级。所以在修改调色板时需要将RGB三个分量修改为256级,根据YUV颜色空间中Y分量计算。

后续持续更新用C语言实现图像处理算法,敬请期待,欢迎关注。

  • 18
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
以下是将灰度图像存储为bmp文件的C语言代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <stdint.h> #pragma pack(push, 1) // 禁用对齐 struct bmp_file_header { uint16_t magic_num; // 文件类型标识符 uint32_t size; // 文件大小 uint16_t reserved1; // 保留字段1 uint16_t reserved2; // 保留字段2 uint32_t offset; // 数据偏移量 }; struct bmp_info_header { uint32_t header_size; // 位图信息头大小 int32_t width; // 图像宽度 int32_t height; // 图像高度 uint16_t planes; // 颜色平面数 uint16_t bit_depth; // 颜色位深度 uint32_t compression; // 压缩类型 uint32_t image_size; // 压缩图像大小 int32_t x_resolution; // 水平分辨率 int32_t y_resolution; // 垂直分辨率 uint32_t color_palette; // 调色板颜色数 uint32_t important_colors; // 重要颜色数 }; #pragma pack(pop) // 恢复对齐 int main() { // 读取图像数据 // TODO: 替换成实际的图像数据 uint8_t *data = NULL; int width = 640; int height = 480; // 打开文件,准备写入 FILE *fp = fopen("example.bmp", "wb"); if (!fp) { perror("failed to open file"); exit(1); } // 计算文件大小和数据偏移量 uint32_t image_size = width * height; uint32_t file_size = sizeof(struct bmp_file_header) + sizeof(struct bmp_info_header) + 1024 + image_size; uint32_t offset = sizeof(struct bmp_file_header) + sizeof(struct bmp_info_header) + 1024; // 写入文件头信息 struct bmp_file_header file_header = { .magic_num = 0x4D42, // BM .size = file_size, .reserved1 = 0, .reserved2 = 0, .offset = offset }; fwrite(&file_header, sizeof(file_header), 1, fp); // 写入位图信息头信息 struct bmp_info_header info_header = { .header_size = sizeof(struct bmp_info_header), .width = width, .height = height, .planes = 1, .bit_depth = 8, .compression = 0, .image_size = image_size, .x_resolution = 0, .y_resolution = 0, .color_palette = 256, .important_colors = 0 }; fwrite(&info_header, sizeof(info_header), 1, fp); // 写入调色板信息 uint8_t palette[1024] = {0}; for (int i = 0; i < 256; i++) { palette[i * 4] = i; palette[i * 4 + 1] = i; palette[i * 4 + 2] = i; } fwrite(palette, sizeof(palette), 1, fp); // 写入像素数据 fwrite(data, image_size, 1, fp); // 关闭文件 fclose(fp); // 释放内存 free(data); return 0; } ``` 这段代码使用了C语言的文件读写API和结构体来生成bmp文件头、位图信息头、调色板信息和像素数据,并将它们写入文件。其中,调色板信息使用了灰度调色板,即将256个颜色值(0-255)都设置为相同的灰度值,以便表示灰度图像。如果需要将其他类型的图像存储为bmp文件,可以相应地修改位图信息头和像素数据。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值