TGA与YUV文件的转换

一、TGA文件介绍

1.简介

TGA(Targa)格式是计算机上应用最广泛的图象格式。在兼顾了BMP的图象质量的同时又兼顾了JPEG的体积优势。并且还有自身的特点:通道效果、方向性。在CG领域常作为影视动画的序列输出格式,因为兼具体积小和效果清晰的特点。
TGA的结构比较简单,属于一种图形、图像数据的通用格式,在多媒体领域有很大影响,是计算机生成图像向电视转换的一种首选格式。TGA图像格式最大的特点是可以做出不规则形状的图形、图像文件,一般图形、图像文件都为四方形,若需要有圆形、菱形甚至是缕空的图像文件时,TGA就可以派上用场了。

2.TGA文件存储格式

1)是以小端模式存储的,包括规格定义和RGB数据,也就是BGR形式存放。
2)看到的图片的左上角一行像素可能放在文件内存中的最后一行(图片y轴可能是世界坐标系的和屏幕坐标系相反),或者文件内存中的第一行就是左上角一行像素。
3) TGA头文件记录了调色板偏移大小和规格,和图像像素数据的偏移大小和规格。
4) TGA分为压缩编码的和非压缩编码的,压缩算法是采用了RLE算法(由于个人能力不足,本文暂时不涉及RLE压缩算法)

3.文件格式

TGA文件具体格式如下:
在这里插入图片描述

二、TGA to YUV的具体实现

1.编程思路

在实现之前,先写了一个思维导图架构了一下工程逻辑:
在这里插入图片描述

2.源代码

header.h:
#pragma once
#include <iostream>

typedef struct
{
    char  IdLength = 0;         
    char  ColourMapType = 0;   
    char  ImageTypeCode = 0;    
    short ColourMapOffset = 0;  
    short ColourMapLength = 0;  
    char  ColourMapDepth = 0;   
    short X_ori = 0;       
    short Y_ori = 0;        
    short Width = 0;          
    short Height = 0;          
    char  BitsPerPixel = 0;     
    char  ImageDescriptor = 0;  
} HEADER;

typedef struct
{
    unsigned char R, G, B, A;
} DATA;

void ReadTGAHeader(HEADER* TGAHdPtr, FILE* TGAPtr);
void ReadColourData(HEADER* TGAHdPtr, DATA* ColourData, FILE* TGAPtr);
void Transform2RGB(DATA* ColourData, unsigned char* RGBBuff, HEADER* TGAHdPtr);
void RGB2YUV(unsigned char* RGB, unsigned char* Y,
    unsigned char* U, unsigned char* V, int Width, int Height);
main.cpp:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <windows.h>
#include "header.h"

using namespace std;

