欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据压缩实验报告二 TGA转YUV

程序员文章站 2022-07-14 22:12:18
...

写在前面:
由于大二上学习C++时没有进行充分的练习,这次的实验先是自己想了很久但是无果,最后只能参考同学的代码。看不懂的地方和同学讨论并逐渐理解。感觉自己的情况就是知道大概的思路方法,但是不知道如何用代码实现。在没有参考的前提下没法自己写出完整的代码,还是需要多思考多练习。

代码:
pga_struct.h(用来创建pga文件的结构体)

#pragma once
#include <windows.h>
#include <iostream>
#include <fstream>
using namespace std;

//TGA文件结构体
typedef struct TgaHeader 
{
    BYTE IDLength;        
    BYTE ColorMapType;    
    BYTE ImageTypeCode;     
} TGAHEAD;

typedef struct TgaHeader_Color 
{
    WORD ColorMapStart;      
    WORD ColorMapLength;     
    BYTE ColorMapDepth;      
}TGAHEAD_Color;

typedef struct TgaHeader_Info
{
    WORD XStart;        
    WORD YStart;        
    WORD w2;           
    WORD h2;         
    BYTE PixelDepth;      
    BYTE ImageDescriptor; 
}TgaHeader_Info;

void Read_rgb(ifstream& file, unsigned char* R_buffer, unsigned char* G_buffer, unsigned char* B_buffer, int h1, int w1);
void Read_rgb_ColorMap(ifstream& file, TGAHEAD_Color& color, unsigned char* R_buffer, unsigned char* G_buffer, unsigned char* B_buffer, int h1, int w1);

rgb2yuv.h(定义rgb2yuv.cpp中所需要的函数)

#pragma once
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <malloc.h>
using namespace std;

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

void table();
void process(int h1, int w1, unsigned char* R, unsigned char* G, unsigned char* B, unsigned char* Y, unsigned char* U, unsigned char* V);
void subsample(int h2, int w2, unsigned char* U, unsigned char* V, unsigned char* U2, unsigned char* V2);
void write(int h2, int w2, unsigned char* Y, unsigned char* U, unsigned char* V);

tga.cpp(主要包含读取rgb数据和颜色表的函数)

#include "tga_struct.h"

void Read_rgb(ifstream& file, unsigned char* R_buffer, unsigned char* G_buffer, unsigned char* B_buffer, int h1, int w1) 
{
	for (int i = h1 - 1; i >= 0; i--)
	{
		for (int j = 0; j < w1; j++)
		{
			file.read((char*)(B_buffer + (i * w1 + j)), 1);
			file.read((char*)(G_buffer + (i * w1 + j)), 1);
			file.read((char*)(R_buffer + (i * w1 + j)), 1);
		}
	}
}

void Read_rgb_ColorMap(ifstream& file, TGAHEAD_Color& color, unsigned char* R_buffer, unsigned char* G_buffer, unsigned char* B_buffer, int h1, int w1)
{
	unsigned char* Table_R = new unsigned char[color.ColorMapLength];
	unsigned char* Table_G = new unsigned char[color.ColorMapLength];
	unsigned char* Table_B = new unsigned char[color.ColorMapLength];
	unsigned char* k = new unsigned char[h1 * w1];

	// 读入颜色表
	for (int i = 0; i < color.ColorMapLength; i++)
	{
		file.read((char*)(Table_B + i), 1);
		file.read((char*)(Table_G + i), 1);
		file.read((char*)(Table_R + i), 1);
	}
	for (int i = h1 - 1; i >= 0; i--) 
	{
		for (int j = 0; j < w1; j++) {
			file.read((char*)(k + (i * w1 + j)), 1);
			*(B_buffer + (i * w1 + j)) = *(Table_B + (*(k + (i * w1 + j))));
			*(G_buffer + (i * w1 + j)) = *(Table_G + (*(k + (i * w1 + j))));
			*(R_buffer + (i * w1 + j)) = *(Table_R + (*(k + (i * w1 + j))));
		}
	}
	if (Table_R != NULL)
		delete Table_R; 
	if (Table_G != NULL) 
		delete Table_G; 
	if (Table_B != NULL) 
		delete Table_B; 
	if (k != NULL)
		delete k;
}

rgb2yuv.cpp(将rgb分量转换为yuv分量、下采样、写文件的函数)

#include "rgb2yuv.h"

