YUV

在开始学习YUV之前,先向大家介绍一款查看YUV图像的查看工具---YUV Eye,这个工具会非常方便调试

1.YUV 概念

YUV 是一种表示颜色的模型,跟RGB是同一个级别的概念,通常用YCbCr这样的形式表示,其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量

2.YUV 和 RGB 比较

2.1 体积对比RGB更小
  • 如果使用RGB
比如RGB888 (R、G、B、每个分量都是8bit),那么
一个像素占用24bit
  • 如果使用YUV
1个像素可以减少至平均只占用12bit(1.5字节)
2.2 组成
  • RGB 数据由R、G、B三个分量组成;
  • YUV数据由Y、U、V三个分量组成,现在通常说的YUV指的是YCbCr
Y:表示亮度(Luminance、Luma),占8bit(1字节)
Cb、Cr:表示色度(Chrominance、Chroma)
- Cb(U):蓝色色度分量,占8bit(1字节)
- Cr(V):红色色度分量,占8bit(1字节)

3.计算公式

3.1 计算公式1
Y = 0.257R + 0.504G + 0.098B + 16
U = -0.148R - 0.291G + 0.439B + 128
V = 0.439R - 0.368G - 0.071B + 128
 
R = 1.164(Y - 16) + 2.018(U - 128)
G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
B = 1.164(Y - 16) + 1.596(V - 128)
  • RGB的取值范围是[0,255]
  • Y的取值范围是[16,235]
  • UV的取值范围是[16,239]
3.2 计算公式2
Y = 0.299R + 0.587G + 0.114B
U = 0.564(B - Y) = -0.169R - 0.331G + 0.500B
V = 0.713(R - Y) = 0.500R - 0.419G - 0.081B
 
R = Y + 1.403V
G = Y - 0.344U - 0.714V
B = Y + 1.770U
  • RGB的取值范围是[0, 1]
  • Y的取值范围是[0, 1]
  • UV的取值范围是[-0.5, 0.5]
3.3 计算公式3
Y = 0.299R + 0.587G + 0.114B
U = -0.169R - 0.331G + 0.500B + 128
V = 0.500R - 0.419G - 0.081B + 128
 
R = Y + 1.403(V - 128)
G = Y - 0.343(U - 128) - 0.714(V - 128)
B = Y + 1.770(U - 128)
  • RGB的取值范围是[0, 255]
  • YUV的取值范围是[0, 255]

4.YUV 格式

YUV格式.png
5.分类标准

我们可以将YUV格式按照数据大小分为三个格式,YUV420,YUV422,YUV444,另外因为人眼中有上亿个感光细胞,其中视杆细胞占了95%,而视锥细胞仅占5%。因此,人眼对亮度的敏感程度要高于对色度的敏感程度,人眼对于亮度的分辨要比对颜色的分辨精细一些。
如果把图像的色度分量减少一些,人眼也丝毫感觉不到变化和差异

- 视杆细胞
感知光线的强弱
没有色彩识别功能
负责夜间非彩色视觉

- 视锥细胞
感知颜色
负责白天彩色视觉
如果你的视锥细胞发育不正常,数量太少,那感知颜色就会受阻,可能会导致你色弱
5.1 采样格式

采样格式通常使用A:B:C的形式来表示,比如4:4:4、4:2:2、4:2:0 等

A:一块A*2个像素的概念区域,一般都是4
B:第1行的色度采样数目
C:第2行的色度采样数目
- C的值一般要么等于B,要么等于0

