ProcessingのOpticalFlowで人の行動を測定しようという企画。過去に何回か話題にあがっている。これとかこれとか、これも。すごい前から「使えそう」と言ってる割に、一回も使っていない。今回は大島さんとの共同研究で、実際に利用することになりそうだ。
ProcessingのOpenCVライブラリには、OpticalFlow関連のサンプルプログラムがある。基本的にOpticalFlowを視覚化するプログラムなのだが、こちらのサイトから、640×480の各点のデータを取得する方法を学び、右半分と左半分を別に平均し、グラフ化、さらにディスクに保存するプログラムを作成した。
結果はまぁまぁ予想どおり。各点の移動方向はVectorで取得できる。さらにそれをmag()関数で大きさを求め、指定範囲の平均を求めている。ProcessingのPVectorの説明はここにある。測定範囲を視覚化し、さらにある程度GUIで指定できるようになると、実用性が増すようにも思えるが、現場の状況を見ないとなんとも言えないので、次のMTGで話あいましょう。
import gab.opencv.*;
import processing.video.*;
Capture video; // ライブカメラ
OpenCV opencv; // OpenCV
String savefile = "data/movement.csv";
PrintWriter output;
void setup() {
size(640, 480); //画面サイズ
video = new Capture(this, 640, 480); //キャプチャーするカメラのサイズ
opencv = new OpenCV(this, 640, 480); //OpenCVの画面サイズ
video.start(); //キャプチャー開始
output = createWriter(savefile); //出力用ファイル
}
/////////////////////////////////
void draw() {
scale(1.0); //描画スケール設定
opencv.loadImage(video); //カメラの画像をOpenCVに読み込み
image(video, 0, 0 ); //カメラ画像を表示
opencv.calculateOpticalFlow(); //OpticalFlowを計算
stroke(255,0,0); //描画設定
opencv.drawOpticalFlow(); //OpticalFlowを描画
float LFlow = averagedFlow(0,0,320,480).mag();
float RFlow = averagedFlow(320,0,320,480).mag();
print(abs(LFlow)+"/"+abs(RFlow)+"\n");
output.println(abs(LFlow)+","+abs(RFlow));
stroke(0,0,255);
rect(0,480-LFlow*100,10,480);
rect(630,480-RFlow*100,640,480);
//PVector aveFlow = opencv.getAverageFlow();
//print(aveFlow.x+"/"+aveFlow.y+"\n");
}
//キャプチャーイベント
void captureEvent(Capture c) {
c.read();
}
/////平均化されたFlowを取得
PVector averagedFlow(int x,int y,int w, int h){
float xsum=0,ysum=0,xavg=0, yavg=0;
float c=0;
for(int i=x;i<x+w;i++){
for(int j=y;j<y+h;j++){
PVector vec = opencv.getFlowAt(i,j);
xsum+=(float)vec.x;
ysum+=(float)vec.y;
c=c+1;
}
}
xavg=xsum/c;
yavg=ysum/c;
PVector rv=new PVector(0,0);
rv.x=xavg;
rv.y=yavg;
return(rv); //ベクトルで返す
}
//終了時処理
void dispose(){
output.close();
println( "dispose start");
}
void keyPressed() {
if (key == TAB) { // Tabキーに反応
output.close();
exit();
}
}