openFrameworksとofxOpenCvを使って、 iPhoneのカメラ入力をリアルタイム解析し、動いている物体を検出する サンプルを作成する手順です。
ofxOpenCVと、ofVideoGrabberを使用します。
関連記事:openFrameworks - 「iPhoneのカメラからの入力をリアルタイム処理する」ための実装を超簡単にする ofVideoGrabber - Qiita [キータ]
##プロジェクトの準備
###プロジェクト作成
videoGrabberExampleをコピー&リネームする
###アドオンの導入
- プロジェクトのaddonsグループに、ofxOpenCVを追加
- [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の差分画像を計算
- 輪郭抽出
輪郭抽出には 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 を修正する