yoppa.org


最終課題について

最終課題発表希望者Form

発表を希望する方は、こちらから記入してください。

最終課題のテーマ「インタラクションと表現」

この「インタラクティブアート論」の講義では、openFrameworksを用いてインタラクティブな表現を行う様々な手法について解説してきました。これを踏まえて、最終課題は「インタラクションと表現」というテーマで何らかのインタラクションを用いた表現を行うプログラムをopenFrameworksで作成してください。

  • ユーザー(鑑賞者)とプログラムで作成した作品の間に何らかのインタラクションがあること。
  • インタラクションの手段は自由です。
  • openFrameworksを用いてプログラミングすること。ただし、他のプログラムとの連携は自由です

提出方法

1. 作品発表(希望者のみ)

  • 人数の都合上希望者のみ
  • 1月23日の最終授業で発表
  • 作品発表をした場合、評点に10点プラスします

2. メールで提出(履修者全員)

  • To: tadokoro+teu16@gmail.com
  • Subject: 最終課題
  • プロジェクト内の「src」フォルダをZip圧縮して添付(注意: プロジェクト全体ではなくsrcフォルダのみ入れること!!)
    • 画像ファイルなどのバイナリデータを使用している場合は、bin/dataフォルダ内のデータもあわせて提出
  • プログラムの実行画面のスクリーンキャプチャを添付
  • 締切: 2017年1月31日まで

メール本文に以下の内容を記述

  • 学籍番号
  • 氏名
  • インタラクションの内容を簡単に記述

openFrameworks – 顔をつかったインタラクション ofxFaceTracker

今回は、フェイストラッキングの技術を使っていろいろ実験していきます。フェイストラッキングとは、カメラから入力した映像の中から人間の顔を検知して、その傾きや大きさ、さらには目や鼻、口、眉といった顔のそれぞれのパーツの位置や大きさを立体的に検知することのできる、画像解析の技術です。この技術を利用して、顔の表情でプログラムをコントロールしたり、自分の顔に他人の顔を合成したりと様々な応用が可能となります。今回は、このフェイストラッキングに必要な環境設定とビルドの方法を解説した上で、その応用方法について考えていきます。

スライド資料

サンプルファイル


最終課題について

最終課題テーマ「デザインとプログラミング」

この講義で学んだProcessingを用いたプログラミングの技術や知識を元に、新たな「デザイン」を表現してください。

ここでいうデザインには、デザインといってまず思い浮かべるグラフィクスデザインも含まれますが、その範囲に留まるものではありません。サウンドデザイン、インタラクションのデザイン、アルゴリズムのデザインなど、デザインを何かを構築する際の「計画」や「設計する行為」と広くとらえ、最終的にそのデザインをProcessingで表現してください。

  • Processingによるプログラミングが介在していれば、出力の手段は問いません (印刷、3Dプリントなども可)
  • Processingと連動して、他のプログラミング環境やアプリケーション使用しても構いません
  • 課題はグループではなく個人で制作してください

最終課題提出FORM

最終課題を発表する方は下記のFORMに内容を記入してください。聴講の方もぜひ発表してください。

締切

2017年1月18日の最後の授業の開始時間(11:10)まで。

今後のスケジュール

  • 12月21日: 通常授業
  • 1月11日: 課題のヒント、質問の受け付け
  • 1月18日: 最終課題講評会

Libraries 4 : OpenCV for Processing – コンピュータ・ビジョン、映像を使ったインタラクション

Processingを使用してインタラクティブな機能を実現するための手段は、センサーを使う方法や、KinectやLeap Motionなどのデバイスを使用する方法などいろいろ考えられます。今回は、最もシンプルな機材構成で可能な方法として、カメラの映像を解析してそこから動きや物体の輪郭を取り出す手法について取り上げます。

