[Processing]OpenCVを利用した人物認識(その2)


開発環境


言語

- Processing 3.1.1

eclipseを使用し、core.jarをインポートした環境でコーディングしているため、ProcessingのIDEでは実行できません。

参考URL

http://hiroyukitsuda.com/archives/1721

- java 1.8.0_91

API

- Video

動画ファイル、ライブカメラ等の映像を扱う機能を提供

https://processing.org/reference/libraries/video/index.html

- OpenCV for Processing

画像処理・画像解析および機械学習等の機能を提供

https://github.com/atduskgreg/opencv-processing

OS

- macOS sierra 10.12.6

参考サイト

光り輝くパーティクルを作ってみよう

http://blog.p5info.com/?p=516

参考著書

Nature of Code -Processingではじめる自然現象のシミュレーション

https://www.borndigital.co.jp/book/5149.html


フロー

1.setup

1.1 動画ファイルを指定

1.2 検知対象を設定

1.3 再生設定

2.draw

2.1 画面の明るさを指定調整し、モノクロで表示

2.2 OpenCVが検知した対象を配列に格納

2.3 検知した対象の頭上に発光する粒子を表示

2.4 全ての検知対象をラインで接続


コード

package detection.phase2;

import java.awt.Rectangle;

import gab.opencv.OpenCV;
import processing.core.PApplet;
import processing.video.Movie;

public class WalkerDetection extends PApplet {
        Movie movie;
        OpenCV openCV;
        
        Rectangle[] detectsFromOCV;
        
        //---発光処理-------------------------------------------
        final int LIGHT_DISTANCE = 500*500;     //光が届く距離
        final int BORDER = 1000;                        //発光する計算範囲(短形)
        
        float baseR,baseG,baseB;                        //光の色
        float baseRAdd,baseGAdd,baseBAdd;       //色の加算量
        final float RED_ADD = 2.7F;                     //赤色
        final float GREEN_ADD = 2.2F;           //緑色
        final float BLUE_ADD = 3.5F;            //青色
        
        float lightPower;                                       //光の大きさ
        
        public void settings() {
                size(1280, 720);
        }
        
        public void setup() {
                //光色の初期化
                baseR = 50;
                baseRAdd = RED_ADD;
                baseB = 100;
                baseBAdd = BLUE_ADD;
                baseG = 150;
                baseGAdd = GREEN_ADD;
                
                //動画ファイルを指定
                movie = new Movie(this, "umeda_rain.m4v");
                openCV = new OpenCV(this, width,height);
                //検知対象に歩行者を指定
                openCV.loadCascade(OpenCV.CASCADE_PEDESTRIAN);
                
                //ループ再生
                movie.loop();
                movie.play();
                //再生スピード
                movie.speed(0.3F);
        }
        
        public void draw() {
                //動画をメモリに展開
                image(movie, 0, 0);
                openCV.loadImage(movie);
                //画面の明るさを調整。モノクロ表示とする。
                openCV.brightness(-80);
                image(openCV.getOutput(), 0, 0 ); 
                
                //OpenCVで検知したオブジェクトを配列に格納
                detectsFromOCV = openCV.detect();
                
                //--光の色を変更
                baseR += baseRAdd*5;
                baseB += baseBAdd*5;
                baseG += baseGAdd*5;
                
                //色が範囲外になった場合は、色の加算値を逆転させる
                colorOutCheck();
                //各ピクセルの色の計算
                int tRed = (int)baseR;
                int tGreen = (int)baseG;
                int tBlue = (int)baseB;
                
                //綺麗に光を出すために二乗する
                tRed *= tRed;
                tGreen *= tGreen;
                tBlue *= tBlue;  
                //各ピクセルの色の計算
                loadPixels();
                
                //各particleの周囲のピクセルの色について、加算を行う
                for(int i=0;i<detectsFromOCV.length;i++){
                        //particleの影響範囲を計算
                        int left = max(0,(int) (detectsFromOCV[i].getCenterX()-BORDER));
                        int right = min(width,(int) (detectsFromOCV[i].getCenterX()+BORDER));
                        int top = max(0,detectsFromOCV[i].y-BORDER);
                        int bottom = min(height,detectsFromOCV[i].y+BORDER);
                        //particle影響範囲の色を加算する
                        for(int y = top;y<bottom;y++){
                                for(int x=left;x<right;x++){
                                        int pixelIndex = x + y * width;
                                        //ピクセルから、赤・緑・青の要素を取りだす
                                        int r = pixels[pixelIndex] >> 16 & 0xFF;
                                        int b = pixels[pixelIndex] >> 8 & 0xFF;
                                        int g = pixels[pixelIndex] & 0xFF;
                                        
                                        //パーティクルとピクセルとの距離を計算する
                                        float dx = (float) (detectsFromOCV[i].getCenterX() -x);
                                        float dy = (detectsFromOCV[i].y + (detectsFromOCV[i].height/9)) - y;
                                        float distance = (dx * dx) + (dy * dy);         //三平方の定理
                                        
                                        //ピクセルとパーティクルの距離が一定以内であれば、色の加算を行う
                                        if(distance < LIGHT_DISTANCE){
                                                if(distance < 1){
                                                        distance = 1;
                                                }
                                                //検知対象の大きさに比例したパーティクルとする
                                                lightPower = detectsFromOCV[i].width/30;
                                                
                                                r += tRed * lightPower/distance;
                                                g += tGreen * lightPower/distance;
                                                b += tBlue * lightPower/distance;
                                        }
                                        //ピクセルの色を変更する
                                        pixels[pixelIndex] = color(r,g,b);
                                }
                        }
                }

                updatePixels();
                
                //検知対象をラインで接続する
                stroke(255,150);
                strokeWeight(2);
                for(int i=0;i<detectsFromOCV.length-1;i++){
                        for(int j=i+1;j<detectsFromOCV.length;j++){
                                line((float)detectsFromOCV[i].getCenterX(),
                                                (float)(detectsFromOCV[i].y + detectsFromOCV[i].height/9), 
                                                (float)detectsFromOCV[j].getCenterX(),
                                                (float)(detectsFromOCV[j].y + detectsFromOCV[j].height/9)
                                                );
                        }
                }
        }
        
        //映像フレーム毎に自動呼び出しされるイベント
        public void movieEvent(Movie m) {
                //現在のフレームを読み込み
                m.read();
        }

        //色の値が範囲外に変化した場合は符号を変える
        private void colorOutCheck() {
                if (baseR < 10) {
                        baseR = 10;
                        baseRAdd *= -1;
                }
                else if (baseR > 255) {
                        baseR = 255;
                        baseRAdd *= -1;
                }
                
                if (baseG < 10) {
                        baseG = 10;
                        baseGAdd *= -1;
                }
                else if (baseG > 255) {
                        baseG = 255;
                        baseGAdd *= -1;
                }
                
                if (baseB < 10) {
                        baseB = 10;
                        baseBAdd *= -1;
                }
                else if (baseB > 255) {
                        baseB = 255;
                        baseBAdd *= -1;
                }
        }
        
        //キー押下
        public void keyPressed() {
                //Spaceキー
                if(key == ' '){
                        //一時停止
                        movie.pause();
                }
                //ENTERキー
                if(key == ENTER){
                        //再生
                        movie.play();
                }
        }
        
        public static void main(String[] args) {
                PApplet.main(WalkerDetection.class.getName());
        }
}

実行結果