void 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;
	}
}
// 计算yuv分量的值
void process(int h1, int w1, unsigned char* R, unsigned char* G, unsigned char* B, unsigned char* Y, unsigned char* U, unsigned char* V) 
{
	float k;
	for (int i = 0; i < h1 * w1; i++) 
	{
		// 计算y分量
		k = RGB2YUV02990[*(R + i)] + RGB2YUV05870[*(G + i)] + RGB2YUV01140[*(B + i)];
		if (k > 236)
			k = 236;
		else if (k < 16)
			k = 16;
		*(Y + i) = (unsigned char)k;
		// 计算u分量
		k = -RGB2YUV01684[*(R + i)] - RGB2YUV03316[*(G + i)] + RGB2YUV05000[*(B + i)] + 128;
		if (k > 236)
			k = 236;
		else if (k < 16)
			k = 16;
		*(U + i) = (unsigned char)k;
		// 计算v分量
		k = RGB2YUV05000[*(R + i)] - RGB2YUV04187[*(G + i)] - RGB2YUV00813[*(B + i)] + 128;
		if (k > 236)
			k = 236;
		else if (k < 16)
			k = 16;
		*(V + i) = (unsigned char)k;
	}
}

//写yuv文件
void write(int h2, int w2, unsigned char* Y, unsigned char* U, unsigned char* V)
{
	ofstream Output_file;
	Output_file.open("new.yuv", ios::binary, ios::trunc);
	if (!Output_file) 
		cout << "Failed to open file" << endl;
	else {
		Output_file.write((char*)Y, h2 * w2);
		Output_file.write((char*)U, h2 * w2 / 4);
		Output_file.write((char*)V, h2 * w2 / 4);
		Output_file.close();
	}
}

// uv分量下采样
void subsample(int h2, int w2, unsigned char* U, unsigned char* V, unsigned char* U2, unsigned char* V2) 
{
	int k = 0;
	float uuu, vvv;
	for (int i = 0; i < h2 * w2 / 4; i++) {
		uuu = (float)(*(U + k) + *(U + k + 1) + *(U + k + w2) + *(U + k + 1 + w2)) / 4;
		vvv = (float)(*(V + k) + *(V + k + 1) + *(V + k + w2) + *(V + k + 1 + w2)) / 4;
		*(U2 + i) = (unsigned char)uuu;
		*(V2 + i) = (unsigned char)vvv;

		if ((i + 1) % (w2 / 2) == 0) 
			k = k + 2 + w2;
		else 
			k = k + 2;
	}
}

task2.cpp(主函数)

#include "rgb2yuv.h"
#include "tga_struct.h"

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

int main(int argc, char* argv[])
{
    unsigned char* buffer_Y = NULL, * buffer_U = NULL, * buffer_V = NULL;
    unsigned char* buffer_R = NULL, * buffer_G = NULL, * buffer_B = NULL;
    unsigned char* U2 = NULL, * V2 = NULL;

    table();
    //判断是否打开文件
    ifstream input_file;
    input_file.open(argv[1], ios::in | ios::binary);
    if (!input_file.is_open()) 
        cout << "input file not opened." << endl;

    // 定义文件头
    TGAHEAD FILE_header;
    TGAHEAD_Color FILE_header_CMap;
    TgaHeader_Info FILE_header_Info;
    // 读文件头
    input_file.read((char*)(&FILE_header), 3);
    input_file.read((char*)(&FILE_header_CMap), 5);
    input_file.read((char*)(&FILE_header_Info), 10);

    int w1 = FILE_header_Info.w2;
    int h1 = FILE_header_Info.h2;

    //建立缓冲区
    buffer_R = new unsigned char[w1 * h1];
    buffer_G = new unsigned char[w1 * h1];
    buffer_B = new unsigned char[w1 * h1];
    buffer_Y = new unsigned char[w1 * h1];
    buffer_U = new unsigned char[w1 * h1];
    buffer_V = new unsigned char[w1 * h1];
    //读rgb文件的内容
    Read_rgb(input_file, buffer_R, buffer_G, buffer_B, h1, w1);
    //计算yuv分量的值
    process(h1, w1, buffer_R, buffer_G, buffer_B, buffer_Y, buffer_U, buffer_V);
    U2 = new unsigned char[int(w1 * h1 / 4)];
    V2 = new unsigned char[int(w1 * h1 / 4)];
    //下采样
    subsample(h1, w1, buffer_U, buffer_V, U2, V2);
    write(h1, w1, buffer_Y, U2, V2);
    //关闭文件,释放缓冲区
    input_file.close();
    if (buffer_Y != NULL) 
        delete buffer_Y; 
    if (buffer_U != NULL) 
        delete buffer_U; 
    if (buffer_V != NULL)
        delete buffer_V; 
    if (U2 != NULL)
        delete U2; 
    if (V2 != NULL) 
        delete V2; 
    if (buffer_R != NULL) 
        delete buffer_R; 
    if (buffer_G != NULL) 
        delete buffer_G; 
    if (buffer_B != NULL)  
        delete buffer_B; 
}

运行结果:数据压缩实验报告二 TGA转YUV原本的TGA图像文件

数据压缩实验报告二 TGA转YUV左上角的墙与原图有色差,眼睛部分明显有被锐化的感觉

相关标签: c++