openframeworks addonを利用する ofxcontrolpanel ofxopencv - 多摩美メディアアートii
TRANSCRIPT
Media Art II 2011 第7回:openFrameworksAddonを利用するofxControlPanel, ofxOpenCv
2011年10月25日多摩美術大学 情報デザイン学科 情報芸術コース田所 淳
今日の内容‣ addon (アドオン) を使用する、addonとは何か?‣ プロジェクトにaddonを追加する方法
‣ 2種類のaddonを試してみる
‣ その1:ofxControlPanel‣ 独自のコントロールパネルのGUIを追加可能‣ プログラムの木目細かな設定が可能
‣ その2:ofxOpenCv‣ 画像処理・画像認識を行う‣ 物体の輪郭を認識させる
サンプルファイルのダウンロード‣ 授業内で紹介する全てのサンプルプログラムは、下記からダウンロードが可能です
‣http://goo.gl/VunsO
アドオンとは‣ OpenFrameworksに機能を拡張するためのライブラリー‣ processingのLibrariesのような存在‣ OpenFrameworks単体ではできなかった様々な機能を実現‣ oF本体の開発者以外でも独自に開発して追加することが可能
‣ アドオン情報‣ addons | openFrameworks‣ http://www.openframeworks.cc/addons
‣ oF addons‣ http://addons.openframeworks.cc/
‣ of unofficial‣ http://www.openframeworks.info/addons
アドオンの機能の一例
コンピュータ・ビジョン / ARofxOpenCv, ofxARToolkitPlus
シミュレーション / 物理計算 / 流体力学ofxBox2d, ofxMSAFluid, ofxMSAPhisics, ofxRuiPhusics2d
音響ofxMidi, ofxOsc, ofxSoundObj, ofxSuperCollider
デバイス / ハードウェアofxiPhone, ofxSuddenMotion
アドオン(addon)とは‣ oF v007には、最初からいくつかのアドオンが付属してくる
アドオンの名称 説明
ofxDirList ディレクトリの項目の一覧を生成
ofxXmlSettings アプリケーションの設定をXML形式で保存、読込み
ofxOsc Open Sound ControlをOpenFrameworksで使用する
ofxOpenCv 画像処理・画像認識用のC言語ライブラリOpenCVを使用できるようにする
ofxNetwork ネットワーク通信のプロトコル、TCPとUDPを使用可能にする、マルチキャストにも対応
ofxThred クロスプラットフォームでスレッドの管理を実現
ofxVectorGraphics OpenFrameworksからPostscriptを生成し出力する
ofx3dModelLoader 3ds形式の3DモデルをOpenFrameworksに読みこむ
アドオン(addon)とは‣ アドオンがインストールされている場所‣ 《oFをインストールしたフォルダ》/addons/
Addonを使ってみる‣ 今回は題材として2つのAddonを試してみます
‣ ofxControlPanel:コントロールパネル (GUI)‣ プログラムで頻繁に調整する必要のあるパラメータをGUIから設定可能にする
‣ 設定した項目は、XML形式で設定ファイルとして保存と読込が可能
‣ ofxOpenCv:人工視覚‣ コンピュータ・ビジョン「ロボットの目」をつくる
Addonをプロジェクトに追加する‣ ofxControlPanelを題材にして、実際に空のプロジェクトにaddonを追加してみる
‣ ofxControlPanelを使用するには依存関係のある2つのaddonもあわせてインストールする必要あり‣ ofxXmlSettings‣ ofxDirList
ofxControlPanelの入手‣ ofxControlPanel は最初からopenFrameworksの本体と一緒に配布されるリストには含まれていない
‣ 利用するにはまずaddonをダウンロードする必要がある
‣ 下記からダウンロード
‣http://goo.gl/OlVT5‣ ※ Theo Watsonさんのバージョンがv007でコンパイルエラーになるので、オリジナルを一部修正したバージョン
ofxControlPanelの入手‣ ダウンロードしたofxControlPanelのフォルダ一式を、addonsフォルダ直下に保存する
Addonをプロジェクトに追加する1. 新規にプロジェクトを作成し、addonsフォルダをコント
ロール+クリック、もしくは右クリック2. 「追加」→「既存のファイル」を選択
Addonをプロジェクトに追加する3. addonsフォルダから「ofxControlPanel」フォルダを選択4. 設定画面を下記のように設定する
Addonをプロジェクトに追加する5. addonsフォルダ内に、ofxControlPanelフォルダが追加さ
れているはず
Addonをプロジェクトに追加する6. ofxControlPanelを使用するには、ofxXmlSettingsと、
ofxDirListの2つのaddonもインストールする必要あり7. ofxControlPanelの際と同じ要領で、それぞれのaddonを
プロジェクトに追加する8. addonsフォルダは下記のようになる
ofxControlPanelを使用する‣ addonの準備ができたので、ofxControlPanelを実際に使用してみましょう
‣ まずは、ofxControlPanelを使用していない普通のプログラムを作成
‣ そこに、ofxControlPanelのGUIを組込みます
‣ サンプルとして、画面中央にx, y, z軸それぞれを任意に回転させた正方形を描きます
ofxControlPanelを使用する‣ testApp.h#pragma once
#include "ofMain.h"
class testApp : public ofBaseApp{!public:! void setup();! void update();! void draw();! void mouseDragged(int x, int y, int button);! void mousePressed(int x, int y, int button);! void mouseReleased(int x, int y, int button);};
ofxControlPanelを使用する‣ testApp.cpp (1 of 2)#include "testApp.h"
void testApp::setup(){ ofSetFrameRate(60); ofBackgroundHex(0x000000);}
void testApp::update(){
}
void testApp::draw(){! float rot_x = 10.0f;! float rot_y = 20.0f;! float rot_z = 30.0f;! float size = 200.0f;! ofPushMatrix();! ofTranslate(ofGetWidth()/2, ofGetHeight()/2);! ofRotateX(rot_x);! ofRotateY(rot_y);! ofRotateZ(rot_z);! ofSetHexColor(0x3399ff);! ofSetRectMode(OF_RECTMODE_CENTER);! ofRect(0, 0, size, size);! ofPopMatrix();}
ofxControlPanelを使用する‣ testApp.cpp (2 of 2)void testApp::mouseDragged(int x, int y, int button){
}
void testApp::mousePressed(int x, int y, int button){
}
void testApp::mouseReleased(int x, int y, int button){
}
ofxControlPanelを使用する‣ 実行結果
ofxControlPanelを使用する‣ このプログラムで使用されている具体的なパラメータ‣ float rot_x:x軸方向の回転角度‣ float rot_y:y軸方向の回転角度‣ float rot_z:z軸方向の回転角度‣ float size:正方形の大きさ(幅と高さ)
‣ この4つのパラメータをスライダーで設定できるようにしてみましょう
ofxControlPanelを使用する‣ testApp.h を修正#pragma once
#include "ofMain.h"
#include "ofxControlPanel.h"
class testApp : public ofBaseApp{!public:! void setup();! void update();! void draw();! void mouseDragged(int x, int y, int button);! void mousePressed(int x, int y, int button);! void mouseReleased(int x, int y, int button); ofxControlPanel gui;
};
addonのヘッダーを読込み
ofxControlPanelのインスタンス
ofxControlPanelを使用する‣ testApp::setup() にGUIの設定を追加void testApp::setup(){ ofSetFrameRate(60); ofBackgroundHex(0x000000); ! //GUI setup gui.setup("control panel test", 0, 0, 340, 400); gui.addPanel("panel 1", 1); gui.addSlider("rect size", "size", 100, 0, 800, false); gui.addSlider("rotate x", "rot_x", 0, 0, 360, false); gui.addSlider("rotate y", "rot_y", 0, 0, 360, false); gui.addSlider("rotate z", "rot_z", 0, 0, 360, false); gui.loadSettings("controlPanel.xml");
}
ofxControlPanelを使用する‣ testApp::draw() を修正void testApp::draw(){ ofPushMatrix(); ofTranslate(ofGetWidth()/2, ofGetHeight()/2); ofRotateX(gui.getValueF("rot_x")); ofRotateY(gui.getValueF("rot_y")); ofRotateZ(gui.getValueF("rot_z"));
ofSetHexColor(0x3399ff); ofSetRectMode(OF_RECTMODE_CENTER); ofRect(0, 0, gui.getValueF("size"), gui.getValueF("size"));
ofPopMatrix(); ofSetRectMode(OF_RECTMODE_CORNER); gui.draw();
}
ofxControlPanelを使用する‣ testApp.cppのマウスイベントに設定を追加
void testApp::mouseDragged(int x, int y, int button){ gui.mouseDragged(x, y, button);}
void testApp::mousePressed(int x, int y, int button){ gui.mousePressed(x, y, button);}
void testApp::mouseReleased(int x, int y, int button){ gui.mouseReleased();}
ofxControlPanelを使用する‣ 実行結果:コントロールパネルのGUIが生成されている
Addon その2:ofxOpenCV‣ アドオンの使用サンプルその2‣ ofxOpenCv
Addon その2:ofxOpenCV‣ ofxOpenCv‣ OpenCVをアドオンとして使用できるようにしたもの
‣ OpenCVとは?‣ OpenCV = Open Computer Vision Library‣ 米 Intel 社で開発された画像処理・画像認識用のC言語ライブラリ
‣ オープンソース、商用・非商用を問わず無料‣ 静止画にも動画にも対応
Addon その2:ofxOpenCV‣ openFrameworksとOpenCVを組みあわせた作品は、数多く存在する
‣ カメラの映像によるインタラクションは、市販の機材で構築可能で、かつメンテナンスも容易
‣ 個人制作する作品にも転用可能
Addon その2:ofxOpenCV‣ openFrameworksとOpenCVを組みあわせた作品は、数多く存在する
‣ カメラの映像によるインタラクションは、市販の機材で構築可能で、かつメンテナンスも容易
‣ 個人制作する作品にも転用可能
OpenCVを活用した作品例‣ YesYesNo “Night Lights”‣ http://yesyesno.com/night-lights
OpenCVを活用した作品例‣ Graffiti Research Lab. “L.A.S.E.R. Tag”‣ http://graffitiresearchlab.com/projects/laser-tag/
OpenCVを活用した作品例‣ The Eye Writer‣ http://www.eyewriter.org/
OpenCVを活用した作品例‣ Chris O'shea “Hand from Above” ‣ http://www.chrisoshea.org/hand-from-above
OpenCVを活用した作品例‣ Chris O'shea “Audience” ‣ http://www.chrisoshea.org/audience
OpenCVを活用した作品例‣ Golan Levin “Double-Taker (Snout)”‣ http://www.flong.com/projects/snout/
OpenCVを活用した作品例‣ boards magazine interactive cover: Rise and Fall‣ http://www.boardsmag.com/community/blogs/behindthescenes/
index.php?p=834
OpenCV で物体を認識する‣ これらの作品に共通する技術‣ カメラで撮影された映像から、動いている物体を検出し、その位置や輪郭を抽出する
‣ 「ロボットの眼」をプログラミングしている
‣ OpenCVを活用すると、この物体の認識が簡単に可能となる
OpenCV で物体を認識する‣ 映像から物体の形態を認識するアルゴリズム
カメラから映像をキャプチャー
グレースケールに変換
背景画像を登録
背景画像と現在の画像の差分を計算
差分の画像を2値化
2値化した画像を解析 (輪郭抽出、重心を算出)
OpenCV で物体を認識する‣ apps > addonsExamples > opencvExample に物体の輪郭を抽出するまでの、わかりやすいサンプルが掲載
‣ まずは、この基本プログラムを読み解いていきたい
ofxOpenCv 基本‣ testApp.h#pragma once#include "ofMain.h"#include "ofxOpenCv.h"//#define _USE_LIVE_VIDEO
class testApp : public ofBaseApp{public:! void setup();! void update();! void draw();! void keyPressed(int key);!! #ifdef _USE_LIVE_VIDEO! ofVideoGrabber vidGrabber;! #else! ofVideoPlayer vidPlayer;! #endif!! ofxCvColorImage colorImg;! ofxCvGrayscaleImage grayImage;! ofxCvGrayscaleImage grayBg;! ofxCvGrayscaleImage grayDiff;! ofxCvContourFinder contourFinder;!! int threshold;! bool bLearnBakground;};
カメラ入力を使用する場合はここをコメントアウト
カメラ入力
動画ファイルを再生
グレースケールに変換後入力された元映像
キャプチャーされた背景画像背景とグレースケール画像の差分輪郭を抽出するためのオブジェクト
画像を2値化する際の閾値(しきいち)背景を記録した際に通知
ofxOpenCv 基本‣ testApp.cpp setup()void testApp::setup(){! ofSetFrameRate(60);!! #ifdef _USE_LIVE_VIDEO! vidGrabber.setVerbose(true);! vidGrabber.initGrabber(320,240);! #else! vidPlayer.loadMovie("fingers.mov");! vidPlayer.play();! #endif!! colorImg.allocate(320,240);! grayImage.allocate(320,240);! grayBg.allocate(320,240);! grayDiff.allocate(320,240);!! bLearnBakground = true;! threshold = 80;}
カメラ入力の場合はカメラを初期化
必要となる画像のためのメモリ領域を確保
動画再生の場合は動画ファイルを読込
背景画像を記録した状態に2値化の閾値を設定
ofxOpenCv 基本‣ testApp.cpp update(), 1 of 2void testApp::update(){! ofBackground(100,100,100);! bool bNewFrame = false;!! #ifdef _USE_LIVE_VIDEO! vidGrabber.grabFrame();! bNewFrame = vidGrabber.isFrameNew();! #else! vidPlayer.idleMovie();! bNewFrame = vidPlayer.isFrameNew();! #endif
新規フレームのとりこみをリセット
カメラ入力の場合はカメラ映像を1コマ取得
動画再生の場合は動画ファイルから1コマ
ofxOpenCv 基本‣ testApp.cpp update(), 2 of 2! if (bNewFrame){! !! ! #ifdef _USE_LIVE_VIDEO! ! colorImg.setFromPixels(vidGrabber.getPixels(), 320,240);! ! #else! ! colorImg.setFromPixels(vidPlayer.getPixels(), 320,240);! ! #endif! ! grayImage = colorImg;
! ! if (bLearnBakground == true){! ! ! grayBg = grayImage;! ! ! bLearnBakground = false;! ! }! !! ! grayDiff.absDiff(grayBg, grayImage);! ! grayDiff.threshold(threshold);! !! ! contourFinder.findContours(grayDiff, 20,
(340*240)/3, 10, true);! }}
取得した映像をキャプチャーしcolorImgに
グレースケールに変換
もし背景取得モードだったら現在のグレースケール画像を背景画像として採用
背景画像とグレー画像の差分を計算後、設定した閾値で2値化
2値化した差分画像の輪郭線を抽出
ofxOpenCv 基本‣ testApp.cpp draw()void testApp::draw(){!! ofSetHexColor(0xffffff);! colorImg.draw(20,20);! grayImage.draw(360,20);! grayBg.draw(20,280);! grayDiff.draw(360,280);!! ofFill();! ofSetHexColor(0x333333);! ofRect(360,540,320,240);!! ofSetHexColor(0xffffff);! contourFinder.draw(360,540);}
カラー画像を描画グレースケール画像を描画キャプチャーした背景を描画2値化した差分画像を描画
抽出した輪郭を表示する背景を描画
抽出した輪郭線を描画
ofxOpenCv 基本‣ 実行結果:動いている物体の輪郭線が抽出される
応用1:ofxOpenCv + ofxControlPanel‣ ofxControlPanelを使用して、OpenCVの解析動画のモニターや、閾値などの調整ができるように
‣ OpenCVを使用したプロジェクトで汎用的に使用可能
‣ プログラムは「03_OpencvControlPanel」に収録
応用1:ofxOpenCv + ofxControlPanel‣ 実行結果 (コントロールパネルを開いた状態)
応用1:ofxOpenCv + ofxControlPanel‣ 実行結果 (コントロールパネルを閉じた状態)
応用2:差分抽出をクラス化‣ キャプチャーした背景の画像と、現在のフレームの画像の差分を抽出する機能を、独立したクラスにする
‣ 大規模なプログラムを作成する際、コードの見通しが良くなる‣ まとまった機能はクラス化するようにする
‣ 差分抽出のためのクラス BackgroundSubtraction を作成
‣ あわせて差分の計算方法も3種類にする‣ BG_ABS:差分の絶対値‣ BG_GREATER:背景より明い領域を抽出‣ BG_LESS:背景より暗い領域を抽出
応用2:差分抽出をクラス化‣ BackgroundSubtraction.h#pragma once#include "ofMain.h"#include "ofxOpenCv.h"
typedef enum{! BG_ABS, BG_GREATER, BG_LESS} captureMode;
class BackgroundSubtraction{public:! void setup(int width, int height);! void update(unsigned char * pixelsIn, int width, int height );! void draw(float x, float y);! void setThreshold(int threshVal);! void setDifferenceMode(int modeIn);! void captureBackground();!! ofxCvColorImage color;! ofxCvGrayscaleImage gray;! ofxCvGrayscaleImage background;! ofxCvGrayscaleImage thresh;! captureMode mode;! int numFrames;! float threshAmnt;};
応用2:差分抽出をクラス化‣ BackgroundSubtraction.cpp - 1 of 3#include "BackgroundSubtraction.h"
void BackgroundSubtraction::setup(int width, int height){!! color.allocate(width, height);! gray.allocate(width, height);! thresh.allocate(width, height);! background.allocate(width, height);!! threshAmnt = 29;! numFrames!= 0;}
void BackgroundSubtraction::update(unsigned char * pixelsIn, int width, int height ){
! color.setFromPixels(pixelsIn, width, height);!! gray = color;!! if( numFrames < 20 ){! ! background = gray;! }!
応用2:差分抽出をクラス化‣ BackgroundSubtraction.cpp - 2 of 3! if( mode == BG_ABS ){! ! thresh.absDiff(gray, background);! }else if( mode == BG_GREATER ){! ! thresh = gray;! ! thresh -= background;! }else if( mode == BG_LESS ){! ! thresh = background;! ! thresh -= gray;!! }!! thresh.threshold(threshAmnt);! numFrames++;}
void BackgroundSubtraction::draw(float x, float y){! ofSetColor(0xFFFFFF);! gray.draw(x, y);! background.draw(x + gray.width, y);! thresh.draw(x, y + gray.height);}
void BackgroundSubtraction::setThreshold(int threshVal){! threshAmnt = (int)threshVal;}
応用2:差分抽出をクラス化‣ BackgroundSubtraction.cpp - 3 of 3void BackgroundSubtraction::captureBackground(){! background = gray;}
void BackgroundSubtraction::setDifferenceMode(int modeIn){! mode = (captureMode)modeIn;}
応用2:差分抽出をクラス化‣ 実行結果:
応用3:OpenCV + VectorField‣ 第5回:「openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム」の授業でとりあげた、VectorFieldを、OpenCVとくみあわせてみる
‣ 差分抽出した画像の濃淡から、VectorFieldを生成する
‣ ソースは「05_OpencvVectorfield」
‣ 2値化させた画像にぼかしを入れる‣ 2D平面状のの値(濃淡)を、VectorFirldに変換する
応用3:OpenCV + VectorField
‣ 画像をベクトル場としてとらえる‣ 向きと方向をもった力が、グリッド上に整列している
応用3:OpenCV + VectorField
‣ 実行結果
応用3:OpenCV + VectorField
応用4:OpenCV + VectorField + Particle‣ さらに、生成したVectorFieldにParticleをのせてみる‣ これも、 第5回:「openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム」の応用
‣ ソースは「06_OpencvParticle」
‣ 実行結果
応用4:OpenCV + VectorField + Particle
‣ さらにParticleを高度なものへ‣ Particle自身に、吸引力と反発力を持たせる‣ 流体のような動きを再現
‣ プログラムサンプルの「07_OpencvParticleParticle」
応用5:さらに高度なParticle
‣ 実行結果
応用5:さらに高度なParticle