TGA文件转换为YUV文件的C++实现

写在前面:这次实验实现起来遇到很大困难,也处理了很久,最后参考了其他博客的代码,并和其他同学讨论了一下,现在才基本完成。但仍然有很多不完善的地方,需要提高编程能力。

首先选取一个JPEG文件,并通过 TGA在线文件转换器 将其转换为TGA文件:(文件大小真的大了好多)
在这里插入图片描述

用 Apple Preview 打开看看:(好像和JPEG并没有什么差别)
在这里插入图片描述

下面对TGA的文件格式进行分析:
(前两篇博客分别分析的是PNG/BMP,但是TGA2YUV应该比PNG更简单,BMP2YUV已经有所介绍,因此改成做TGA,重新学习一下格式)
相关参考链接:
TGA规范
Truevision TGAª—FILE FORMAT SPECIFICATION—Version 2.0
TrueVision TGA 2.0一致性套件

All Targa formats are identified by a Data Type field, which is a one
byte binary integer located in byte three of the file. The various
file types specified by this field are as follows:

   0  -  No image data included.
   1  -  Uncompressed, color-mapped images.
   2  -  Uncompressed, RGB images.
   3  -  Uncompressed, black and white images.
   9  -  Runlength encoded color-mapped images.
  10  -  Runlength encoded RGB images.
  11  -  Compressed, black and white images.
  32  -  Compressed color-mapped data, using Huffman, Delta, and
                runlength encoding.
  33  -  Compressed color-mapped data, using Huffman, Delta, and
                runlength encoding.  4-pass quadtree-type process.

Here we only consider DATA TYPE 2: Unmapped RGB images.

OffsetLengthDescription
01Number of Characters in Identification Field. This field is a one-byte unsigned integer, specifying the length of the Image Identification Field. Its value is 0 to 255. A value of 0 means that no Image Identification Field is included.
11Color Map Type. This field contains either 0 or 1. 0 means no color map is included. 1 means a color map is included, but since this is an unmapped image it is usually ignored. TIPS ( a Targa paint system ) will set the border color the first map color if it is present.
21Image Type Code. This field will always contain a binary 2. ( That’s what makes it Data Type 2 ).
35Color Map Specification. Ignored if Color Map Type is 0; otherwise, interpreted as follows:
32Color Map Origin. Integer ( lo-hi ) index of first color map entry.
52Color Map Length. Integer ( lo-hi ) count of color map entries.
71Color Map Entry Size. Number of bits in color map entry. 16 for the Targa 16, 24 for the Targa 24, 32 for the Targa 32.
810Image Specification.
82X Origin of Image. Integer ( lo-hi ) X coordinate of the lower left corner of the image.
102Y Origin of Image. Integer ( lo-hi ) Y coordinate of the lower left corner of the image.
122Width of Image. Integer ( lo-hi ) width of the image in pixels.
142Height of Image. Integer ( lo-hi ) height of the image in pixels.
161Image Pixel Size. Number of bits in a pixel. This is 16 for Targa 16, 24 for Targa 24, and … well, you get the idea.
171Image Descriptor Byte.
18variesImage Identification Field. Contains a free-form identification field of the length specified in byte 1 of the image record. It’s usually omitted ( length in byte 1 = 0 ), but can be up to 255 characters. If more identification information is required, it can be stored after the image data.
variesvariesColor map data. If the Color Map Type is 0, this field doesn’t exist. Otherwise, just read past it to get to the image. The Color Map Specification describes the size of each entry, and the number of entries you’ll have to skip. Each color map entry is 2, 3, or 4 bytes.
variesvariesImage Data Field. This field specifies (width) x (height) pixels. Each pixel specifies an RGB color value, which is stored as an integral number of bytes.

接下来开始写代码:(Visual Studio 2017)
tga2yuv.cpp

#include "pch.h"
#include <stdio.h>
#include<cstdlib>
#include"tga2yuv.h"
using namespace std;

struct TGA_HEADER
{
	unsigned short IDLength;
	unsigned short ImageType;
	unsigned short ColorMapLen;
	unsigned char ColorMapBits;
	unsigned int Width;
	unsigned int Height;
	unsigned char bitsPerPixel;
}TGAHEADER;

