要求
1.编写C++将RGB格式图片转换为YUV格式
2.编写C++将YUV格式图片转换为RGB格式,并分析与原RGB图像的误差
简介
1.图片分辨率为256x256,YUV格式文件为4:2:0格式采样
2.软件用的是Visual studio 2019,用fstream库读写文件
3.虽然老师给了代码,但还是想自己写哈哈,途中只遇到了一个小问题,特此感谢李老师的帮助:出现一些小红点和小蓝点,原来是unsigned char类型的数据上限只有255,下限是0,如果给一个数260就会变成5,实际上应该把它变成255,需要定义一个int类型先接收数据进行转换
实现
1.公式
RGB转VUY的公式:
Y = 0.299R+0.587G+0.114B
U = -0.1684R-0.3316G+0.5B
V = 0.5R-0.4187G-0.0813B
用个简单的matlab程序得到RGB转YUV的公式:
%format long %多看几位小数
a = [0.299 0.587 0.114;-0.1684 -0.3316 0.5;0.5 -0.4187 -0.0813];
inv(a) % 得到逆矩阵,也就是YUV转RGB的矩阵
结果为:
ans =
1.0000 -0.0000 1.4020
1.0000 -0.3441 -0.7139
1.0000 1.7718 -0.0013
也就是:
R = Y+1.4020V
G = Y-0.3441U-0.7139V
B = Y+1.7718U-0.0013V
2.图像格式
RGB格式:读取的一列数据为[b g r][b g r][b g r]…
每一个括号为一个像素点,实际上得到的数据就是bgrbgrbgr…256x256个像素点,每个像素点3个通道分量
YUV格式:此处为4:2:0格式采样,先读取256x256个Y分量,再读取128x128个U分量,最后读取128x128个V分量
4.代码
RGB转YUV
读取数据,初始化变量
#include<iostream>
#include<fstream>
using namespace std;
// yuv为4:2:0格式,且图像宽高都为偶数,
// 参数:输入图像路径,输出图像路径,宽,高
void rgb2yuv(const char* in_path,const char* out_path, int width, int height)
{
int i, k = 0;
int w = width;
int h = height;
unsigned char* buffer = new unsigned char[w * h * 3];// 存储RGB数据
ifstream in(in_path, ios::binary);
ofstream out(out_path, ios::binary);
in.read((char*)buffer, w * h * 3);// 读取RGB数据
unsigned char* y = new unsigned char[w * h];
unsigned char* temple_u = new unsigned char[w * h]; // 得到一个w*h的U和V的矩阵暂时存着,后面得转成w/2*h/2的矩阵
unsigned char* temple_v = new unsigned char[w * h];
unsigned char* u = new unsigned char[w * h / 4]; // 存储真正的UV分量
unsigned char* v = new unsigned char[w * h / 4];
将每个像素点的BGR分量转化为YUV分量,但由于是4:2:0格式,此时的UV分量不是最后写入文件的UV分量
for (i = 0; i < w * h; i++)
{
// [k]里面存着b,[k+1]里面存着g,[k+2]里面存 着r,k+3跳到下一个b
y[i] = 0.114 * buffer[k] + 0.587 * buffer[k + 1] + 0.299 * buffer[k + 2];
temple_u[i] = 0.5 * buffer[k] - 0.3316 * buffer[k +