实验二:TGA文件格式转化为YUV

实验目的:熟悉TGA图像文件格式,将TGA格式的图像转换成YUV文件**(4:2:0).**

简单回顾YUV文件的存储方式:

在这里插入图片描述

TGA文件格式简介

参考:Truevision TGA FILE FORMAT SPECIFICATION Version 2.0
https://en.wikipedia.org/wiki/Truevision_TGA

TGA格式图像文件的数据可以大致分为五大部分:

  • TGA文件头(TGA File Header)
  • 图像/颜色表数据(Image/Color Data Map)
  • 开发者区域 (Developer Area)

其中主要涉及格式转化的为前两个部分,第三个部分完全由开发者决定,读取图像数据时可以忽略。

1.TGA文件头
  • 文件头长度固定(18字节),按顺序由以下字段构成:
    图像信息字段长度 ID Length 1字节
  • 颜色表类型 Color Map Type 1字节:0则代表无颜色表,1代表有,2-127:reserved by Truevision, 128-255: available for developer use
  • 图像类型 Image Type 1字节 各取值说明如下:
Image Type 取值说明
0无图像数据
1未压缩颜色表索引图象
2未压缩RGB真彩图像
3未压缩灰度图像
9压缩颜色表索引图象
10压缩RGB真彩图像
11压缩灰度图像

表中所列的压缩方法皆为RLE行程编码

此外,还有:32 - 使用 huffman,delta 和 runlength 编码的颜色表图像;33 - 使用 huffman,delta 和 runlength 编码的颜色映射图像,4 趟四叉树类型处理。较为复杂,本文暂不涉及。

  • 颜色表规约 Color Map Specification 共5字节,包括以下字段:(无颜色表则全为0)
字段名长度(字节)说明
颜色表首地址 First Entry Index2第一个颜色表的索引
颜色表长度 Color Map Length2颜色表表项数量
颜色表表项大小 Color Map Entry Size1各表项占用位数,有15,16,24,32
  • 图像规约 Image Specification 共10字节,由以下字段构成:
字段名长度(字节))说明
图像x起始位置 X-origin of Image2图像起始点水平坐标
图像y起始位置 Y-origin of Image2图像左起始点垂直坐标
图像宽度 Image Width2单位为像素
图像高度 Image Height2同上
像素深度 Pixel Depth1一个像素占用位数,一般为8.16.24.32
图像描述符 Image Descriptor1规定了一些信息(包括图像起始位置),不是特别重要,略过

各长度大于1字节的字段,都是低位在前高为在后

为方便起见,本实验规定图像起始点为左下角,和BMP一样。

2.图像/颜色表数据

按顺序主要有三部分组成:

图像信息字段 Image ID :长度由Fileheader中的 Image ID Length 决定,储存了图像的身份信息。

颜色表数据 Color Map Data:包含了LUT数据,长度由文件头中相关字段决定。一个表项由整数倍字节进行存储。若深度为24,则BGR分别占8字节;若为32位,则BGR和属性值A各占8字节。

图像数据 Image Data:是本次实验的重中之重,顺序存储了图像中各像素的信息。RAW,unmapped图像数据的存储方式:

首先,一个像素的颜色信息所占字节数由FileHeader中的Pixel Depth决定:

Pixel Depth = 16:

此时一个像素存储2字节16位,具体构成为:arrrrrgg gggbbbbb 其中低位在前,高为在后

Pixel Depth = 15:

其余同上,一项颜色变为15bit,即:rrrrrgg gggbbbbb

具体读取算法可表示为:

rgbBuf[j] = (Buf[0] & 0x1f) << 3;//b
rgbBuf[j + 1] = (Buf[0] & 0xe0) >> 2 + (Buf[1] & 0x03) << 6;//b
rgbBuf[j + 2] = (Buf[1] & 0x7c) << 1;//r

Pixel Depth = 24 :

BGR各存储8字节,顺序为BGR

Pixel Depth = 32 :

BGR仍旧各存储8字节,此外属性值A也为8字节,即BGRA

这两种个情况的代码表示:

rgbBuf[j] = Buf[0];//b
rgbBuf[j + 1] = Buf[1];//g
rgbBuf[j + 2] = Buf[2];//r

若为Mapped 数据,则每个像素为整数个字节的索引值(如1,2个)规范中并无具体规定,本实验暂不涉及mapped image

