实验二(1)——8bit像素深度bmp图片与24bit像素深度bmp图片互转2021-03-20

一.实验要求

编写8bit像素深度bmp图片与24bit像素深度bmp图片互相转换的程序,将给定的8bitbmp图片和24bitbmp图片分别转换为24bitbmp图片和8bitbmp图片,其中24bit转换成8bit时,转换规则及8bitbmp图片的调色板自行设定。

二.实验原理

1.8bit转换为24bit

只需将原8bit图像实际位图数据通过查找调色板获得对应的RGB数值直接写入到24bit图像的实际位图数据中。

2.24bit转换成8bit

先自行设定8bit图像的调色板及24bit转8bit的转换规则,将24bit图像的实际位图数据根据转换规则转换为8bit图像的实际位图数据。

三.实验过程

1.变量名称对应图

2.8bit转换为24bit:

1)24bit实际位图数据的结构

2)完整代码

#include<stdio.h>
#include<Windows.h>
int main(int argc,char** argv)
{
	char *filename_8,*filename_24;
	filename_8=argv[1];
	filename_24=argv[2];
	BITMAPFILEHEADER eight_bit_f,twenty_4_bit_f;
	BITMAPINFOHEADER eight_bit_info,twenty_4_bit_info;
	RGBQUAD eight_color_buffer[256];
	unsigned char *eight_buffer=NULL,*twenty_4_buffer=NULL;//存放实际位图数据
	unsigned char *twenty_4_buffer_wr;
	unsigned char *eight_buffer_del,*twenty_4_buffer_del;
	FILE *fp_8,*fp_24;
	fp_8=fopen(filename_8,"rb");
	fp_24=fopen(filename_24,"wb");
	fread(&eight_bit_f,sizeof(BITMAPFILEHEADER),1,fp_8);
	fread(&eight_bit_info,sizeof(BITMAPINFOHEADER),1,fp_8);
	fread(&eight_color_buffer,sizeof(RGBQUAD),256,fp_8);
	//*需要判断图像大小是否为四字节整数倍(若不是biSizeImage凑整,并且在二进制文件末尾补零,即在图片第一行前补黑电平行,知道行数为4的整数倍)*/
	int size=eight_bit_info.biSizeImage;
	eight_buffer=new unsigned char[size];
	twenty_4_buffer=new unsigned char[3*size];
	if(eight_buffer==NULL||twenty_4_buffer==NULL)
	{
		printf("can not new unsigned char/n");
	}
	int size_arc=size;//实际图片大小
	//判断宽高是否有一个为四的倍数
	if((eight_bit_info.biHeight%4!=0) && (eight_bit_info.biWidth%4!=0))
	{
		size_arc=eight_bit_info.biHeight*eight_bit_info.biWidth;
	}
	fread(eight_buffer,sizeof(unsigned char),size,fp_8);
	twenty_4_buffer_wr=twenty_4_buffer;
	twenty_4_buffer_del=twenty_4_buffer;
	eight_buffer_del=eight_buffer;
	if(eight_bit_f.bfType!=0x4D42)//判断是否为bmp文件(?直接读出的bfType字节序也是反的吗)
	{
		printf("please input .bmp file/n");
	}
	for(int i=0;i<size_arc;i++)
	{
		*(twenty_4_buffer+2)=(eight_color_buffer[*eight_buffer]).rgbRed;
		*(twenty_4_buffer+1)=(eight_color_buffer[*eight_buffer]).rgbGreen;
		*(twenty_4_buffer)=(eight_color_buffer[*eight_buffer]).rgbBlue;
		twenty_4_buffer+=3;
		eight_buffer++;
	}
	//只处理实际宽高对应的像素,补零补成4的倍数
	if(size!=size_arc)
	{
		for(int i=0;i<(size-size_arc);i++)
		{
			*(twenty_4_buffer+2)=*(twenty_4_buffer+1)=*(twenty_4_buffer)=0;
			twenty_4_buffer+=3;
		}
	}
	twenty_4_bit_f.bfType=0x4D42;
	twenty_4_bit_f.bfSize=(14+40+3*size);
	twenty_4_bit_f.bfReserved1=0;
	twenty_4_bit_f.bfReserved2=0;
	twenty_4_bit_f.bfOffBits=14+40;
	twenty_4_bit_info.biSize=40;
	twenty_4_bit_info.biWidth=eight_bit_info.biWidth;
	twenty_4_bit_info.biHeight=eight_bit_info.biHeight;
	twenty_4_bit_info.biBitCount=24;
	twenty_4_bit_info.biPlanes=1;
	twenty_4_bit_info.biCompression=eight_bit_info.biCompression;
	twenty_4_bit_info.biSizeImage=3*eight_bit_info.biSizeImage;
	twenty_4_bit_info.biXPelsPerMeter=eight_bit_info.biXPelsPerMeter;
	twenty_4_bit_info.biYPelsPerMeter=eight_bit_info.biYPelsPerMeter;
	twenty_4_bit_info.biClrUsed=0;
	twenty_4_bit_info.biClrImportant=0;
	fwrite(&twenty_4_bit_f,sizeof(BITMAPFILEHEADER),1,fp_24);
	fwrite(&twenty_4_bit_info,sizeof(BITMAPINFOHEADER),1,fp_24);
	fwrite(twenty_4_buffer_wr,sizeof(unsigned char),3*size,fp_24);
	fclose(fp_8);
	fclose(fp_24);
	delete[] eight_buffer_del;
	delete[] twenty_4_buffer_del;
	return 0;
}

