巨大な折り紙、振動モータ、プロジェクタ、超磁歪素子スピーカ(壁上)を使って相互作用する。
室内壁面上に氷をつくる(ペルチェ素子使用)
カーテンがモータ制御によって自動的に開閉し、重心移動によりカーテンレール自体が回転する。
四谷アートステュディウム・建築発明工作ゼミ(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桁だけを取り出す