0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DJI ドローンライブ映像のYUV画像をRGB画像に変換

Last updated at Posted at 2021-10-15

本記事では、DJI ドローンの映像ストリーミングから取得したYUV画像をRGBコンバートについてご紹介します。

DJI ドローンライブ映像のYUV画像取得

ストリーミングからYUV画像取得を参考してDJI Mobile SDKでドローンの映像ストリーミングからYUV画像取得します。

image.png

    public void onYuvDataReceived(MediaFormat format, 
                                  final ByteBuffer yuvFrame, 
                                  int dataSize, 
                                  final int width, 
                                  final int height) {
// The obtained data of format is MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar 
// and the width and height must be even.
    }

YUVとは

YUVやYCbCrやYPbPrとは、輝度信号Yと、2つの色差信号を使って表現される色空間。

何故YUVフォーマット

人間の目は明るさの変化には敏感だが, 色の変化には鈍感であるというわけで,色度を抑え、輝度により広い帯域やビット数を割くことにより、少ない損失で効率の良い伝送や圧縮を実現するフォーマット。

RGB と YCbCr

RGB方式では、Red, Green, Blueの3つの原色を混ぜ合わせることで 色を表現する手法である。
YCbCr方式では、輝度成分のYと青から輝度を引いた青色差Cb(B-Y)、赤から輝度を引いた赤色差Cr(R-Y)と3種類で色を表現する。
RGB と YCbCr は 以下の計算式で相互に変換が可能である

RGB to YUV
Y =  0.299R + 0.587G + 0.114B
U = -0.169R - 0.331G + 0.500B
V =  0.500R - 0.419G - 0.081B
YUV to RGB
R = 1.000Y          + 1.402V
G = 1.000Y - 0.344U - 0.714V
B = 1.000Y + 1.772U

輝度Y には G の成分が多く含まれており、B の成分が少ないことがわかる。 人間の目には緑色G は明るく感じ、青色Bは暗く感じることから、このような変換式になっている。
image.png

YUV形式

ビデオ業界全体で、さまざまな YUV 形式が定義されています。
MSDNから各形式について説明があります。

クロマチャネル(色差Cb/Cr)は、知覚品質が大幅に失われることなく、ルミナンスチャネル(輝度Y)よりも低いサンプリングレートを持つことができます。

ルミナンス(輝度Y)のサンプルはクロスで表され、
クロマチャネル(色差Cb/Cr)のサンプルは円で表されます。

  • 4:4:4 は、クロマチャネルのダウンサンプリングがないことを意味します。
  • 4:2:2 は、垂直ダウンサンプリングを使用せずに、2:1 の水平ダウンサンプリングを意味します。
  • 4:2:0 は、2:1 垂直ダウンサンプリングを使用して、2:1 の水平ダウンサンプリングを意味します。
  • 4:1:1 は、垂直ダウンサンプリングを使用せずに、4:1 の水平ダウンサンプリングを意味します。

image.png

image.png

image.png

    4:4:4 (32 bpp)
        AYUV
    4:2:2 (16 bpp)
        YUY2
        UYVY
    4:2:0 (16 bpp)
        IMC1
        IMC3
    4:2:0 (12 bpp)
        IMC2
        IMC4
        YV12
        NV12

4:4:4 形式、32ビット/ピクセル

AYUV

各ピクセルが4つの連続するバイトとしてエンコードされた、アルファの値が含まれます。最高クォリティの画質です。
image.png

4:2:2 形式、16ビット/ピクセル

各マクロピクセルは、4つの連続するバイトとしてエンコードされた2ピクセルです。 この結果、彩度の水平ダウンサンプリングが2倍になります。

YUY2

データを符号なしの char 値の配列として処理できます。最初のバイトには最初の y サンプル、2番目のバイトには最初の U (Cb) サンプル、3番目のバイトには第2の y (Cr) のサンプルが含まれます。

image.png

UYVY

YUY2 形式と同じですが、バイト順が反転される点が異なっています。

image.png

4:2:0 形式、ピクセルあたり 16 ビット

2 つの 4:2:0 16 ビット/ピクセル (bpp) 形式、 水色チャネルは、水平方向と垂直方向の両方の次元で 2 の係数でサブサンプリングされます。

IMC1

すべての Y サンプルは、符号なし char 値の配列としてメモリ内で最初に 表示 されます。 その後に、すべての V (Cr) サンプル、およびすべての U (Cb) サンプルが続きます。

image.png

Strideは、画面の幅 (バイト単位) です。

BYTE* pV = pY + (((Height + 15) & ~15) * Stride);
BYTE* pU = pY + (((((Height * 3) / 2) + 15) & ~15) * Stride);
IMC3

この形式は IMC1 と同じですが、UとVのプレーンがスワップされる点が異なっています。
image.png

4:2:0 形式、ピクセルあたり 12 ビット

4 つの 4:2:0 12-bpp 形式、チャネルチャネルは水平方向と垂直方向の両方の次元で 2 の係数でサブサンプリングされます。

IMC2

この形式は、次の違いを除いて IMC1 と同じです。V (Cr) と U (Cb) の行は、半ストライド境界でインターリーブされます。IMC1 よりもアドレス空間を効率的に使用できます。

image.png

IMC4

IMC2 と同じですが、U (Cb) と V (Cr) の行がスワップされます。
image.png

YV12

V 平面のストライドは、Y 平面のストライドの半分です。V プレーンには、Y 平面の半分の数の線が含まれている。 V プレーンの直後には、V 平面と同じストライドと線数を持つすべての U (Cb) サンプルが続きます。
image.png
image.png

NV12

Y 平面の直後には、パックされた U (Cb) サンプルと V (Cr) サンプルを含む符号なし char 値の配列が続きます。
image.png
image.png

image.png

YUVフォーマットの詳細な説明

 変換部分のコード

# define CLIP(x) do{if(x < 0){x = 0;} else if(x > 255){x = 255;}} while(0)
# define CONVERT_R(Y, V)    ((298 * (Y - 16) + 409 * (V - 128) + 128) >> 8)
# define CONVERT_G(Y, U, V) ((298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8)
# define CONVERT_B(Y, U)    ((298 * (Y - 16) + 516 * (U - 128) + 128) >> 8)

void NV12ToRGB(u8* rgbBuffer, u8* yuvBuffer, int width, int height)
{
    u8* uvStart = yuvBuffer + width * height;
    u8 y[2] = { 0, 0 };
    u8 u = 0;
    u8 v = 0;
    int r = 0;
    int g = 0;
    int b = 0;
    for (int rowCnt = 0; rowCnt < height; rowCnt++)
    {
        for (int colCnt = 0; colCnt < width; colCnt += 2)
        {
            u = *(uvStart + colCnt + 0);
            v = *(uvStart + colCnt + 1);

            for (int cnt = 0; cnt < 2; cnt++)
            {
                y[cnt] = yuvBuffer[rowCnt * width + colCnt + cnt];

                r = CONVERT_R(y[cnt], v);
                CLIP(r);
                g = CONVERT_G(y[cnt], u, v);
                CLIP(g);
                b = CONVERT_B(y[cnt], u);
                CLIP(b);
                rgbBuffer[(rowCnt * width + colCnt + cnt) * 3 + 0] = (u8)r;
                rgbBuffer[(rowCnt * width + colCnt + cnt) * 3 + 1] = (u8)g;
                rgbBuffer[(rowCnt * width + colCnt + cnt) * 3 + 2] = (u8)b;
            }
        }

        uvStart += width * (rowCnt % 2);
    }
}
0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?