因为之前分析的PNG格式文件数据有压缩,不太好提取数据,所以这一次尝试将TGA格式的文件转化为YUV格式的文件。
TGA文件的文件头中包括图片类型、图片的宽高数据、每像素占用的bit位数等数据,本次的转化程序只支持图片类型为2也就是无压缩无调色板数据的TGA文件,并且每像素占用的bit位数为24位。
程序的设计思路是:
1、先建立一个TGA文件的头文件结构体,用于读取头文件数据。
2、从头文件中获得图片长宽数据,因为只支持类型为2的文件,在无调色板无图像信息的情况下,数据的偏移量固定为18。
3、定好偏移量后,因为TGA文件的数据是从左下角读入,也就是图片的上下是颠倒的,读取RGB数据时需要将图片正向读入。
4、之前写过RGB2YUV的程序,因此在读入RGB数据后,可以直接调用转化为YUV图像。
程序如下:
头文件结构体函数:
#ifndef HEAD_DEFINE_H_INCLUDED
#define HEAD_DEFINE_H_INCLUDED
typedef struct{
char IDlength = 0;
char Colormaptype = 0;
char Imagetypecode = 0;
short Colormapoffset = 0;
short Colormaplength = 0;
char Colormapdepth = 0;
short Xorigin = 0;
short Yorigin = 0;
short Width = 0;
short Height = 0;
char Bitsperpixel = 0;
char Imagedescriptor = 0;
}Headfile;
void initialHeadfile(unsigned char* buffer, Headfile* H){
H->IDlength = buffer[0];
H->Colormaptype = buffer[1];
H->Imagetypecode = buffer[2];
H->Colormapoffset = (buffer[3]<<4) + buffer[4];
H->Colormaplength = (buffer[5]<<4) + buffer[6];
H->Colormapdepth = buffer[7];
H->Xorigin = (buffer[8]<<4) + buffer[9];
H->Yorigin = (buffer[10]<<4) + buffer[11];
H->Width = (buffer[13]*256) + buffer[12];
H->Height = (buffer[15]*256) + buffer[14];
H->Bitsperpixel = buffer[16];
H->Imagedescriptor = buffer[17];
}
#endif // HEAD_DEFINE_H_INCLUDED
RGB2YUV文件如下:
#ifndef RGB2YUV_H_INCLUDED
#define RGB2YUV_H_INCLUDED
#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
using namespace std;
void transf(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* rgb, FILE* out, int W, int H){
unsigned char* ybuffer = new unsigned char[W*H];
unsigned char* ubuffer = new unsigned char[W*H/4];
unsigned char* vbuffer = new unsigned char[W*H/4];
unsigned char* u444buffer = new unsigned char[W*H];
unsigned char* v444buffer = new unsigned char[W*H];
int i;
int j;
int coun=0;
for(i = 0; i < W*H; i++){
b[i] = rgb[3*i];
g[i] = rgb[3*i+1];
r[i] = rgb[3*i+2];
}
for(i = 0; i < W*H; i++){
ybuffer[i] = ((66*r[i] + 129*g[i] + 25*b[i]) >> 8) + 16;
u444buffer[i] = ((-38*r[i] - 74*g[i] + 112*b[i]) >> 8) + 128;
v444buffer[i] = ((112*r[i] - 94*g[i] - 18*b[i]) >> 8) + 128;
}
for (int i = 0; i < H; i += 2)
{
for (int j = 0; j < W; j += 2)
{
ubuffer[i/2*W/2 + j/2] = u444buffer[i * W + j];
vbuffer[i/2*W/2 + j/2] = v444buffer[i * W + j];
}
}
//for(i = 0; i < H; i++){
// for(j = 0; j < W; j++){
// ybuffer[i*W+j] = ((66*r[i*W+j] + 129*g[i*W+j] + 25*b[i*W+j]) >> 8) + 16;
// if((!(i%2))&&(!(j%2))){
// ubuffer[coun] = ((-38*r[coun] - 74*g[coun] + 112*b[coun]) >> 8) + 128;
// vbuffer[coun] = ((112*r[coun] - 94*g[coun] - 18*b[coun]) >> 8) + 128;
// coun++;
// cout<<i<<" "<<j<<endl;
// }
// }
//}
fwrite(ybuffer, sizeof(unsigned char), W*H, out);
fwrite(ubuffer, sizeof(unsigned char), W*H/4, out);
fwrite(vbuffer, sizeof(unsigned char), W*H/4, out);
cout<<"yuv file settled down"<<endl;
delete ybuffer;
delete ubuffer;
delete vbuffer;
}
#endif // RGB2YUV_H_INCLUDED
这里有一个小疑问,被注释掉的代码是我之前的思路,但输出的图像的U和V数据似乎有问题,但并没有看出来哪里错了。
main函数如下:
#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
#include"head_define.h"
#include"rgb2yuv.h"
using namespace std;
int main(int argc, char* argv[]){
char* imgaddr = argv[1];
char* outaddr = argv[2];
FILE* TGAfile = fopen(imgaddr,"rb");
FILE* YUVfile = fopen(outaddr,"w");
int TGAfileSize;
fseek(TGAfile, 0L, SEEK_END);
TGAfileSize = ftell(TGAfile);
rewind(TGAfile);
cout<<"The tga space is "<<TGAfileSize<< endl; //输出tga文件大小
int offset = 18;
unsigned char* headbuffer = new unsigned char[offset];
fread(headbuffer, sizeof(unsigned char), offset, TGAfile);
Headfile Header;
initialHeadfile(headbuffer, &Header); //初始化头文件
if((Header.IDlength)!=0 ||(Header.Colormaptype)!=0 ||(Header.Imagetypecode)!=2 ||(Header.Bitsperpixel)!=24){
cout<<"It is out of my ability"<<endl;
return -1;
}
cout<<"The width of the image is "<<int(Header.Width)<<endl;
cout<<"The Height of the image is "<<int(Header.Height)<<endl;
int W = int(Header.Width);
int H = int(Header.Height);
unsigned char* rgbbuffer = new unsigned char[W*H*3];
unsigned char* bbuffer = new unsigned char[W*H];
unsigned char* gbuffer = new unsigned char[W*H];
unsigned char* rbuffer = new unsigned char[W*H];
unsigned char* tgabuffer = new unsigned char[TGAfileSize];
fread(tgabuffer, sizeof(unsigned char), TGAfileSize, TGAfile);
int i;
int j;
int a = 0;
for(i = H-1; i >= 0; i--){
for(j = 0; j < 3*W; j++){
rgbbuffer[a] = tgabuffer[3*i*W + j];
a++;
}
}
//FILE* rgb = fopen("E:\\数据压缩奇怪的作业们\\作业3\\作业3\\2.rgb","w" );
//fwrite(rgbbuffer, sizeof(unsigned char), 3*W*H, rgb);
transf(rbuffer, gbuffer, bbuffer, rgbbuffer, YUVfile, W, H); //转化为yuv文件并输出
delete tgabuffer;
delete rgbbuffer;
delete rbuffer;
delete gbuffer;
delete bbuffer;
}
原图是这样的:
最终输出出来的YUV文件为:
程序运行后结果如下: