この記事で説明すること
忙しい人のために先にまとめておくと、AVFoundationを使ったビデオ撮影は、解像度が同じデバイスフォーマットでも「ビニング」のあるなしで画質が大きく違いますよ、高フレームレートのフォーマットが常に正義というわけではないですよ、という話です。(あと、書籍「上を目指すプログラマーのためのiPhoneアプリ開発テクニック(iOS 7編)」をよろしくね、という話です)
準備(キャプチャデバイスのフォーマットについて)
AVFoundationを使ったビデオ撮影で解像度やフレームレート(fps)を設定するには、AVCaptureDeviceクラスのformatsプロパティとactiveFormatプロパティの2つを使います。formatsプロパティで得られる配列から、目的に合ったフォーマットをactiveFormatプロパティに設定します。
// AVCaptureDeviceクラス
// キャプチャデバイスがキャプチャに使うフォーマットを指定する
@property(nonatomic, retain) AVCaptureDeviceFormat *activeFormat
// activeFormatプロパティに設定可能なフォーマットの一覧を取得する
@property(nonatomic, readonly) NSArray *formats
AVCaptureDeviceFormatクラスは、キャプチャデバイス(iOS7時点ではカメラモジュールのみ)がサポートしている撮影モードの情報を持ちます。このオブジェクトをactiveFormatプロパティに指定することで、同オブジェクトが示す条件で撮影できるようになります。
※フォーマットを指定する具体的な方法は、 @shu223 さんの書いた記事「AV Foundationで120fpsスローモーション動画撮影を実装する」や、書籍「iPhoneアプリ開発エキスパートガイド iOS 6対応」の277ページ以降にある説明を参考にしてください。
今回は、このAVCaptureDeviceFormatクラスを見たときに思うであろう、「同じ撮影サイズなのにfpsが異なるフォーマットがあるのはなぜ?どう使い分けるの?」について説明します。
同じ撮影サイズのフォーマットが4つ??
formatsプロパティが返す結果をNSLog()関数で表示させると、同じ撮影サイズでも複数のフォーマットが存在しています。各サイズで420v/420fの違いで2種類、そして60fps以上の高fpsをサポートするフォーマットだとfps上限の違うもので2種類、合計4種類ものフォーマットが用意されていることに気付きます(下はiPhone5sで出力した結果の抜粋)。
いったい、これらは何が違うのでしょうか。
:
"<AVCaptureDeviceFormat: 'vide'/'420v' 1280x 720, { 2- 30 fps}, fov:58.400, supports vis, max zoom:114.75 (upscales @2.32)>",
"<AVCaptureDeviceFormat: 'vide'/'420f' 1280x 720, { 2- 30 fps}, fov:58.400, supports vis, max zoom:114.75 (upscales @2.32)>",
"<AVCaptureDeviceFormat: 'vide'/'420v' 1280x 720, { 3-120 fps}, fov:58.400, binned, supports vis, max zoom:57.25 (upscales @1.16)>",
"<AVCaptureDeviceFormat: 'vide'/'420f' 1280x 720, { 3-120 fps}, fov:58.400, binned, supports vis, max zoom:57.25 (upscales @1.16)>",
:
AVCaptureDeviceFormatの項目
まず、ログに出力された各要素を説明します。それぞれは次表に示す意味を持っています。
要素 | 意味 |
---|---|
'vide' | デバイスのメディアタイプ。ビデオを表す |
'420v'/'420f' | ピクセルフォーマット |
○○x ○○ | 撮影サイズ |
{ X-XXX fps} | 設定可能なフレームレートの範囲 |
fov | 画角 |
binned | 「ビニング」によるキャプチャかどうか |
supports vis | 手ぶれ補正の有無 |
max zoom | デジタルズームを含めた最大ズーム倍率 |
upscales | 無劣化ズームになる最大ズーム倍率 |
420v/420fはビデオフレームのデータの並び順のことで、どちらも420なのでBi-Planar Component Y'CbCr 8-bit 4:2:0を表しますが、420vは値域がビデオレンジ(luma=[16,235] chroma=[16,240])であるのに対し、420fはフルレンジ(luma=[0,255] chroma=[1,255])を表します。
一般的には420fの方が細かな表現に優れますが、実際のところあまり違いはありません。Core VideoとOpenGLとを組み合わせる場合には420vを使うことになります(ここは)。
fpsはフレームレート、fovは画角です。iOS6以前だと、画角を調べるには一度撮影したムービーのメタデータを調べるという面倒な作業が必要でしたが、今は撮影する前から確認できるようになっています。便利ですね。あとsupports visは手ぶれ補正のサポート有無を表します。max zoomとupscalesはズームのパラメータです。
そして、今回のキーとなる「binned」です。実はこの値が、画質を左右させる大きな要因になっているのです。
「binned」=「ビニング」そのメリットとデメリット
ようやく本題です。
「binned」または「binning」は、日本語では「ビニング」と呼ばれる、イメージセンサーで使われる用語です。あまり馴染みのない単語ですが、これは隣接するピクセルを仮想的に1まとめにして扱い、各サブピクセルの平均値をピクセル値として扱う技術です(Google画像検索すればイメージが掴めるはず)。複数のピクセルが力を合わせて1ピクセルを作り上げるので、暗所でも画質の劣化を抑えられますし、逆に言えばシャッタースピードの速い(フレームレートの高い)撮影でも暗くなりにくいメリットを持っています。
しかし、ビニングはいいことばかりではありません。複数ピクセルで1ピクセルを担うため、センサー全体での解像度は逆に低下してしまうのです。実際に、720pで「ビニングの無い上限30fpsのフォーマット(上記フォーマットログの上から2番目)」と、「ビニングしている上限120fpsのフォーマット(同4番目)」の2つを使って評価チャートを撮影し、その結果の一部を拡大したのが次の図です。
チャートは、画像検索で見つかったこのサイトの写真を画面表示して撮影しました。問題があれば差し替えますので教えてください。
撮影には拙作のビデオカメラアプリ「スムーズビデオカメラ」を使いました。今回紹介したフォーマットも、fpsも選択できるのが役立ちました(宣伝)
左のビニングしないフォーマットで撮影したチャートは文字の1つ1つがはっきり見えています。しかし、右のビニングしたフォーマットでの結果は全体的にぼやけた絵になっていることが分かります。ちなみに、どちらも30fpsで撮影したものです。
まとめ
720pで撮影するからといって、常に120fps(60fps)までサポートするフォーマットが正義というわけではありません。とくに、30fpsに抑えて撮影するとなれば、むしろ画質を落として撮影していることになってしまいます。
したがって、高フレームレートで撮影するアプリでも、30fps以下の設定で撮影する場合は、ビニングの無いフォーマットを選び直した方が良いことが分かりますね。
私たちで、より良いアプリを作っていきましょう。
(その際は、お手元に「上を目指すプログラマーのためのiPhoneアプリ開発テクニック(iOS 7編)」をお忘れなく!)