Daily Archives: 26 Jan 2013

Anna

26 Jan 2013

Tldr : All the jagged lines in FaceOSC’s mask-thingy made me think of teeth. The fact that I could control something by chewing also made me think of teeth. I really like oceans, bizarre villainous things, and distractingly shiny things. All these facts put together resulted in a Processing approximation of an anglerfish.

Title credit to classmate Kim Harvey, who saw me meddling with this at my desk and promptly exclaimed “It’s like Nemo’s Nightmare…!”

If you don’t know what she’s talking about, here, have some Pixar:

The full implementation of this is in shambles right now. My intent was to create a set of schooling fish that would direct themselves toward the “light”, which is controlled by the coordinates of your nose in FaceOSC. Right now, that doesn’t quite work, but I did manage to create a set of random ‘fishies’ that don’t exactly school but will move toward the approximate location of your nose using the overall facial position coordinates (pos.x, pos.y) instead. The other thing I wanted to do was enable ‘eating’ of the little fishies, by writing some kind of collision detection between them and the (hidden) mouth ellipse.

But like I said in my other post: I am so not that classy yet. If you don’t believe me, check out the scary anglerfish of a code below, or at the GitHub Repo.

nemostill

// Nemo's Nightmare - a processing app using FaceOSC
// created by Anna von Reden, 2013
// for the IACD Spring 2013 class at the CMU School of Art
//
// created using a template for receiving face tracking osc messages from
// Kyle McDonald's FaceOSC https://github.com/kylemcdonald/ofxFaceTracker
//
// 2012 Dan Wilcox danomatika.com
// for the IACD Spring 2012 class at the CMU School of Art
//
// adapted from from Greg Borenstein's 2011 example
// http://www.gregborenstein.com/
// https://gist.github.com/1603230
//
//TEARDROP CURVE
//M. Kontopoulos (11.2010)
//Based on the parametric equation found at
//http://mathworld.wolfram.com/TeardropCurve.html
//
//STEERING BEHAVIOR
//Based on code examples by iainmaxwell, found here:
// http://www.supermanoeuvre.com/blog/?p=372

import oscP5.*;
OscP5 oscP5;

// num faces found
int found;

// pose
float poseScale;
PVector posePosition = new PVector();
PVector poseOrientation = new PVector();

// gesture
float mouthHeight;
float mouthWidth;
float eyeLeft;
float eyeRight;
float eyebrowLeft;
float eyebrowRight;
float jaw;
float nostrils;

// shape constants & variables
float r = 5;
float a = 5;

ArrayList nemos; // an arraylist to store all of our nemos!
PVector shiny; // The shiny will be the current position of the mouse!

int numnemos = 50;
int stageWidth = 640; // size of the environment in the X direction
int stageHeight = 480; // size of the environment in the Y direction

