巨大な折り紙、振動モータ、プロジェクタ、超磁歪素子スピーカ(壁上)を使って相互作用する。
室内壁面上に氷をつくる(ペルチェ素子使用)
カーテンがモータ制御によって自動的に開閉し、重心移動によりカーテンレール自体が回転する。
四谷アートステュディウム・建築発明工作ゼミ(2008年度)の授業サブノート
主にProcessingやArduinoについて記載しています。
import processing.serial.*;
import cc.arduino.*;
Arduino arduino;
color off = color(4, 79, 111);
color on = color(84, 145, 158);
int[] values = { Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW,
Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW,
Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW };
void setup() {
size(470, 200);
println(Arduino.list());
arduino = new Arduino(this, Arduino.list()[0], 115200);
for (int i = 0; i <= 13; i++)
arduino.pinMode(i, Arduino.OUTPUT);
}
void draw() {
background(off);
stroke(on);
for (int i = 0; i <= 13; i++) {
if (values[i] == Arduino.HIGH)
fill(on);
else
fill(off);
rect(420 - i * 30, 30, 20, 20);
}
}
void mousePressed()
{
int pin = (450 - mouseX) / 30;
if (values[pin] == Arduino.LOW) {
arduino.digitalWrite(pin, Arduino.HIGH);
values[pin] = Arduino.HIGH;
} else {
arduino.digitalWrite(pin, Arduino.LOW);
values[pin] = Arduino.LOW;
}
}
arduino.pinMode(ピン番号, 入出力設定);
arduino.digitalWrite(ピン番号, 出力値);
デジタル入力:arduino.digitalRead(ピン番号)
アナログ入力:arduino.analogRead(ピン番号)
アナログ出力:arduino.analogWrite(ピン番号,出力値)
import processing.video.*; Capture video; PFont font; int w=320; int h=240; //前回画面ピクセル色を保存するための配列を用意 color[] exColor=new color[w*h]; //許容値の変数:50に設定しておく int tolerance=50; int sumX,sumY;//平均値を求めるための合計座標値の変数 int pixelNum;//変化のあったピクセルを数えるための変数 float x,y;//座標値の変数 float filterX,filterY;//フィルタをかけた座標値の変数 boolean movement=false;//動体の有無のフラグ void setup(){ size(w, h); video = new Capture(this, w, h); font=createFont("Monaco",10); textFont(font); rectMode(CENTER); noStroke(); } void draw() { if(video.available()){ background(0); video.read(); set(0,0,video);//カメラ映像表示 loadPixels();//画面内ピクセルをロードしておく movement=false;//動体のフラグをfalseに戻しておく for(int i=0;i<w*h;i++){ //前回と今回の画面のピクセルの各色の差を求める float difRed=abs(red(exColor[i])-red(video.pixels[i])); float difGreen=abs(green(exColor[i])-green(video.pixels[i])); float difBlue=abs(blue(exColor[i])-blue(video.pixels[i])); //色の差が許容値以上の場合(動体がある場合) if(difRed>tolerance && difGreen>tolerance && difBlue>tolerance){ movement=true;//動体有りのフラグをtrueにしておく pixels[i]=color(0,255,0);//そのピクセルを緑にする sumX+=i%w;//平均値を求めるためにX座標値を加算する sumY+=i/w;//平均値を求めるためにY座標値を加算する pixelNum++;//変化のあったピクセル数を数える } //次回ループのために今回の画面を前回の画面として保存しておく exColor[i]=video.pixels[i]; } //動体があった場合(画面内に変化があった場合) if(movement==true){ updatePixels();//画面内ピクセルをアップデート x=sumX/pixelNum;//X座標平均値を求める y=sumY/pixelNum;//Y座標平均値を求める //各変数を初期化しておく sumX=0; sumY=0; pixelNum=0; } } filterX+=(x-filterX)*0.3;//X座標にフィルタをかける filterY+=(y-filterY)*0.3;//Y座標にフィルタをかける fill(255,0,0); rect(filterX,filterY,20,20);//正方形描画 text(tolerance,10,10);//許容値を表示 } void keyPressed(){ if(key=='c'){ video.settings();//カメラセッティング } if(key==CODED){ if(keyCode==LEFT){ tolerance-=1;//許容値を-1する } if(keyCode==RIGHT){ tolerance+=1;//許容値を+1する } } }
import processing.video.*; Capture video; PFont font; int w=320; int h=240; //前回画面ピクセル色を保存するための配列を用意 color[] exColor=new color[w*h]; int tolerance=20; float y;//右パドルのY座標 int sumY;//平均値を求めるための合計座標値の変数 int pixelNum;//変化のあったピクセル数を数えるための変数 float filterY;//フィルタをかけたY座標変数 boolean movement=false;//動体検知フラグ float y2;//左パドルのY座標 int sumY2;//平均値を求めるための合計座標値の変数 int pixelNum2;//変化のあったピクセル数を数えるための変数 float filterY2;//フィルタをかけたY座標変数 boolean movement2=false;//動体検知フラグ int ballX=-200,ballY=height/3;//ボール座標 int dirX=1,dirY=1;//ボールの向きの変数 int speedX=2,speedY=2;//ボール移動量変数 int pt=0,pt2=0;//点数の変数 void setup(){ size(w, h); video = new Capture(this, w, h); font=createFont("Monaco",10); textFont(font); rectMode(CENTER); noStroke(); } void draw() { if(video.available()){ background(0); video.read(); scale(-1,1);//画面を鏡像(左右反転) image(video,-w,0);//鏡像のため映像のX座標を-wにして表示 scale(-1,1);//鏡像を戻しておく movement=false;//動体検知のフラグをfalseにしておく(初期化) movement2=false; for(int i=0;i<w*h;i++){ //前回と今回の画面のピクセルの各色の差を求める float difRed=abs(red(exColor[i])-red(video.pixels[i])); float difGreen=abs(green(exColor[i])-green(video.pixels[i])); float difBlue=abs(blue(exColor[i])-blue(video.pixels[i])); //色の差が許容値以上の場合(動体がある場合) if(difRed>tolerance && difGreen>tolerance && difBlue>tolerance){ if(i%w<50){//X座標が50以下の場合(画面右側の場合) movement=true;//動態検知フラグをtrueにしておく sumY+=i/w;//平均値を求めるために座標値を加算しておく pixelNum++;//ピクセル数を数えておく } if(i%w>width-50){//X座標が270以上の場合(画面左側の場合) movement2=true; sumY2+=i/w; pixelNum2++; } } //次回ループのために今回の画面を前回の画面として保存しておく exColor[i]=video.pixels[i]; } if(movement==true){//動体検知した場合(画面右) y=sumY/pixelNum;//平均Y座標を求める //0に戻しておく(初期化) sumY=0; pixelNum=0; } if(movement2==true){//動体検知した場合(画面左) y2=sumY2/pixelNum2; sumY2=0; pixelNum2=0; } } //フィルタをかけたパドルのY座標値 filterY+=(y-filterY)*0.4; filterY2+=(y2-filterY2)*0.4; //ボール上下跳ね返りの処理 if(ballY<5){ ballY=5; dirY=1; } if(ballY>height-5){ ballY=height-5; dirY=-1; } //ボールがパドルに当たって跳ね返る処理 if(ballX>25 && ballX<30 && ballY>filterY2-28 && ballY<filterY2+28 && dirX==-1){ ballX=30; dirX=1; } if(ballX>width-30 && ballX<width-25 && ballY>filterY-28 && ballY<filterY+28 && dirX==1){ ballX=width-30; dirX=-1; } //ボールが画面端から出てしまったときの処理(得点処理) if(ballX<0 && dirX==-1){ ballX=width+200;//ボールを画面反対側へ移動 pt+=1;//左プレイヤー点数加算 } if(ballX>width && dirX==1){ ballX=-200;//ボールを画面反対側へ移動 pt2+=1;//右プレイヤー点数加算 } //ボールの移動量 ballX+=speedX*dirX; ballY+=speedY*dirY; fill(255);//塗り色(白) rect(width-20,filterY,10,50);//右パドル表示 rect(20,filterY2,10,50);//左パドル表示 rect(ballX,ballY,10,10);//ボール表示 text(pt,60,20);//左プレイヤー点数表示 text(pt2,width-65,20);//右プレイヤー点数表示 } void keyPressed(){ if(key=='c'){//cキーでカメラセッティング video.settings(); } if(key==' '){//スペースキーで点数をリセット pt=0; pt2=0; } if(key==CODED){ if(keyCode==LEFT){ tolerance-=1; if(tolerance<0){ tolerance=0; } } if(keyCode==RIGHT){ tolerance+=1; } } }
//ビデオライブラリのインポート
import processing.video.*;
Capture video;//インスタンス生成
PFont font;//フォントを用意
int w=320;//画面幅
int h=240;//画面高
int tolerance=15;//色許容値用の変数(後で調整可)
color targetColor=color(255,0,0);//物体の色用の変数(後で変更可)
int x;//図形座標用変数
int y;
int xmin=w,xmax=0;//左端X座標、右端X座標
int ymin=h,ymax=0;//上端Y座標、下端Y座標
boolean detection=false;//物体検知のフラグ
void setup(){
size(w, h);//画面サイズ設定
smooth();//滑らかな描画に設定
video = new Capture(this, w, h);//キャプチャ映像の設定
font=loadFont("Monaco-10.vlw");//フォントをロード
textFont(font);//フォントの設定
noStroke();//外形線なし
}
void draw() {
if(video.available()){//キャプチャ映像がある場合
video.read();//映像読み込み
//video.filter(BLUR,2);必要に応じてぼかしフィルタをつかう(ノイズ除去用)
set(0,0,video);//映像表示
detection=false;//物体検知のフラグをfalse(検知なし)にしておく
for(int i=0;i<w*h;i++){//画面全体のピクセル数だけ繰り返し処理
//物体の色と各ピクセルの色の差を求める(RGB3色分)
float difRed=abs(red(targetColor)-red(video.pixels[i]));
float difGreen=abs(green(targetColor)-green(video.pixels[i]));
float difBlue=abs(blue(targetColor)-blue(video.pixels[i]));
//RGB各色が許容値以内の場合(近似色である場合)
if(difRed<tolerance && difGreen<tolerance && difBlue<tolerance){
//フラグを物体検知有りにする
detection=true;
//左端、右端のX座標、上端、下端のY座標を導く
//今回の値と今までの値を比較し、最小値、最大値を調べる
xmin=min(i%w,xmin);//左端(X最小値)
xmax=max(i%w,xmax);//右端(X最大値)
ymin=min(i/w,ymin);//上端(Y最小値)
ymax=max(i/w,ymax);//下端(Y最大値)
}
}
if(detection==true){//物体検知有りの場合
x=(xmin+xmax)/2;//X座標を左端と右端の座標の中点とする
y=(ymin+ymax)/2;//Y座標を上端と下端の座標の中点とする
//左端、右端、上端、下端の座標値を初期化しておく
xmin=w;
xmax=0;
ymin=h;
ymax=0;
}
}
fill(255,0,0);//塗り色:赤
ellipse(x,y,20,20);//円描画(求めたXY座標を代入)
//以下は設定内容の表示
fill(targetColor);//指定した物体の色
rect(0,0,10,10);//矩形表示
String s;//物体検知有無表示の文字列変数
if(detection==true){//物体検知有りの場合
s="detected";//表示:「検知」
}else{
s="none";//表示:「なし」
}
text(tolerance+": "+s,20,10);//文字列表示(許容値:物体検知有無)
}
void mousePressed(){//クリックしたら
//マウス座標上のピクセルの色(物体の色)を記憶しておく
targetColor=video.pixels[mouseX+mouseY*w];
}
void keyPressed(){
if(key=='c'){//「c」キーを押した場合
video.settings();//カメラセッティング
}
if(key==CODED){
if(keyCode==LEFT){//左キーを押した場合
tolerance-=1; //許容値を-1する
}
if(keyCode==RIGHT){//右キーを押した場合
tolerance+=1; //許容値を+1する
}
}
}
import processing.video.*;
Capture video;
PFont font;
int w=320;
int h=240;
int tolerance=20;
color targetColor=color(255,0,0);
float x;//X座標変数(小数値)
float y;//Y座標変数(小数値)
int sumX,sumY;//座標平均値を求めるための加算用変数
int pixelNum;//近似色ピクセルの個数用変数
float filterX,filterY;//滑らかな動きのためのフィルタ用変数
boolean videoImage=true;//カメラ映像の表示/非表示切り替えフラグ
boolean detection=false;
void setup(){
size(w, h);
smooth();
video = new Capture(this, w, h);
font=loadFont("Monaco-10.vlw");
textFont(font);
noStroke();
}
void draw() {
if(video.available()){
video.read();
scale(-1.0,1.0);//鏡像反転
if(videoImage){//カメラ映像表示の場合
image(video, -w, 0);//カメラ映像を表示する
}else{ //カメラ映像非表示の場合
background(0); //背景(黒)にする
}
detection=false;
for(int i=0;i<w*h;i++){
float difRed=abs(red(targetColor)-red(video.pixels[i]));
float difGreen=abs(green(targetColor)-green(video.pixels[i]));
float difBlue=abs(blue(targetColor)-blue(video.pixels[i]));
if(difRed<tolerance && difGreen<tolerance && difBlue<tolerance){
detection=true;
sumX+=(i%w);//X座標値を加算する
sumY+=(i/w);//Y座標値を加算する
pixelNum++;//近似色ピクセルの個数を加算する
}
}
if(detection){//物体検知有りの場合
x=sumX/pixelNum;//X座標平均値を求める
y=sumY/pixelNum;//Y座標平均値を求める
//初期化しておく
sumX=0;
sumY=0;
pixelNum=0;
tolerance--;//許容値を-1ずつ下げる
if(tolerance<2){//許容値が2より小さくなったら
tolerance=2; //許容値を2に戻す
}
}else{//物体検知無しの場合
tolerance++;//許容値を+1ずつ上げる
if(tolerance>25){//許容値が25より大きくなったら
tolerance=25; //許容値を25に戻す
}
}
}
scale(-1.0,1.0);//鏡像反転を戻しておく
filterX+=(x-filterX)*0.3;//X座標変化量のフィルタ、「0.3」は係数
filterY+=(y-filterY)*0.3;//Y座標変化量のフィルタ、「0.3」は係数
fill(255,0,0);//塗り色(赤)
ellipse(w-filterX,filterY,20,20);//フィルタ値を用いて円描画
//ellipse(w-x,y,20,20);//フィルタ値を使わない場合
fill(targetColor);
rect(0,0,10,10);
text(tolerance,20,10);
String s;
if(detection){
s="detected";
}else{
s="none";
}
text(s,40,10);
}
void mousePressed(){
targetColor=video.pixels[w-mouseX+mouseY*w];
}
void keyPressed(){
if(key=='c'){
video.settings();
}
if(key=='v'){//「v」キーを押して表示/非表示を切り替える
if(videoImage){
videoImage=false;
}else{
videoImage=true;
}
}
/*許容値調整は自動なので以下は使わない
if(key==CODED){
if(keyCode==LEFT){
tolerance-=1;
}
if(keyCode==RIGHT){
tolerance+=1;
}
}
*/
}
AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
11111111000000001111111100000000
red(pixels[i])
(pixels[i] >> 16) & 0xFF
(pixels[i] >> 8) & 0xFF //緑:8ビット右にシフトし下位8桁だけを取り出す
pixels[i] & 0xFF //青:下位8桁だけを取り出す