画像処理ではRGB形式の他にYUV形式がある。
YUV形式のフォーマットは一般にPlanar, Semi-Planar, Interleavedの3つある。
![YUV planar semi-planar inter](https://stat.ameba.jp/user_images/20110609/19/ekispresso/00/90/j/t02200159_0800057911280338388.jpg?caw=800)
尚ここでCr == V、Cv == U と同じ意味であることに注意。
planarはそれぞれのYUVのチャンネル毎にまとめてデータが置かれている。
semi-planarはYだけデータが置かれており、UVは交互に並んでいる。
interleavedはYUVが交互に並んで置かれている。
444であれば、それぞれのチャンネルはフルでサイズ分もっており、
422であればYだけフル、U, Vは1/2ずつ、
420(別名411)はYだけフル、U, Vは1/4ずつ持つ。
422, 420にする理由はデータ量圧縮のためである。
Androidにおいてカメラデバイスから来るフォーマットはAndroidは420 semiplanar( 420SP )で有ることがほとんどのようだ。
自身の端末のフォーマットについては確かめたほうが良く、以下のメソッドで確かめることができる。
|
cameraはカメラオブジェクトである。(詳細は前回の記事参照のこと)
getPreviewFormatの返り値はintegerである。
0x11,(NV21)はYVU420SPを意味する。
0x16,(NV16)はYUV422SPを意味する。
ちなみ、NV21はYVUで、NV16はYUVであり、UとVの並び順が違うので注意すること!!
カメラからのプレビューの画像データを取得するには
|
のメソッドを定義すればよい。プレビュー画像の配列はbyte型でくる。
カメラデバイスからY, U, Vに関して,最小値と最大値は0x00-0xffの範囲で返却される。
注意として、JAVAでは強制的にカメラデバイス側の符号を無しのデータを、signed型として扱ってしまう。
つまり、byte型配列を扱おうとすると、128から上の数は符号がマイナスになってしまう。
(ex. 255->-1, 254->-2 .. 2の補数。127までは問題が無い)
0-255を正しく扱うためには0xffでANDをとってやる必要がある。具体的には以下のようにしてアクセスする。
|
これで-128~127の値が0~255として変換される。
尚、Native(JNI、C言語)で呼び出す場合はこうした処理をしなくともunsignedでキャストしてやれば事が足りる。
JNIについて
JNIを触る際、一番参考にするのはNDKをインストールした際についてくるサンプルコードである。コレが一番わかり易い。
これからNDKを勉強した人は必ず一回サンプルコードを実行すること!!!!変に文献やWEBは逆に遠回りである。
作成したC言語のファイルをコンパイルするには以下を呼ぶだけで良い。(makeコマンド相当)
|
Android.mkがMakefileとなっている。これがないとコンパイルされない。
JNIを使うときはプロンプトでndk-buildを叩いて、イクリプス上で実行して実機に流すという、ややたるいステップとなっている。
またC言語をで変更してndk-buildしても、JAVA上のソースコードに変更(更新)が無いとCライブラリの転送が行われないので注意。
C言語側のソースで作成する関数名にはルールがある。
例えばJava側のパッケージ名を
|
としていた場合、
JNIを呼び出すクラス名がCameraView、
関数名がaddであれば、C言語側の関数名は
Java_com_ekispresso_camera2_CameraView_add
となる。(_区切り)
以下はその具体例である.
例)
--Java側
|
--C言語側
|
注意:JNIEnvとjobjectの二つは必ず引数として入れなければならない。Java側で引数が二つある場合は4つとなる。
jintの他にも jfloatなどがあり、これはint, float と等価であるため、c=a+bのようなことは問題ない。
配列を引数として扱いたい場合はちょっと注意が必要である。
byteやIntである場合、
|
のようにして使用する。
上記はJava側に明示的に上記の配列を使用してますよ!GCしないでね!と伝えている。
使い終わったあとはReleaseなどを忘れない様に。
C言語ソース側ではmallocなども問題なく使える。
Android.mkの書き方
インクルードパスをLOCAL_C_INCLUDESにガンガン足していく
|
コンパイルしたいC言語のファイルをガンガン足していく。具体的には
LOCAL_SRC_FILES :=rendering.c ./src/core/ekispresso_core_malloc.c ./src/core/ekispresso_heap.c ./src/core/ekispresso_crc32.c ./src/core/ekispresso_environment.c ./src/core/ekispresso_core_sincos.c ./src/core/ekispresso_prng_xorshift.c
とひたすら書く。
モジュール名を定義する。コレはなんでもいい。
LOCAL_MODULE := rendering
これで終わり。
正しくインクルードパスなど設定で来ていればndk-buildすれば通るはず。
Androidのデフォルトのサンプルを参考にすると良い。
株式会社OctOpt
コンピューターサイエンス会社OctOptの技術公式ブログ
等々力 康弘
@rocky_house