Edited at

【openFrameworks】アドオンofxOpenCvの ofxCvContourFinderで抽出した輪郭に線をかく。

前回までofxOpenCvを色々いじってきましたが、

とりあえず第1章のシメとして、輪郭に線を引きたかったのです。

こんな感じ。こんくらいの精度で良いのかなぁ??

前回まで

http://www.sudara-bluse.tokyo/entry/openframeworks_11


処理内容

カメラから映像をキャプチャー



グレースケールに変換



スペースキーで背景画像を登録



背景画像と現在の画像の差分を求める(grayDiff)



差分の画像を2値化(grayDiff.threshold())



2値化した画像から輪郭を抽出



発見した輪郭の点を結んで線を描く


ofApp.h


#pragma once

#include "ofMain.h"
#include "ofxOpenCv.h"

class ofApp : public ofBaseApp{

public:
void setup();
void update();
void draw();

void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);

// カメラ
ofVideoGrabber cam;

// カメラから入った1フレーム分の画像
ofxCvColorImage colorImg;

// カメラから入った1フレーム分のグレースケールの画像
ofxCvGrayscaleImage grayImg;

// グレースケール画像で背景用と差分
ofxCvGrayscaleImage grayBase;
ofxCvGrayscaleImage grayDiff;

// フレームを保存したかどうかのフラグ
bool isSave;

// 輪郭検出用
ofxCvContourFinder contourFinder;

// しきい値
int threshold;

// 輪郭線を格納する動的配列
vector <ofPolyline> edgeLines;

};



ofApp.cpp


#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

// 背景を黒に
ofBackground(0, 0, 0);

/* 今回は1024*768です! */
// カメラからの取り込み
cam.initGrabber(640, 480);

// それぞれを処理するメモリ領域を確保 allocate(割り当てる)
colorImg.allocate(640, 480);
grayImg.allocate(640, 480);
grayBase.allocate(640, 480);
grayDiff.allocate(640, 480);

// フラグ初期化
isSave = true;

threshold = 80;

}

//--------------------------------------------------------------
void ofApp::update(){

// カメラの更新
cam.update();

// 一個一個のピクセルデータをカラーイメージにほりこんでる
colorImg.setFromPixels(cam.getPixels().getData(), 640, 480);
colorImg.mirror(false, true);

// グレースケールイメージにカラーデータを入れる
grayImg = colorImg;

// スペースキー押した時に、元画像に現在のグレーイメージを入れる
if(isSave == true){
grayBase = grayImg;
isSave = false;
}
// 白黒画像と動体検知のベースとなる画像の差を求める
grayDiff.absDiff(grayBase, grayImg);

// 二値化 (白黒はっきりさせる)
grayDiff.threshold(threshold);

// 輪郭を描く
// 第1引数 輪郭検出対象
// 第2引数 検出する最小の大きさ(20)
// 第3引数 検出する最大の大きさ
// 第4引数 検出する数
// 第5引数 穴が空いたものを検出するかどうか trueで 検出する
contourFinder.findContours(grayDiff, 20, (640*480)/3, 10, true);

// 動的配列をクリアする
edgeLines.clear();

//-----------------------------------------
// 輪郭線の座標を結んで線にする
//-----------------------------------------

// 1周目for文で複数の輪郭にアクセス
for(int i = 0; i< contourFinder.nBlobs; i++){
ofPolyline line;
// 2周目for文でそれぞれの輪郭の点にアクセスし、点を結んで線にする。
for(int j =0; j<contourFinder.blobs[i].pts.size(); j++){
// 点を線にする。
line.addVertex(contourFinder.blobs[i].pts[j]);
}
// 作成した線を格納
edgeLines.push_back(line);
}
}

//--------------------------------------------------------------
void ofApp::draw(){

// カラー画像の描画
ofSetColor(255, 255, 255);
colorImg.draw(0,0, 640, 480);

// 境界線のサイズと色指定
ofSetLineWidth(5);
ofSetColor(255, 255, 0);
// 輪郭線の描画
for(int cnt = 0; cnt< edgeLines.size(); cnt++){
edgeLines[cnt].draw();
}

}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

switch (key){
case ' ':
isSave = true; // スペースキーを押す事によってフレームを保存
break;
case '+':
threshold ++; //しきい値を上げる
if (threshold > 255) threshold = 255;
break;
case '-':
threshold --; //しきい値を下げる
if (threshold < 0) threshold = 0;
break;
}

}