mengineer's blog

ニッチなネタばかりですが。

eBUS SDK 使ってみる その4 画像バッファ参照

前回の下記ネタの後半、eBUSのバッファの中身を参照していました。

mengineer.hatenablog.com

が、とんでもなく嘘を書いていましたので、ここで訂正させて下さい。

× 画像の先頭行ですが、 今回は8bitのカラー画像なので幅の3倍
→ PixelFormatが”BayerRG8”でしたので、幅はそのままで変わりません

もし”RGB8”等でしたら、各画素毎にRGBが有りますので3倍になります。

それ以前にBayerって何?ってお話は、下記辺りを見て下さい、
要はMonoと同じデータ量でカラー画像を表せる仕組みです。

ja.wikipedia.org

と言うわけで、eBUSの前にBayerの補足説明をもう少しだけ。

Bayer時の画像データ

センサー表面のカラーフィルターの色の並びをBayerパターンと呼び、
代表的なものとして、下記のようなパターンが有ります。

f:id:mengineer:20190430124216p:plain

RGだと画像左上からR,Gの順に色が並んでいます。

カメラとしてはPixelFormatを見れば、どのパターンかが判ります。

BayerGR8   8bit GRパターン
BayerRG10  10bit RGパターン
BayerBG10p 10bit BGパターン、末尾のpはPacked (データを詰める)

Bayerの場合、各画素毎の元データはRGBいずれか一色になるので、
データ量はMonoと変わりません。(データ量減らせるのはメリット)

各画素毎に、自分に無い色は周辺の画素から計算します、
これをBayer補間、デモザイクなどと言います。

例えば下記中央の”B”画素ははBlueの色しか持っていないため、
B画素のR情報 = (R1 + R2 + R3 + R4) / 4
B画素のG情報 = (G1 + G2 + G3 + G4) / 4

f:id:mengineer:20190430144358p:plain

というふうに、周辺画素の色を参照し、平均して使います、
これを画像全体に実施することで、画像全体のRGB画像が得られます。

上記は一番シンプルな方法で、実際はもっと複雑なやり方だとか、
各メーカーやSDKなどで、色々工夫されているようです。

余談ですが、Bayerパターンも上記以外にもっと複雑なやつとか、
IRデータが入ったパターンなども出てきているようです。

eBUSのバッファを見てみる

今回の本題、eBUSの話に戻ります、前回同様のカラーバー出力状態、
PixelFormatは”BayerRG8"に設定しています。

f:id:mengineer:20190417115036p:plain

今回も先頭行だけ読むので、UnSafe部分を下記に変更しました。

// Operation result of buffer is OK, display.
if (lOperationResult.IsOK)
{
    // Get TimeStamp
    lThis.label3.Text = lBuffer.Timestamp.ToString();

    // Display Image
    lThis.displayControl.Display(lBuffer);

    // Get Raw Data
    unsafe
    {
        lThis.sb.Clear();
        byte* pArray = lBuffer.DataPointer;
        for (int i = 0; i < lBuffer.Image.Width; i++)
        {
            lThis.sb.Append(pArray[i].ToString());
            lThis.sb.Append("\r\n");
        }
    }
}

画像の幅は1936Pixel、カラーバー8色なので一色辺りは 1936 / 8 = 242Pixel
先頭行は下記のような並びになっていると考えられます。 f:id:mengineer:20190430131827p:plain

PixelFormatがBayerRG8なので、先頭行はR,G,R,G,R,G,R,G...の順に色が入っています、
カラーバーの切り替わる座標毎にRとGの色を調べると、こんな感じに。 f:id:mengineer:20190430132421p:plain

更に二行目(B,G,B,G....の順)を読み、同様にBの色も入れると f:id:mengineer:20190430132601p:plain

当たり前ですが、カラーバー通りのRGB各色が入っていることが判りました、
実際の表示は、先ほどのBayer変換を施して全体をRGB画像としているはず。

PilxelFormatを”BayerRG10”に変えてみる

PixelFormatを”BayerRG10”に変えて、同様に先頭行を読んでみます、
この場合、1画素辺り2Byteになります、先頭12Byte(6画素分)こんな感じ。 f:id:mengineer:20190430133701p:plain

以前のJAISDKネタで書きましたが、下記データ並びになっています。
(ややこしいですが、上図と上位下位逆で見て下さい) f:id:mengineer:20190430133812p:plain

先頭部分はカラーバーの白なので、8bit時はRGBとも222 でした、
上記を計算すると0x037A→ 890 で4倍になっており、
合ってそうです。(これも当たり前ですね)

PilxelFormatを”BayerRG10p”に変えてみる

PixelFormatを”BayerRG10p”に変えて、同様に先頭行を読んでみます、
この場合ちょっとややこしいです、先頭12Byteのデータ並びはこんな感じに。 f:id:mengineer:20190430135050p:plain

5Byte=40bitで4画素分を表しています、ってこれも以前書いてましたね。   f:id:mengineer:20190430140211p:plain

先頭行全体は (1936 / 4) * 5 = 2420 Byteになります。
先ほどのBayerRG10だと、1936*2 = 3872 Byte必要なので、
同じ10bitでも、データ量を約63%ほどに抑えることが出来ます。

例えば先頭の5Byteから得られる4画素分の各画素値は
下記のように計算出来ます。(当然ながら全て890になります)

画素1 = 122 | (( 235 & 0x03) << 8)
画素2 = (235 >> 2) | ((173 & 0x0F) << 6)
画素3 = (173 >> 4) | ((183 & 0x3F) << 4)
画素4 = (183 >> 6) | (222 << 2)

まとめ

eBUS SDKでは、lBuffer.DataPointerでバッファの先頭アドレスを取得出来る、
UnSafeコードでJAISDKと同様にバッファを参照出来ることも判りました。

Packedの場合、データの取り扱い(並べ替え)が少し面倒臭いです、
eBUS SDK側で並び替えて出してくれる方法が有るのか? 調べてみます、
うまく行けば次回のネタですね、今回はここまで。