void setup() {
size(stageWidth, stageHeight, P3D);
frameRate(30);

nemos = new ArrayList(); // make our arraylist to store our nemos

shiny = new PVector(stageWidth/2, stageHeight/2, 0); // make a starting shiny

// loop to make our nemos!
for (int i = 0; i < numnemos; i++) { nemos.add( new Nemo() ); } smooth(); oscP5 = new OscP5(this, 8338); oscP5.plug(this, "found", "/found"); oscP5.plug(this, "poseScale", "/pose/scale"); oscP5.plug(this, "posePosition", "/pose/position"); oscP5.plug(this, "poseOrientation", "/pose/orientation"); oscP5.plug(this, "mouthWidthReceived", "/gesture/mouth/width"); oscP5.plug(this, "mouthHeightReceived", "/gesture/mouth/height"); oscP5.plug(this, "eyeLeftReceived", "/gesture/eye/left"); oscP5.plug(this, "eyeRightReceived", "/gesture/eye/right"); oscP5.plug(this, "eyebrowLeftReceived", "/gesture/eyebrow/left"); oscP5.plug(this, "eyebrowRightReceived", "/gesture/eyebrow/right"); oscP5.plug(this, "jawReceived", "/gesture/jaw"); oscP5.plug(this, "nostrilsReceived", "/gesture/nostrils"); } void draw() { background(0, 0, 30); noStroke(); if (found > 0) {
for (int i = 0; i < nemos.size(); i++) { Nemo A = (Nemo) nemos.get(i); A.run(); // Pass the population of nemos to the nemo! } translate(posePosition.x, posePosition.y); scale(poseScale); shiny = new PVector(posePosition.x, posePosition.y-50, 0); // if mouse is pressed then update shiny // fill(140, 180, 240); // stroke(0,0,30); // ellipse(-10, eyeLeft * -9, 5, 4); //ellipse(10, eyeRight * -9, 5, 4); //fill(0,0,30); //ellipse(0, 20, mouthWidth*5, mouthHeight * 5); noStroke(); fill(25, 45, 45); beginShape(TRIANGLES); vertex(mouthWidth-2, mouthHeight*5); vertex(mouthWidth+2, mouthHeight*5); vertex(mouthWidth+6, mouthHeight); vertex(mouthWidth-10, mouthHeight*6); vertex(mouthWidth-6, mouthHeight*2); vertex(mouthWidth-2, mouthHeight*5); vertex(mouthWidth-14, mouthHeight*6); vertex(mouthWidth-12, mouthHeight*2); vertex(mouthWidth-10, mouthHeight*6); vertex(mouthWidth-18, mouthHeight*6); vertex(mouthWidth-16, mouthHeight*2); vertex(mouthWidth-14, mouthHeight*6); vertex(mouthWidth-26, mouthHeight*5); vertex(mouthWidth-22, mouthHeight*2); vertex(mouthWidth-18, mouthHeight*6); vertex(mouthWidth-34, mouthHeight); vertex(mouthWidth-30, mouthHeight*5); vertex(mouthWidth-26, mouthHeight*5); vertex(mouthWidth-2, mouthHeight*-7); vertex(mouthWidth+2, (mouthHeight*-5)+20); vertex(mouthWidth+6, mouthHeight*-3); vertex(mouthWidth-10, mouthHeight*-9); vertex(mouthWidth-6, (mouthHeight*-5)+20); vertex(mouthWidth-2, mouthHeight*-7); vertex(mouthWidth-14, mouthHeight*-9); vertex(mouthWidth-12, (mouthHeight*-5)+20); vertex(mouthWidth-10, mouthHeight*-9); vertex(mouthWidth-18, mouthHeight*-9); vertex(mouthWidth-16, (mouthHeight*-5)+20); vertex(mouthWidth-14, mouthHeight*-9); vertex(mouthWidth-26, mouthHeight*-7); vertex(mouthWidth-22, (mouthHeight*-5)+20); vertex(mouthWidth-18, mouthHeight*-9); vertex(mouthWidth-34, mouthHeight*-3); vertex(mouthWidth-30, (mouthHeight*-5)+20); vertex(mouthWidth-26, mouthHeight*-7); endShape(); fill(180, 200, 100); beginShape(); for (int i=0; i<360; i++) { float x = (nostrils*-1)/4 + sin( radians(i) ) * pow(sin(radians(i)/2), 1.5) *r; float y = (nostrils*-1)/4 + cos( radians(i) ) *r; vertex(x+3, -y-15); } endShape(); //ellipse(0, nostrils * -1, 10, 10); } } class Nemo { PVector pos, vel, acc; float maxVel, maxForce, nearTheShiny; int nemoSize; Nemo() { pos = new PVector( random(0, width), random(0, height), 0 ); vel = new PVector( random(-1, 1), random(-1, 1), 0 ); acc = new PVector(0, 0, 0); maxVel = random(.5, 1.0); maxForce = random(0.2, 1.5); nearTheShiny = 200; nemoSize = 20; } void run() { seek(shiny.get(), nearTheShiny, true); // update position vel.add(acc); // add the acceleration to the velocity vel.limit(maxVel); // clip the velocity to a maximum allowable pos.add(vel); // add velocity to position acc.set(0, 0, 0); // make sure we set acceleration back to zero! toroidalBorders(); render(); } //Get to the Shiny! void seek(PVector shiny, float threshold, boolean slowDown) { acc.add( steer(shiny, threshold, slowDown) ); } //Steering PVector steer (PVector shiny, float threshold, boolean slowDown ) { PVector steerForce; // The steering vector shiny.sub(pos); float d2 = shiny.mag(); if ( d2 > 0 && d2 < threshold) {
shiny.normalize();
if ( (slowDown) && d2 < threshold/2 ) shiny.mult( maxVel * (threshold/stageWidth) );
else shiny.mult(maxVel);
shiny.sub(vel);
steerForce = shiny.get();
steerForce.limit(maxForce);
}
else {
steerForce = new PVector(0, 0, 0);
}
return steerForce;
}

//keep fishies on screen
void toroidalBorders() {
if (pos.x < 0 ) pos.x = stageWidth; if (pos.x > stageWidth) pos.x = 0;
if (pos.y < 0 ) pos.y = stageHeight; if (pos.y > stageHeight) pos.y = 0;
}

void render() {
stroke(120, 190, 200);
fill(120, 190, 200);
ellipse(pos.x, pos.y, nemoSize/(int(poseScale)+1), nemoSize/(int(poseScale)+1));
line(pos.x, pos.y, pos.x-(vel.x*nemoSize/(int(poseScale)+1)), pos.y-(vel.y*nemoSize/(int(poseScale)+1)) );
}
}