int main(int argc, char** argv)
{
    FILE* TGAFile, * yuvFile;
    HEADER Hd; 
    int Width, Height, pxCount;

	char* TGAFileName = NULL;
	char* yuvFileName = NULL;
	TGAFileName = argv[1];
	yuvFileName = argv[2];

	if (fopen_s(&TGAFile, TGAFileName, "rb") == 0)
	{
		cout << "File opened! " << TGAFileName << "." << endl;
	}
	else
	{
		cout << "File not opened! " << TGAFileName << "." << endl;
		exit(0);
	}
	if (fopen_s(&yuvFile, yuvFileName, "wb+") == 0)
	{
		cout << "File opened! " << yuvFileName << "." << endl;
	}
	else
	{
		cout << "File not opened!  " << yuvFileName << "." << endl;
		exit(0);
	}

	ReadTGAHeader(&Hd, TGAFile);
	
	Width = Hd.Height;
	Height = Hd.Width;
	pxCount = Width * Height;
	unsigned char* RGB = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height * 3));
	unsigned char* Y, * U, * V;
	unsigned char* R, * G, * B;
	R = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height));
	G = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height));
	B = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height));
	Y = (unsigned char*)malloc(sizeof(char) * (Width * Height));
	U = (unsigned char*)malloc(sizeof(char) * (Width * Height / 4));
	V = (unsigned char*)malloc(sizeof(char) * (Width * Height / 4));

	DATA* RGBaData = NULL;
	RGBaData = new DATA[Hd.Width * Hd.Height];
	memset(RGBaData, 0, Hd.Height * Hd.Width);   
	RGB = new unsigned char[Hd.Width * Hd.Height * 3];
	memset(RGB, 0, Hd.Height * Hd.Width * 3);   

	int Ost = 0;
	Ost += Hd.IdLength;
	Ost += Hd.ColourMapType * Hd.ColourMapLength * Hd.ColourMapDepth;
	fseek(TGAFile, Ost, SEEK_CUR); 

	ReadColourData(&Hd, RGBaData, TGAFile);

	Width = Hd.Width;
	Height = Hd.Height;
	for (int i = 0; i < Height; i++)
	{
		for (int j = 0; j < Width; j++)
		{
			int RGBPxNum = (Height - 1 - i) * Width + j;
			int TGAPxNum = i * Width + j;

			RGB[3 * RGBPxNum + 2] = RGBaData[TGAPxNum].R;
			RGB[3 * RGBPxNum + 1] = RGBaData[TGAPxNum].G;
			RGB[3 * RGBPxNum] = RGBaData[TGAPxNum].B;
		}
	}

	RGB2YUV(RGB, Y, U, V, Width, Height);
	free(RGB);

	fwrite(Y, sizeof(unsigned char), Width * Height, yuvFile);
	fwrite(U, sizeof(unsigned char), Width * Height / 4, yuvFile);
	fwrite(V, sizeof(unsigned char), Width * Height / 4, yuvFile);
	fclose(yuvFile);
}
ReadTGA.cpp:
#include <iostream>
#include "header.h"
using namespace std;

void ReadTGAHeader(HEADER* TGAHdPtr, FILE* TGAPtr)
{

    fread(&TGAHdPtr->IdLength, 1, 1, TGAPtr);
    fread(&TGAHdPtr->ColourMapType, 1, 1, TGAPtr);
    fread(&TGAHdPtr->ImageTypeCode, 1, 1, TGAPtr);
    fread(&TGAHdPtr->ColourMapOffset, 2, 1, TGAPtr);
    fread(&TGAHdPtr->ColourMapLength, 2, 1, TGAPtr);
    fread(&TGAHdPtr->ColourMapDepth, 1, 1, TGAPtr);
    fread(&TGAHdPtr->X_ori, 2, 1, TGAPtr);
    fread(&TGAHdPtr->Y_ori, 2, 1, TGAPtr);
    fread(&TGAHdPtr->Width, 2, 1, TGAPtr);
    fread(&TGAHdPtr->Height, 2, 1, TGAPtr);
    fread(&TGAHdPtr->BitsPerPixel, 1, 1, TGAPtr);
    fread(&TGAHdPtr->ImageDescriptor, 1, 1, TGAPtr);


    if (TGAHdPtr->ImageTypeCode != 2 && TGAHdPtr->ImageTypeCode != 10)
    {
        cout << "本程序仅支持 Image Type Code 为 2(无压缩、无调色板的RGB图像)或 10(游程编码的RGB图像)\n";
        exit(-1);
    }
    if (TGAHdPtr->BitsPerPixel != 16 && TGAHdPtr->BitsPerPixel != 24 && TGAHdPtr->BitsPerPixel != 32)
    {
        cout << "本程序仅支持 Image pixel size 为 16,24,32 的图像\n";
        exit(-1);
    }
    if (TGAHdPtr->ColourMapType != 0 && TGAHdPtr->ColourMapType != 1)
    {
        cout << "本程序仅支持 Colour Map Type 为 0 或 1 的图像\n";
        exit(-1);
    }


    cout << "\nTGA header information:\n";
    printf("ID length:         %d\n", TGAHdPtr->IdLength);
    printf("Colour Map type:   %d\n", TGAHdPtr->ColourMapType);
    printf("Image type code:   %d\n", TGAHdPtr->ImageTypeCode);
    printf("Colour map Ost: %d\n", TGAHdPtr->ColourMapOffset);
    printf("Colour map length: %d\n", TGAHdPtr->ColourMapLength);
    printf("Colour map depth:  %d\n", TGAHdPtr->ColourMapDepth);
    printf("X origin:          %d\n", TGAHdPtr->X_ori);
    printf("Y origin:          %d\n", TGAHdPtr->Y_ori);
    printf("Width:             %d\n", TGAHdPtr->Width);
    printf("Height:            %d\n", TGAHdPtr->Height);
    printf("Image pixel size:  %d\n", TGAHdPtr->BitsPerPixel);
    printf("Descriptor:        %d\n\n", TGAHdPtr->ImageDescriptor);
}
RGB2YUV.cpp:
#include<stdio.h>
#include "header.h"


