.28 2013

CloudAR API βを使ってみる(3)

Tasakiです。


最近は、急激な温度変化で体調を崩された方を電車の中で必ずといっていいほど見かけます。手洗い、うがいなどの感染予防を心がけたいですね。

さて、今回から実際にCloudAR APIβを利用したサンプルアプリの開発に取りかかりたいと思います。
とはいうものの、ベースがなければいけませんので、今回はAR機能を利用するにあたってのカメラビューコントローラの作成法をご紹介します。
ARの場合のカメラには、UIImagePickerViewControllerではなく、AVCaptureSessionとAVCaptureVideoPreviewLayerを使用します。
UIImagePickerVIewControllerでも不可能ではないと思いますが、後者の方がカメラをよりハードウェアに近いところで扱えるので、細かい調整ができたりパフォーマンスの面で優れていたりなどといった利点があります。

まずは、下記のコードで「カメラのプレビューを表示するビューコントローラ」が実装できます。

//
// CATMainViewController.m
// CloudARAPITest
//


#import "CATMainViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface CATMainViewController () <AVCaptureVideoDataOutputSampleBufferDelegate>

@property (nonatomic, strong) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;
@property (nonatomic, strong) AVCaptureSession *captureSession;

@property (strong) UIImage *capturedImage;

- (void) initCaptureSession;
- (void) startCaptureSession;
- (void) stopCaptureSession;

@end

@implementation CATMainViewController

- (id) initWithNibName:(NSString *) nibNameOrNil
bundle:(NSBundle *) nibBundleOrNil {
self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil];
if (self) {
}
return self;
}

- (void) viewDidLoad {
[super viewDidLoad];
//キャプチャ初期設定
[self initCaptureSession];
}

- (void) didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (BOOL) shouldAutorotate {
return NO;
}

- (void) viewDidAppear:(BOOL) animated {
[super viewDidAppear: animated];

[self startCaptureSession];
}

- (void) initCaptureSession {
AVCaptureDevice *captureDevice = nil;
AVCaptureDeviceInput *captureDeviceInput = nil;
NSError *error = nil;

//ビデオ入力の設定
self.captureSession = [[AVCaptureSession alloc] init];
self.captureSession.sessionPreset = AVCaptureSessionPresetMedium;
captureDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
captureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice: captureDevice
error: &error];
if ([self.captureSession canAddInput: captureDeviceInput]) {
// セッションにデータ入力を追加
[self.captureSession addInput: captureDeviceInput];
}

// ビデオプレビューレイヤーの作成
self.captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession: self.captureSession];
self.captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.captureVideoPreviewLayer.frame = self.view.bounds;
self.captureVideoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
[self.view.layer addSublayer: self.captureVideoPreviewLayer];

// ビデオデータ出力の作成
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
AVCaptureVideoDataOutput *dataOutput = [[AVCaptureVideoDataOutput alloc] init];
[settings setObject: @(kCVPixelFormatType_32BGRA)
forKey: (id) kCVPixelBufferPixelFormatTypeKey];
dataOutput.videoSettings = settings;
dispatch_queue_t queue = dispatch_queue_create("test.api.cloudar.VideoCaptureQueue", NULL);
[dataOutput setSampleBufferDelegate: self queue: queue];
if ([self.captureSession canAddOutput: dataOutput]) {
// セッションにデータ出力を追加
[self.captureSession addOutput: dataOutput];
}
}

- (void) startCaptureSession {
// キャプチャセッションを開始
if (!self.captureSession.isRunning) {
[self.captureSession startRunning];
}
}

- (void) stopCaptureSession {
// キャプチャセッションを停止
if (self.captureSession.isRunning) {
[self.captureSession stopRunning];
}
}

