Core Imageの顔認識をOS Xで - その10 [OpenCV関係]
こないだの顔認識比較用アプリのソースにちょっと追加。
NSViewでの表示にCIImageを使うのではなくCMSampleBufferから直接表示する方法。
CIImageはカメラの生画像をNSViewに表示するために作っていた。CMSampleBufferからビットマップデータを取り出してIplmageを作ってOpenCVに渡すのと同時に、CMSampleBufferからCIImageを作ってCore ImageのCIDetectorに渡して顔認識させるのとNSViewのサブクラスに渡して生画像を表示するのに使っていた。どのみちIplImageとCIImageの両方を作らないといけないのはしょうがないんだけど、カメラ画像表示のためにはCIImageではなくCMSampleBufferから直接作ることができる。
10.5から追加されたCALayerというのがある。これはCore Animationの一部で、スパッと表示が切り替わるのではなく、徐々に変化させることで視認性を高めるための技術のもとになっている。このアイデアはiOSに移植されて、App Kitよりもわかりやすいユーザインターフェイスを構築するのに大きな役割を果たした。iOSではCALayerの機能は拡大されて、それがOS Xに戻ってきた。
CALayerはなるべくGPUを使ってアニメーションとその表示をしようというもので、CPUの負荷を軽くしようという意図もある。OS XではGPUの性能も高いので、表示内容次第ではCALayerを使うと非常に軽いアプリにすることが可能になる。もちろんなんでも速くなるわけではない。例えばOS Xの昔からのウリであるBezier pathによる解像度に依存しないしゃきっとした表示に対しては、Bezier pathをビットマップに展開するのに手間がかかるのでそれほど速くはならない。また、フレーム内でJPEG圧縮された動画の表示は結局、ぱらぱらマンガと同じでCALayerを使っても負荷が軽くはならない。
今回、CMSampleBufferからCIImageを作ってNSViewで表示する方法ではほとんどGPUはパイプラインの最後のほうしか使われない。しかもCIImageを作るためにCMSampleBufferからいったんメモリにビットマップがコピーされるようである。ところがCMSampleBufferからCALayerに直接画像を渡す手段が提供されていて、その場合メモリコピーは発生しない(と思われる。その辺りの正確な記述はない)。
ということで今回も生画像表示にCIImageではなく、CALayerを使ってみようと思った。ところがなかなかうまくいかない。CALayerはCore Animationの一部でCMSampleBufferの詳細な解説はAV Foundationを見ないといけない。ところがiOSのUIViewでの扱いは詳しくてSample Codeなんかも手に入るんだけど、OS XのNSViewでの扱いの記述は中途半端な場合が多い。UIViewとNSViewで動作が同じなら問題ないんだけど、CALayerに関する動作はかなり違っている。そのせいでNSViewで表示させるのにずいぶん苦労した。
でも、できてしまえはそれほど難しくはない。どうするかというと、NSViewのサブクラスでこんなメソッドを定義する。
NSViewでは備わったCALayerを動作させるために(3)のコードを書けとドキュメントにある。が、それだけでは表示されなかった。もうひとつ必要なのが上の(4)のメソッド起動。NSViewの表示領域を知らせる必要がある。
しかしこれでもまだダメで、あともうひとつ、Inferface Builderの画面でここ
の、これ
Layer Viewにチェックを入れる必要があった。さっきのドキュメントにはこのチェックか、setWantsLayer:にYESを渡すかすればCALayerでの表示が動作するとあるが、setWantsLayer:には関係なくこのInterface Builderでのチェックがなければ何も表示されなかった。このへん、どうなってるのかわからない。
ということで、試行錯誤でCMSampleBufferからCALayerのサブクラスでNSViewに表示できるようになった。しかしどうも比較的新しいFrameworkはiOSとOS Xとの両方で動作するとはいえ、OS Xではおいてけぼり感がある。まあいつのまにかOS XプログラマよりiOSプログラマの方が何倍も多くなってしまったもんな。
ところで、CALayerを使うとどのくらい軽くなるか、といえばOpenCVもCore Imageもどちらも顔認識が重すぎて差が全然わからなかった。でも顔認識を全部やめて単なるカメラ画像の表示だけをやるとCIImageではCPUの負荷が20〜30%だったのにCALayerにすると10%を切った(FaceTimeカメラの1280x720カラーを640x360NSViewにフルフレーム表示して)。単独ではやっぱり軽いということがわかったけど、そんな(何もせずただFaceTimeカメラ画像を表示するだけの)OS Xアプリはありえない。それって難しいことをしてるけどただの鏡。まあ、ようするに使い方次第だなあ。
NSViewでの表示にCIImageを使うのではなくCMSampleBufferから直接表示する方法。
CIImageはカメラの生画像をNSViewに表示するために作っていた。CMSampleBufferからビットマップデータを取り出してIplmageを作ってOpenCVに渡すのと同時に、CMSampleBufferからCIImageを作ってCore ImageのCIDetectorに渡して顔認識させるのとNSViewのサブクラスに渡して生画像を表示するのに使っていた。どのみちIplImageとCIImageの両方を作らないといけないのはしょうがないんだけど、カメラ画像表示のためにはCIImageではなくCMSampleBufferから直接作ることができる。
10.5から追加されたCALayerというのがある。これはCore Animationの一部で、スパッと表示が切り替わるのではなく、徐々に変化させることで視認性を高めるための技術のもとになっている。このアイデアはiOSに移植されて、App Kitよりもわかりやすいユーザインターフェイスを構築するのに大きな役割を果たした。iOSではCALayerの機能は拡大されて、それがOS Xに戻ってきた。
CALayerはなるべくGPUを使ってアニメーションとその表示をしようというもので、CPUの負荷を軽くしようという意図もある。OS XではGPUの性能も高いので、表示内容次第ではCALayerを使うと非常に軽いアプリにすることが可能になる。もちろんなんでも速くなるわけではない。例えばOS Xの昔からのウリであるBezier pathによる解像度に依存しないしゃきっとした表示に対しては、Bezier pathをビットマップに展開するのに手間がかかるのでそれほど速くはならない。また、フレーム内でJPEG圧縮された動画の表示は結局、ぱらぱらマンガと同じでCALayerを使っても負荷が軽くはならない。
今回、CMSampleBufferからCIImageを作ってNSViewで表示する方法ではほとんどGPUはパイプラインの最後のほうしか使われない。しかもCIImageを作るためにCMSampleBufferからいったんメモリにビットマップがコピーされるようである。ところがCMSampleBufferからCALayerに直接画像を渡す手段が提供されていて、その場合メモリコピーは発生しない(と思われる。その辺りの正確な記述はない)。
ということで今回も生画像表示にCIImageではなく、CALayerを使ってみようと思った。ところがなかなかうまくいかない。CALayerはCore Animationの一部でCMSampleBufferの詳細な解説はAV Foundationを見ないといけない。ところがiOSのUIViewでの扱いは詳しくてSample Codeなんかも手に入るんだけど、OS XのNSViewでの扱いの記述は中途半端な場合が多い。UIViewとNSViewで動作が同じなら問題ないんだけど、CALayerに関する動作はかなり違っている。そのせいでNSViewで表示させるのにずいぶん苦労した。
でも、できてしまえはそれほど難しくはない。どうするかというと、NSViewのサブクラスでこんなメソッドを定義する。
- (void)setCaptureSession:(AVCaptureSession *)session { AVCaptureVideoPreviewLayer *previewLayer; previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:session]; CALayer *layer = [self layer]; // (1) [layer addSublayer:previewLayer]; // (2) // [self setWantsLayer:YES]; // (3) [previewLayer setFrame:[self bounds]]; // (4) }これはAV FoundationのAVCaptureSessionを渡して、それからAVCaptureVideoPreviewLayerのインスタンスを作っている。これがCMSampleBufferから直接表示を作るためのCALayerのサブクラスとなっている。NSViewにはCALayerが備わっているけど、それを指定しなければ動作しない。上のコードの(1)で備わったCALayerのインスタンスを要求することでNSViewをCALayer対応にスイッチすることになる。そのCALayerに(2)でAVCaptureVideoPreviewLayerをサブレイヤとして追加する。実はUIViewだとこれだけでカメラ画像が表示されるが、NSViewではなにも起こらない。
NSViewでは備わったCALayerを動作させるために(3)のコードを書けとドキュメントにある。が、それだけでは表示されなかった。もうひとつ必要なのが上の(4)のメソッド起動。NSViewの表示領域を知らせる必要がある。
しかしこれでもまだダメで、あともうひとつ、Inferface Builderの画面でここ
の、これ
Layer Viewにチェックを入れる必要があった。さっきのドキュメントにはこのチェックか、setWantsLayer:にYESを渡すかすればCALayerでの表示が動作するとあるが、setWantsLayer:には関係なくこのInterface Builderでのチェックがなければ何も表示されなかった。このへん、どうなってるのかわからない。
ということで、試行錯誤でCMSampleBufferからCALayerのサブクラスでNSViewに表示できるようになった。しかしどうも比較的新しいFrameworkはiOSとOS Xとの両方で動作するとはいえ、OS Xではおいてけぼり感がある。まあいつのまにかOS XプログラマよりiOSプログラマの方が何倍も多くなってしまったもんな。
ところで、CALayerを使うとどのくらい軽くなるか、といえばOpenCVもCore Imageもどちらも顔認識が重すぎて差が全然わからなかった。でも顔認識を全部やめて単なるカメラ画像の表示だけをやるとCIImageではCPUの負荷が20〜30%だったのにCALayerにすると10%を切った(FaceTimeカメラの1280x720カラーを640x360NSViewにフルフレーム表示して)。単独ではやっぱり軽いということがわかったけど、そんな(何もせずただFaceTimeカメラ画像を表示するだけの)OS Xアプリはありえない。それって難しいことをしてるけどただの鏡。まあ、ようするに使い方次第だなあ。
2013-08-07 22:11
nice!(0)
コメント(1)
トラックバック(0)
沒有醫生的處方
how to buy cialis online usa http://kawanboni.com/ Cialis for sale
by Viagra or cialis (2018-04-14 07:08)