人が動いた後にいろいろなエフェクトがかかるサンプル。
import processing.video.*;
Capture video; //キャプチャ用変数
int[] previousFrame; //一つ前のフレーム
int pixelNum; //キャプチャ画面の総ピクセル数
int noiseFilter = 50; //ノイズを拾わないためのフィルタ(値を増やすとフィルタが強くかかる)
int reduction = 8; //画面に対してのキャプチャ映像の縮小度合い 8の場合は、キャプチャ画像が画面の1/8という意味になる
int movementSum; //一つのフレームでの動作量
float[] eSize; //円のサイズ
float[] eSpeed; //円の拡大のスピード
float[] eAlpha; //円の透明度
float[] eAlphaSpeed; //円の透明度のスピード
int[] eFlag; //円の透明度が0になったかどうかを判断するためのフラッグ
void setup() {
// 640 x 480が大きすぎて遅かったら、320 x 240に変更する
size(640, 480);
//画面サイズのキャプチャ画像を生成。画面がコマ落ちするようだったら、
//一番右のフレームレートを上げる。
//この場合は、80x60のキャプチャ画像、90フレーム/秒を設定
video = new Capture(this, width/reduction, height/reduction, 90);
pixelNum = video.width * video.height; //キャプチャ画像の総ピクセル数
previousFrame = new int[pixelNum]; //一つ前のフレーム(配列)
eSize = new float[pixelNum]; //円の大きさ
eSpeed = new float[pixelNum]; //円の拡大スピード
eAlpha = new float[pixelNum]; //円の透明度
eAlphaSpeed = new float[pixelNum]; //円の透明化のスピード
eFlag = new int[pixelNum]; //円が表示されている状態かそうでないかを判断するフラッグ
//円の属性の初期化
for(int i = 0; i < pixelNum; i ++){
eSize[i] = 0.0;
eSpeed[i] = 1.0;
eAlpha[i] = 200.0;
eAlphaSpeed[i] = 2.0;
eFlag[i] = 0;
}
loadPixels(); //画面に画像のピクセルを展開
}
void draw() {
background(0);
float m = millis(); //時間をカウント
if (video.available()) { //もしキャプチャができたら、
video.read(); //ビデオフレームの読み込み
video.loadPixels(); //ビデオのピクセルを操作できるようにする
movementSum = 0; //一つのフレームでの動作量
//1ピクセルごとに色を調べる。
for (int y = 0; y < video.height; y ++) {
for (int x = 0; x < video.width; x ++) {
//ビデオのピクセルを抜き出す
int currColor = video.pixels[y*video.width + x];
int prevColor = previousFrame[y*video.width + x];
//現在のピクセルのR, G, Bを抜き出す
int currR = (currColor >> 16) & 0xFF;
int currG = (currColor >> 8 ) & 0xFF;
int currB = currColor & 0xFF;
//一つ前のフレームの色を抜き出す
int prevR = (prevColor >> 16) & 0xFF;
int prevG = (prevColor >> 8 ) & 0xFF;
int prevB = prevColor & 0xFF;
//現在のピクセルから前のピクセルの色を引いた絶対値
int diffR = abs(currR - prevR);
int diffG = abs(currG - prevG);
int diffB = abs(currB - prevB);
//noiseFilterの値よりも大きかったらmovementSumに足していく
//そして、現在の色に更新
//以下の条件文は3秒後に有効になる
if(diffR + diffG + diffB > noiseFilter && eFlag[y*video.width + x] == 0 && m > 3*1000){
eFlag[y*video.width + x] = 1; //フラッグを1にする(円が再生中)
movementSum ++;
//以下の4行のコードは動いたところにラインを発生させるコードである(左右を反転させている)
float lineSize = (float)(diffR + diffG + diffB)/(255*3)*20.0;
stroke(currR, 100, 255, 80);
line(((video.width-x)-lineSize)*reduction, y*reduction, ((video.width-x)+lineSize)*reduction, y*reduction);
stroke(255, 100, currB, 80);
line((video.width-x)*reduction, (y-lineSize/2)*reduction, (video.width-x)*reduction, (y+lineSize/2)*reduction);
}
//透明度(Alpha)が0.0未満にならない限りは、円はひたすら大きくなり、透明度はひたすら下がる
if(eFlag[y*video.width + x] == 1 && eAlpha[y*video.width + x] >= 0.0){
eSize[y*video.width + x] += eSpeed[y*video.width + x];
eAlpha[y*video.width + x] -= eAlphaSpeed[y*video.width + x];
noStroke();
fill(currR, currG, currB, (int)(eAlpha[y*video.width + x]));
ellipse((video.width-x)*reduction, y*reduction, eSize[y*video.width + x], eSize[y*video.width + x]);
} //透明度(Alpha)が0.0未満になったら、円の属性をリセットする
else if(eFlag[y*video.width + x] == 1 && eAlpha[y*video.width + x] < 0.0){
eSize[y*video.width + x] = 0.0;
eAlpha[y*video.width + x] = 100.0;
eFlag[y*video.width + x] = 0;
}
previousFrame[y*video.width + x] = currColor; //現在の色を一つ前のフレームの色として保存
}
}
textSize(12); //テキストのサイズ
fill(255);
text(movementSum, 30,30); //変化したピクセルの総数を画面にプリント
}
}