对 gray image, image data 一个像素为为8/16字节,pixel depth = 8/16,16字节时,gray_level在低位,属性值alpha在高位。

在这个基础上,需要着重介绍的是在Image Type = 9 10 11的图像中使用的压缩算法RLE

TGA中的RLE行程编码

我们直接了解RLE编码下的图像数据存储方式:

在RLE中,图像数据以“数据包”作为单位,可以分为以下两种数据包:

  • A类:包含连续的不同像素颜色值。
  • B类:包含连续的相同像素颜色值。

每个数据包构成如下:

  • 包头Header 1字节
  • 数据 Data 可变长

其中数据包类型由包头Header的第一位决定:0表示A类,1表示B类。

若是A类,则剩下7位代表数据包内颜色项的数量size

若是B类,则包头接下来应该仅包含一个组颜色值,具体长度由Pixel Depth决定。而剩下7位代表此颜色在接下来顺序像素中的重复次数runsize。

由此可以想到数据读取大致算法:

while(...)
	读取header第一位
	读取header剩下7位
	if header第一位 = 0
		while(size)
			依次读取各像素值并存储
	else if header第一位 = 1
		读取像素值
		while(runsize)
			依次存储该像素值
	else
		数据包有误

压缩,未压缩的颜色表内的数据存储形式也可参照上述的存储形式。

实验代码:

由于时间关系与个人能力原因,本实验暂时只涉及RLE压缩与未压缩的rgb真彩图像和和灰度图像,即Image Type = 2,3,10,11。其他暂不涉及。对RGB真彩图像有Bit Depth = 16,24,32。对灰度图像有Bit Depth = 8,16.

考虑:

  • 为了代码简洁可观,有必要设定相应的结构体简化代码书写。
  • 各Image Type的算法有许多相似之处,可适当的定义函数以减少代码冗余。
  • 充分考虑到可能出现的错误情况。
  • 输出图像与算法相关信息以便检查,修改代码。
  • 本实验选择图像起始点皆为左下角,需作上下倒向处理。

实验代码如下:

header.h
#pragma once
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
#include<stdint.h>
using namespace std;
typedef struct
{
	uint8_t ID_len; //图像信息字段Image ID长度(单位字节)
	uint8_t colormap_type;  //0:无颜色表   1:有颜色表
	uint8_t image_type;  //图像类型,很多,不一一介绍
	uint16_t colormapPos;  //第一个颜色表表项位置
	uint16_t colormap_len;   //颜色表表项数量
	uint8_t colormap_entrysize;  //颜色表表项大小,可以为15,16,24,32(bit)
	uint16_t x_orig;   //图像左下角水平坐标,前低后高
	uint16_t y_orig;   //图像左下角垂直坐标,前低后高
	uint16_t width;    //图像宽度,前低后高
	uint16_t height;   //图像高度,前低后高
	uint8_t depth;     //图像颜色深度 8,16,24,32(位)
	uint8_t descriptor;//描述符
}FILEHEADER;


void rgb_to_yuv(unsigned char* rgbBuf, unsigned char* yBuf, unsigned char* uBuf, unsigned char* vBuf, int Width, int Height);
void readfileheader(FILEHEADER* hd, FILE* tga);
void readRGB (FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h);
void readGray(FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h);

rgb2yuv.cpp
#include"header.h"

