EliRosen – FaceOSC

by eli @ 3:29 am 24 January 2012

[youtube https://www.youtube.com/watch?v=LCVDSafRvH8&w=600&h=437]
I used the FaceOSC data to animate a simple puppet of an old man. I put the puppet together in photoshop from an image I found on google images. The old man’s glasses move up and down in response to the user moving his eyebrows. The user also controls the old mans mouth. When the puppet opens its mouth it spews colorful balls towards the screen.

// A puppet by Eli Rosen based on
// 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
//
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;
//variables for puppet images
PImage face;
PImage glasses;
PImage chin;
 
//variable to store last eyebrow value (for reducing jitter)
float eyebrowLast = eyebrowRight;
 
//array of particle positions
PVector[] pArray = new PVector[1];
//array of particle sizes
float[] pSize = new float[1];
//particle color array
color[] pColor = new color[1];
 
void setup() {
  size(640, 480);
  frameRate(30);
  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");
  //load the puppet images
  face = loadImage("face.png");
  glasses = loadImage("glasses.png");
  chin = loadImage("chin.png");
  //set color mode to HSB
  colorMode(HSB, 255);
  smooth();
 
}
 
void draw() {  
  background(255);  
  if(found > 0) {
    //center and scale the elements
    translate(posePosition.x, posePosition.y);
    scale(poseScale*.8);
    //draw the face
    image(face, -45, -65,face.width*.25, face.height*.25);
    //save the new eyebrow position
    float eyebrowNew = eyebrowRight;
    //get the difference between the old eyebrow position and the new one
    float eyebrowDif = eyebrowNew - eyebrowLast;
    // check if the eyebrow moved beyond a certain threshold
    if(Math.abs(eyebrowDif) > .35)
    {
      //if it did then draw it with the new position
      image(glasses, -29, /*-10*/(eyebrowNew*-4)+22,glasses.width*.25, glasses.height*.25);
      //update the last eyebrow variable
      eyebrowLast = eyebrowNew;
    }
    // if eyebrows did not move enough redraw the glasses in the same position as last time
    else
    {
      image(glasses, -29, /*-10*/(eyebrowLast*-4)+22,glasses.width*.25, glasses.height*.25);
    }
    // draw the chin based on jaw position
    image(chin, -14, jaw*1.6,chin.width*.25, chin.height*.25);
 
    // check if the jaw is open
    if(jaw > 22)
    {
      //generate a random hue number
      int randomHue = int(random(0,256));
      // get a random x and y that fall within the mouth area
      float xPos = random(-2,14);
      float yPos = random(36,40);
      // use the random hue to create a color
      color fillColor = color(randomHue,200,40);
      // create a new pVector and store the random x and y
      PVector p = new PVector(xPos, yPos);
      // create temporary arrays for copying the current arrays
      PVector[] tempArray = new PVector[pArray.length+1];
      float[] tempArray2 = new float[pSize.length+1];
      color[] tempArray3 = new color[pColor.length+1];
      // copy the current particle attribute arrays
      for (int i = 0; i < pArray.length; i++)
      {
        tempArray[i] = pArray[i];
        tempArray2[i] = pSize[i];
        tempArray3[i] = pColor[i];
      }
      // set the global arrays to be the new updated arrays
      pArray = tempArray;
      pSize = tempArray2;
      pColor = tempArray3;
      // add the new Pvector to the pvector array
      pArray[pArray.length-1] = p;
      // add the new color to the color array
      pColor[pColor.length-1] = fillColor;
      // set the drawing style for the new particle
      noStroke();
      fill(fillColor);
      // set the size of the new particle
      float newSize = 2;
      // add the new particle size to the particle size array
      pSize[pSize.length-1]=newSize;
      // draw the new particle
      ellipse(p.x,p.y,newSize,newSize);
    }
 
    // loop through all particles
    for(int i=1; i < pArray.length; i++)
    {
      // move the particles y positions down
      pArray[i].y =  pArray[i].y + random(1,3);
      // get the particles distance from the center of the face
      float xDif = Math.abs(pArray[i].x - 6);
      // if the particle is to the left of center move it further left
      if(pArray[i].x <=6)
      {
        // base magnitude of move on distance from center
        pArray[i].x =  pArray[i].x - random(1,3)*.05*xDif;
      }
      // if particle is to the right of center move it further right
      else
      {
        // base magnitude of move on distance from center
        pArray[i].x =  pArray[i].x + random(1,3)*.05*xDif;
      }
      // increase the size of the particle
      pSize[i]= pSize[i]+random(0,1);
      // brighten the particle
      float tempH = hue(pColor[i]);
      float tempS = saturation(pColor[i]);
      float tempB = brightness(pColor[i])+13;
      pColor[i] = color(tempH, tempS, tempB);
      // set fill color to new brighter color 
      fill(pColor[i]);
      // draw the particle with all updated attributes
      ellipse(pArray[i].x, pArray[i].y, pSize[i], pSize[i]);
    }
  }
}
 
// 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);
  }
}

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2023 Interactive Art and Computational Design, Spring 2012 | powered by WordPress with Barecity