【コラム】
前回は、ビデオカメラアプリを作るために必要なセッションの説明をした。メディアのキャプチャを行うには、セッションを作成して、インプットとアウトプットを接続する。アウトプットとしては、AVCaptureVideoDataOutputクラスを利用した。今回は、アウトプットを受け取るところから始めよう。
AVCaptureVideoDataOutputクラスは、キャプチャしたデータをそのままアプリに渡してくれるものだ。そのデータを受け取るために、デリゲートメソッドが用意されている。AVCaptureVideoDataOutputSampleBufferDelegateプロトコルで定義される、captureOutput:didOutputSampleBuffer:fromConnection:メソッドだ。宣言は次のようになる。
List 1.
- (void)captureOutput:(AVCaptureOutput*)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection*)connection;
このメソッドには、引き数が3つある。1つめは、アウトプットのインスタンス。2つめは、CMSampleBufferRefという型のオブジェクトで、ここからキャプチャされたデータを取り出す。3つめは、AVCaptureConnectionというクラスのオブジェクトで、このセッションにおけるインプットとアウトプットの接続状態を表すものだ。
先に、AVCaptureConnectionを調べてみよう。このクラスを使うと、キャプチャされたビデオやオーディオの状態を知る事ができる。今回はビデオのキャプチャなので、このクラスが持っているプロパティのうち、以下のものに興味がある。
videoMirroredとsupportsVideoMirroringは、ビデオが鏡像表示されているかどうかを表すもの。videoOrientationとsupportsVideoOrientationは、ビデオデータの向きを表すものだ。これらの値によって、取得されたデータをどう取り扱えばいいのかが分かる。
手元にある、iPhone 4のカメラでこれらの値を確認してみた。すると、videoMirroredとsupportsVideoMirroringは、常にNO。videoOrientationは、バックカメラだとAVCaptureVideoOrientationLandscapeLeft、フロントカメラだとAVCaptureVideoOrientationLandscapeRightという結果だった。つまり、ビデオデータは常に横向きで送られてくることになる。これはデバイスを縦に持っていても、データとしては強制的に横向きにされることを表している。画像処理を行うためにUIImageなどのインスタンスを作るときは、注意が必要だ。
続いて、2つめの引き数であるCMSampleBufferRefを調べてみよう。これは、CMで名前が始まっていることから分かるように、Core Mediaフレームワークのオブジェクトになる。Core Mediaは低レベルのメディアデータに直接アクセスするためのフレームワークだ。CMSampleBufferRefは、そのメディアデータのバッファを表すものになる。
このバッファからは、ビデオデータの場合CVImageBufferオブジェクトを取り出す事ができる。似たような名前が続いて混乱するかもしれないが、今度はCVで名前が始まっているので、Core Videoフレームワークのオブジェクトになる。CVImageBufferからは、ビデオ画像のピクセルデータを取得する事ができる。
ピクセルデータさえ取得できれば、これをCore GraphicsのCGImageにすることができ、さらにUIImageにすることができる。こうなれば、自由に画面に貼付けて使えるだろう。
まとめると、次のような流れになる。
CMSampleBuffer
→CVImageBuffer
→CGImage
→UIImage
このような変換を行おう。
では実装だ。AVCaptureVideoDataOutputのデリゲートメソッドを、次のように実装する。
List 2.
- (void)captureOutput:(AVCaptureOutput*)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection*)connection
{
// イメージバッファの取得
CVImageBufferRef buffer;
buffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// イメージバッファのロック
CVPixelBufferLockBaseAddress(buffer, 0);
// イメージバッファ情報の取得
uint8_t* base;
size_t width, height, bytesPerRow;
base = CVPixelBufferGetBaseAddress(buffer);
width = CVPixelBufferGetWidth(buffer);
height = CVPixelBufferGetHeight(buffer);
bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);
// ビットマップコンテキストの作成
CGColorSpaceRef colorSpace;
CGContextRef cgContext;
colorSpace = CGColorSpaceCreateDeviceRGB();
cgContext = CGBitmapContextCreate(
base, width, height, 8, bytesPerRow, colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
// 画像の作成
CGImageRef cgImage;
UIImage* image;
cgImage = CGBitmapContextCreateImage(cgContext);
image = [UIImage imageWithCGImage:cgImage scale:1.0f
orientation:UIImageOrientationRight];
CGImageRelease(cgImage);
CGContextRelease(cgContext);
// イメージバッファのアンロック
CVPixelBufferUnlockBaseAddress(buffer, 0);
// 画像の表示
_imageView.image = image;
}
まず、CMSampleBufferからCVImageBufferを取得しよう。これには、CMSampleBufferGetImageBufferという関数を利用する。
CVImageBufferを取得したら、処理を始める前にこれをロックしないといけない。ロックしないと、カメラから送られてくるデータで次々と書き換えられてしまう事になる。そこで、CVPixelBufferLockBaseAddressという関数を使ってロックする。
次に、CVImageBufferの各種情報を取得する。取得しているので、データのベースアドレス、横幅ピクセル数、縦幅ピクセル数、1行あたりのバイト数、だ。
これらの情報がそろえば、Core Graphicsのイメージコンテキストを作成する事ができる。CGBitmapContextCreateを使って、CGContextを作成しよう。
後は、CGContextからCGImageを取得し、そこからUIImageを作成する。ただし、このとき1つ気をつける事がある。それは、ビデオデータの向きだ。先ほど説明したように、ビデオデータの向きはAVCaptureConnectionのvideoOrientationから取得できるのだが、それに応じた変換を行わなくてはいけない。そのためだろうか、iOS 4.0からUIImageの初期化メソッドが追加されている。imageWithCGImage:scale:orientation:というものだ。引き数に画像データの向きを指定して、それに合わせて変換してくれるものだ。ここでは、iPhone 4のバックカメラを想定して、UIImageOrientationRightを指定している。
UIImageの取得ができたら、CVImageBufferを忘れずにアンロックしておこう。これで次のデータが送られてくる。
取得したUIImageを画面上に貼付ければ、ビデオ画像が表示される事になる。実際にアプリを起動して、デバイスをかざして動かしてほしい。きちんとビデオカメラとして機能する事が分かるだろう。
キャプチャされる画像のサイズは、AVCaptureSessionのsessionPresetというプロパティで決定される。前回のソースコードでは、AVCaptureSessionPresetMediumを指定していた。指定可能なプリセットと、そのときに取得できる画像サイズの表を示そう。
画像サイズが大きくなればなるほど画質は良くなるが、それだけレスポンスも落ちてくる。また、プリセットによって画像のアスペクト比も変化する事に注意してほしい。
アプリの目的に合わせて適切なサイズを選ぶようにしよう。
次回は、キャプチャした画像にエフェクトを加えてみよう。
ここまでのソースコード: VideoCamera-1.zip
| 理研、脳・脊髄形成に必要な神経板湾曲の仕組みを解明 [20:16 5/25] |
| 京大、「慢性閉塞性肺疾患」患者の労作時呼吸困難は鍼治療が有効と実証 [20:08 5/25] |
| 120Hz SHVカメラ用イメージセンサーを使った撮像装置 - SHVフルスペック化へ [18:10 5/25] |
| 京大、視覚による物体認知は前頭前野からのトップダウン信号が重要と確認 [17:45 5/25] |
| 製品数の拡大だけでなくBCPの展開なども含めた総合力で事業の強化を図るTI [17:25 5/25] |
|
【連載】これだけは要チェック! TOEIC(R)単語帳 第108回 今回のお題は…「issue」 [20:00 5/27] キャリア |
|
TVアニメ『ペルソナ4』、新規カットを加えた再編集版を劇場でイベント上映 [20:00 5/27] ホビー |
|
[9nine]制服姿見納め? セーラー服で登場も川島海荷「4人はコスプレ」 [19:15 5/27] エンタメ |
|
「NO.6」4巻は書き下ろしドラマCD付、木乃のサイン会も [18:49 5/27] ホビー |
|
[今週の新刊]マンガ大賞3回ノミネート「アイアムアヒーロー」 カープ愛「球場ラヴァーズ」も [18:33 5/27] ホビー |
4つの診断で、自分の適性を見つめなおそう!
働くこと・挑戦し続けることへの思いを綴ったインタビュー
あなたにピッタリのアドバイスを読むことができます。
転職に必要な情報が収集できます
企業からアプローチのメッセージが届きます。