void rgb_to_yuv(unsigned char* rgbBuf, unsigned char* yBuf, unsigned char* uBuf, unsigned char* vBuf, int Width, int Height)
{
	int y = 0;
	for (int i = 0; i < Width * Height * 3; i = i + 3)
	{
		yBuf[y] = 0.114 * rgbBuf[i] + 0.587 * rgbBuf[i + 1] + 0.299 * rgbBuf[i + 2];//bgr顺序
		//Y范围:16-235
		if (yBuf[y] > 235)
			yBuf[y] = 235;
		if (yBuf[y] < 16)
			yBuf[y] = 16;
		y++;
	}
	int u = 0, v = 0;
	for (int i = 0; i < Width * Height * 3;)
	{
		uBuf[u] = 0.5 * (rgbBuf[i] + rgbBuf[i + 3] + rgbBuf[i + Width * 3] + rgbBuf[i + Width * 3 + 3]) / 4
			- 0.3316 * (rgbBuf[i + 1] + rgbBuf[i + 4] + rgbBuf[i + Width * 3 + 1] + rgbBuf[i + Width * 3 + 4]) / 4
			- 0.1684 * (rgbBuf[i + 2] + rgbBuf[i + 5] + rgbBuf[i + Width * 3 + 2] + rgbBuf[i + Width * 3 + 5]) / 4 + 128;
		vBuf[v] = -0.083 * (rgbBuf[i] + rgbBuf[i + 3] + rgbBuf[i + Width * 3] + rgbBuf[i + Width * 3 + 3]) / 4
			- 0.4187 * (rgbBuf[i + 1] + rgbBuf[i + 4] + rgbBuf[i + Width * 3 + 1] + rgbBuf[i + Width * 3 + 4]) / 4
			+ 0.5 * (rgbBuf[i + 2] + rgbBuf[i + 5] + rgbBuf[i + Width * 3 + 2] + rgbBuf[i + Width * 3 + 5]) / 4 + 128;
		u++;
		v++;
		//U,V范围:16-240
		if (uBuf[u] > 240)
			uBuf[u] = 240;
		if (uBuf[u] < 16)
			uBuf[u] = 16;
		if (vBuf[v] > 240)
			vBuf[v] = 240;
		if (vBuf[v] < 16)
			vBuf[v] = 16;
		if ((i / 3) % Width == 254)
			i = i + (Width + 2) * 3;
		else
			i = i + 6;
	}
}
readfileheader.cpp
#include"header.h"
void readfileheader(FILEHEADER* hd, FILE* tga)
{
	fread(&hd->ID_len, sizeof(uint8_t), 1, tga);
	fread(&hd->colormap_type, sizeof(uint8_t), 1, tga);
	fread(&hd->image_type, sizeof(uint8_t), 1, tga);
	fread(&hd->colormapPos, sizeof(uint16_t), 1, tga);
	fread(&hd->colormap_len, sizeof(uint16_t), 1, tga);
	fread(&hd->colormap_entrysize, sizeof(uint8_t), 1, tga);
	fread(&hd->x_orig, sizeof(uint16_t), 1, tga);
	fread(&hd->y_orig, sizeof(uint16_t), 1, tga);
	fread(&hd->width, sizeof(uint16_t), 1, tga);
	fread(&hd->height, sizeof(uint16_t), 1, tga);
	fread(&hd->depth, sizeof(uint8_t), 1, tga);
	fread(&hd->descriptor, sizeof(uint8_t), 1, tga);
	switch((uint8_t)hd->image_type)
	{
	case 0:
		{
			printf("No image data in the image.\n");
			system("pasue");
			exit(1);
		}
	case 1:
		{
			printf("Uncompressed Color_Mapped Image.\n");
			break;
		}
	case 2:
		{
			printf("Uncompressed Ture_Color Image.\n");
			break;
		}
	case 3:
		{
			printf("Uncompressed Grey Image.\n");
			break;
		}
	case 9:
		{
			printf("Compressed Color_Mapped Image.\n");
			break;
		}
	case 10:
		{
			printf("Compressed Ture_Color Image.\n");
			break;
		}
	case 11:
		{
			printf("Compressed Grey Image.\n");
			break;
		}
	default:
		{
			printf("TGA Image may be invalid, or unsuitable for this program.\n");
			system("pasue");
			exit(1);
		}
	}
	printf("ID Length\t%d\n" ,(uint8_t)hd->ID_len); //不能用cout,"0"的问题
	printf("Color Map Type\t%d\n", (uint8_t)hd->colormap_type);
	printf("Image Type\t%d\n", (uint8_t)hd->image_type);
	printf("Color Map Offset\t%d\n",(uint16_t)hd->colormapPos);
	printf("Color Map Length\t%d\n", (uint16_t)hd->colormap_len);
	printf("Color Map Entry Size\t%d\n", (uint8_t)hd->colormap_entrysize);
	printf("X Original\t%d\n",(uint16_t)hd->x_orig);
	printf("Y Original\t%d\n", (uint16_t)hd->y_orig);
	printf("Width\t%d\n", (uint16_t)hd->width);
	printf("Height\t%d\n", (uint16_t)hd->height);
	printf("Bit Depth\t%d\n", (uint8_t)hd->depth);
	printf("Image Descriptor\t%d\n", (uint8_t)hd->descriptor);
	system("pause");
}
readRGB.cpp
#include"header.h";
void read_rgb_depth16(unsigned char* rgbBuf, unsigned char *Buf, int j)
{
	rgbBuf[j] = (Buf[0] & 0x1f) << 3;//b
	rgbBuf[j + 1] = (Buf[0] & 0xe0) >> 2 + (Buf[1] & 0x03) << 6;//g
	rgbBuf[j + 2] = (Buf[1] & 0x7c) << 1;//r
}