コンピュータで、映像から実世界の情報を取得して認識するための研究で「コンピュータ・ビジョン (Conputer Vision)」という分野が存在します。わかりやすく言うなら「ロボットの目」をつくるような研究です。このコンピュータ・ビジョンの様々な成果をオープンソースで公開しているOpenCVというライブラリーがあります。今回は、このOpenCVをProcessingで使用できるようにした、OpenCV for Processingライブラリーを使用したプログラミングを体験します。

スライド資料

サンプルプログラム

カメラキャプチャー基本

import gab.opencv.*;
import processing.video.*;

Capture video; // ライブカメラ

void setup() {
  //初期設定
  size(640, 480); //画面サイズ
  //キャプチャーするカメラのサイズ
  video = new Capture(this, 640, 480);
  //キャプチャー開始
  video.start();
}

void draw() {
  //カメラ画像を表示
  image(video, 0, 0 );
}

//キャプチャーイベント
void captureEvent(Capture c) {
  c.read();
}

OpenCV輪郭抽出

import gab.opencv.*;
import processing.video.*;

Capture video; // ライブカメラ
OpenCV opencv; // OpenCV
ArrayList contours; //輪郭の配列

void setup() {
  //初期設定
  size(640, 480); //画面サイズ
  //キャプチャーするカメラのサイズ
  video = new Capture(this, 640, 480);
  //OpenCVの画面サイズ
  opencv = new OpenCV(this, 640, 480);
  //キャプチャー開始
  video.start();
}

void draw() {
  //カメラの画像をOpenCVに読み込み
  opencv.loadImage(video);
  //カメラ画像を表示
  image(video, 0, 0 );
  //閾値の設定(マウスのX座標で変化)
  int threshold = int(map(mouseX, 0, width, 0, 100));
  opencv.threshold(threshold);
  //輪郭抽出
  contours = opencv.findContours();
  //描画設定
  noFill();
  strokeWeight(1);
  //検出された輪郭の数だけ、輪郭線を描く
  for (Contour contour : contours) {
    stroke(0, 255, 0);
    contour.draw();
  }
}

//キャプチャーイベント
void captureEvent(Capture c) {
  c.read();
}

OpenCVによる顔検出

import gab.opencv.*;
import processing.video.*;
import java.awt.*;

Capture video; //ビデオキャプチャー
OpenCV opencv; //OpenCV

void setup() {
  size(640, 480);
  //ビデオキャプチャー初期化
  video = new Capture(this, 640/2, 480/2);
  //OpenCV初期化(ビデオキャプチャーの半分のサイズ)
  opencv = new OpenCV(this, 640/2, 480/2);
  //顔の学習データを読み込み
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
  //ビデオキャプチャー開始
  video.start();
}

void draw() {
  //二倍サイズで表示
  scale(2);
  //画像を読み込み
  opencv.loadImage(video);
  //カメラ画像を描画
  image(video, 0, 0 );
  
  //顔を検出
  Rectangle[] faces = opencv.detect();
  //検出した顔の周囲を四角形で描画
  noFill();
  stroke(0, 255, 0);
  strokeWeight(3);
  for (int i = 0; i < faces.length; i++) {
    rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
  }
}

//キャプチャーイベント
void captureEvent(Capture c) {
  c.read();
}

OpenCVによる顔検出 - 目線を入れてみる

import gab.opencv.*;
import processing.video.*;
import java.awt.*;

Capture video; //ビデオキャプチャー
OpenCV opencv; //OpenCV

void setup() {
  size(640, 480);
  //ビデオキャプチャー初期化
  video = new Capture(this, 640/2, 480/2);
  //OpenCV初期化(ビデオキャプチャーの半分のサイズ)
  opencv = new OpenCV(this, 640/2, 480/2);
  //顔の学習データを読み込み
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
  //ビデオキャプチャー開始
  video.start();
}

