YUV_420_888
12月11日水曜日、晴れ。ときどき雨
会社を出たら降っていた。ええー、聞いてないよ!
* * *
これは画像処理だ。昨日そうおもったので学生時代の(20年以上前の)教科書をひっぱりだして職場に持っていく。残念なことに肝心のところは対象外だった。結局行き帰りに一冊分の重みを加えただけだったという悲しみ。
* * *
Android カメラから取り込む画像データ。
生データは YUV_420_888 という形式で表現されているらしい。輝度成分 Y のプレーン #0、青色信号差分 U のプレーン #1、赤色信号差分 V のプレーン #2。
輝度は画像サイズそのままであることに対して U と V は1ピクセルおき、1ラインおきにサンプリングされている。つまり輝度 2 x 2 に対して 1 サンプル。 Y の 4 ピクセル分に対して U/V が奇数ラインに 2 ピクセル、偶数ラインでは 0 ピクセル分ということで 4、 2、 0 という数字がついているようだ。
人の視覚は色味よりも輝度に対して鋭く働くので、だから輝度成分を重視する──あるいは色情報を落としてデータ量を少なくする。(RGB の3プレーンで表現した場合とくらべてデータ量は半分で済む)
そして YUV_420_888 のプレーン情報。各プレーンはそれぞれ 8 ビット(1バイト)幅でピクセルデータを記録している。これは ByteBuffer に詰められており、 pixel stride と row stride という補足がつく。
1ラインが何バイトになるかを row stride があらわしていて、ライン上のピクセルを何バイトおきに見るかを pixel stride があらわす。
プレーン #0 は pixel stride 1、 row stride は画像幅に等しくなり、プレーン #1 と #2 はカメラによって pixel stride が 2、 row stride が画像幅になる場合と、 pixel stride 1 で row stride が画像幅の半分になる場合とがあるみたいだ。(前者の場合 UV がインターリーブされて格納されている同じバッファを 1 ピクセル分ずらして #1 と #2 が参照しているとか)
* * *
640 x 480 の画像に対してプレーン #0 は 707200 バイト(= 640 x 480)、しかしてプレーン #1 と #2 が 153599 バイトと半端な数字になっていた。
76800(= 320 x 240)でなく、この2倍の 163600 よりひとつだけ小さい。
いったいどういうことかと頭を悩ませたのだけれど pixel stride が 2 で row stride が 640 になっていて納得。
UV は V と U の順でインターリーブされているようで、163600 バイトのバッファーの先頭をプレーン #2 が、バッファー先頭+1バイト目をプレーン #1 が参照していると、そういうことだった。
この記事が気に入ったらサポートをしてみませんか?