void read_rgb_depth24and32(unsigned char* rgbBuf, unsigned char *Buf, int j)
{
	rgbBuf[j] = Buf[0];//b
	rgbBuf[j + 1] = Buf[1];//g
	rgbBuf[j + 2] = Buf[2];//r
}

void extract_raw_rgb(int flag, FILE* tga, unsigned char* rgbBuf, int w, int h)//顺序bgr
{
	int j = 0;
	switch(flag)
	{
	case 16:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
			for (int i = 0; i < w * h; i++)
			{
				fread(Buf, sizeof(unsigned char), 2, tga);
				read_rgb_depth16(rgbBuf, Buf, j);
				j = j + 3;
			}
			break;
		}
	case 24:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 3);
			for (int i = 0; i < w * h; i++)
			{
				fread(Buf, sizeof(unsigned char), 3, tga);
				read_rgb_depth24and32(rgbBuf, Buf, j);
				j = j + 3;
			}
			break;
		}
	case 32:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 4);
			for (int i = 0; i < w * h; i++)
			{
				fread(Buf, sizeof(unsigned char), 4, tga);
				read_rgb_depth24and32(rgbBuf, Buf, j);
				j = j + 3;
			}
			break;
		}
	default:
		{
			printf("Invalid Bit Depth!");
			system("pause");
			exit(1);
		}
	}
}



void extract_RLE_rgb(int flag, FILE* tga, unsigned char* rgbBuf,  int w, int h)
{
	int j = 0;
	int packsize,packid;
	unsigned char packheader = (unsigned char)malloc(sizeof(unsigned char));
	switch(flag)
	{
	case 16:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
			for (int i = 0; i < w * h;)//i标记像素点
			{
				fread(&packheader, 1, 1, tga);
				packid = (packheader & 0x80) >> 7;
				packsize = (packheader & 0x7f) + 1;
				if (packid == 1)//RLE compressed data
				{
					if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
						break;
					for (int k = 0; k < packsize; k++)
					{
						read_rgb_depth16(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else if (packid == 0)//raw data
				{
					for (int k = 0; k < packsize; k++)
					{
						if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
							break;
						read_rgb_depth16(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else
				{
					printf("error in packet data!");
					system("pause");
					exit(1);
				}
			}
			break;
		}
	case 24:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 3);
			for (int i = 0; i < w * h; )//i标记像素点
			{
				fread(&packheader, 1, 1, tga);
				packid = (packheader & 0x80) >> 7;
				packsize = (packheader & 0x7f) + 1;
				if (packid == 1)//RLE compressed data
				{
					if (fread(Buf, sizeof(unsigned char), 3, tga) == NULL)
							break;
					for (int k = 0; k < packsize; k++)
					{
						read_rgb_depth24and32(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else if (packid == 0)//raw data
				{
					for (int k = 0; k < packsize; k++)
					{
						if (fread(Buf, sizeof(unsigned char), 3, tga) == NULL)
							break;
						read_rgb_depth24and32(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else
				{
					printf("error in packet data!");
					system("pause");
					exit(1);
				}
			}
			break;
		}
	case 32:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 4);
			for (int i = 0; i < w * h; )//i标记像素点
			{
				fread(&packheader, 1, 1, tga);
				packid = (packheader & 0x80) >> 7;
				packsize = (packheader & 0x7f) + 1;
				if (packid == 1)//RLE compressed data
				{
					if (fread(Buf, sizeof(unsigned char), 4, tga) == NULL)
							break;
					for (int k = 0; k < packsize; k++)
					{
						read_rgb_depth24and32(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else if (packid == 0)//raw data
				{
					for (int k = 0; k < packsize; k++)
					{
						if (fread(Buf, sizeof(unsigned char), 4, tga) == NULL)
							break;
						read_rgb_depth24and32(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else
				{
					printf("error in packet data!");
					system("pause");
					exit(1);
				}
			}
			break;
		}
	default:
		{
			printf("Invalid Bit Depth!");
			system("pause");
			exit(1);
		}
	}
}


void readRGB(FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h)
{
	if ((uint8_t)hd->image_type == 2)//Uncompressed Ture_Color Image
		extract_raw_rgb((uint8_t)hd->depth, tga, rgbBuf, w, h);
	if ((uint8_t)hd->image_type == 10)//Compressed Ture_Color Image
		extract_RLE_rgb((uint8_t)hd->depth, tga, rgbBuf, w, h);
}
readGray.cpp
#include"header.h"
void read_gray_depth8and16(unsigned char* rgbBuf, unsigned char *Buf, int j)
{
	rgbBuf[j] = Buf[0];//b
	rgbBuf[j + 1] = Buf[0];//g
	rgbBuf[j + 2] = Buf[0];//r
}

void extract_raw_gray(int flag, FILE* tga, unsigned char* rgbBuf,  int w, int h)
{
	int j = 0;
	switch(flag)
	{
	case 8:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char));
			for (int i = 0; i < w * h; i++)
			{
				fread(Buf, sizeof(unsigned char), 1, tga);
				read_gray_depth8and16(rgbBuf, Buf, j);
				j = j + 3;
			}
			break;
		}
	case 16:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
			for (int i = 0; i < w * h; i++)
			{
				fread(Buf, sizeof(unsigned char), 2, tga);
				read_gray_depth8and16(rgbBuf, Buf, j);
				j = j + 3;
			}
			break;
		}
	default:
		{
			printf("Invalid Bit Depth!");
			system("pause");
			exit(1);
		}
	}
}

void extract_RLE_gray(int flag, FILE* tga, unsigned char* rgbBuf,  int w, int h)
{
	int j = 0;
	int packsize,packid;
	unsigned char packheader = (unsigned char)malloc(sizeof(unsigned char));
	switch(flag)
	{
	case 8:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char));
			for (int i = 0; i < w * h;)//i标记像素点
			{
				fread(&packheader, 1, 1, tga);
				packid = (packheader & 0x80) >> 7;
				packsize = (packheader & 0x7f) + 1;
				if (packid == 1)//RLE compressed data
				{
					if (fread(Buf, sizeof(unsigned char), 1, tga) == NULL)
							break;
					for (int k = 0; k < packsize; k++)
					{
						read_gray_depth8and16(rgbBuf, Buf, j);
						j = j + 3;
						i++;
					}
				}
				else if (packid == 0)//raw data
				{
					for (int k = 0; k < packsize; k++)
					{
						if (fread(Buf, sizeof(unsigned char), 1, tga) == NULL)
							break;
						read_gray_depth8and16(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else
				{
					printf("error in packet data!");
					system("pause");
					exit(1);
				}
			}
			break;
		}
	case 16:
		{
			unsigned char *Buf = (unsigned char*)malloc(sizeof(unsigned char) * 2);
			for (int i = 0; i < w * h;)//i标记像素点
			{
				fread(&packheader, 1, 1, tga);
				packid = (packheader & 0x80) >> 7;
				packsize = (packheader & 0x7f) + 1;
				if (packid == 1)//RLE compressed data
				{
					if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
							break;
					for (int k = 0; k < packsize; k++)
					{
						read_gray_depth8and16(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else if (packid == 0)//raw data
				{
					for (int k = 0; k < packsize; k++)
					{
						if (fread(Buf, sizeof(unsigned char), 2, tga) == NULL)
							break;
						read_gray_depth8and16(rgbBuf, Buf, j);
						i++;
						j = j + 3;
					}
				}
				else
				{
					printf("error in packet data!");
					system("pause");
					exit(1);
				}
			}
			break;
		}
	default:
		{
			printf("Invalid Bit Depth!");
			system("pause");
			exit(1);
		}
	}
}


void readGray(FILEHEADER* hd, FILE* tga, unsigned char* rgbBuf, int w, int h)
{
	if ((uint8_t)hd->image_type == 3)//Uncompressed Ture_Color Image
		extract_raw_gray((uint8_t)hd->depth, tga, rgbBuf, w, h);
	if ((uint8_t)hd->image_type == 11)//Compressed Ture_Color Image
		extract_RLE_gray((uint8_t)hd->depth, tga, rgbBuf, w, h);
}
main.cpp
#include"header.h"
int read_image_and_colormap(FILEHEADER* hd, FILE* tga)
{
	int offset = 0;
	if ((uint8_t)hd->ID_len == 0)
		printf("No Image ID information.\n");
	else
	{
		unsigned char *image_id = (unsigned char*)malloc(sizeof(unsigned char) * (uint8_t)hd->ID_len);
		offset += (uint8_t)hd->ID_len;
		fread(image_id, sizeof(unsigned char), (uint8_t)hd->ID_len, tga);
		cout << "Image ID:\t" << image_id << "\n";
	}
	if ((int8_t)hd->colormap_type == 0)
		printf("No PALETTE in tga image.\n");
	else if ((int8_t)hd->colormap_type == 1)
	{
		offset += (uint16_t)hd->colormap_len * (uint8_t)hd->colormap_entrysize;
	}
	system("pause");
	return offset;
}



int main(int argc, char *argv)
{
	FILE* tga = NULL;
	FILE* yuv = NULL;
	FILEHEADER hd;
	memset(&hd, 0, sizeof(FILEHEADER));
	tga = fopen(argv[1], "rb");//argv[1]为tga文件位置
	if (tga == NULL)
	{
		printf("errors in opening tga file.");
		exit(1);
	}
	readfileheader(&hd, tga);//读取图像信息

	//读取其他信息
	const int Width = hd.width;
	const int Height = hd.height;
	int offset = read_image_and_colormap(&hd, tga) + 18;
	fseek(tga, offset, SEEK_SET);

	//读取颜色信息
	unsigned char *rgbBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height * 3));
	switch((uint8_t)hd.image_type)
	{
	case 2:
	case 10://真彩图
		{
			readRGB(&hd, tga, rgbBuf, Width, Height);//读出数据
			printf("rgb\n");
			break;
		}
	case 3:
	case 11://灰度图
		{
			readGray(&hd, tga, rgbBuf, Width, Height);//读出数据
			printf("gray\n");
			break;
		}
	default:
		{
			printf("the program does not support this type of image.");
			system("pause");
			exit(0);
		}
	}
	fclose(tga);

	//上下倒向
	unsigned char *newBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height * 3));
	for (int i = 0; i < Height; i++)
	{
		for (int j = 0; j < Width * 3; j = j + 3)
		{
			newBuf[i * Width * 3 + j] = rgbBuf[(Height - i - 1) * Width * 3 + j];
			newBuf[i * Width * 3 + j + 1] = rgbBuf[(Height - i - 1) * Width * 3 + j + 1];
			newBuf[i * Width * 3 + j + 2] = rgbBuf[(Height - i - 1) * Width * 3 + j + 2];
		}
	}
	
	//转向YUV空间
	unsigned char *yBuf, *uBuf, *vBuf;
	yBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height));
	uBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height / 4));
	vBuf = (unsigned char*)malloc(sizeof(unsigned char) * (Width * Height / 4));
	rgb_to_yuv(newBuf, yBuf, uBuf, vBuf, Width, Height);//RGBtoYUV




	//输出YUV文件
	yuv = fopen(argv[2], "wb");//argv[2]为输出YUV文件文件位置
	if (yuv == NULL)
	{
		printf("errors in opening yuv file.");
		system("pause");
		exit(1);
	}
	fwrite(yBuf, sizeof(unsigned char), Width * Height, yuv);
	fwrite(uBuf, sizeof(unsigned char), Width * Height / 4, yuv);
	fwrite(vBuf, sizeof(unsigned char), Width * Height / 4, yuv);
	fclose(yuv);
	printf("convert sucessfully\n");
	system("pause");
}
实验结果:

实验共测试了8种图像(256*256):

24,32色非压缩RGB真彩图像

24,32色RLE压缩RGB真彩图像

8,16级非压缩灰度图像

8,16级RLE压缩灰度图像

转换成YUV文件后用YUVviewerPlus打开后如下:

在这里插入图片描述

从这几张图看效果还是很不错的。

实验中碰到的问题:

  • cout输出’0’时会碰到输出空字符的情况,要注意。
  • 算法一定要确认无误再进行扩展,改代码是在痛苦。。
  • 尤其注意对内存分配的相关应用和容易出现的问题。
  • 对结构体指针等的应用应该更加熟悉,避免出现低级错误。
  • 代码其实可以更加简洁,写代码前务必理清思路。

其他:

对有颜色表的图像可参考github上的大佬写的代码,本实验的测试图片也是这里找的。

https://github.com/npedotnet/TGAReader

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值