3)注意事项

用windows.h头文件,可直接使用两个header

3.24bit转换为8bit:

1)8bit图像调色板及转换规则的设计

*调色板设计思路:共RGB三个分量,设每个分量有x种取值,故RGB共x^{3}种取值,令x^{3}<256且x^{3}最接近256,可得x=6。R、G、B分别有六种取值,且R、G、B的取值范围都在0~255,故取每个分量六种取值之间的增量为42(42*6=252,最接近256),即以R为例,若24bit图中R取值为0~41则8bit图中R取21,若24bit图中R取值为42~81则8bit图中R取(42+21),以此类推。

*调色盘0~255的划分:

2)关键代码及分析

for(int i=0;i<size_arc;i++)
	{
		int a=(int)*(twenty_4_buffer+2)/42;
		int b=(int)*(twenty_4_buffer+1)/42;
		int c=(int)*(twenty_4_buffer)/42;
		*eight_buffer=a*36+b*6+c;
		eight_buffer++;
		twenty_4_buffer+=3;
	}

twenty_4_bit_buffer指向当前像素的B值,twenty_4_bit_buffer+1指向当前像素的G值,twenty_4_bit_buffer+2指向当前像素的R值,将24bit实际位图数据转换为8bit实际位图数据时先判断R值再判断G值最后判断B值,将调色板看作数组,以R为例,若R值在(0,41)之间,则其对应数据一定在调色板256个数组的前36个数组中,即在上图对应的R1区域中,以此类推。

3)完整代码