// OSC CALLBACK FUNCTIONS

public void found(int i) {
println("found: " + i);
found = i;
}

public void poseScale(float s) {
println("scale: " + s);
poseScale = s;
}

public void posePosition(float x, float y) {
println("pose position\tX: " + x + " Y: " + y );
posePosition.set(x, y, 0);
}

public void poseOrientation(float x, float y, float z) {
println("pose orientation\tX: " + x + " Y: " + y + " Z: " + z);
poseOrientation.set(x, y, z);
}

public void mouthWidthReceived(float w) {
println("mouth Width: " + w);
mouthWidth = w;
}

public void mouthHeightReceived(float h) {
println("mouth height: " + h);
mouthHeight = h;
}

public void eyeLeftReceived(float f) {
println("eye left: " + f);
eyeLeft = f;
}

public void eyeRightReceived(float f) {
println("eye right: " + f);
eyeRight = f;
}

public void eyebrowLeftReceived(float f) {
println("eyebrow left: " + f);
eyebrowLeft = f;
}

public void eyebrowRightReceived(float f) {
println("eyebrow right: " + f);
eyebrowRight = f;
}

public void jawReceived(float f) {
println("jaw: " + f);
jaw = f;
}

public void nostrilsReceived(float f) {
println("nostrils: " + f);
nostrils = f;
}

// all other OSC messages end up here
void oscEvent(OscMessage m) {
if (m.isPlugged() == false) {
println("UNPLUGGED: " + m);
}
}

Anna

26 Jan 2013

“Listen as the bonds fall off, which hold you, above and below….”

So… hey there: AvR here, with a bucket of gatorade, a pile of saltines, and a bunch of code to share with you. Delightful!

This is my solution for recreating TextRain in Processing. In short, it knocks out the background by making everything two-toned, and then searches for the darker pixel color. Nothing super fancy, but fancy by my standards, because I’m not super fast at this yet…

I wanted to say a bit about the text itself. The lines are from Guillaume Apollinaire’s famous French calligram “Il Pleut” (It Rains). Calligrams are poems where the typographic layout and shape of the words contribute to the meaning of the poem. The original looks like this:

ilpleut

I’ve always loved the work of Apollinaire, and this assignment seemed like the perfect opportunity to breathe new life into his ideas. Obviously ‘Gui’ didn’t have a computer available to him, and he was forced to rely on static shapes to convey the idea of rain. I liked the idea of being able to add a little motion to the mix. The idea of ‘freeing’ the letters from their frozen position on the page, to me, fits nicely the final line of the poem: “Listen as the bonds fall off, which hold you, above and below….”

