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);
}
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;
}
};
}