ちおさん雑記帳

何の役にも立たない雑記から、誰かの役に立つ(かも知れない)メモなど・・

CLR YUV422形式の画像データをRGB24に変換する処理のサンプル

処理書いたのでぺとぺと貼り付けておきますです。

(動作確認はしてあるので、2017.03.16現在では少なくともちゃんと動きます)

 

YUV422のYUY2およびUYVYに対応してあります。

第6引数で指定して読み込みbyte位置を切り替えています。

 

変換に使用している計算式は調べてみるとわかりますが、幾つかの値があり、どれを使えばいいの?となるかと思います。

今回私は、openCVのドキュメントを元に値を流用しました。

(ですので、恐らくopenCVで変換した結果と同じになると思います(試してません))

 

変換処理の内容が理解しやすいように書いたつもりです。

なので、若干というか、かなり速度的に重いコードになっているかとは自覚していますw

本当はビットシフト等を使えば早くなるような気もします。

(そういうサンプルが載っている記事も見かけますが、初心者には分かりにくいかも知れません)

 

ちなみに、この処理でも、Debugビルドしたもので動かしても、デコードおよび描画で60fps以上余裕で間に合います

 

という訳で、以下、ソース

 

 


// yuvCnvLib.h

#pragma once

using namespace System;

namespace ChiorinSoft {

    inline Byte Clip(double x) {
        if (x < 0) {
            return 0;
        }
        if (x > 255) {
            return 255;
        }
        return static_cast<Byte>(x);
    }

    public enum class eDecodeKind : unsigned short {
        UYVY = 0,   /* UYUV形式 */
        YUY2 = 1    /* YUY2形式 */
    };

    public ref class yuvCnvLib
    {
    public:
        yuvCnvLib() {};
        ~yuvCnvLib() {};
        bool yuv2bmp(array<Byte> ^ yuv, array<Byte> ^ outArray, UInt32 width, UInt32 height, eDecodeKind kind) {
            double U1, Y2, V3, Y4;
            double R1, G1, B1, R2, G2, B2;
            pin_ptr<Byte> reader = &yuv[0];
            pin_ptr<Byte> writer = &outArray[0];

            if(outArray->Length < (int)(width * height * 3)) {
                return false;   // 出力バッファが足りない
            }
            if (yuv->Length < (int)(width * height * 2)) {
                return false;   // 指定解像度に対して、入力YUVのデータが足りない
            }

            for (unsigned int j = height; j > 0; j--) {
                for (unsigned int i = 0; i < width; i += 2) {
                    /*
                    ●YUV画像データ配列
                    U1 Y2 V3 Y4 U5 Y6 V7 Y8 … または Y2 U1 Y4 V3 Y6 U5 Y8 V7 …
                    Y2,Y4に対応するRGBの算出に、U1,V3を使用。すなわち
                    (RGB)1 = f(Y2, U1, V3) … Y2に対応するピクセルのRGB値
                    (RGB)2 = f(Y4, U1, V3) … Y4に対応するピクセルのRGB値
                    ●YUV->RGB変換式
                    R = Y                 + 1.403 * (V-128)
                    G = Y - 0.344 * (U-128) - 0.714 * (V-128)
                    B = Y + 1.773 * (U-128)
                    */
                    if (kind == eDecodeKind::UYVY) {
                        // UYVY形式
                        // 並び順:U1 Y2 V3 Y4 U5 Y6 V7 Y8 …
                        U1 = static_cast<double>(reader[0]);
                        Y2 = static_cast<double>(reader[1]);
                        V3 = static_cast<double>(reader[2]);
                        Y4 = static_cast<double>(reader[3]);
                    } else {
                        // YUY2形式
                        // 並び順:Y2 U1 Y4 V3 Y6 U5 Y8 V7 …
                        U1 = static_cast<double>(reader[1]);
                        Y2 = static_cast<double>(reader[0]);
                        V3 = static_cast<double>(reader[3]);
                        Y4 = static_cast<double>(reader[2]);
                    }
                    // Y2に対するピクセルのRGB
                    R1 = Y2 + 1.403 * (V3 - 128);
                    G1 = Y2 - 0.344 * (V3 - 128) - 0.714 * (U1 - 128);
                    B1 = Y2 + 1.773 * (U1 - 128);
                    // Y4に対するピクセルのRGB
                    R2 = Y4 + 1.403 * (V3 - 128);
                    G2 = Y4 - 0.344 * (V3 - 128) - 0.714 * (U1 - 128);
                    B2 = Y4 + 1.773 * (U1 - 128);
                    //
                    *writer++ = Clip(B1);
                    *writer++ = Clip(G1);
                    *writer++ = Clip(R1);
                    //
                    *writer++ = Clip(B2);
                    *writer++ = Clip(G2);
                    *writer++ = Clip(R2);

                    reader += 4;
                }
            }
            reader = nullptr;
            writer = nullptr;
            return true;
        }
    };
}