像素格式:YUV

494 阅读7分钟

YUVRGB是我们常见的两大类像素格式。

YUV是一种颜色模型。相比较于RGB,它在考虑人类感知的情况下对彩色图像进行编码,从而减少色度分量的带宽。

在YUV模型的定义中:Y表示亮度分量,可以看作是灰度图。UV是两个色度分量,分别代表蓝色投影、红色投影。

YUV与YCrCb

YCrCbYUV的别称,CrCb分别指UV

下采样:4:4:4、4:2:2、4:1:1、4:2:0

下采样:人眼对亮度的变化敏感度是高于对色度变化的。所以,YUV的下采样,在不改变亮度分量Y的情况下,对U、V两个颜色分量,采取不同的下采样策略,以达到适当降低图像质量,优化内存占用的目的。

YUV4:4:4:无下采样。Y、U、V每个像素都进行采样。如果每个分量占8bit,那么每个像素占24bit。

YUV4:2:2:使用 2:1 的水平下采样。Y每个像素都进行采样,而U、V则在水平方向上每两个像素采样一次。如果每个分量占8bit,则两个像素占32bit,即平均一个像素占16bit。

YUV4:1:1:使用 4:1 的水平下采样。Y每个像素都进行采样,而U、V则在水平方向上每四个像素采样一次。如果每个分量占8bit,则四个像素占48bit,即平均一个像素占12bit。

YUV4:2:0:使用 2:1 的水平下采样和 2:1 的垂直下采样。Y每个像素都进行采样,而U、V则在每个 2x2 像素块处采样一次。如果每个分量占8bit,则四个像素占48bit,即平均一个像素占12bit。

Packed、Planar和Semi-planar

关于Packed、Planar,可参考:图像存储策略:Packed与Planar

YUV的存储格式有三种:PackedPlanarSemi-planar

Packed:Y、U、V三个分量,在内存中交错保存。如YUYV422

Planar:Y、U、V三个分量,保存在不同的平面中。不同的平面代表不同的连续内存块。通常内存排列先是Y平面,然后紧跟U平面,最后是V平面。当然,拆开保存成不同的文件亦可。该格式通常以P为结尾,如YUV420P

Semi-Planar:Y分量保存在一个平面。U、V分量保存在另一个平面,两者交错保存。该格式通常以SP为结尾,如YUV420SP

I420与YV12

两者都是YUV420P,区别在于UV的内存排列:

I420:先是Y平面,然后是U平面,最后是V平面。(I420又称IYUV)

YV12:先是Y平面,然后是V平面,最后是U平面。

NV12与NV21

两者都是YUV420SP,Y分量保存在一个平面。U、V分量保存在另一个平面,两者交错保存。区别在于UV的排列先后。

NV12:在U&V平面,第一个字节是U,第二个字节是V。周而复始。

NV21:在U&V平面,第一个字节是V,第二个字节是U。周而复始。

YUV444P10BE与YUV444P10LE

BE即大端字节序。LE即小端字节序。

10即10bit表示一个分量:

YUV444P采用8bit表示一个分量。每个分量的可取值是有8 = 256种。每个像素的可取值有 28 * 28 * 28 = 16,777,216种。

YUV444P10采用10bit表示一个分量。每个分量的可取值有210 = 1,024种。每个像素的可取值有 210 * 210 * 210 = 1,073,741,824种,远多于YUV444P。能在光暗、颜色上表现得更加细腻、逼真,但内存占用也更大。

计算YUV大小

一张分辨率为w * h的YUV图:

如果是YUV444P,则:

size(YUV) = size(Y) + size(U) + size(V) 
          = w * h + w * h + w * h 
          = w * h * 3

如果是YUV422P,则:

size(YUV) = size(Y) + size(U) + size(V) 
          = w * h + (w / 2) * h + (w / 2) * h 
          = w * h * 2

如果是YUV420P,则:

size(YUV) = size(Y) + size(U) + size(V) 
          = w * h + (w / 2) * (h / 2) + (w / 2) * (h / 2) 
          = w * h * 1.5

YUVResource提供了几张不同YUV格式,分辨率均为720P,即1280x720的图片。

park_joy_444_1280x720.yuvYUV444P,则:

size = 1280 * 720 * 3 = 2,764,800 byte = 2700 kb

