Zack J-W Face_OSC
One of the first things I noticed about Face_OSC is that it’s awesome and my wife thought you had to yell at it for it work. The next thing I noticed is that it doesn’t read facial hair well and, well, I have some.
So I thought it would be appropriate to use Face_OSC to deal with the one thing it hadn’t, err, faced at least in a metaphorical sense. I came to find out that it was a known unknown. Golan lamented that it dealt with beards in a maddening way and Dan Wilcox suggested with one frown that it was a computational nightmare. So I hope programmers get a kick out of it.
One technical hurdle was, using a camera for both the background image and face tracking meant two cameras (at least in my limited capacity as a coder). Processing would not share with Face_OSC and vice versa from the computers built in camera. Having an external web-cam meant I was always going to have an offset between the two focal points which is exacerbated by scale and movement. A better code may be able to compensate for this.
Credit where credit is due: Thanks to Dan Wilcox for bringing the Titty Tracker into the world. Clearly an inspiration.
Video becomes worthless after 1:30…
[youtube https://www.youtube.com/watch?v=VToNr8IQTp4]
import processing.video.*; Capture video; import oscP5.*; OscP5 oscP5; PImage[] images = new PImage[6]; int b, 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; void setup() { size(640,480); frameRate(2); imageMode(CENTER); b = 0; video = new Capture(this, width, height); 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"); for ( int i = 0; i< images.length; i++ ) { images[i] = loadImage( i + ".png" ); // make sure images "0.png" to "?.png" exist } } void draw() { if (video.available()) { video.read(); image(video, width/2, height/2); // background(0); if(found > 0) { scale(poseScale*.12); image(images[b], posePosition.x*poseScale - width*.75 ,posePosition.y*poseScale + height*.1); } } } void keyPressed() { if (keyPressed && key == ' ' ) { b = (b + 1) % 6; } redraw(); } // 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); } } |