今見てくれてる人の数

ホンキートンク・スーダラブルース

ゆるコラム、oF、邦ロックや歌謡曲、小説の感想。ドラクエ、JavaScript、ドラゴンボール超など。湘南あたりを転がってる石コロのゆるゆる生きてく超雑多な軌跡です。

【openFrameworks 冒険記17】ofxOpenCv + ofxBox2d Box2dの円を手でキャッチする。

f:id:sudara_bluse:20171123145115p:plain

変なポーズでこんにちは。

 

関係ないんすが、

水曜ドラマ、綾瀬はるかさん主演「奥様は取り扱い注意」にハマってます。笑

旦那の西島秀俊の正体気になる。。。

sudara-bluse.hatenablog.com

 

今回は、

下記2つの記事の合わせ技 ofxOpenCvで輪郭線を検出、

その輪郭線でofxBox2dの円をキャッチというのをやってみます。

 

sudara-bluse.hatenablog.com

sudara-bluse.hatenablog.com

 

 

完成図動画↓

 

 

コード

ofApp.h
#pragma once

#include "ofMain.h"
#include "ofxBox2d.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);


    /* box2d で使うもの */
    ofxBox2d box2d; // box2dのインスタンス変数
    ofxBox2dRect rects[10]; // box2dの四角形
    ofColor randColor[10]; // ランダムな色

    static const int BOLB_NUM = 10; // 検出する輪郭線の数
    // Box2dの線を動的配列に
    ofPtr<ofxBox2dPolygon> edges[BOLB_NUM];


    /* openCVで使うもの */
    ofVideoGrabber cam;
    ofxCvColorImage colorImg;
    ofxCvGrayscaleImage grayImg;
    ofxCvGrayscaleImage grayBg;
    ofxCvGrayscaleImage grayDiff;
    bool isSave;
    int threshold = 100; // しきい値
    ofxCvContourFinder contourFinder; // 輪郭線のインスタンス
    ofPolyline edgeLines[BOLB_NUM]; //検出したエッジ(輪郭線)

};
ofApp.cpp
#include "ofApp.h"


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

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

    // box2dの世界を作る
    box2d.init();
    box2d.setGravity(0, 9.8); // y方向に9.8の重力設定
    box2d.setFPS(30);


    for(int cnt = 0; cnt < 10; cnt++){
        rects[cnt].setPhysics(10.0,1.0,0); // 質量(密度)、反発係数、摩擦

        int x = ofRandom(0, ofGetWidth());
        int y = -100;

        // xはランダム、yは-100のところに位置設定
        rects[cnt].setup(box2d.getWorld(),x, y, 40, 40);
        randColor[cnt] = ofColor(ofRandom(255), ofRandom(255), ofRandom(255)); // 色設定
    }


    /****   openCV    *****/
    cam.initGrabber(1024, 768); // カメラの初期設定
    colorImg.allocate(1024, 768); // 処理領域確保
    grayImg.allocate(1024, 768);
    grayBg.allocate(1024, 768);
    grayDiff.allocate(1024, 768);

    // 背景saveしたか
    isSave = true;

    // box2dのポリゴン初期化
    for(int cnt = 0; cnt < BOLB_NUM; cnt++){
        edges[cnt] = ofPtr<ofxBox2dPolygon>(new ofxBox2dPolygon);
    }


}

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

    box2d.update();

    for(int cnt = 0; cnt < 10; cnt++){
        // 画面下+100 を超えたら位置セットし直して、また降ってくる
        if(rects[cnt].getPosition().y > ofGetHeight() + 100){
            rects[cnt].setPosition(ofRandom(0, ofGetWidth()), -100);
        }
    }



    /* openCV */

    // カメラを更新して、データをカラー画像に変換
    cam.update();
    colorImg.setFromPixels(cam.getPixels().getData(), 1024, 768);
    colorImg.mirror(false, true); // 映像反転
    colorImg.blur(); // エッジを取りやすくするためブラー


    // 差分を取るための背景の設定
    grayImg = colorImg;

    // 背景画像をセット
    if(isSave == true){
        grayBg = grayImg;
        isSave = false;
    }

    // 差分を求める
    grayDiff.absDiff(grayBg, grayImg);

    // しきい値設定
    grayDiff.threshold(threshold);

    // 輪郭線の検出
    contourFinder.findContours(grayDiff, 20, (1024*768)/4, BOLB_NUM, true);


    // 最大10個検出する
    int num = contourFinder.nBlobs;
    for(int cnt = 0; cnt < BOLB_NUM; cnt++){

        // 古い情報を削除
        edgeLines[cnt].clear();
        edges[cnt].get()->clear();

        // ループで落ちないように
        if(cnt < num){

            // 検出した物体にアクセス
            for(int cnt2 = 0; cnt2<contourFinder.blobs[cnt].pts.size(); cnt2++){
                // エッジ 輪郭線を引く
                edgeLines[cnt].addVertex(contourFinder.blobs[cnt].pts[cnt2]);
            }
            // エッジを閉じる
            edgeLines[cnt].close();
            // エッジの簡易化
            edgeLines[cnt].simplify();

            //box2dの線(ポリゴン)に変換
            edges[cnt].get()->addVertexes(edgeLines[cnt]);
            //box2dの世界に放り込む
            edges[cnt].get()->create(box2d.getWorld());
        }

    }





}

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

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


    // エッジ(輪郭)を描画
    ofSetColor(255,255,0);
    ofSetLineWidth(3);
    for(int cnt = 0; cnt < BOLB_NUM; cnt++){
        edgeLines[cnt].draw();
    }

    // box2dの四角形を描画
    for(int cnt = 0; cnt < 10; cnt++){
        ofSetColor(randColor[cnt]);
        rects[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;
    }

}

 

 

中島らもさんの「心が雨漏りする日には。」

が良さそうなので、祝日ですが

こんな雨の日は部屋に引きこもって読書しよと思います。

 

完。