FlowerFace

I don’t know why, but it appears to be simply so that whenever one mentions face tracking, one of the first things that comes to mind is a flower. Even before Golan explicitly stated “Don’t all make daisies,” I was thinking about building a face-tracking flower, even while I was still in high school. Now, having learned to use to OSC with Kyle’s FaceOSC demo, I now have a method to make it into reality. So here I am with my flower-y face. In light of the monotony of petal-laced visages, I decided to make mine in 3 dimensions. Tis’ a simple design, but it works decently well. It tracks the orientation of the whole head, the positions of both eyes and eyebrows, and also the dimensions of the mouth. I threw in some wavy little leaf-arms for the heck of it (not tracked). In implementing this 3D flower face, I’ve also learned that Processing’s 3D transformation system is based on local spaces rather than world space – which is why the eyes look slightly “off” when I tilt my head. All in all, this was an interesting learning experience for me and now I know how to track and map faces in real time.

 
/* FlowerFace by John Choi.
 * Built off of Golan's sample.  Runs off of FaceOSC:
 * Kyle McDonald's FaceOSC https://github.com/kylemcdonald/ofxFaceTracker */

/* --- PRE SETUP --- */
//import necessray libraries
import oscP5.*;
OscP5 oscP5;

//create a sky background
PImage sky;
//create 3d object vars
PShape leftEye;
PShape rightEye;
PShape mouth;
PShape face;
PShape stem;
PShape leftLeaf;
PShape rightLeaf;
// 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;

float timer = 0;

/* ----- SETUP ----- */
void setup() {
  //set up 3D view
  size(640, 480,P3D);
  perspective();
  
  //load sky image
  sky = loadImage("sky.png");
  
  //load 3d objects
  leftEye = loadShape("eye.obj");
  rightEye = loadShape("eye.obj"); 
  mouth = loadShape("mouth.obj"); 
  face = loadShape("face.obj"); 
  stem = loadShape("stem.obj"); 
  leftLeaf = loadShape("leftLeaf.obj"); 
  rightLeaf = loadShape("rightLeaf.obj"); 

  //setup FaceOSC
  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");

}

/* --- MAIN LOOP --- */
void draw() {  
  background(0);
  lights();
  timer += 1;

  //draw skybox
  hint(DISABLE_DEPTH_MASK);
  image(sky, 0, 0, width, height);
  hint(ENABLE_DEPTH_MASK);
  
  //draw 3D objects
  drawShape(leftEye,-.1*eyeLeft,.03*eyebrowLeft,0, 
            poseOrientation.x,poseOrientation.y,-poseOrientation.z, 
            1,.1*eyebrowLeft,1);
  drawShape(rightEye,.1*eyeRight,.03*eyebrowRight,0,
            poseOrientation.x,poseOrientation.y,-poseOrientation.z, 
            1,.1*eyebrowRight,1);
  drawShape(mouth,0,-.5,0, 
            poseOrientation.x,poseOrientation.y,-poseOrientation.z,  
            .1*mouthWidth,.2*mouthHeight,1);
  drawShape(face,0,0,0, 
            poseOrientation.x,poseOrientation.y,-poseOrientation.z, 
            1,1+.02*(eyebrowLeft+eyebrowRight),1);
  drawShape(stem,0,0,0, 0,0,0, 1,1,1);
  drawShape(leftLeaf,0,-2.75,0, 
            0,.2*sin(timer*0.01)-.1,.5*sin(timer*0.04)-.25, 
            1,1,1);
  drawShape(rightLeaf,0,-2.75,0,
            0,.2*sin(timer*0.02)-.0,.5*sin(timer*0.03)-.25, 
            1,1,1);

}

//helper function to shape
void drawShape(PShape obj, float x, float y, float z, 
               float rx, float ry, float rz,
               float sx, float sy, float sz) {
  pushMatrix();
  translate(width/2,height/2,300);
  scale(20,-20,20);
  translate(x,y,z);
  rotateY(ry);
  rotateX(rx);
  rotateZ(rz);
  scale(sx,sy,sz);
  shape(obj);
  popMatrix();
}

/* --- 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) {
  /* print the address pattern and the typetag of the received OscMessage */
  println("#received an osc message");
  println("Complete message: "+m);
  println(" addrpattern: "+m.addrPattern());
  println(" typetag: "+m.typetag());
  println(" arguments: "+m.arguments()[0].toString());
  if(m.isPlugged() == false) { println("UNPLUGGED: " + m); }
}

Comments are closed.