Java(BlobDetection.jar)で動体検知(風)

 

「空間内の人の動きを検出したい」

 

そう思ったこと、あると思います。
今回ご紹介する「BlobDetectionライブラリ」は、そんな「人の動き検出(風なこと)」を
Processing(Proce55ing, P5)とWebカメラでお手軽に行えるなんとも便利なライブラリです。
#ただし、正確には「動体検出」ではなく、「塊検出」とのことです。 

Processing向けに開発されているだけあって、サンプルアプリも洒落ていて且つ動きも滑らかです(写真はプロジェクトTOPページより抜粋)。
 

この「BlobDetectionライブラリ」は使用実績も優秀です。
Shadow Monsters」という影絵風メディアアートや、にも使われているそうです。 

使い方ですが、もちろんProcessingのPDEから直接利用してもいいですが、
折角なので、Javaから直接叩いてみます。

Javaから直接叩く手順は、以下の通りです(以下はMacの手順)。

  1. /Applications/Processing.app/Contents/Resources/Java/core.jarをJavaのビルドパスに追加
  2. Eclipseなどのエディタで以下のソースを記述&Runする
/Applications/Processing.appの中身はデフォルトでは見えないので、右クリック→パッケージの中身を表示、という手順でcore.jarを見つけてください。
以下が、サンプルに若干手を加えたものの実行画面&ソースコードです。 
「動体検知」ではなく「塊検知」なので、「動いているもの」というより
「映像内の同じRGB値が集まっている場所」を見つけるようです(多分)。
ただ、この塊を見つける閾値を調整&塊が動いているかどうかを判定するよう修正すれば、
動体検知らしいことをしているように出来ますね。     

拡張したらまたアップします。

 

[java]
package jp.ac.naka.cc.app.labad;

import java.awt.Image;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PImage;
import processing.video.Capture;
import blobDetection.Blob;
import blobDetection.BlobDetection;
import blobDetection.EdgeVertex;

