SSブログ

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

昨日Core Imageフレームワークの顔認識の基本的な使い方をまとめた。今日はiMacやMacBook ProにビルトインされたFaceTimeカメラを読み込むためにAV Foundationフレームワークを使いやり方をまとめる。以前やったQTKit Captureに良く似ている。

3  FaceTimeカメラをAV Foundationで読む

ついでにAV FoundationでFaceTimeカメラの画像を読み込む方法をまとめておく。AV FoundationフレームワークはむかしやったQTKit Captureとまったく同じ思想で作られている。なんでわざわざ別にしたかと言うとQTKit Captureは名前の通りQuickTimeがベースになっていて、iOSではQuickTimeが存在しないからである。

QTKit CaptureのあたまのQTの文字をAVにするだけで、だいたい動く。

AVSessionが前代のデータの流れを制御して、AVCaptureDeviceInputが入力でAVCaptureDeviceがデバイスそのもの、AVCaptureVideoDataOutputが外にデータを持ち出すためのクラスで、実際のハード(たとえばFaceTimeカメラ)に対応するAVCaptureDeviceを作ってAVCaptureDeviceInputにつないで、そのAVCaptureDeviceInputをAVSessionに入力として渡す。AVCaptureVideoDataOutputもAVSessionに出力として渡してAVSessionにstartRunningメッセージを投げると、AVCaptureVideoDataOutputからデータがdelegateに渡される、というしくみ。

3.1  入力デバイス用オブジェクト

入力に使えるハードウェアデバイスはメディアタイプごとに分類されている。メディアタイプは
  • AVMediaTypeVideo
  • AVMediaTypeAudio
  • AVMediaTypeText
  • AVMediaTypeClosedCaption
  • AVMediaTypeSubtitle
  • AVMediaTypeTimecode
  • AVMediaTypeTimedMetadata
  • AVMediaTypeMuxed
これだけある。QTKitのときはvideoとaudioとmuxedのみっつしかなかった。タイムコードや字幕をとることもできるらしい。MPEG-2ファイルなんか以外にそういうソースがあるのは珍しいかもしれないけど。

画像の場合、AVMediaTypeVideoかAVMediaTypeMuxedを選ぶことになる。FaceTimeカメラはAVMediaTypeVideoに分類されている(AVMediaTypeMuxedは昔は1394経由のDVストリームぐらいだったけど、DisplayPortやHDMIなんかを受けたときもこれになるのかな。今のMacはターゲットディスプレイモード以外では受け取れないのかな)。

使える入力デバイスは
    NSArray *devices = [AVCaptureDevice devices];
    for (id device in devices)
        NSLog(@"%@", [device localizedName]);
で、そのとき実際に繋がっているすべてのデバイスのdescriptionを表示できる。わかりやすいものとそうでないものがあって、ハードに依存する。実際のアプリではこのdescriptionをNSMenuItemに表示させてユーザに選択させる、という手はずになるだろう。もうすこし限定する形でdevicesWithMediaType:メソッドや、決めうちするdefaultDeviceWithMediaType:メソッドもある。

入力デバイスが決まればそれで
    AVCaptureDeviceInput    *deviceInput;
    deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device
                                                        error:&error];
AVCaptureDeviceInputのインスタンスを作る。

3.2  出力用オブジェクト

同じように出力用に
    AVCaptureVideoDataOutput* dataOutput = [[AVCaptureVideoDataOutput alloc] init];
    [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
とする。これはAVCaptureVideoDataOutputのインスタンスを作って、データを受け取るdelegate(上の場合はself)を指定する。QT Kit Captureと違ってGCDのどのディスパッチキューを使うか指定することができる。これでdelegateが呼ばれるスレッドを変更することができる。

3.3  AVCaptuireSessionとの接続

これであとは
    session = [[AVCaptureSession alloc] init];
    [session addInput:deviceInput];
    [session addOutput:dataOutput];
としてセッションのインスタンスを作って
    [session startRunning];
とやればいい。

ところで、セッションが特定の入力デバイスや出力オブジェクトを拒否する場合があるらしい。これはセッションに
    if ([session canAddInput:deviceInput])
        [session addInput:deviceInput];
    if ([session canAddOutput:dataOutput])
        [session addOutput:dataOutput];
というふうに問い合わせてから接続しろ、とReferenceには書いてある。どういう場合に拒否されるのかはよくわからない。

3.4  データの受け取り

データを受け取るにはdelegateに
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection;
というメソッドを実装すればいい。このメソッドはAVCaptureVideoDataOutputSampleBufferDelegateプロトコルで定義されていて、delegateはこのプロトコルをconformするのがいい。

入力画像のデータはCMSampleBufferRefに入っている。ちなみにQTKit CaptureではCVImageBufferRefだった。どうちがうかというとほとんど違わない。CMSampleBufferRefはCore Mediaのオブジェクトで、CVImageBufferRefはCore Videoになっている。QTKit Captureは画像が中心だったけどAV Foundationではテキストなんかも受けられるようにしたのでCore Videoによく似たCore Mediaを作ってそれを使うようにしたんだろう、おそらく。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

献立07/28献立07/29 ブログトップ

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