LoginSignup
80
79

More than 5 years have passed since last update.

openFrameworks × OpenCV で動体検出するiOSアプリをつくる

Posted at

openFrameworksとofxOpenCvを使って、 iPhoneのカメラ入力をリアルタイム解析し、動いている物体を検出する サンプルを作成する手順です。

ofxOpenCVと、ofVideoGrabberを使用します。

関連記事:openFrameworks - 「iPhoneのカメラからの入力をリアルタイム処理する」ための実装を超簡単にする ofVideoGrabber - Qiita [キータ]

プロジェクトの準備

プロジェクト作成

videoGrabberExampleをコピー&リネームする

アドオンの導入

  1. プロジェクトのaddonsグループに、ofxOpenCVを追加
  2. [User Header Search Paths] に "../../../addons/ofxOpenCv/libs" を recursive で追加する。

実装

ヘッダ

ヘッダをinclude

#include "ofxOpenCv.h"

メンバ変数を追加

ofxCvColorImage     colorImg;
ofxCvGrayscaleImage grayImage;
ofxCvGrayscaleImage grayBg;
ofxCvGrayscaleImage grayDiff;
ofxCvContourFinder  contourFinder;

float   capW;
float   capH;
int     threshold;
bool    bLearnBakground;

タッチイベントのハンドラ

画面をタップしたときにフラグが true になるようにする。

void testApp::touchDown(ofTouchEventArgs & touch){

    bLearnBakground = true;
}

セットアップ

void testApp::setup(){  

    // フレームレート
    ofSetFrameRate(20);

    // ofVideoGrabber初期化
    grabber.initGrabber(320, 568, OF_PIXELS_BGRA);

    // 幅、高さ
    capW = grabber.getWidth();
    capH = grabber.getHeight();

    // 各Imageオブジェクトのメモリ確保
    colorImg.allocate(capW,capH);
    grayImage.allocate(capW,capH);
    grayBg.allocate(capW,capH);
    grayDiff.allocate(capW,capH);

    // フラグ、閾値を初期化
    bLearnBakground = true;
    threshold = 80;
}

画像解析

毎フレーム呼ばれる処理。ここで画像解析を行う。

void testApp::update(){

    ofBackground(255,255,255);

    // カメラ入力取得
    grabber.update();
    colorImg.setFromPixels(grabber.getPixels(), capW, capH);
    grayImage = colorImg;

    // 背景画像取得
    if (bLearnBakground == true) {

        grayBg = grayImage;
        bLearnBakground = false;
    }

    // 差分画像を計算
    grayDiff.absDiff(grayBg, grayImage);
    grayDiff.threshold(threshold);

    // 輪郭抽出
    contourFinder.findContours(grayDiff,        // input
                               20,              // minArea
                               (capW*capH)/3,   // maxArea
                               10,              // nあered
                               true);           // find holes
}

ここでやってる画像解析のアルゴリズム

  1. カメラ入力取得
  2. 背景画像取得
  3. 1と2の差分画像を計算
  4. 輪郭抽出

輪郭抽出には ofxCvContourFinder::findContours() を利用。

描画

得られた各種画像を画面上に描画。

void testApp::draw(){   

    ofPushMatrix();
    ofScale(0.5, 0.5, 1);
    ofSetHexColor(0xffffff);

    // カメラ入力を描画
    grabber.draw(0, 0);

    // カメラ入力をグレー化した画像を描画
    grayImage.draw(320, 0);

    // 背景画像を描画
    grayBg.draw(0, capH);

    // 差分画像を描画
    grayDiff.draw(320, capH);

    // blob領域を描画
    for (int i = 0; i < contourFinder.blobs.size(); i++){

        contourFinder.blobs[i].draw(capW, capH);
    }

    ofPopMatrix();
}

できあがり

左上から、右下に向かって、

  • 元画像
  • 元画像をグレー化した画像
  • 背景画像
  • 差分画像

が表示されていて、差分画像上に水色で輪郭が、ピンクでblog領域が描画されています。

(本来は カメラに手をかざすと、手の輪郭を検出し、指をblobとして抽出してくれる サンプルなのですが、スクショを取るのに両手が必要で、自動録画をいれるのも面倒だったので、結局手もかざさないスクショとなっています。あと、スクショとるときにぶれています。)

あと、ここまで書いておいてなんですが、実は、opencvExample で

#define _USE_LIVE_VIDEO

すれば、これとほぼ同じ実装になります。

いずれ調べる

ofVideoGrabber で iPhone のフロントカメラを使う方法

  • ofVideoGrabberのヘッダをみても、直接セットできそうなメソッドや定数の定義は見当たらなかった。
  • setDeviceID(int _deviceID)listDevices() っていうメソッドがある
    • listDevices でフロントカメラのデバイスIDを探して、 setDeviceID でセットすると使えるかも
  • 最悪、 AVFoundationVideoGrabber を修正する
80
79
2

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
80
79