作业2、实验二(2)——TGA转YUV

一.实验要求

了解TGA文件的存储格式,将TGA格式文件转换为YUV格式。

二.TGA的文件解析

1.TGA文件头共分为五个部分:TGA文件头、图像/颜色表数据、开发者区域、拓展区域、TGA文件注脚

2.TGA文件头(共18个字节):

字段1:uint8_t idLength 用来存储图像/颜色表数据中的第一个字段图像信息字段的长度

字段2:uint8_t colorMapType 颜色表类型,用来表示颜色表的有无,0表示无调色板,1表示有

字段3:uint8_t ImageType 图像类型

字节内容对应类型
0无图像数据
1无压缩有调色板的图像
2无压缩无调色板的RGB图像
3无压缩黑白图像
9有调色板的RLE编码图像
10有压缩(RLE)RGB真彩图像
11有压缩的黑白图像
32使用Huffman、Delta、RLE编码的有调色板图像
33使用Huffman、Delta、RLE编码的有调色板图像四趟四叉树类型处理

 

字段4:uint16_t FirstColIndex 颜色表首地址

字段5:uint16_t ColorMapLength 颜色表长度

字段6:uint8_t ColorMapPerEnSize 颜色表每个表项占用的位数

字段7:uint16_t FirstX x的起始位置

字段8:uint16_t FirstY y的起始位置

字段9:uint16_t Width 图像宽度

字段10:uint16_t Height 图像高度

字段11:uint8_t IndexDipth 像素深度

字段12:uint8_t ImageDescrip 图像描述符

3.图像/颜色表数据:

字段1:可变长 ImageID 存储图像身份信息,其长度由文件头第一个字段决定

字段2:可变长 ColorMapdata 若文件头字段2为0则该字段不存在,否则由文件头中的字段5和字段6共同决定

字段3:可变长 ImageData 这个字段包含Width*Height个像素,每个像素的格式:用伪彩色表示,则是一个颜色图的一个索引号;真彩图,则是属性,红,绿,蓝顺序的数据;用调配色表示,就是独立的颜色表索引。

*TGA文件中字序为低位在前高位在后,像素存储的起始点为最后一行的第一个像素,即图片左下角像素

*后三个区域本次实验中不需要使用,在此不做说明

三.实验过程

1.游程编码(RLE)的说明:游程编码后的图像数据,数据包有两种类型,第一种类型为连续的不同像素,第二种类型为连续的相同像素,每个包中第一字节作为该包的header,除第一个字节外其余字节为该包的数据data。header的首位为标志位,该位为0则说明该数据包为第一类数据包,该位为1则说明该数据包为第二类数据包。若为第一类数据包,则header中余下7位为连续的不同像素的个数减一,data中存储所有像素的数据,若为第二类数据包,则header中余下7位为连续的相同像素个数减一,data中只存储一遍该相同像素对应的数据。

2.实验代码:

1)tgaheader.h

#include<stdio.h>
#include<stdint.h>
struct TGAHEADER
{
	uint8_t idLength;//存储图像/颜色表数据中的第一个字段图像信息字段的长度
	uint8_t colorMapType;//颜色表类型0表示无颜色表1表示有颜色表
	uint8_t ImageType;//图像类型
	uint16_t FirstColIndex;//颜色表首地址
	uint16_t ColorMapLength;//颜色表长度
	uint8_t ColorMapPerEnSize;//颜色表每个表项占用的位数
	uint16_t FirstX;//x的起始位置
	uint16_t FirstY;//y的起始位置
	uint16_t Width;//图像宽度
	uint16_t Height;//图像高度
	uint8_t IndexDipth;//像素深度
	uint8_t ImageDescrip;//图像描述符
};
void Type0A(FILE* fp_tga,unsigned char* YUV_buffer,int size,int dipth,int height,int width,FILE* fp_rgb,FILE* fp_yuv);



2)type0A.cpp

#include<stdio.h>
static float r0299[256],g0587[256],b0114[256],r01684[256],g03316[256],b05[256],r05[256],g04187[256],b00813[256];
void Table()
{
	for(int i=0;i<256;i++) r0299[i]=0.299*i;
	for(int i=0;i<256;i++) g0587[i]=0.587*i;
	for(int i=0;i<256;i++) b0114[i]=0.114*i;
	for(int i=0;i<256;i++) r01684[i]=0.1684*i;
	for(int i=0;i<256;i++) g03316[i]=0.3316*i;
	for(int i=0;i<256;i++) b05[i]=0.5*i;
	for(int i=0;i<256;i++) r05[i]=0.5*i;
	for(int i=0;i<256;i++) g04187[i]=0.4187*i;
	for(int i=0;i<256;i++) b00813[i]=0.0813*i;
}


