Core Imageの顔認識をOS Xで - その5 [OpenCV関係]
3日目になるピクセルフォーマットの問題。今日は急転直下解決することになった。でも本来の解決ではない。けどまあ、今回は許す。
ところがまた微妙な悩ましい問題がある。cvCvtColor()が変換できるカラーフォーマットはRGB順ではαチャンネルが最後になるRGBAしかない。いっぽうAV Foundationの出力オブジェクトAVCaptureVideoDataOutputはRGB順のフォーマットはARGBしかない。さらにCIImageはARGBだけ、しかもαチャンネルのないRGB(24ビット3バイト)では作ることができない。
ようするにCIDetectorとOpenCVとAVCaptureVideoDataOutputで共通のフォーマット(メモリをコピーするだけでいいフォーマット)は存在しない、ということになる。なんちゅうこっちゃろ。ひどいなあ。
どうせグレーに変換するんだからRGBAもBGRAもグレーにすれば変わらないじゃん、とも言える。グレーの変換のときRとBの重みが倍程度違ってるけど一般的な画像ではまったく違った結果になる、ということはあまりない。しかしまああまり美しくないのと、あとになって「なんだこれ、間違ってるじゃん」なんてまたフォーマットを探しまわるなんてことにもなりかねない。というか僕はそういうことがよくある。
cvCvtColor()を使わないで、AccelerateフレームワークにあるvImageには
ということはすなわちピクセルフォーマットを気にせずにOpenCVとCIDetectorを両立する方法はない、ということになる。そうなると途中でフォーマットを変換するのは無駄なオーバーヘッドなので、CIDetectorとOpenCVとでAVCaptureVideoDataOutputからの出力フォーマットを変えるということになる。まあ、当然CIDetectorとOpenCVの顔認識を同じ画像に対して同時に使うことはないので、それでもかまわない。
ようするにReferenceで保証された動作ではないけど、AVCaptureVideoDataOutputのフォーマットをBGRAにしておくとCIDetectorでもOpenCVでも使えるということになる。
Instrumentsのプロファイル出力ではimageWithCVImageBuffer:メソッドでBGRAのCIImageを作ってもARGBの場合と較べてそれほど重くない(同じサイズの画像をmemcpyでコピーするのに較べるとずっと軽い)。ということはこのなかでBGRA→ARGBの変換は起こっていないんだろうと思われる。じゃあなぜBGRAをサポートしているようにReferenceに書かないのか、というとよくわからない。実装は終わっていてこれからサポートを表明する予定なのか、それとも今後はやめるつもりなのか、どうでもいいと思ってるのか。本来はこう言うReferenceに記述がない動作に依存すると、OSのバージョンが上がると急に動かなくなったりするので売り物のアプリなんかでは避けるべきだよな。
ところでこのピクセルフォーマットの話、とりあえず無駄のない結論に辿り着いたけど、さっと読むだけでは何のことだか全然わからないな。まあ、いいや。
4.4 CMSampleBufferからCIImageを作るときの問題
こないだCMSampleBufferからCIImageはCIImage *ciimage = [CIImage imageWithCVImageBuffer:buffer];で、簡単にできる、と書いた。ところがピクセルフォーマットの指定によってはimageWithCVImageBuffer:メソッドがnilを返すことがある。どういう場合ダメかというと少なくとも
- 1コンポーネントが8ビット以下ではNG
- 1ピクセルが2バイトや3バイトではNG
- 1コンポーネントが2バイト以上の高精度サンプルではエンディアンによってはNG
4.5 OpenCVとのインターフェイス
OpenCVのIplImageはどんなフォーマットでも作ることができるか、というとそうでもなくて- デフォルトではBGR並び
- αチャンネルがある場合は最後(BGRAなど)
ところがまた微妙な悩ましい問題がある。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のバージョンが上がると急に動かなくなったりするので売り物のアプリなんかでは避けるべきだよな。
ところでこのピクセルフォーマットの話、とりあえず無駄のない結論に辿り着いたけど、さっと読むだけでは何のことだか全然わからないな。まあ、いいや。
2013-07-31 22:11
nice!(0)
コメント(0)
トラックバック(0)
コメント 0