前面已经说过人眼对Y的敏感度远超过于对U和V的敏感,所以有时候可以多个Y分量共用一种UV,这样既可以极大得节省空间,又可以不太损失质量。

  • YUV 420,由4个Y分量共用一套UV分量

  • YUV 422,由2个分量共用一套UV分量

  • YUV 444,不共用,一个Y分量使用一套UV分量
    下面进行图文解释一下:❌代表亮度,⭕️代表色度

  • 4:4:4

  • 第一行采集4组CbCr分量,第二行采集4组CbCr分量

  • 第一个像素都有自己独立的1组分量

    • Y分量与CbCr分量的水平方向比例是1:1(每1列都有1组CbCr分量)
    • Y分量与CbCr分量的垂直方向比例是1:1 (每1行都有1组CbCr分量)
    • Y分量与CbCr分量的总比例是1:1
  • 1个像素占用24bit(3字节),跟RGB888体积一样

    • 24bpp(bits per pixel)


      YUV444.png
  • 4:2:2

  • 第一行采集2组CbCr分量,第二行采集2组CbCr分量

  • 水平方向相邻的2个像素(1行2列)共用1组CbCr分量

    • Y分量与CbCr分量的水平方向比例是2:1(每2列就有1组CbCr分量)
    • Y分量与CbCr分量的垂直方向比例是1:1(每1行都有1组CbCr分量)
    • Y分量与CbCr分量的总比例是2:1
  • 1个像素平均占用16bit(2字节)

    • 16bpp
    • 因为2个像素共占用32bit(4字节 = 2个Y分量 + 1个Cb分量 + 1个Cr分量)


      YUV422.png
  • 4:2:0

  • 第一行采集2组CbCr分量,第二行共享第一行的CbCr分量

    • Y分量与CbCr分量的水平方向比例是2:1(每2列就有1组CbCr分量)
    • Y分量与CbCr分量的垂直方向比例是2:1(每2行就有1组CbCr分量)
    • Y分量与CbCr分量的总比例是4:1
  • 1个像素平均占用12bit(1.5 字节)

    • 12bpp
    • 因为4个像素共占用48bit(6字节 = 4个Y分量 + 1个Cb分量 + 1个Cr分量)


      YUV420.png
按照多个Y分量共用一个UV的方式,我们可以把YUV分为420,422,444 三种类型,而在这三种类型之下,我们又可以按照YUV的排列存储顺序,将其细分为好多种格式

6.存储格式

存储格式,决定了YUV数量是如何排列和存储的


YUV格式.png
6.1 分类
YUV的存储格式可以分为3大类:
  • Plannar 平面
Y、U、V分量单独存储
名称通常以字母p结尾
  • Semi-Plannar(半平面)
Y分量单独存储,U、V分量交错存储
名称通常以字母sp结尾
  • Packed(紧凑)
或者叫Interleaved,YUV分量交错存储
6.2 具体分类

4:4:4

  • Plannar
  • I444
Y Y Y Y
Y Y Y Y
U U U U
U U U U
V V V V
V V V V
  • YV24
Y Y Y Y
Y Y Y Y
V V V V
V V V V
U U U U
U U U U
  • Semi-Plannar
  • NV24
Y Y Y Y
Y Y Y Y
U V U V U V U V
U V U V U V U V
  • NV42
Y Y Y Y
Y Y Y Y
V U V U V U V U
V U V U V U V U

4:2:2

  • Plannar
  • I422
Y Y Y Y
Y Y Y Y
U U
U U
V V
  • YV16
Y Y Y Y
Y Y Y Y
V V
V V
U U
U U
  • Semi-Plannar
  • NV16
Y Y Y Y
Y Y Y Y
U V U V
U V U V
  • NV61
Y Y Y Y
Y Y Y Y
V U V U
V U V U
  • Packed
  • UYVY
U Y V Y U Y V Y
U Y V Y U Y V Y
  • YUYV
Y U Y V Y U Y V
Y U Y V Y U Y V
  • YVYU
Y V Y U Y V Y U
Y V Y U Y V Y U

4:2:0

  • Plannar
  • I420 属于YUV 420 Plannar 的一种,YUV分量分别存放,先是w * h 长度的Y,后面跟着w * h * 0.25 长度的U,最后是w * h * 0.25长度的V,总长度为w * h * 1.5;
Y Y Y Y
Y Y Y Y
U U
V V
  • YV12
Y Y Y Y
Y Y Y Y
V V
U U
  • Semi-Plannar
  • NV12
Y Y Y Y
Y Y Y Y
U V U V
  • NV21
Y Y Y Y
Y Y Y Y
V U V U

7 格式转换

71.其他图片格式转YUV

ffmpeg -i in.png -s width*height -pix_fmt yuv420p out.yuv

 ✘ songlin@feng-sl  ~/audio/YUV   master ±  ffmpeg -i in.png -s 686x370 -pix_fmt yuv420p out.yuv
ffmpeg version 4.3.2 Copyright (c) 2000-2021 the FFmpeg developers
  built with Apple clang version 12.0.0 (clang-1200.0.32.29)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.3.2_4 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
Input #0, png_pipe, from 'in.png':
  Duration: N/A, bitrate: N/A
    Stream #0:0: Video: png, rgba(pc), 686x370, 25 tbr, 25 tbn, 25 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (png (native) -> rawvideo (native))
Press [q] to stop, [?] for help
Output #0, rawvideo, to 'out.yuv':
  Metadata:
    encoder         : Lavf58.45.100
    Stream #0:0: Video: rawvideo (I420 / 0x30323449), yuv420p, 686x370, q=2-31, 75480 kb/s, 25 fps, 25 tbn, 25 tbc
    Metadata:
      encoder         : Lavc58.91.100 rawvideo
frame=    1 fps=0.0 q=-0.0 Lsize=     369kB time=00:00:00.04 bitrate=75480.0kbits/s speed=5.16x
video:369kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

上面命令生成的yuv文件大小是:imageSize = width * height = 686 * 370 * 1.5 = 380730 字节

  • - s
  • 设置图片的尺寸
  • 可以使用一些固定字符串表示尺寸,比如hd720表示1280 * 720
  • 如果不设置此项,默认会跟随输入图片的尺寸
  • -pix_fmt
  • 设置像素格式
  • 可以通过ffmpeg -pix_fmts 查看FFmpeg支持的像素格式
  • 如果不设置此选项,默认会跟随输入图片的像素格式
    • 比如可能是rgb24,rgba8,pal8等
    • 可以通过ffprobe查看某图片的像素格式,比如ffprobe in.png
7.2 YUV 转其他图片格式

ffmpeg -s 680x370 -pix_fmt yuv420p -i out.yuv out.jpg

songlin@feng-sl  ~/audio/YUV   master ±  ffmpeg -s 686x370 -pix_fmt yuv420p -i out.yuv out.jpg
ffmpeg version 4.3.2 Copyright (c) 2000-2021 the FFmpeg developers
  built with Apple clang version 12.0.0 (clang-1200.0.32.29)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.3.2_4 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
[rawvideo @ 0x7f924b809600] Estimating duration from bitrate, this may be inaccurate
Input #0, rawvideo, from 'out.yuv':
  Duration: 00:00:00.04, start: 0.000000, bitrate: 75480 kb/s
    Stream #0:0: Video: rawvideo (I420 / 0x30323449), yuv420p, 686x370, 75480 kb/s, 25 tbr, 25 tbn, 25 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (rawvideo (native) -> mjpeg (native))
Press [q] to stop, [?] for help
[swscaler @ 0x7f924b086000] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x7f924b086000] Warning: data is not aligned! This can lead to a speed loss
Output #0, image2, to 'out.jpg':
  Metadata:
    encoder         : Lavf58.45.100
    Stream #0:0: Video: mjpeg, yuvj420p(pc), 680x370, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
    Metadata:
      encoder         : Lavc58.91.100 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: N/A
frame=    1 fps=0.0 q=4.0 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=8.71x
video:24kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

8 显示YUV

8.1 完整YUV

可以通过ffplay显示YUV数据

  • YUV中直接存储的是所有像素的颜色信息,可以理解为原始数据
  • 必须得设置YUV的尺寸(-s)、像素格式(-pix_fmt)才能正常显示,和音频pcm播放的时候需要设置采样率(-ar)、声道数(-ac)、采样格式(-f)类似
fplay -s 686x370 -pix_fmt yuv420p out.yuv
ffplay version 4.3.2 Copyright (c) 2003-2021 the FFmpeg developers
  built with Apple clang version 12.0.0 (clang-1200.0.32.29)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.3.2_4 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
Option -s is deprecated, use -video_size.
Option -pix_fmt is deprecated, use -pixel_format.
//可以看到我们上面输入的两个参数有一些已经过期了,建议我们使用新参数
ffplay -video_size 686x370 -pixel_format yuv420p out.yuv
ffplay-yuv.png
8.2 单个分量

可以使用过滤器filter 显示其中的单个分量(r、g、b、y、u、v)

  • 只显示r分量
 ffplay -vf extractplanes=r in.png
ffplay-r.png
  • 只显示g分量
ffplay -vf extractplanes=g in.png
ffplay-g.png
  • 只显示b分量
ffplay -vf extractplanes=b in.png
ffplay-b.png
  • 只显示y分量
ffplay -video_size 686x370 -pixel_format yuv420p -vf extractplanes=y out.yuv
ffplay-y.png
  • 只显示u分量
ffplay -video_size 686x370 -pixel_format yuv420p -vf extractplanes=u out.yuv
ffplay-u.png
  • 只显示v分量
ffplay -video_size 686x370 -pixel_format yuv420p -vf extractplanes=v out.yuv
ffplay-v.png

可以看到显示U分量和V分量的时候,图片的面积会变小,这个就是存储格式导致的,4:2:0的存储格式水平和垂直Y和UV分量比例都是2:1,所以整体就是4:1,所以面积会变小

好了YUV的介绍,到这里差不多了

你可能感兴趣的:(YUV)