#include<stdio.h>
#include<Windows.h>
int main(int argc,char** argv)
{
	char *filename_8,*filename_24;
	filename_8=argv[1];
	filename_24=argv[2];
	BITMAPFILEHEADER eight_bit_f,twenty_4_bit_f;
	BITMAPINFOHEADER eight_bit_info,twenty_4_bit_info;
	RGBQUAD eight_color_buffer[256];
	unsigned char *eight_buffer=NULL,*twenty_4_buffer=NULL;//存放实际位图数据
	unsigned char *eight_buffer_del,*twenty_4_buffer_del;
	unsigned char *eight_buffer_wr;
	FILE *fp_8,*fp_24;
	fp_8=fopen(filename_8,"wb");
	fp_24=fopen(filename_24,"rb");
	fread(&twenty_4_bit_f,sizeof(BITMAPFILEHEADER),1,fp_24);
	fread(&twenty_4_bit_info,sizeof(BITMAPINFOHEADER),1,fp_24);
	//设计8bit调色板
	int color=0;
	for(int r=0;r<6;r++)
	{
		for(int g=0;g<6;g++)
		{
			for(int b=0;b<6;b++)
			{
				eight_color_buffer[color].rgbBlue=b*42+21;
				eight_color_buffer[color].rgbGreen=g*42+21;
				eight_color_buffer[color].rgbRed=r*42+21;
				eight_color_buffer[color].rgbReserved=0;
				color++;
			}
		}
	}
	//218到255之间被浪费
	while(color<256)
	{
		eight_color_buffer[color].rgbBlue=eight_color_buffer[color].rgbGreen=eight_color_buffer[color].rgbRed=eight_color_buffer[color].rgbReserved=0;
		color++;
	}
	int size=twenty_4_bit_info.biSizeImage/3;
	eight_buffer=new unsigned char[size];
	twenty_4_buffer=new unsigned char[3*size];
	eight_buffer_wr=eight_buffer;
	twenty_4_buffer_del=twenty_4_buffer;
	eight_buffer_del=eight_buffer;
	if(eight_buffer==NULL||twenty_4_buffer==NULL)
	{
		printf("can not new unsigned char/n");
	}
	fread(twenty_4_buffer,sizeof(unsigned char),size*3,fp_24);
	int size_arc=size;
	if((twenty_4_bit_info.biHeight%4!=0) && (twenty_4_bit_info.biWidth%4!=0))
	{
		size_arc=twenty_4_bit_info.biHeight*twenty_4_bit_info.biWidth;
	}
	for(int i=0;i<size_arc;i++)
	{
		int a=(int)*(twenty_4_buffer+2)/42;
		int b=(int)*(twenty_4_buffer+1)/42;
		int c=(int)*(twenty_4_buffer)/42;
		*eight_buffer=a*36+b*6+c;
		eight_buffer++;
		twenty_4_buffer+=3;
	}
	if(size!=size_arc)
	{
		for(int i=0;i<(size-size_arc);i++)
		{
			*eight_buffer=0;
			eight_buffer++;
		}
	}
	eight_bit_f.bfType=0x4D42;
	eight_bit_f.bfSize=(14+40+size+256*4);
	eight_bit_f.bfReserved1=0;
	eight_bit_f.bfReserved2=0;
	eight_bit_f.bfOffBits=14+40+256*4;
	eight_bit_info.biSize=40;
	eight_bit_info.biWidth=twenty_4_bit_info.biWidth;
	eight_bit_info.biHeight=twenty_4_bit_info.biHeight;
	eight_bit_info.biPlanes=1;
	eight_bit_info.biBitCount=8;
	eight_bit_info.biCompression=twenty_4_bit_info.biCompression;
	eight_bit_info.biSizeImage=size;
	eight_bit_info.biXPelsPerMeter=twenty_4_bit_info.biXPelsPerMeter;
	eight_bit_info.biYPelsPerMeter=twenty_4_bit_info.biYPelsPerMeter;
	eight_bit_info.biClrUsed=0;
	eight_bit_info.biClrImportant=0;
	fwrite(&eight_bit_f,sizeof(BITMAPFILEHEADER),1,fp_8);
	fwrite(&eight_bit_info,sizeof(BITMAPINFOHEADER),1,fp_8);
	fwrite(&eight_color_buffer,sizeof(RGBQUAD),256,fp_8);
	fwrite(eight_buffer_wr,sizeof(unsigned char),size,fp_8);
	fclose(fp_8);
	fclose(fp_24);
	delete[] eight_buffer_del;
	delete[] twenty_4_buffer_del;
	return 0;
}

四.实验结果

转换生成的24bit图像与上课发的24bit图像对比(左边是发的,右边是8bit转24bit生成的)

转换生成的8bit图像与上课发的8bit图像对比(左边是发的,右边是24bit转8bit生成的)

结果分析:转换生成的图片与课上发的图片在色彩上有细微差别,可能是调色板的设计不同造成的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值