park_joy_422_1280x720.yuvYUV422P,则:

size = 1280 * 720 * 2 = 1,843,200 byte = 1800 kb

park_joy_420_1280x720.yuvYUV420P,则:

size = 1280 * 720 * 1.5 = 1,382,400 byte = 1350 kb

YUV像素处理

请参考雷霄骅的视音频数据处理入门:RGB、YUV像素数据处理

(1)分离YUV420P像素数据中的Y、U、V分量

(2)分离YUV444P像素数据中的Y、U、V分量

(3)将YUV420P像素数据去掉颜色(变成灰度图)

(4)将YUV420P像素数据的亮度减半

(5)将YUV420P像素数据的周围加上边框

(6)生成YUV420P格式的灰阶测试图

(7)计算两个YUV420P像素数据的PSNR

YUV查看工具

推荐雷霄骅的修改了一个YUV/RGB播放器。下载地址:yuvplayer.exe

该软件支持YUV/RGB的查看。

YUV转RGB

转换公式

RGB888转为YUV444

Y = ((66 * R + 129 * G +  25 * B + 128) >> 8) +  16
U = ((-38 * R -  74 * G + 112 * B + 128) >> 8) + 128
V = ((112 * R -  94 * G -  18 * B + 128) >> 8) + 128

YUV444转为RGB888

R = clip(( 298 * (Y - 16 )                   + 409 * (V - 128) + 128) >> 8)
G = clip(( 298 * (Y - 16 ) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8)
B = clip(( 298 * (Y - 16 ) + 516 * (U - 128)                   + 128) >> 8)

clip()表示将结果裁剪到[0..255]的范围。

实现代码可以参考YUVSample

注意:示例代码是采用逐像素替换的方式,时间复杂度是O(wh),也是最低效的转换方式

高效转换的几种方法

  • libyuv:Google开源的一个YUV缩放和转换功能的开源项目。libyuv使用CPU的特殊指令集,对CPU的运算做加速,如:row_neon.cc
  • FFmpeg:开源的音视频处理库。它的libswscale也会使用CPU指令集进行加速,如:yuv2rgb_neon.S
  • OpenCV:开源计算机视觉库。与前两者类似,支持指令集加速,如:color_yuv.simd.hpp
  • GPU转换:比如调用OpenGL来转换,速度远大于CPU。但如果转换的结果,要作为其他运算的输入,比如人脸识别,就需要拷贝结果到CPU上,那整体耗时又不如单纯靠CPU处理了。关于如何高效拷贝GPU数据,可参考:Unreal:如何高效的将数据从GPU拷贝到CPU
  • NPU转换:嵌入式同事的一个思路:直接以NV21作为模型输入,利用NPU来做YUV到RGB的转换。模型输出(或后处理)同时可级联至其他模型(detector)的输入(或复用它的前处理)。这样做的目的是,CPU拷贝的数据量少,传输要求带宽少。测试结果来看,速度和CPU相差无几。
  • 2D图形加速驱动:看看厂商有没有提供2D图形加速驱动。嵌入式同事:2D图形加速驱动,驱动是内核本来就会自动调用的,会比CPU特殊指令集还快。

FFmpeg YUV转换命令

YUV444转YUV420

ffmpeg -s 1280x720 -pix_fmt yuv444p -i park_joy_444_1280x720.yuv -pix_fmt yuv420p park_joy_420_1280x720.yuv

YUV444转RGB24

ffmpeg -s 1280x720 -pix_fmt yuv444p -i  park_joy_444_1280x720.yuv -pix_fmt rgb24  park_joy_888_1280x720.rgb

截取YUV视频流某一帧

ffmpeg  -i park_joy_444_720p50.y4m -video_size hd70 -c:v rawvideo -filter:v "select='between(n\, 100\, 100)'" park_joy_444_1280x720.yuv

参考资料

YUV

About YUV Video

About YUV formats

Image Downsampling

Pixel and Planar Image Formats

视音频数据处理入门:RGB、YUV像素数据处理

Recommended 8-Bit YUV Formats for Video Rendering

libyuv提高ffmpeg图像转换效率

使用ffmpeg库进行YUV420到RGB的转化

移动端 YUV_NV21 加速怎么做?