void Type0A(FILE* fp_tga,unsigned char* YUV__buffer,int size,int dipth,int height,int width,FILE* fp_rgb,FILE* fp_yuv)
{
	//Table();
	unsigned char data_header;
	int count;
	unsigned char *data,*data_del;
	unsigned char *data_ori;
	data=new unsigned char[size*3];
	data_ori=data;
	data_del=data;
	int size_temp=size;
	while(size_temp>0)
	{
		fread(&data_header,sizeof(unsigned char),1,fp_tga);
		if((data_header&0x80)==0)
		{
			count=data_header+1;
			fread(data,3*sizeof(unsigned char),count,fp_tga);
			data+=3*count;
			size_temp-=count;
		}
		if((data_header&0x80)==0x80)
		{
			count=int(data_header-128+1);
			unsigned char temp[3];
			fread(&temp,3*sizeof(unsigned char),1,fp_tga);
			while(count)
			{
				*(data)=temp[0];
				data++;
				*(data)=temp[1];
				data++;
				*(data)=temp[2];
				data++;
				count--;
				size_temp--;
			}
		}
	}
	/*fwrite(data_ori,3*sizeof(unsigned char),size,fp_rgb);
	fclose(fp_rgb);*/
	unsigned char *data_pseq,*data_pseq_ori;
	data_pseq=new unsigned char[size*3];
	
//将图像上下颠倒(参考了往届同学的写法)
	for(int i=0;i<height;i++)
	{
		for(int j=0;j<width*3;j=j+3)
		{
			data_pseq[i*width*3+j]=data_ori[(height-i-1)*width*3+j];
			data_pseq[i*width*3+j+1]=data_ori[(height-i-1)*width*3+j+1];
			data_pseq[i*width*3+j+2]=data_ori[(height-i-1)*width*3+j+2];
		}
	}
	fwrite(data_pseq_ori,3*sizeof(unsigned char),size,fp_rgb);
	fclose(fp_rgb);
	unsigned char *RGB__buffer;
	RGB__buffer=data_pseq;
//以下为之前RGB转YUV的代码段
	Table();
	unsigned char *b_buffer,*g_buffer,*r_buffer;
	unsigned char *Y_buffer,*U_buffer,*V_buffer;
	unsigned char *u_buffer,*v_buffer;
	unsigned char *pu_up1,*pu_up2,*pv_up1,*pv_up2;
	Y_buffer=YUV__buffer;
	U_buffer=YUV__buffer+height*width;
	V_buffer=YUV__buffer+height*width*5/4;
	u_buffer=new unsigned char[height*width];
	v_buffer=new unsigned char[height*width];
	unsigned char *u_buffer_del,*v_buffer_del;
	u_buffer_del=u_buffer;
	v_buffer_del=v_buffer;
	pu_up1=u_buffer;
	pu_up2=u_buffer+width;
	pv_up1=v_buffer;
	pv_up2=v_buffer+width;
	b_buffer=RGB__buffer;
	g_buffer=RGB__buffer+1;
	r_buffer=RGB__buffer+2;
	unsigned char *pu_buffer,*pv_buffer;
	pu_buffer=u_buffer;
	pv_buffer=v_buffer;
	for(int i=0;i<height;i++)
	{
		for(int j=0;j<width;j++)
		{
			if(r0299[*r_buffer]+g0587[*g_buffer]+b0114[*b_buffer]<0)
				*Y_buffer=(unsigned char)0;
			else
				if(r0299[*r_buffer]+g0587[*g_buffer]+b0114[*b_buffer]>255)
					*Y_buffer=(unsigned char)255;
				else *Y_buffer=unsigned char (r0299[*r_buffer]+g0587[*g_buffer]+b0114[*b_buffer]);
			if(-r01684[*r_buffer]-g03316[*g_buffer]+b05[*b_buffer]<-128)
				*pu_buffer=(unsigned char)0;
			else
				if(-r01684[*r_buffer]-g03316[*g_buffer]+b05[*b_buffer]>128)
					*pu_buffer=(unsigned char)255;
				else *pu_buffer=unsigned char(-r01684[*r_buffer]-g03316[*g_buffer]+b05[*b_buffer]+128);
			if(r05[*r_buffer]-g04187[*g_buffer]-b00813[*b_buffer]<-128)
				*pv_buffer=(unsigned char)0;
			else
				if(r05[*r_buffer]-g04187[*g_buffer]-b00813[*b_buffer]>128)
					*pv_buffer=(unsigned char)255;
				else *pv_buffer=unsigned char(r05[*r_buffer]-g04187[*g_buffer]-b00813[*b_buffer]+128);
			Y_buffer++;
			pu_buffer++;
			pv_buffer++;
			r_buffer+=3;
			g_buffer+=3;
			b_buffer+=3;
		}
	}
	for(int i=0;i<height/2;i++)
	{
		for(int j=0;j<width/2;j++)
		{
			*U_buffer=(*pu_up1+*(pu_up1+1)+*pu_up2+*(pu_up2+1))/4;
			*V_buffer=(*pv_up1+*(pv_up1+1)+*pv_up2+*(pv_up2+1))/4;
			U_buffer++;
			V_buffer++;
			pu_up1+=2;
			pu_up2+=2;
			pv_up1+=2;
			pv_up2+=2;
		}
		if(i!=height/2)
		{
			pu_up1+=width;
			pu_up2+=width;
			pv_up1+=width;
			pv_up2+=width;
		}
	}
	delete[] u_buffer_del;
	delete[] v_buffer_del;

	fwrite(YUV__buffer,3*sizeof(unsigned char),size*3/2,fp_yuv);
	fclose(fp_yuv);

	delete[] data_del;
}

3)主函数

#include<stdio.h>
#include<stdlib.h>
#include"tgaheader.h"
int main(int argc,char** argv)
{
	char *filename_tga,*filename_yuv,*filename_rgb;
	filename_tga=argv[1];
	filename_yuv=argv[2];
	filename_rgb=argv[3];
	unsigned char *YUV_buffer,*Y_buffer,*U_buffer,*V_buffer;
	TGAHEADER header;
	FILE *fp_tga,*fp_yuv,*fp_rgb;
	fp_tga=fopen(filename_tga,"rb");
	fp_yuv=fopen(filename_yuv,"wb");
	fp_rgb=fopen(filename_rgb,"wb");
	fread(&header.idLength,sizeof(uint8_t),1,fp_tga);
	fread(&header.colorMapType,sizeof(uint8_t),1,fp_tga);
	fread(&header.ImageType,sizeof(uint8_t),1,fp_tga);
	fread(&header.FirstColIndex,sizeof(uint16_t),1,fp_tga);
	fread(&header.ColorMapLength,sizeof(uint16_t),1,fp_tga);
	fread(&header.ColorMapPerEnSize,sizeof(uint8_t),1,fp_tga);
	fread(&header.FirstX,sizeof(uint16_t),1,fp_tga);
	fread(&header.FirstY,sizeof(uint16_t),1,fp_tga);
	fread(&header.Width,sizeof(uint16_t),1,fp_tga);
	fread(&header.Height,sizeof(uint16_t),1,fp_tga);
	fread(&header.IndexDipth,sizeof(uint8_t),1,fp_tga);
	fread(&header.ImageDescrip,sizeof(uint8_t),1,fp_tga);
	int size=(header.Height)*(header.Width);
	if(size%4!=0)
	{
		printf("can not change into YUV\n");
		exit(1);
	}
	YUV_buffer=new unsigned char[3*size/2];
	unsigned char *YUV_buffer_del;
	YUV_buffer_del=YUV_buffer;
	Y_buffer=YUV_buffer;
	U_buffer=YUV_buffer+size;
	V_buffer=YUV_buffer+5*size/4;
	int type=header.ImageType;
	if(type==0x0A)
	Type0A(fp_tga,YUV_buffer,size,header.IndexDipth,header.Height,header.Width,fp_rgb,fp_yuv);
	//fwrite(YUV_buffer,sizeof(unsigned char),size*5/4,fp_yuv);
	fclose(fp_tga);
	//fclose(fp_yuv);
	delete[] YUV_buffer_del;
	return 0;
}

四.实验结果

原图:

转换后的图像:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值