void draw() {
  //二倍サイズで表示
  scale(2);
  //画像を読み込み
  opencv.loadImage(video);
  //カメラ画像を描画
  image(video, 0, 0 );
  
  //顔を検出
  Rectangle[] faces = opencv.detect();
  //検出した顔の周囲を四角形で描画
  fill(0);
  for (int i = 0; i < faces.length; i++) {
    //ちょうど目の場所にくるよう、場所とサイズを調整
    float x = faces[i].x + faces[i].width * 0.15;
    float y = faces[i].y + faces[i].height * 0.3;
    float width = faces[i].width * 0.7;
    float height = faces[i].height * 0.15;
    //目線を描画
    rect(x, y, width, height);
  }
}

//キャプチャーイベント
void captureEvent(Capture c) {
  c.read();
}

Optical Flowの描画

import gab.opencv.*;
import processing.video.*;

Capture video; // ライブカメラ
OpenCV opencv; // OpenCV

void setup() {
  //初期設定
  size(640, 480); //画面サイズ
  //キャプチャーするカメラのサイズ
  video = new Capture(this, 640/2, 480/2);
  //OpenCVの画面サイズ
  opencv = new OpenCV(this, 640/2, 480/2);
  //キャプチャー開始
  video.start();
}

void draw() {
  //描画スケール設定
  scale(2.0);
  //カメラの画像をOpenCVに読み込み
  opencv.loadImage(video);
  //カメラ画像を表示
  image(video, 0, 0 );
  //OpticalFlowを計算
  opencv.calculateOpticalFlow();
  //描画設定
  stroke(255,0,0);
  //OpticalFlowを描画
  opencv.drawOpticalFlow();
}

//キャプチャーイベント
void captureEvent(Capture c) {
  c.read();
}

OpticalFlow + Particle

import gab.opencv.*;
import processing.video.*;

Capture video; // ライブカメラ
OpenCV opencv; // OpenCV

int NUM = 500;
ParticleVec3[] particles = new ParticleVec3[NUM];

void setup() {
  //初期設定
  size(640, 480, P3D); //画面サイズ
  //キャプチャーするカメラのサイズ
  video = new Capture(this, 640/2, 480/2);
  //OpenCVの画面サイズ
  opencv = new OpenCV(this, 640/2, 480/2);
  //キャプチャー開始
  video.start();
  
  for (int i = 0; i < NUM; i++) {
    particles[i] = new ParticleVec3();
    particles[i].radius = 4.0;
    particles[i].position.set(random(width/2), random(height/2), 0);
    particles[i].minx = 0;
    particles[i].miny = 0;
    particles[i].maxx = width/2;
    particles[i].maxy = height/2;
  }
}

void draw() {
  background(0);
  blendMode(ADD);
  //描画スケール設定
  scale(2.0);
  //カメラの画像をOpenCVに読み込み
  opencv.loadImage(video);
  //カメラ画像を表示
  //image(video, 0, 0 );
  //OpticalFlowを計算
  opencv.calculateOpticalFlow();
  //描画設定
  stroke(255, 0, 0);
  //OpticalFlowを描画
  opencv.drawOpticalFlow();
  
  noStroke();
  fill(0, 127, 255);
  for (int i = 0; i < NUM; i++) {
    //パーティクルの位置を更新
    particles[i].update();
    //パーティクルを描画
    particles[i].draw();
    //画面の端で反対側から出現するように
    particles[i].throughOffWalls();
    //OpticalFlowから力を算出してパーティクルに反映する
    if (particles[i].position.x > 0
        && particles[i].position.x < width/2
        && particles[i].position.y > 0
        && particles[i].position.y < height/2 ) {
      PVector vec = opencv.getFlowAt(int(particles[i].position.x),
                                     int(particles[i].position.y));
      particles[i].addForce(vec.mult(0.1));
    }
  }
}

//キャプチャーイベント
void captureEvent(Capture c) {
  c.read();
}

class ParticleVec3 {
  PVector position;
  PVector velocity;
  PVector acceleration;
  float friction;
  float radius;
  float mass;
  float minx, miny, minz;
  float maxx, maxy, maxz;

