C++实现TGA到YUV文件转换

本次试验通过C++,实现将TGA文件转换为YUV文件。目前只支持非压缩无颜色表24、32位格式以及非压缩有颜色表格式的转换。

一、基本原理

1. TGA文件结构

具体参见:TGA文件格式解析

2. RGB2YUV彩色空间转换基本原理

具体参见:C++实现RGB2YUV/YUV2RGB

二、试验流程

在这里插入图片描述

三、代码实现

//main.cpp
#include <stdio.h>
#include <windows.h>
#include "pch.h"
#include <iostream>
#include "tga2yuv.h"

struct TGA_HEADER
{
	unsigned short IDLength;
	unsigned short ImageType;
	unsigned short ColorMapLen;
	unsigned char ColorMapBits;//颜色表项位数
	unsigned short Width;
	unsigned short Height;
	unsigned char bitsPerPixel;//像素位数
}TGAHEARD;

struct COLOR_MAP
{
	unsigned char Blue;
	unsigned char Green;
	unsigned char Red;
};

void STRUCTTGA(FILE *Tfile)
{
	unsigned char typeHeader[18] = { 0 };
	fread(typeHeader, sizeof(unsigned char), 18, Tfile);//fread改变文件指针的指向位置
	TGAHEARD.IDLength = typeHeader[0];
	TGAHEARD.ImageType = typeHeader[2];
	TGAHEARD.ColorMapLen = (typeHeader[6] << 8) + typeHeader[5];
	TGAHEARD.ColorMapBits = typeHeader[7];
	TGAHEARD.Width = (typeHeader[13] << 8) + typeHeader[12];
	TGAHEARD.Height = (typeHeader[15] << 8) + typeHeader[14];
	TGAHEARD.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].Blue=ColorMapBuffer[j];
		COLORMAP[i].Green = ColorMapBuffer[j+1];
		COLORMAP[i].Red = 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;
	if ((err = fopen_s(&tgaFile, tgaFileName, "rb")) == 0)//打开tga文件
		printf("The file\t%s\twas opened\n", tgaFileName);
	else
		printf("The file\t%s\twas not opened\n", tgaFileName);
	if ((err = fopen_s(&yuvFile, yuvFileName, "wb")) == 0)//打开yuv文件
		printf("The file\t%s\twas opened\n", yuvFileName);
	else
		printf("The file\t%s\twas not opened\n", yuvFileName);

	//数组初始化
	STRUCTTGA(tgaFile);	
	pixel = TGAHEARD.bitsPerPixel / 8;
	ColorPixel = TGAHEARD.ColorMapBits / 8;
	int T = TGAHEARD.ImageType;
	int Len = TGAHEARD.ColorMapLen;
	if ((TGAHEARD.Width % 2) == 0)
		width = TGAHEARD.Width;
	else
		width = TGAHEARD.Width; +1;
	if ((TGAHEARD.Height % 2) == 0)
		height = TGAHEARD.Height;
	else
		height = TGAHEARD.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 (T == 1)//有颜色表存在
	{
		tgaBuffer = (unsigned char *)malloc(width*height*ColorPixel);//存tga中取出的bgr信息
		rgbBuffer = (unsigned char *)malloc(width*height*ColorPixel);//存上下颠倒后的bgr信息
		
		struct COLOR_MAP *COLORMAP = (struct COLOR_MAP*)malloc(Len*sizeof(struct COLOR_MAP));//*sizeof(COLOR_MAP)
		ColorMapBuffer = (unsigned char *)malloc(3*Len);
		fseek(tgaFile,18, SEEK_SET);
		fread(ColorMapBuffer, sizeof(unsigned char), 3*Len,tgaFile);
	
		COLORMAPDATA(ColorMapBuffer, COLORMAP, offset, Len);//调色盘数据初始化

		ColorBuffer = (unsigned char *)malloc(width*height*pixel);
		offset = 18 + TGAHEARD.IDLength + TGAHEARD.ColorMapLen * 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]].Blue;
			tgaBuffer[g] = COLORMAP[ColorBuffer[i]].Green;
			tgaBuffer[r] = COLORMAP[ColorBuffer[i]].Red;
			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(T==2)//无颜色表
	{
		rgbBuffer = (unsigned char *)malloc(width*height*3);
		tgaBuffer = (unsigned char *)malloc(width*height*3);
		offset = 18 + TGAHEARD.IDLength;
		fseek(tgaFile,offset, SEEK_SET);
		switch (pixel)
		{
		case 3: //3字节
			fread(tgaBuffer, sizeof(unsigned char), width*height*pixel, tgaFile);
			break;
		case 4:	//4字节
			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 "pch.h"
#include <iostream>
#include "tga2yuv.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;
	for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
	for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
	for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
	for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
	for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
	for (i = 0; i < 256; 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 InitLookupTa

四、结果

图片描述tga原图yuv图
非压缩有颜色表8位在这里插入图片描述在这里插入图片描述
非压缩无颜色表24位在这里插入图片描述在这里插入图片描述
非压缩无颜色表32位在这里插入图片描述在这里插入图片描述

以下依次为图1、2、3的运行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值