SSブログ

Core Imageの顔認識をOS Xで - その5 [OpenCV関係]

3日目になるピクセルフォーマットの問題。今日は急転直下解決することになった。でも本来の解決ではない。けどまあ、今回は許す。

4.4  CMSampleBufferからCIImageを作るときの問題

こないだCMSampleBufferからCIImageは
    CIImage *ciimage = [CIImage imageWithCVImageBuffer:buffer];
で、簡単にできる、と書いた。ところがピクセルフォーマットの指定によってはimageWithCVImageBuffer:メソッドがnilを返すことがある。どういう場合ダメかというと少なくとも
  • 1コンポーネントが8ビット以下ではNG
  • 1ピクセルが2バイトや3バイトではNG
  • 1コンポーネントが2バイト以上の高精度サンプルではエンディアンによってはNG
などとかなりうるさい。なんでもできるわけではないらしい。しかし8バイトARGBだけしか作れないわけではないらしいことはわかった。

4.5  OpenCVとのインターフェイス

OpenCVのIplImageはどんなフォーマットでも作ることができるか、というとそうでもなくて
  • デフォルトではBGR並び
  • αチャンネルがある場合は最後(BGRAなど)
でそれ以外は変換が必要になる。この変換にはcvCvtColor()という関数が使える。最終的にOpenCVの顔認識用の関数cvHaarDetectObjects()はグレースケールの画像だけを受け付けるのでどのみちRGBからグレーへ変換しないといけない。

ところがまた微妙な悩ましい問題がある。cvCvtColor()が変換できるカラーフォーマットはRGB順ではαチャンネルが最後になるRGBAしかない。いっぽうAV Foundationの出力オブジェクトAVCaptureVideoDataOutputはRGB順のフォーマットはARGBしかない。さらにCIImageはARGBだけ、しかもαチャンネルのないRGB(24ビット3バイト)では作ることができない。

ようするにCIDetectorとOpenCVとAVCaptureVideoDataOutputで共通のフォーマット(メモリをコピーするだけでいいフォーマット)は存在しない、ということになる。なんちゅうこっちゃろ。ひどいなあ。

どうせグレーに変換するんだからRGBAもBGRAもグレーにすれば変わらないじゃん、とも言える。グレーの変換のときRとBの重みが倍程度違ってるけど一般的な画像ではまったく違った結果になる、ということはあまりない。しかしまああまり美しくないのと、あとになって「なんだこれ、間違ってるじゃん」なんてまたフォーマットを探しまわるなんてことにもなりかねない。というか僕はそういうことがよくある。

cvCvtColor()を使わないで、AccelerateフレームワークにあるvImageには
vImage_Error vImagePermuteChannels_ARGB8888 (
   const vImage_Buffer *src,
   const vImage_Buffer *dest,
   const uint8_t permuteMap[4],
   vImage_Flags flags
);
というのがあって、任意に入れ替えることができる。しかしこれも速いとはいえ、普通のプログラマには無意味なオーバーヘッドでしかない。

ということはすなわちピクセルフォーマットを気にせずにOpenCVとCIDetectorを両立する方法はない、ということになる。そうなると途中でフォーマットを変換するのは無駄なオーバーヘッドなので、CIDetectorとOpenCVとでAVCaptureVideoDataOutputからの出力フォーマットを変えるということになる。まあ、当然CIDetectorとOpenCVの顔認識を同じ画像に対して同時に使うことはないので、それでもかまわない。

4.6  ピクセルフォーマットの結論

しかし今日になって実は、CIImageはimageWithBitmapData:bytesPerRow:size:format:colorSpace:メソッドで作るとARGB各8ビットのピクセルフォーマットしかできないけど、imageWithCVImageBuffer:メソッドだとBGRAでもOKだということがわかった。これはReferenceにはないので動作保証されていないけど、とりあえず今はこれで動く。

ようするにReferenceで保証された動作ではないけど、AVCaptureVideoDataOutputのフォーマットをBGRAにしておくとCIDetectorでもOpenCVでも使えるということになる。

Instrumentsのプロファイル出力ではimageWithCVImageBuffer:メソッドでBGRAのCIImageを作ってもARGBの場合と較べてそれほど重くない(同じサイズの画像をmemcpyでコピーするのに較べるとずっと軽い)。ということはこのなかでBGRA→ARGBの変換は起こっていないんだろうと思われる。じゃあなぜBGRAをサポートしているようにReferenceに書かないのか、というとよくわからない。実装は終わっていてこれからサポートを表明する予定なのか、それとも今後はやめるつもりなのか、どうでもいいと思ってるのか。本来はこう言うReferenceに記述がない動作に依存すると、OSのバージョンが上がると急に動かなくなったりするので売り物のアプリなんかでは避けるべきだよな。

ところでこのピクセルフォーマットの話、とりあえず無駄のない結論に辿り着いたけど、さっと読むだけでは何のことだか全然わからないな。まあ、いいや。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立07/31献立08/01 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。