63
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

openFrameworksAdvent Calendar 2013

Day 8

「iPhoneのカメラからの入力をリアルタイム処理する」ための実装を超簡単にする ofVideoGrabber

Last updated at Posted at 2013-12-10

iPhoneのカメラからの入力をリアルタイムに取得し、何らかの画像処理を行う、つまり iOSアプリで動画処理を行う のは、なかなか面倒です。

下記記事を見るとわかりますが、

シャッター音の鳴らないカメラアプリの実装方法 - Over&Out その後

AVFoundation を用いて、 カメラからの入力を毎フレーム取得しようとするだけで、かなりやることが多い です。デリゲートメソッドに渡されてくる画像データが CMSampleBufferRef という型で渡ってくるのも(個人的には)ハードルを感じる部分で、毎回「どう取り扱うんだっけ?」とググってしまいます。

さらに、毎フレーム送られてくる画像情報をリアルタイムに処理をしようとすると、やっぱり OpenGL ベースで処理 する必要が出てきて、これまた(個人的には)気が重くなってしまうところです。

ところが、videoGrabberExample という openFrameworks に同梱されているサンプルのソースを見ると、実にシンプルな実装で、カメラからの入力のリアルタイム処理が実現されていました。

openFrameworks for iOS のサンプル一覧 - Qiita [キータ]

こりゃ便利そう、ということで、その使い方と、チラッとソースをのぞいてみた内容を以下にまとめます。

##実装

こんな感じで、カメラからの入力に対してリアルタイムに反転処理をかけ、左下に表示するための実装手順です。(基本的には videoGrabberExample のコードをシンプルにしてコメントつけただけです)

###セットアップ

メンバ変数に

ofVideoGrabber grabber;
ofTexture tex;
unsigned char * pix;

を定義しておき、

void testApp::setup(){

    // ofVideoGrabberを初期化
    grabber.initGrabber(480, 360, OF_PIXELS_BGRA);

    // テクスチャをallocate
    tex.allocate(grabber.getWidth(), grabber.getHeight(), GL_RGB);

    // バッファ確保
    pix = new unsigned char[ (int)( grabber.getWidth() * grabber.getHeight() * 3.0) ];
}

###カメラからの入力を取得して画像処理

void testApp::update(){
    
    // カメラからの入力を取得
    grabber.update();
    unsigned char * src = grabber.getPixels();
    
    // 画素数 x チャンネル数
    int totalPix = grabber.getWidth() * grabber.getHeight() * 3;
    
    // 反転処理
    for(int k = 0; k < totalPix; k+= 3){
        pix[k  ] = 255 - src[k];
        pix[k+1] = 255 - src[k+1];
        pix[k+2] = 255 - src[k+2];        
    }
    
    // テクスチャデータ生成
    tex.loadData(pix, grabber.getWidth(), grabber.getHeight(), GL_RGB);
}

上記コードではフレーム毎の入力を取得して、そこに各画素値を反転させる処理を行っています。

###描画

void testApp::draw(){    

    // カメラからの入力を描画    
    grabber.draw(0, 0);
    
    // 生成したテクスチャを描画
    tex.draw(0, 0, tex.getWidth() / 4, tex.getHeight() / 4);
}

##ソースの中身をのぞいてみる

先日書いた こちらの記事 で、一部の oF クラスに、 単なるラッパー疑惑 を抱いたのですが、これはその逆ですごく便利なので、どんな感じにラップされてるのかソースの中身をみてみました。

###AVFoundationVideoGrabber

ソースは addons/ofxiOS/src/video/AVFoundation にあるのですが、AVFoundation まわりの諸々はこの AVFoundationVideoGrabber というクラスでラップされてました。

###ofxiOSVideoGrabber

このクラスのソースは addons/ofxiOS/src/video にあります。

上記の AVFoundationVideoGrabber へのポインタを持っています。ofBaseVideoGrabber を継承していて、オーバーライドしている各メソッドの中身では、AVFoundationVideoGrabber のメソッドを呼んでいます。

###ofVideoGrabber

ソースの場所は libs/openFrameworks/video

iOS環境の場合に、ofxiOSVideoGrabber をインスタンスとして持つように実装されています。

#ifdef OF_VIDEO_CAPTURE_IOS
    #include "ofxiOSVideoGrabber.h"
    #define OF_VID_GRABBER_TYPE ofxiOSVideoGrabber
#endif
if( grabber == NULL ){
    setGrabber( ofPtr<OF_VID_GRABBER_TYPE>(new OF_VID_GRABBER_TYPE) );
}

AVFoundation 以外 の諸々(OpenGLのテクスチャとしての描画とか)はここに実装されています。

##いずれ調べる

iOS アプリで OpenGL で画像/動画処理をする場合、GPUImage を利用することが多いので、それと併用するにはどうやるのがいいか(何かしらの共通フォーマットにすればいいと思うので、それを、どのタイミングで、どのフォーマットにするのがいいか)というのをいずれ調べようと思います。

63
67
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?