float RGB2YUV02990[256], RGB2YUV05870[256], RGB2YUV01140[256], RGB2YUV01684[256],
RGB2YUV03316[256], RGB2YUV05000[256], RGB2YUV04187[256], RGB2YUV00813[256];

void InitRGB_table() {
	for (int i = 0; i < 256; i++)
	{
		RGB2YUV02990[i] = (float)0.2990 * i;
		RGB2YUV05870[i] = (float)0.5870 * i;
		RGB2YUV01140[i] = (float)0.1140 * i;
		RGB2YUV01684[i] = (float)0.1684 * i;
		RGB2YUV03316[i] = (float)0.3316 * i;
		RGB2YUV05000[i] = (float)0.5000 * i;
		RGB2YUV04187[i] = (float)0.4187 * i;
		RGB2YUV00813[i] = (float)0.0813 * i;
	}
}


void RGB2YUV(unsigned char* RGB, unsigned char* Y, unsigned char* U, unsigned char* V, int Width, int Height)
{
	int y = 0;
	for (int i = 0; i < Width * Height * 3; i = i + 3)
	{
		InitRGB_table();
		Y[y] = RGB2YUV01140[RGB[i]] + RGB2YUV05870[RGB[i + 1]] + RGB2YUV02990[RGB[i + 2]];
		//Y范围:16-235
		if (Y[y] > 235)
			Y[y] = 235;
		if (Y[y] < 16)
			Y[y] = 16;
		y++;
	}

	int m = 0, n = 0;
	for (int i = 0; i < Width * Height * 3;)
	{
		unsigned char* rgb;
		rgb = new unsigned char[Width * Height * 3];
		rgb[i] = (RGB[i] + RGB[i + 3] + RGB[i + Width * 3] + RGB[i + Width * 3 + 3]) / 4;
		InitRGB_table();
		U[m] = RGB2YUV05000[rgb[i]] - RGB2YUV03316[rgb[i + 1]] - RGB2YUV01684[rgb[i + 2]] + 128;
		V[n] = -RGB2YUV00813[rgb[i]] - RGB2YUV04187[rgb[i + 1]] * +RGB2YUV05000[rgb[i + 2]] + 128;
		m++;
		n++;
		//U,V范围:16-240
		if (U[m] > 240)
			U[m] = 240;
		if (U[m] < 16)
			U[m] = 16;
		if (V[n] > 240)
			V[n] = 240;
		if (V[n] < 16)
			V[n] = 16;
		if ((i / 3) % 256 == 254)
			i = i + 258 * 3;
		else
			i = i + 6;
		delete[]RGB;
	}
}

三、实验结果

原图:

在这里插入图片描述

运行结果:
16位24位32位
在这里插入图片描述在这里插入图片描述在这里插入图片描述
程序截图:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值