int main(int argc, char **argv)
{
	FILE *TgaFile = NULL;
	FILE *YuvFile = NULL;
	char *TgaFileName = NULL;
	char *YuvFileName = NULL;

	TgaFileName = argv[1];
	YuvFileName = argv[2];

	int Height, Width;
	int offset = 0;

	if (fopen_s(&TgaFile, TgaFileName, "rb") == 0)
		printf("The tgafile was opened: %s \n", TgaFileName);
	else printf("The tgafile cannot open: %s \n", TgaFileName);
	fopen_s(&YuvFile, YuvFileName, "wb");

	unsigned char typeHeader[18] = { 0 };
	fread(typeHeader, 1, 18, TgaFile);
	TGAHEADER.IDLength = typeHeader[0];
	TGAHEADER.ImageType = typeHeader[2];
	TGAHEADER.ColorMapLen = (typeHeader[6] << 8) + typeHeader[5];
	TGAHEADER.ColorMapBits = typeHeader[7];
	TGAHEADER.Width = (typeHeader[13] << 8) + typeHeader[12];
	TGAHEADER.Height = (typeHeader[15] << 8) + typeHeader[14];
	TGAHEADER.bitsPerPixel = (typeHeader[17] << 8) + typeHeader[16];

	unsigned short pixel = TGAHEADER.bitsPerPixel / 8;
	unsigned short ColorPixel = TGAHEADER.ColorMapBits / 8;
	Width = TGAHEADER.Width;
	Height = TGAHEADER.Height;

	printf("该tga图片的大小为: %d * %d \n", TGAHEADER.Width, TGAHEADER.Height);

	int i, j;

	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);
	tgaBuffer = (unsigned char *)malloc(Width*Height * 3);
	rgbBuffer = (unsigned char *)malloc(Width*Height * 3);

	offset = TGAHEADER.IDLength + 18;
	fseek(TgaFile, offset, SEEK_SET);

	switch (pixel)
	{
	case 3:
		fread(tgaBuffer, 1, Width*Height*pixel, TgaFile);
		break;
	case 4:
		unsigned char *tgaB = NULL;
		fread(tgaB, 1, Width*Height*pixel, TgaFile);

		int a = 0, b = 0;
		for (i = 0; i < Height; i++)
		{
			for (j = 0; j < Width; j++)
			{
				tgaBuffer[a] = tgaB[b];
				tgaBuffer[a + 1] = tgaB[b + 1];
				tgaBuffer[a + 2] = tgaB[b + 2];
				a += 3;
				b += 4;
			}
		}
		free(tgaB);
	}

	for (i = 0; i < Height; i++)
		for (j = 0; j < Width * 3; j++)
		{
			rgbBuffer[Width * 3 * i + j] = tgaBuffer[Width * 3 * (Height - i - 1) + j];
		}


	if ((rgb2yuv(rgbBuffer, yBuffer, uBuffer, vBuffer, Width, Height) == 0))
		printf("yuvFile has finished\n");
	else
	{
		printf("error\n");
		exit(1);
	}

	fwrite(yBuffer, 1, Width*Height, YuvFile);
	fwrite(uBuffer, 1, Width*Height / 4, YuvFile);
	fwrite(vBuffer, 1, Width*Height / 4, YuvFile);

	free(yBuffer);
	free(uBuffer);
	free(vBuffer);
	free(tgaBuffer);
	free(rgbBuffer);
	fclose(TgaFile);
	fclose(YuvFile);
	system("pause");
	return 0;
}

rgb2yuv.cpp

#include <cstdlib>
#include <stdio.h>
#include"tga2yuv.h"
#include "pch.h"
using namespace std;

int rgb2yuv(void* rgb_s, void* y_s, void* u_s, void* v_s, int W, int H)
{
	unsigned char *r = NULL, *g = NULL, *b = NULL, *rgb = NULL;
	unsigned char *y, *u, *v, *U, *V;

	rgb = (unsigned char *)rgb_s;
	y = (unsigned char *)y_s;
	u = (unsigned char *)u_s;
	v = (unsigned char *)v_s;

    // 动态存储分配
	r = (unsigned char *)malloc(sizeof(char)*(W*H)); 
	g = (unsigned char *)malloc(sizeof(char)*(W*H));
	b = (unsigned char *)malloc(sizeof(char)*(W*H));
	U = (unsigned char *)malloc(sizeof(char)*(W*H));
	V = (unsigned char *)malloc(sizeof(char)*(W*H));

	int j = 0;
	for (int i = 0; i < W*H; i++)
	{
		b[i] = rgb[j];
		g[i] = rgb[j + 1];
		r[i] = rgb[j + 2];
		j += 3;
	}

	for (int i = 0; i < H*W; i++)
	{
		y[i] = r[i] * 0.2990 + g[i] * 0.5870 + b[i] * 0.1140;
		U[i] = r[i] * (-0.1684) - g[i] * 0.3316 + b[i] * 0.5 + 128;
		V[i] = r[i] * 0.5 - g[i] * 0.4187 - b[i] * 0.0813 + 128;
	}

	int k = 0;
	for (int i = 0; i < H; i = i + 2)
	{
		for (j = 0; j < W; j = j + 2)
		{
			u[k] = (U[W*i + j] + U[W*i + j + 1] + U[(i + 1)*W + j] + U[(i + 1)*W + j + 1]) / 4;
			v[k] = (V[W*i + j] + V[W*i + j + 1] + V[(i + 1)*W + j] + V[(i + 1)*W + j + 1]) / 4;
			k++;
		}
	}
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
通过 YUVviewerPlus 查看,生成的 YUV 文件图像内容与 TGA 文件一致。

遇到的困难:太多了,主要是报了很多错,debug花了很长时间。除了程序上的错误,还有一些很奇怪的错误…主要通过在网上查找方案解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值