  ParticleVec3() {
    radius = 4.0;
    friction = 0.01;
    mass = 1.0;
    position = new PVector(width/2.0, height/2.0, 0);
    velocity = new PVector(0, 0, 0);
    acceleration = new PVector(0, 0, 0);
    minx = 0;
    miny = 0;
    minz = -height;
    maxx = width;
    maxy = height;
    maxz = height;
  }

  void update() {
    velocity.add(acceleration);
    velocity.mult(1.0 - friction);
    position.add(velocity);
    acceleration.set(0, 0, 0);
  }

  void draw() {
    pushMatrix();
    translate(position.x, position.y, position.z);
    ellipse(0, 0, radius * 2, radius * 2);
    popMatrix();
  }

  void addForce(PVector force) {
    force.div(mass);
    acceleration.add(force);
  }

  void bounceOffWalls() {
    if (position.x > maxx) {
      position.x = maxx;
      velocity.x *= -1;
    }
    if (position.x < minx) {
      position.x = minx;
      velocity.x *= -1;
    }
    if (position.y > maxy) {
      position.y = maxy;
      velocity.y *= -1;
    }
    if (position.y < miny) {
      position.y = miny;
      velocity.y *= -1;
    }
    if (position.z > maxz) {
      position.z = maxz;
      velocity.z *= -1;
    }
    if (position.z < minz) {
      position.z = minz;
      velocity.z *= -1;
    }
  }

  void throughOffWalls() {
    if (position.x < minx) {
      position.x = maxx;
    }
    if (position.y < miny) {
      position.y = maxy;
    }
    if (position.z < minz) {
      position.z = maxz;
    }
    if (position.x > maxx) {
      position.x = minx;
    }
    if (position.y > maxy) {
      position.y = miny;
    }
    if (position.z > maxz) {
      position.z = minz;
    }
  }

  void addAttractionForce(PVector force, float radius, float scale) {
    float length = PVector.dist(position, force);
    PVector diff = new PVector();
    diff = position.get();
    diff.sub(force);
    boolean bAmCloseEnough = true;
    if (radius > 0) {
      if (length > radius) {
        bAmCloseEnough = false;
      }
    }
    if (bAmCloseEnough == true) {
      float pct = 1 - (length / radius);
      diff.normalize();
      diff.mult(scale);
      diff.mult(pct);
      acceleration.sub(diff);
    }
  }
}

Livecoding Workshop – from Sketch to Live “Introduction”

  • 2016年12月9日、17日
  • Art & Science gallery lab AXIOM

今秋に発足したアート&サイエンスのためのラボ「Art & Science gallery lab AXIOM」で、ライブコーディングのワークショップを行いました。両日とも定員の20名でチケットもソールドアウトして、ライブコーディングへの興味と期待の高さを感じました。

今回のワークショップは、来年(2017年)よりシリーズ化して始める予定の、より本格的なライブコーディングワークショップの「イントロダクション」という位置付けで行いました。まず、そもそもライブコーディングとは何なのか、どのような経緯で生まれてきたのかという概要から解説して、Sonic Piを使用してライブコーディングの入口を体験するという内容です。

今回のワークショップに参加していただいた方はもちろん、公開したスライドを見て興味を持った方は、ぜひ来年から始まるシリーズにご期待下さい。日程は今後このサイトやAXIOMのFacebook Pageなどで告知していく予定です。

スライド資料


openFrameworks – Open Sound Control (OSC) によるアプリケーション間通信 ofxOsc

今回は、Addonの使用の4回目として、ネットワークを活用したインタラクションについて考えていきます。ofxOscは、openFrameworksでOpen Sound Control(OSC)という通信プロトコルを使用するためのAddonです。OSCは、openFrameworksのアプリケーション同士をEthernetを介して通信することができ、これにより、ネットワークを介して複数のユーザが1つのアプリケーションを操作することが可能となります。またopenFrameworksのアプリケーションを他のアプリケーション、例えば、Max/MSPやPd、SuperCollider、さらにはTouchOSCといったiPhoneアプリなどからコントロールすることが出来るようになります。