Credit where credit is due: I listened to John‘s suggestion to redraw the webcam image as a set of larger rectangles — not because it looked cool, but because it helped Processing deal with the ridiculous output of my retinabook. Mike also nudged me in the right direction about locating individual pixels to gauge brightness, because on my first attempt I’d written myself into a processing abyss with a whole pile of letter classes, and couldn’t figure out if I was the dimmest bulb in the chandelier, much less if a pixel was the dimmest pixel in the window…….

Merci Beaucoup.

textrain shots

Github Repo

import processing.video.*;
Capture retinacam;
PFont f;
final int pixeler = 4;
int[] time = { 0, 20000, 40000 };

String lineone = "Il pleut des voix de femmes comme si elles étaient mortes même dans le souvenir";
String linetwo = "c’est vous aussi qu’il pleut, merveilleuses rencontres de ma vie. ô gouttelettes";
// String linethree = "et ces nuages cabrés se prennent à hennir tout un univers de villes auriculaires";
// String linefour = "écoute s’il pleut tandis que le regret et le dédain pleurent une ancienne musique;"
// String linefive = "écoute tomber les liens qui te retiennent en haut et en bas":

int[] charx = new int[lineone.length()];
int[] chary = new int[lineone.length()];
int[] charx2 = new int[linetwo.length()];
int[] chary2 = new int[linetwo.length()];

void setup() {
  size(1280, 720);

  String[] cameras = Capture.list();

  if (cameras.length == 0) {
    println("There are no cameras available for capture.");
    exit();
  }
  else {
    println("Available cameras:");
    for (int i = 0; i < cameras.length; i++) {
      println(cameras[i]);
    }
  }
  retinacam = new Capture(this, cameras[0]);
  retinacam.start();
  colorMode(HSB, 255);
  noStroke();
  f = createFont("Futura", 24, true);
  textFont(f);
//
//for (int i = 0; i < linetwo.length(); i++) {
// chary2[i] = -200;
//}

  charx[0] = 10;
  for (int i=1; i < lineone.length(); i++) {
    charx[i]= charx[i-1] += 15;
    println(textWidth(lineone.charAt(i-1)));
  }

    charx2[0] = 10;
  for (int i=1; i < linetwo.length(); i++) {
    charx2[i]= charx2[i-1] += 15;
    println(textWidth(linetwo.charAt(i-1)));
  }
}

void draw() {
  if (retinacam.available()==true) {
    retinacam.read();
  }

 // retinacam.loadPixels();
  int threshold = 60;

  for (int x = 0; x < retinacam.width; x+=pixeler) {
    for (int y = 0; y < retinacam.height; y+=pixeler) {
      int loc = x + y*retinacam.width;
      if (brightness(retinacam.pixels[loc]) > threshold) {
        fill(160, 100, 100);
      }
      else {
        fill(200, 100, 50);
      }
      rect(x, y, pixeler, pixeler);
    }
  }

  retinacam.updatePixels();

  //image(retinacam, 0, 0);

if( millis() >= time[0] ){
for (int i = 0; i < lineone.length(); i++) {
if((chary[i] > retinacam.height)||(chary[i]<0)){
     chary[i] = 0;
     }
     else {
     chary[i] = chary[i] + int((brightness(get(charx[i], chary[i]))-60)/random(10,15));
     }
    fill(112, 250, 180);
    text(lineone.charAt(i), charx[i], chary[i]);
  }
  }

if( millis() >= time[1] ){
  for (int i = 0; i < linetwo.length(); i++) {
if((chary2[i] > retinacam.height)||(chary2[i]<0)){
     chary2[i] = 0;
     }
     else {
     chary2[i] = chary2[i] + int((brightness(get(charx2[i], chary2[i]))-60)/random(5,29));
     }
    fill(35, 250, 250);
    text(linetwo.charAt(i), charx2[i], chary2[i]);
  }
}

}

Robb

26 Jan 2013

I combined the AudioOutput Example and the Billboard Example.
One thousand, one hundred eleven asses fill the screen as a horrible screech takes over your mind.
This is very conceptual. You might not understand.
I spent some serious time tweaking the numbers on the skin tone of those butts.
The artifacts of noise and blurriness are intentional. Easy enough to remove.
Enjoy.

Butt Image Credit:High-school Robb