public class NakaClock extends PApplet {
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//BlobDetection by v3ga
//May 2005
//Processing(Beta) v0.85
//
// Adding edge lines on the image process in order to ‘close’ blobs
//
// ~~~~~~~~~~
// software :
// ~~~~~~~~~~
// – Super Fast Blur v1.1 by Mario Klingemann
// – BlobDetection library
//
// ~~~~~~~~~~
// hardware :
// ~~~~~~~~~~
// – Sony Eye Toy (Logitech)
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Capture cam;
BlobDetection theBlobDetection;
PImage img;
boolean newFrame=false;
PFont font;
PImage newImage;
boolean isHijacked = false;

// ==================================================
// setup()
// ==================================================
public void setup()
{
// Size of applet
size(640, 480);
frameRate(6);
// Capture
cam = new Capture(this, 40*4, 30*4, 15);
// BlobDetection
// img which will be sent to detection (a smaller copy of the cam frame);
img = new PImage(80,60);
theBlobDetection = new BlobDetection(img.width, img.height);
theBlobDetection.setPosDiscrimination(true);
theBlobDetection.setThreshold(0.2f); // will detect bright areas whose luminosity > 0.2f;

//フォント
PFont font = loadFont(“jp/ac/naka/cc/data/p5/Monaco-24.vlw”);
textFont(font,24);
}

// ==================================================
// captureEvent()
// ==================================================
public void captureEvent(Capture cam)
{
cam.read();
newFrame = true;
}

// ==================================================
// draw()
// ==================================================
public void draw()
{
if (newFrame)
{
newFrame=false;
if (this.isHijacked && this.newImage != null) { // ここをCC用に条件分岐
image(newImage,0,0,width,height);
fastblur(newImage, 2);
theBlobDetection.computeBlobs(newImage.pixels);
} else {
image(cam,0,0,width,height);
img.copy(cam, 0, 0, cam.width, cam.height,
0, 0, img.width, img.height);
fastblur(img, 2);
theBlobDetection.computeBlobs(img.pixels);
}
drawBlobsAndEdges(true,true);
}
}

// ==================================================
// drawBlobsAndEdges()
// ==================================================
void drawBlobsAndEdges(boolean drawBlobs, boolean drawEdges)
{
noFill();
Blob b;
EdgeVertex eA,eB;
for (int n=0 ; n

{
b=theBlobDetection.getBlob(n);
if (b!=null)
{
// Edges
if (drawEdges)
{
strokeWeight(3);
stroke(0,255,0);
for (int m=0;m
{
eA = b.getEdgeVertexA(m);
eB = b.getEdgeVertexB(m);
if (eA !=null && eB !=null)
line(
eA.x*width, eA.y*height,
eB.x*width, eB.y*height
);
}
}

// Blobs
if (drawBlobs)
{
strokeWeight(1);
stroke(255,0,0);
rect(
b.xMin*width,b.yMin*height,
b.w*width,b.h*height
);
debugBlobID(b,2);//ここに追加
}

}

}
}

// ==================================================
// Super Fast Blur v1.1
// by Mario Klingemann
//
// ==================================================
void fastblur(PImage img,int radius)
{
if (radius<1){
return;
}
int w=img.width;
int h=img.height;
int wm=w-1;
int hm=h-1;
int wh=w*h;
int div=radius+radius+1;
int r[]=new int[wh];
int g[]=new int[wh];
int b[]=new int[wh];
int rsum,gsum,bsum,x,y,i,p,p1,p2,yp,yi,yw;
int vmin[] = new int[max(w,h)];
int vmax[] = new int[max(w,h)];
int[] pix=img.pixels;
int dv[]=new int[256*div];
for (i=0;i<256*div;i++){
dv[i]=(i/div);
}

yw=yi=0;

for (y=0;y
rsum=gsum=bsum=0;
for(i=-radius;i<=radius;i++){
p=pix[yi+min(wm,max(i,0))];
rsum+=(p & 0xff0000)>>16;
gsum+=(p & 0x00ff00)>>8;
bsum+= p & 0x0000ff;
}
for (x=0;x

r[yi]=dv[rsum];
g[yi]=dv[gsum];
b[yi]=dv[bsum];

if(y==0){
vmin[x]=min(x+radius+1,wm);
vmax[x]=max(x-radius,0);
}
p1=pix[yw+vmin[x]];
p2=pix[yw+vmax[x]];

rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
yi++;
}
yw+=w;
}

for (x=0;x
rsum=gsum=bsum=0;
yp=-radius*w;
for(i=-radius;i<=radius;i++){
yi=max(0,yp)+x;
rsum+=r[yi];
gsum+=g[yi];
bsum+=b[yi];
yp+=w;
}
yi=x;
for (y=0;y
pix[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
if(x==0){
vmin[y]=min(y+radius+1,hm)*w;
vmax[y]=max(y-radius,0)*w;
}
p1=x+vmin[y];
p2=x+vmax[y];

rsum+=r[p1]-r[p2];
gsum+=g[p1]-g[p2];
bsum+=b[p1]-b[p2];

yi+=w;
}
}

}

//追加
void debugBlobID(Blob b,int type){
String text2show = “nakalab”;
//色
// fill(255,0,0);

switch(type){
//左上
case 1:
text(text2show,(int)(b.xMin*width),(int)(b.yMin*height));
break;

//右上
case 2:
text(text2show,(int)(b.xMin*width)+(b.w*width),(int)(b.yMin*height));
break;

//右下
case 3:
text(text2show,(int)(b.xMax*width),(int)(b.yMax*height));
break;

//左下
case 4:
text(text2show,(int)(b.xMin*width),(int)(b.yMin*height)+(b.h*height));
break;
}
}
}
[/java]

カテゴリー: diary, programming パーマリンク

コメントを残す