スライド資料

サンプルプログラム


Processing Libraries 3 : oscP5 – OSCによるアプリケーション間通信

今回は、ネットワークを活用したサンプルを紹介します。Open Sound Control(OSC)というプロトコルを使用して、アプリケーション同士をネットワークを介して通信する方法について解説します。これにより、Processingのスケッチ間で通信したり、複数のユーザが1つのスケッチを遠隔操作することが可能となります。またProessingのスケッチを他のアプリケーション、例えば、Sonic Pi、Max/MSPやPd、SuperColliderなどの音楽アプリケーション、さらにはTouchOSCといったiPhoneアプリなどからコントロールすることが出来るようになります。

スライド資料

サンプルプログラム


openFrameworks – 物理シミュレーション ofxBox2D

今回は物理シミュレーションを行うことができる、ofxBox2DというAddonをとりあげます。

ofxBox2Dは、Box2DというC++で書かれた2Dの物理演算エンジンをopenFrameworksのAddon化したものです。Box2Dは質量、力、速度、摩擦といった古典物理学(ニュートン力学)の演算を高速に行う、物理法則の演算のためのライブラリーで、もともとはC++で書かれていますが、現在では、Java、C#、Python、JavaScriptなど様々な言語に移植されています。ofxBox2Dを使うことで簡単な物理法則を援用したアニメーションだけでなく、2次元のゲームやインタラクティブなコンテンツなどに応用可能です。今回は、ofxBox2Dの導入から、形を定義して物理世界に追加する方法、大量の物体を追加するための工夫などを紹介していきます。

スライド資料

サンプルファイル


Processing Libraries 2 : Sound – 音の再生と視覚化

今回はProcessingのライブラリー活用の2回目として、Processingで音を扱うためのSoundライブラリーを紹介します。

Soundライブラリーは、Contributionライブラリーではなく、Processing Foundationで開発されているライブラリーで、Processingのパッケージに最初から含まれています。サウンドファイルの再生や、マイクやライン入力のキャプチャーだけでなく、音にエフェクトをかけたり、波形自体を生成したりと、サウンドに関する様々な機能が活用できます。さらに、FFTクラスを使用すると、音に含まれる周波数成分をリアルタイムに解析することが可能となります。この機能を使うことで、音の周波数成分を可視化して「音を視る」ことが可能となります。今回は、Soundライブラリーを用いたサウンドファイルの再生から、FFTを使用した音のビジュアライズまでを順番に解説していきます。

スライド資料

サンプルプログラム


インタラクティブアート論 – 中間課題

「インタラクティブアート論」の講義も中盤を過ぎて後半に入りました。ここまで内容の理解を確認するため、中間課題を出題します。課題は成績判定の評価基準の1つとなります。必ず期限内に提出するようにしてください。

課題: 授業で扱ったopenFrameworksのサンプルを改造

これまでの授業で紹介したopenFrameworksのサンプルプログラムを元にして、そこに何らかの変更を加えて、独自の表現を行ってください。使用するプログラム、何を改造するのかは自由です。元のプログラムに何らかの変更が加えられていればOKです。

提出方法

  • メールで提出
  • To: tadokoro+teu16@gmail.com
  • Subject: 中間課題
  • プロジェクト内の「src」フォルダをZip圧縮して添付(注意: プロジェクト全体ではなくsrcフォルダのみ入れること!!)
  • プログラムの実行画面のスクリーンキャプチャを添付

メール本文に以下の内容を記述

  • 学籍番号
  • 氏名
  • 元にしたプログラム(例: 第○○回の授業のパーティクルを複製するサンプル)
  • プログラムを変更した場所、何を変更したのか

提出期限: 2016年12月19日の授業開始前まで!