写在前面:
由于大二上学习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图像文件
左上角的墙与原图有色差,眼睛部分明显有被锐化的感觉