YUV是电视系统所采用的一种颜色编码方法,yuv属于像素层,它的原理是把亮度与色度分离,因为研究证明,人眼对亮度很敏感,对色度不是那么敏感。基于上述人眼视觉系统的特点,对不敏感的色度信息进行压缩,有效地节省了图像的数据量。
获取YUV格式图像
mp4转换yuv:ffmpeg -i test.mp4 out.yuv
注意打印信息:格式yuv420p,大小640x272(后面需要用到)
播放: ffplay -f rawvideo -video_size 680x272 out.yuv
YUV存储格式
YUV4:2:0
指每4个Y分量采样,对应2个U采样、或2个V采样。
常见格式I420: YYYYYYYY UU VV => YUV420P
1、分离yuv420p格式图像中的y、u、v分量
①代码:
void yuv420_split(char *yuvfile, int w, int h, int num) {
FILE *fp = fopen(yuvfile, "r");
FILE *fy = fopen("output_420_y.y", "w+");
FILE *fu = fopen("output_420_u.y", "w+");
FILE *fv = fopen("output_420_v.y", "w+");
char framebuf[w*h*3/2]; // yuv420p
for (int i = 0; i < num; i++) {
fread(framebuf, 1, w*h*3/2, fp); //取一帧数据
fwrite(framebuf, 1, w*h, fy); // y
fwrite(framebuf + w*h, 1, w*h/4, fu); // u
fwrite(framebuf + w*h + w*h/4 , 1, w*h/4, fv); // v
}
fclose(fp);
fclose(fy);
fclose(fu);
fclose(fv);
}
调用函数:yuv420_split("test_yuv420p.yuv", 640, 272, 1); // 取一帧图像
②查看分量图像
得到的output_420_u.y 、output_420_v.y 、output_420_y.y文件,使用YUV Player查看图片:
注意:
1、所有分量的图像都使用Y分量的格式播放
2、U,V分量的w和h都是Y分量的一半,即设为320,136
下图依次是Y,U,V分量的图像:
2、分离yuv444格式图像中的y、u、v分量
3、将YUV420图像的颜色设为灰色
for (int i = 0; i < num; i++) {
fread(framebuf, 1, w*h*3/2, fp); //取一帧数据
// y表示明亮度,u,v则是色度、浓度
memset(framebuf + w*h, 128, w*h/2);
fwrite(framebuf, 1, w*h*3/2, fgray);
}
结果对比:
4、在灰度图基础上将亮度减为原来的一半
出现了一个问题
:将y分量缩小后得到下面的图像
原因:yuv分量数据是unsigned char类型的。
从灰度图那(设置u,v分量为128)应该可以想到的。正确图像如下:
5、给图像加边框
函数void yuv420_border(char *yuvfile, int w, int h, int border, int num)
核心代码:
unsigned char framebuf[w*h*3/2];
for (int i = 0; i < num; i++) {
fread(framebuf, 1, w*h*3/2, fp); // 取一帧数据
for (int j = 0; j < h; j++) { // 行扫描
for (int k = 0; k < w; k++) {// 列扫描
if (j < border || j > h - border || \
k < border || k > w - border)
framebuf[j*w + k] = 255; // 白边框
}
}
fwrite(framebuf, 1, w*h*3/2, fborder);
}
函数调用:yuv420_border("output_gray.yuv", 640, 272, 20, 1);