- (void) captureOutput:(AVCaptureOutput *) captureOutput
didOutputSampleBuffer:(CMSampleBufferRef) sampleBuffer
fromConnection:(AVCaptureConnection *) connection {
// イメージバッファの取得
CVImageBufferRef buffer = CMSampleBufferGetImageBuffer(sampleBuffer);

// イメージバッファのロック
CVPixelBufferLockBaseAddress(buffer, 0);

// イメージバッファ情報の取得
uint8_t* base = CVPixelBufferGetBaseAddress(buffer);
size_t width = CVPixelBufferGetWidth(buffer);
size_t height = CVPixelBufferGetHeight(buffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);

// ビットマップコンテキストの作成
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef cgContext = CGBitmapContextCreate(base, width, height, 8,
bytesPerRow, colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);

// 画像の作成
CGImageRef cgImage = CGBitmapContextCreateImage(cgContext);
UIImage *image = [[UIImage alloc] initWithCGImage: cgImage
scale: 1.0
orientation: UIImageOrientationUp];
self.capturedImage = image;
CGImageRelease(cgImage);
CGContextRelease(cgContext);

// イメージバッファのアンロック
CVPixelBufferUnlockBaseAddress(buffer, 0);
}

@end

上記のコードのうち、比較的ステップ数が多いinitCaptureSessionとcaptureOutput:didOutputSampleBuffer:fromConnection:が肝の部分となっています。

まず、initCaptureSessionですが、ここで行っていることは大きく3つに分けられます。
・キャプチャセッションの作成
・プレビューレイヤーの作成
・ビデオデータ出力の受け取り設定

これらを少し細かく見ていきましょう。

キャプチャセッションの作成


まずキャプチャセッションを作成します。
これは、カメラから映像を受け取るための仲介役です。
セッションに対してどのカメラからどういう解像度で映像を受け取るかを指定します。
上の例ではカメラをdefaultDeviceにしています。これは、両面にカメラを搭載したiPhoneやiPadでは背面カメラを指定していることになります。
最近の端末はカメラが必ず付いているのですが、廉価版iPod touchだけは背面カメラを搭載していなかったりするので、その場合は前面カメラの映像が表示されると思われます。(正直、こういうイレギュラー端末はやめてほしいのですが...)

ビデオプレビューレイヤーの作成


セッションを作成したら、それを用いてビデオプレビューレイヤーを作成し、ビューコントローラのビュー上に載せます。
これについては、ちょっと特殊なレイヤー程度の考え方でよさそうです。
映像の向きに付いてはconnection.videoOrientationで指定します。

ビデオ出力の受け取り


レイヤーの作成と配置が終わったら、最後にビデオデータを受け取るための設定を行います。
ビデオデータ出力オブジェクトと処理用のディスパッチキューを作成し、セッションに渡します。
ビデオデータの取り扱いはマシンパワーを消費するので、メインスレッドで行うのは得策ではありません。(固まります)
そこで専用のキューを作成した上で、その中で処理用のコードを記述するように設計されています。
そのイベントハンドラとなるのが、2つ目のメソッドcaptureOutput:didOutputSampleBuffer:fromConnection:です。

ビデオデータから画像を抽出


最後にビデオデータから画像を抽出する処理を解説します。
captureOutput:didOutputSampleBuffer:fromConnection:内部で行っているのですが、このメソッドでビデオの各フレームのピクセルデータはサンプルバッファという形式で渡されます。
このサンプルバッファからピクセルデータを抽出し、画像コンテキストに書き込んで画像オブジェクトを作成するというのがここで行う処理です。

結果としてcapturedImageというプロパティでキャプチャ画像を扱えるようにしてみました。
次回は、このcapturedImageを利用してタップした瞬間のカメラ画像をCloudAR APIβに問い合わせるという内容を実装し解説したいと思います。

関連記事
スポンサーサイト



Comment

Post comment

  • comment
  • secret
  • 管理者にだけ表示を許可する

Trackback

trackbackURL:http://appteam.blog114.fc2.com/tb.php/280-9c491406

ブログ内検索

関連リンク

製品情報

最新記事

カテゴリ

プロフィール

neoxneo



NEXT-SYSTEM iOS Developers Blog


  • UTO:
    カナダ版iPhone4Sは、マナーモードでシャッター音がならない…


  • Ehara:
    ...


  • Hayate:
    ...


  • Tasaki:
    Developer登録完了...したのはいいけど


  • Ueda:
    ...



リンク