TGA转YUV
【前期准备】得到TGA文件
通过https://convertio.co/zh/tga-converter/将GIF文件转换为TGA文件,选取其中一幅
【程序思路】
1.打开文件
2.建立结构体-头文件信息,并初始化
3.判断颜色表是否存在
a存在,则
建立结构体-颜色表,并初始化
计算offset,恢复bgr值
b不存在,则
计算offset,读取bgr值
4.图像数据上下颠倒
5.调用RGB2YUV函数完成转换
6.y,u,v写入yuv文件
7.判断并释放内存
8.关闭文件
【代码】
tga2yuv.cpp
#include "stdafx.h"
#include <stdio.h>
#include <malloc.h>
#include <iostream>
using namespace std;
#include "tga2yuv.h"
struct TGA_HEADER
{
unsigned short IDlength;//图像信息字段长度
unsigned short ImageType;//图像类型
unsigned short ColorMapLength;//颜色表长度
unsigned char ColorMapBits;//颜色表项位数
unsigned short Width;
unsigned short Height;
unsigned char bitsPerPixel;//像素位数
}HEADER;
struct COLOR_MAP
{
unsigned char R,G,B;
};
void STRUCTTGA(FILE *Tfile)
{
unsigned char typeHeader[18] = { 0 };
fread(typeHeader, sizeof(unsigned char), 18, Tfile);
HEADER.IDlength = typeHeader[0];
HEADER.ImageType = typeHeader[2];
HEADER.ColorMapLength = (typeHeader[6] << 8) + typeHeader[5];
HEADER.ColorMapBits = typeHeader[7];
HEADER.Width = (typeHeader[13] << 8) + typeHeader[12];
HEADER.Height = (typeHeader[15] << 8) + typeHeader[14];
HEADER.bitsPerPixel = (typeHeader[17] << 8) + typeHeader[16];
}
//颜色表数据
void COLORMAPDATA(unsigned char *ColorMapBuffer, struct COLOR_MAP *COLORMAP,int offset,int Len)
{
int j = 0;
for (int i = 0; i <Len; i++)
{
COLORMAP[i].B=ColorMapBuffer[j];
COLORMAP[i].G = ColorMapBuffer[j+1];
COLORMAP[i].R = ColorMapBuffer[j+2];
j += 3;
}
}
int main(int argc, char *argv[])
{
FILE *tgaFile = NULL, *yuvFile = NULL;
char *tgaFileName = argv[1];
char *yuvFileName = argv[2];
unsigned short width = 0, height = 0, pixel = 0,ColorPixel=0;
int offset = 0;
int W = 0;
errno_t err;
err = fopen_s(&tgaFile, tgaFileName, "rb");
if (err == 0)//打开tga文件
printf("The file\t%s\t open sucess \n", tgaFileName);
else
printf("The file\t%s\t open fail\n", tgaFileName);
err = fopen_s(&yuvFile, yuvFileName, "wb");
if (err == 0)//打开yuv文件
printf("The file\t%s\t open sucess \n", yuvFileName);
else
printf("The file\t%s\t open fail\n", yuvFileName);
//数组初始化
STRUCTTGA(tgaFile);
pixel = HEADER.bitsPerPixel / 8;
ColorPixel = HEADER.ColorMapBits / 8;
int Type = HEADER.ImageType;
int Length = HEADER.ColorMapLength;
if ((HEADER.Width % 2) == 0)
width = HEADER.Width;
else
width = HEADER.Width; +1;
if ((HEADER.Height % 2) == 0)
height = HEADER.Height;
else
height = HEADER.Height + 1;
printf("W=%d\n", width);
printf("H=%d\n",height);
//四个动态内存区指针
unsigned char* tgaBuffer = NULL;
unsigned char* rgbBuffer = NULL;
unsigned char* yBuffer = NULL;
unsigned char* uBuffer = NULL;
unsigned char* vBuffer = NULL;
unsigned char* ColorBuffer = NULL;
unsigned char *ColorMapBuffer = NULL;
//分配动态内存
yBuffer = (unsigned char *)malloc(width*height);
uBuffer = (unsigned char *)malloc(width*height / 4);
vBuffer = (unsigned char *)malloc(width*height / 4);
int i, j, b = 0, g = 1, r = 2;
if (Type == 1)//有颜色表
{
tgaBuffer = (unsigned char *)malloc(width*height*ColorPixel);
rgbBuffer = (unsigned char *)malloc(width*height*ColorPixel);
struct COLOR_MAP *COLORMAP = (struct COLOR_MAP*)malloc(Length*sizeof(struct COLOR_MAP));
ColorMapBuffer = (unsigned char *)malloc(3*Length);
fseek(tgaFile,18, SEEK_SET);
fread(ColorMapBuffer, sizeof(unsigned char), 3*Length,tgaFile);
COLORMAPDATA(ColorMapBuffer, COLORMAP, offset, Length);//调色盘数据初始化
ColorBuffer = (unsigned char *)malloc(width*height*pixel);
offset = 18 + HEADER.IDlength + HEADER.ColorMapLength * 3;
fseek(tgaFile, offset, SEEK_SET);
fread(ColorBuffer, sizeof(unsigned char), width*height*pixel, tgaFile);
for (i = 0; i < width*height; i++)
{
tgaBuffer[b] = COLORMAP[ColorBuffer[i]].B;
tgaBuffer[g] = COLORMAP[ColorBuffer[i]].G;
tgaBuffer[r] = COLORMAP[ColorBuffer[i]].R;
b += 3;
g += 3;
r += 3;
}
free(COLORMAP);
W = width * ColorPixel;
for (i = 0; i < height; i++)//图像上下颠倒
for (j = 0; j < W; j++)
{
rgbBuffer[W*i + j] = tgaBuffer[W*(height - 1 - i) + j];
}
}
if(Type==2)//无颜色表
{
rgbBuffer = (unsigned char *)malloc(width*height*3);
tgaBuffer = (unsigned char *)malloc(width*height*3);
offset = 18 + HEADER.IDlength;
fseek(tgaFile,offset, SEEK_SET);
switch (pixel)
{
case 3: //3字节
fread(tgaBuffer, sizeof(unsigned char), width*height*pixel, tgaFile);
break;
case 4: //4字节
unsigned char* tgaBuffer1 = NULL;
tgaBuffer1 = (unsigned char *)malloc(width*height*pixel);
fread(tgaBuffer1, sizeof(unsigned char), width*height*pixel, tgaFile);
int b0 = 0, b1 = 0;
for(i=0;i<height;i++)
for (j = 0; j < width; j++)
{
tgaBuffer[b0] = tgaBuffer1[b1];
tgaBuffer[b0+1] = tgaBuffer1[b1+1];
tgaBuffer[b0+2] = tgaBuffer1[b1+2];
b0 += 3;
b1 += 4;
}
free(tgaBuffer1);
}
for (i = 0; i < height; i++)
for (j = 0; j <width*3; j++)
{
rgbBuffer[width*3*i+j] = tgaBuffer[width*3*(height-1-i)+j];
}
}
//调用RGB2YUV函数实现转换
if ((RGB2YUV(rgbBuffer, yBuffer, uBuffer, vBuffer, width, height)) == 0)
printf("changed successfully");
else
{
printf("fail");
exit(1);
}
//动态内存写入yuv
fwrite(yBuffer, sizeof(unsigned char), width*height, yuvFile);
fwrite(uBuffer, sizeof(unsigned char), width*height / 4, yuvFile);
fwrite(vBuffer, sizeof(unsigned char), width*height / 4, yuvFile);
//释放内存,关闭文件
free(yBuffer);
free(uBuffer);
free(vBuffer);
if(tgaBuffer)
free(tgaBuffer);
if (ColorBuffer)
free(ColorBuffer);
if(rgbBuffer)
free(rgbBuffer);
if (ColorMapBuffer)
free(ColorMapBuffer);
fclose(tgaFile);
fclose(yuvFile);
system("pause");
return 0;
}
rgb2yuv.cpp
#include <iostream>
#include "tga2yuv.h"
#include "stdafx.h"
static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];
int RGB2YUV(void* rgb, void* y_out, void* u_out, void* v_out, int W, int H)
{
unsigned char *b = NULL, *g = NULL, *r = NULL;
unsigned char *y, *u, *v;
b = (unsigned char *)rgb;
y = (unsigned char *)y_out;
u = (unsigned char *)u_out;
v = (unsigned char *)v_out;
InitLookupTable();//调用数据表
int i, j;
//亮度信号转换
for (i = 0; i < W*H; i++)
{
g = b + 1;
r = b + 2;
*y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
b += 3;
y++;
}
//色差信号转换
b = (unsigned char *)rgb;
for (j = 0; j < H; j++)
{
for (i = 0; i < W; i++)
{
g = b + 1;
r = b + 2;
if (i % 2 == 0 && j % 2 == 0)
{
*u = (unsigned char)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);
*v = (unsigned char)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
u++;
v++;
}
b += 3;
}
}
return 0;
}
void InitLookupTable()
{
int i;
for (i = 0; i < 256; i++)
{
RGBYUV02990[i] = (float)0.2990 * i;
RGBYUV05870[i] = (float)0.5870 * i;
RGBYUV01140[i] = (float)0.1140 * i;
RGBYUV01684[i] = (float)0.1684 * i;
RGBYUV03316[i] = (float)0.3316 * i;
RGBYUV04187[i] = (float)0.4187 * i;
RGBYUV00813[i] = (float)0.0813 * i;
}
}
tga2yuv.h
int RGB2YUV(void* rgb, void* y_out, void* u_out, void* v_out, int W, int H);
void InitLookupTable();
【实验结果】
图像对比,都是截图所得,图像实际没有大小差异
yuv图像
原gif图像的截图(没有合适的图用于转换)