数据压缩(6):将TGA图像转为YUV文件

1.了解TGA文件里数据的储存方式
在这里插入图片描述
2.代码实现

#include "stdafx.h"
using namespace std;
#include <iostream>
#include <cstdio>
#include <fstream>
#include <windows.h>
#include <malloc.h>
#include <stdlib.h>


typedef struct _TgaHeader
{
    BYTE IDLength;        /* 00h  Size of Image ID field */
    BYTE ColorMapType;    /* 01h  Color map type */
    BYTE ImageType;       /* 02h  Image type code */
}TGAHEAD;

typedef struct _TgaHeaderCMap
{
    WORD CMapStart;       /* 03h  Color map origin */
    WORD CMapLength;      /* 05h  Color map length */
    BYTE CMapDepth;       /* 07h  Depth of color map entries */
}TGAHEADCMAP;

typedef struct _TgaHeaderImage
{
    WORD XOffset;         /* 08h  X origin of image */
    WORD YOffset;         /* 0Ah  Y origin of image */
    WORD Width;           /* 0Ch  Width of image */
    WORD Height;          /* 0Eh  Height of image */
    BYTE PixelDepth;      /* 10h  Image pixel size */
    BYTE ImageDescriptor; /* 11h  Image descriptor byte */
}TGAHEADIMG;
int main()
{
	FILE *TgaFile = NULL,*YuvFile = NULL,*RgbFile = NULL;
	if((TgaFile=fopen("D:\\大三下\\数据压缩\\cx24.tga","rb")) == NULL)
	{
		printf("tga file open failed!");
		exit(0);
	}
	if ((YuvFile=fopen("D:\\大三下\\数据压缩\\cx24.yuv","wb"))== NULL) 
	{
		printf("yuv file  open failed!");
		exit(0);
	}
	
    TGAHEAD tga_header;
    TGAHEADCMAP tga_header_cmap;
    TGAHEADIMG tga_header_img;
	fread(&tga_header,3,1,TgaFile);
	fread(&tga_header_cmap,5,1,TgaFile);
	fread(&tga_header_img,10,1,TgaFile);
	unsigned char* ImageData = NULL;
    unsigned char* b = NULL;
    unsigned char* g = NULL;
    unsigned char* r = NULL;
	unsigned char* R = NULL;
    unsigned char* G = NULL;
    unsigned char* B = NULL;
	unsigned char* Y = NULL;
    unsigned char* U = NULL;
    unsigned char* V = NULL;
	unsigned char* u = NULL;
    unsigned char* v = NULL;
    unsigned char* RGB = NULL;
    unsigned char* YUV = NULL;

	if (tga_header.ColorMapType == 0)//不带颜色表
    {
        if (tga_header.ImageType == 0)
            exit(0);
        else if (tga_header.ImageType == 2)//未压缩的真彩色图像
        {
            int depth = tga_header_img.PixelDepth;
            int width = tga_header_img.Width;
            int height = tga_header_img.Height;
            int size = width * height * depth / 8;//整个图像块的大小
            cout << "该文件是未压缩的真彩色图像" << endl;
            cout << "图像分辨率为" << width << "×" << height << endl;
            cout << "像素深度为" << depth << "bit" << endl;
            ImageData = new unsigned char[size];
            fread(ImageData,1,size,TgaFile);
            b = (unsigned char *)malloc(sizeof(char)*(width * height));
            g = (unsigned char *)malloc(sizeof(char)*(width * height));
            r = (unsigned char *)malloc(sizeof(char)*(width * height));
			R = (unsigned char *)malloc(sizeof(char)*(width * height));
            G = (unsigned char *)malloc(sizeof(char)*(width * height));
            B = (unsigned char *)malloc(sizeof(char)*(width * height));
			Y = (unsigned char *)malloc(sizeof(char)*(width * height));
			U = (unsigned char *)malloc(sizeof(char)*(width * height));
			V = (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));
            RGB = new unsigned char[width * height * 3];

			//16位
			if (tga_header_img.PixelDepth == 16)
			{
			for (int j=0 ,i = 0; i < width * height; i++)
		{
		   {
			   b[i] = (ImageData[j] & 0x1F) << 3;
			   g[i] = ((ImageData[j + 1] & 0x03) << 6) + ((ImageData[j] & 0xE0) >> 2);
			   r[i] = ((ImageData[j + 1] & 0x7C)) << 1;
			   j = j + 2;
			  }
		  }
			}

			//24位
			if (tga_header_img.PixelDepth == 24)
			{
			for (int j=0 ,i = 0; i < width * height; i++)
		{
		   b[i] = ImageData[j];
		   g[i] = ImageData[j + 1];
		   r[i] = ImageData[j + 2];
		   j = j + 3;
		  }
			}

			//32位
			if (tga_header_img.PixelDepth == 32)
			{
			for (int j=0 ,i = 0; i < width * height; i++)
		{
			   b[i] = ImageData[j];
			   g[i] = ImageData[j + 1];
			   r[i] = ImageData[j + 2];
			   j = j + 4;
		  }
			}

		 for (int k=0,i = height-1; i >= 0; i--)
		 {
		  for (int j = 0; j < width; j++)
		  {
		   RGB[k] = b[j + i * width];
		   RGB[k+1] = g[j + i * width];
		   RGB[k+2] = r[j + i * width];
		   k = k + 3;
		  }
		 }
	for(int i=0,j=0;i<width*height*3;i=i+3,j++)
		{
		R[j]=RGB[i+2];
		G[j]=RGB[i+1];
		B[j]=RGB[i];
		}
	//计算YUV分量
	for(int i=0,j=0;i<width*height;i++,j++)
	{
		Y[j]=0.2990*R[i]+0.5870*G[i]+0.1140*B[i];
		U[j]=-0.1684*R[i]-0.3316*G[i]+0.5*B[i]+128;
		V[j]=0.5*R[i]-0.4187*G[i]-0.0813*B[i]+128;
	}
	//对UV下采样
	for(int k=0, i=0;i<height;i=i+2)
	{
		for(int j=0;j<width;j=j+2)
		{
		u[k]=(U[width*i+j]+U[width*i+j+1]+U[(i+1)*width+j]+U[(i+1)*width+j+1])/4;
		v[k]=(V[width*i+j]+V[width*i+j+1]+V[(i+1)*width+j]+V[(i+1)*width+j+1])/4;
		
		k++;
		}
	}
	//YUV量化后码电平分配
	for(int k=0;k<width*height;k++)
	{
		if(Y[k]>235)
			Y[k]=235;
		 if(Y[k]<16)
			Y[k]=16;
	}
	for(int k=0;k<width*height/4;k++)
	{
		if(u[k]>240)
			u[k]=240;
		if(u[k]<16)
			u[k]=16;
		if(v[k]>240)
			v[k]=240;
		if(v[k]<16)
			v[k]=16;
	}
	
	fwrite(Y,1,width*height,YuvFile);
	fwrite(u,1,width*height/4,YuvFile);
	fwrite(v,1,width*height/4,YuvFile);
        }

    }
    else
        exit(0);
	if(ImageData);
	free(ImageData);
	if(b);
	free(b);
	if(g);
	free(g);
	if(r);
	free(r);
	if(Y);
	free(Y);
	if(U);
	free(U);
	if(V);
	free(V);
	if(u);
	free(u);
	if(v);
	free(v);
	if(RGB);
	free(RGB);
	fclose(TgaFile);
	fclose(YuvFile);
	 return 0;
}

3.结果
原图:
在这里插入图片描述

无压缩真彩色16bit运行截图
在这里插入图片描述在这里插入图片描述
无压缩真彩色24bit运行截图
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

4.实验心得
通过这次实验我对有文件头的图像文件有了进一步的了解,尤其是对TGA文件,对结构体的定义和使用有了浅显的了解,但是对于如何调用函数还是有点问题,所以我把代码都写在一个main里了,这部分代码只能处理无压缩真彩色图像,对于有压缩图像和有颜色表的图像还不太会处理,今后对C++语言和多媒体文件还需多加学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值