目录
YUV文件的存储结构
取样结构
这组图图每一行即为一行像素点,以Y为基准,蓝色和红色表示 C b / U C_b/U Cb/U和 C r / V C_r/V Cr/V
4:4:4
4:2:2
4:1:1
4:2:0格式1
4:2:0格式2
存储结构
一下均指一帧的情况,实际上是一帧内容按照相应格式存储完成后,再存储下一帧。
YUVY(4:2:2)
Y
0
C
b
0
Y
1
C
r
0
Y
2
C
b
1
Y
3
C
r
2
⋯
Y_0C_{b_0}Y_1C_{r_0}Y_2C_{b_1}Y_3C_{r_2}\cdots
Y0Cb0Y1Cr0Y2Cb1Y3Cr2⋯
即
Y
Y
Y后跟
C
b
C_b
Cb与
Y
Y
Y后跟
C
r
C_r
Cr交替出现。
UYVY(4:2:2)
C
b
0
Y
0
C
r
0
Y
1
C
b
1
Y
2
C
r
2
Y
3
⋯
C_{b_0}Y_0C_{r_0}Y_1C_{b_1}Y_2C_{r_2}Y_3\cdots
Cb0Y0Cr0Y1Cb1Y2Cr2Y3⋯。
即
C
b
C_b
Cb后跟
Y
Y
Y与
C
r
C_r
Cr后跟
Y
Y
Y交替出现。
YUV422P(4:2:2)
先存储完所有Y,再存储完所有 C b C_b Cb,最后再存储所有 C r C_r Cr。
YV12,YU12(4:2:0)
先存储完所有Y,再存储完所有 C b C_b Cb,最后再存储所有 C r C_r Cr。
NV12,NV21(4:2:0)
先存储完所有Y,之后 C b x C_{b_x} Cbx C b x + 1 C_{b_{x+1}} Cbx+1 C r x C_{r_x} Crx C r x + 1 C_{r_{x+1}} Crx+1的结构交替出现,即两字节 C b C_b Cb之后再存储两字节 C r C_r Cr。
所占空间计算
每一个像素点用1字节存储信息。知道分辨率,即高
h
h
h和宽度
w
w
w之后,
h
×
w
h\times w
h×w即是Y所占空间大小,再根据取样结构算出U和V所占比例,相加即为一帧所占大小。
如4:2:0格式,Y占用
h
×
w
h\times w
h×w,U和V占用
h
×
w
×
2
4
h\times{w}\times\frac{2}{4}
h×w×42,加起来一帧所占的空间就是
3
h
w
2
\frac{3hw}{2}
23hw
使用c++进行处理
知道文件怎么存储之后,就可以进行处理了。以288乘352的YV12格式为例。
如果我想把它变成黑白的,那么我只需要保留Y的信息,其余都抹掉即可。那么去掉U,V是否是把他们变成0呢?并不是,因为U,V有负值,而处理数据的时候却不按照负值处理,于是U,V的0的位置,被128代替;也就是说128才是实际意义上的0。
#include <fstream>
#include <iostream>
using namespace std;
const char* inPath = "miss.cif";
const char* outPath = "miss_out.cif";
int main()
{
ifstream in(inPath, ios::binary);
in.seekg(0, ios::end);
int size = in.tellg();
in.seekg(0, ios::beg);
char* inBuffer = new char[size];
in.read(inBuffer, size);
in.close();
char* outBuffer = new char[size];
int width = 352, height = 288, inFrameSize = width * height * 3 / 2;
int frameNum = size / inFrameSize;
for (int i = 0; i < frameNum; ++i)
for (int j = 0; j < inFrameSize; ++ j)
outBuffer[i * inFrameSize + j] = j < width * height ? inBuffer[i * inFrameSize + j] : 128;
ofstream out(outPath,ios::binary);
out.write(outBuffer, size);
out.close();
}
处理完成后使用YUV播放器查看效果:
处理前:
处理后: