LoginSignup
17
10

YUVフォーマットの違いを世界一分かりやすく解説

Last updated at Posted at 2022-12-09

YUY2 I420 といった単語をよく目にするけど、こいつらって結局どう違うんじゃい!
というのを完全に理解できるようにまとめた

そもそも、YUVとは

RGBで1pixelを表すと、R, G, B で8bitずつ、計24bit必要だが、
YUVでは 輝度信号(白黒)色差信号 に分割し、色差信号 の情報量を減らす(ダウンサンプリングする)ことで伝送効率等を良くする。
人間の目は輝度の変化には敏感な一方で、色の変化には鈍感なため、多少間引いても分からないらしい。

サンプル比 Y U V bpp ダウンサンプリングの方式
YUV444 8bit 8bit 8bit 24bit ダウンサンプリング無し
YUV422 8bit 4bit 4bit 16bit 水平ダウンサンプリング
YUV411 8bit 2bit 2bit 12bit 水平ダウンサンプリング
YUV420 8bit 2bit 2bit 12bit 水平ダウンサンプリング
垂直ダウンサンプリング

※bpp(bits per pixel)

例えば YUV422 だと、UV をそれぞれ半分に間引き(水平ダウンサンプリング)して、 8 + 4 + 4 で16bppとなる。
しかし YUV420 では0といってもVが0になるわけではなく、水平ダウンサンプリングと垂直ダウンサンプリングを併用して 8 + 2 + 2 で12bppとなる。

ダウンサンプリングについてはこちらの図が分かりやすいため引用

https://learn.microsoft.com/ja-jp/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#yuv-sampling
image.png

代表的なYUVフォーマット

サンプル比 format FOURCC コード 並び順 bpp
YUV422 Packed YUY2 YUV 16bit
YUV420 Planar I420 YUV 12bit
YUV420 Semi-planar NV12 YUV 12bit

メモリ上への配置の仕方の違い(Packed format, Planar format, Semi-planar format)によって名前が変わったりする
ここからはちょっとややこしくなる

以下、1920x1080の画像がメモリ上にどう並ぶのかの例

YUV422, Packed format, YUY2

YUYVのパックが順に並ぶ

- stride height
YUYVのパック 3840 1080

YUY2.png

YUV420, Planar format, I420

Y, U, V のPlanar(平面)が順に並ぶ

- stride height
Y 1920 1080
U 960 540
V 960 540

I420.png

ほとんどのビデオデコーダは生の画像をI420形式で出力するため、目にする機会も多い。
自分はこれをそのまま取り扱おうとしてパディングの問題でハマったことがある。
パディングについては後述する

YUV420, Semi-planar format, NV12

YのPlanar(平面)が並んだ後、
UとVが交互に配置されたPlanar(平面)が並ぶ

- stride height
Y 1920 1080
U, V 1920 540

NV12.png

まとめ

サンプル比 format FOURCC メモリ上でのビットの並び(1ピクセル) bpp
- - RGB RRRRRRRR GGGGGGGG BBBBBBBB 24bit
YUV444 Planar I444 YYYYYYYY UUUUUUUU VVVVVVVV 24bit
YUV444 Packed IYU2 UYVUYV UYVUYV UYVUYV UYVUYV 24bit
YUV422 Packed YUY2 YUYV YUYV YUYV YUYV 16bit
YUV422 Packed UYVY UYVY UYVY UYVY UYVY 16bit
YUV420 Planar I420 YYYYYYYY UU VV 12bit
YUV420 Planar YV12 YYYYYYYY VV UU 12bit
YUV420 Semi-planar NV12 YYYYYYYY UVUV 12bit
YUV420 Semi-planar NV21 YYYYYYYY VUVU 12bit

【おまけ】OpenCVで読み込む

ビデオデコーダから渡されたデータをOpenCVで読み込むこともできる
以下はNV12のデータを読み込んでRGBに変換する例

cv::Mat process(void *a_frame)
{
    cv::Mat src(m_height * 1.5, m_width, CV_8UC1, a_frame);
    cv::Mat rgb;
    cv::cvtColor(src, rgb, cv::COLOR_YUV2RGB_NV12);
    return rgb;
}

【おまけ】パディングでおかしくなる

ビデオデコーダから生で出力されたI420形式のデータにはパディングが含まれている場合がある。
これをそのままOpenCV等で扱おうとすると、色合いが狂う

I420-with-padding.png

例えばGStreamerであれば、offsetという変数を見ることでpaddingがあるかどうかを判断できる

参考サイト

おわりに

間違ってる箇所があったらコメントください

17
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
10