LJ/plugins/trckr.py

648 lines
16 KiB
Python

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
trckr
Work with clmtrackr-dev and www/trckr/trckr.html
v0.1.0
LICENCE : CC
by Sam Neurohack
To test the examples locally, you need to run a local server.
One easy way to do this is to install http-server, a small node.js utility:
npm install -g http-server.
Then run http-server in the root of clmtrackr and go to
- read a video :
http://localhost:8080/examples/trckr.html
- webcam
clmtrackr :
https://github.com/auduno/clmtrackr/tree/dev/examples
'''
import sys
import os
print()
ljpath = r'%s' % os.getcwd().replace('\\','/')
# import from shell
sys.path.append(ljpath +'/../libs3/')
#import from LJ
import log
print ("")
log.infog("Trckr Plugin v0.1")
sys.path.append('../libs3')
sys.path.append(ljpath +'/../../libs3')
from OSC3 import OSCServer, OSCClient, OSCMessage
import lj23layers as lj
import redis
import math
import time
import argparse
OSCinPort = 8017
print ("")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="trckr example for LJ")
argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str)
argsparser.add_argument("-s","--scene",help="LJ scene number (0 by default)",type=int)
#argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int)
argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int)
argsparser.add_argument("-m","--myIP",help="Local IP (127.0.0.1 by default) ",type=str)
args = argsparser.parse_args()
if args.scene:
ljscene = args.scene
else:
ljscene = 0
'''
if args.laser:
plnumber = args.laser
else:
plnumber = 0
'''
# Redis Computer IP
if args.redisIP != None:
redisIP = args.redisIP
else:
redisIP = '127.0.0.1'
print("redisIP",redisIP)
# myIP
if args.myIP != None:
myIP = args.myIP
else:
myIP = '127.0.0.1'
print("myIP",myIP)
if args.verbose:
debug = args.verbose
else:
debug = 0
# Useful variables init.
white = lj.rgb2int(255,255,255)
red = lj.rgb2int(255,0,0)
blue = lj.rgb2int(0,0,255)
green = lj.rgb2int(0,255,0)
# 3D to 2D projection parameters
fov = 256
viewer_distance = 2.2
width = 800
height = 600
centerX = width / 2
centerY = height / 2
TrckrPts = [[0,0]] * 70
#
# LJ inits
#
layer = 0
# Setup LJ library mandatory properties for this layerugin
lj.Config(redisIP, ljscene, "trckr")
# Define properties for each drawn "element" : name, intensity, active, xy, color, red, green, blue, layer , closed
FaceForm = lj.FixedObject('Face', True, 255, [], red, 255, 0, 0, layer , False)
# 'Destination' for given layer : name, number, active, layer , scene, laser
Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0) # Dest0 will send layer 0 points to scene 0, laser 0
#
# OSC
#
oscserver = OSCServer( (myIP, OSCinPort) )
oscserver.timeout = 0
# this method of reporting timeouts only works by convention
# that before calling handle_request() field .timed_out is
# set to False
def handle_timeout(self):
self.timed_out = True
# funny python's way to add a method to an instance of a class
import types
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
# OSC callbacks
# /trckr/ljscene
def OSCljscene(path, tags, args, source):
print("Got /trckr/ljscene with value", args[0])
lj.WebStatus("trckr to virtual "+ str(args[0]))
ljscene = args[0]
lj.Ljscene(ljscene)
# /trckr/layer
def OSClayer(path, tags, args, source):
print()
print()
print("Got /trckr/layer with value", args[0])
lj.WebStatus("trckr to layer "+ str(args[0]))
FaceForm.layer = int(args[0])
Dest0.layer = int(args[0])
Dest0.laser = int(args[0])
# /trckr/frame
def OSCtrckr(path, tags, args, source):
global TrckrPts
#print("trckr got frame", args[0])
if debug != 0:
print("trckr plugin got frame", args[0])
print(len(args),"args", args)
counter =0
TrckrPts = []
for dot in range(1,len(args)-1,2):
TrckrPts.append([float(args[dot]), float(args[dot+1])])
print(TrckrPts)
# /trckr/frame layernumber framenumber points
def OSCTrckrframe(path, tags, args, source):
global TrckrPts
if debug != 0:
print("trckr plugin got frame", args[1], "for layer", args[0], "with path", path)
print(len(args),"args", args)
TrckrPts[args[0]] = []
for dot in range(2,len(args)-1,2):
TrckrPts[args[0]].append([float(args[dot]), float(args[dot+1])])
#/trckr/color/0 red ?
def OSColor():
global FaceForm
if debug != 0:
print("trckr color got ", args[1], "for layer", args[0], "with path", path)
print(len(args),"args", args)
FaceForm.color = args[1]
# default handler
def OSChandler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
print()
print("trckr default OSC Handler :", path, "from Client :" + str(source[0]))
#
# Face Tracking
#
# get absolute face position points
def getPART(pose_points):
dots = []
for dot in pose_points:
dots.append((TrckrPts[dot][0], TrckrPts[dot][1],0))
return dots
# Face keypoints
def face():
pose_points = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
return getPART(pose_points)
def browL():
pose_points = [15,16,17,18]
return getPART(pose_points)
def browR():
pose_points = [22,21,20,19]
return getPART(pose_points)
def eyeR():
pose_points = [25,64,24,63,23,66,26,65,25]
return getPART(pose_points)
def eyeL():
pose_points = [28,67,29,68,30,69,31,28]
return getPART(pose_points)
def pupR():
pose_points = [27]
return getPART(pose_points)
def pupL():
pose_points = [32]
return getPART(pose_points)
def nose1():
pose_points = [62,41,33]
return getPART(pose_points)
def nose2():
pose_points = [40,39,38,43,37,42,36,35,34]
return getPART(pose_points)
def mouth():
pose_points = [50,49,48,47,46,45,44,55,54,53,52,51,50]
return getPART(pose_points)
def mouthfull():
pose_points = [50,49,48,47,46,45,44,55,54,53,52,51,50,59,60,61,44,56,57,58,50]
return getPART(pose_points)
def Proj(x,y,z,angleX,angleY,angleZ):
rad = angleX * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
y2 = y
y = y2 * cosa - z * sina
z = y2 * sina + z * cosa
rad = angleY * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
z2 = z
z = z2 * cosa - x * sina
x = z2 * sina + x * cosa
rad = angleZ * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
x2 = x
x = x2 * cosa - y * sina
y = x2 * sina + y * cosa
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
x = x * factor + centerX
y = - y * factor + centerY
return (x,y)
#
# Main
#
def Run():
Facepts = []
counter =0
lj.WebStatus("trckr")
lj.SendLJ("/trckr/start 1")
# OSC Server callbacks
print("Starting OSC server at",myIP," port",OSCinPort,"...")
oscserver.addMsgHandler( "/trckr/ljscene", OSCljscene)
oscserver.addMsgHandler( "/trckr/layer", OSClayer)
oscserver.addMsgHandler( "/trckr/frame", OSCtrckr)
oscserver.addMsgHandler( "/trckr/color", OSColor)
# Add OSC generic layerugins commands : 'default", /ping, /quit, /pluginame/obj, /pluginame/var, /pluginame/adddest, /pluginame/deldest
lj.addOSCdefaults(oscserver)
oscserver.addMsgHandler( "default", OSChandler )
try:
while lj.oscrun:
lj.OSCframe()
#print("browL", browL(), "browR", browR(), "nose1", nose1(), "mouth", mouth())
lj.rPolyLineOneColor(browL(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(eyeL(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(browR(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(eyeR(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(pupL(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(pupR(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(nose1(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(nose2(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.rPolyLineOneColor(mouthfull(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
lj.DrawDests()
time.sleep(0.005)
counter += 1
if counter > 360:
counter = 0
except KeyboardInterrupt:
pass
# Gently stop on CTRL C
finally:
lj.ClosePlugin()
Run()
'''
//
// a template for receiving face tracking osc messages from
// Kyle McDonald's trckr 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
//
//Xavier Apostol
//Generative Faces: Plotter Project Concept
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;
float sz = 1;
float spacing = 100;
float genSz = spacing/4;
float fcOff = genSz/2;
//Initialization of Colors
float R = random(255);
float G = random(255);
float B = random(255);
//Initialization of Head
float rotInt = 15;
float hdX = cos(sz) + random(genSz, 3*genSz);
float hdY = sin(sz) + random(genSz, 3*genSz);
float rotAngle = random(-rotInt,rotInt);
//Initialization of Eyes
float lEyeX1 = sin(sz*0) + random(genSz);
float lEyeY1 = cos(sz*0) + random(genSz);
float rEyeX1 = sin(sz*0) + random(genSz);
float rEyeY1 = cos(sz*0) + random(genSz);
float lEyeX2 = sin(sz*1) + random(genSz);
float lEyeY2 = cos(sz*1) + random(genSz);
float rEyeX2 = sin(sz*1) + random(genSz);
float rEyeY2 = cos(sz*1) + random(genSz);
float ranREye = random(7, 9);
float ranLEye = random(7, 9);
//Initialization of Mouth
float mthX = cos(sz) + random(genSz);
float mthY = sin(sz) + random(genSz);
float ranM = random(-0.1, 1.5);
//Initialization of Spine
float hdOffset = hdY/1.5;
float spineSz = random(genSz/2);
float spXOff1 = random(-8, 8);
float spYOff1 = hdOffset + random(genSz/3);
float spXOff2 = random(-8, 8)+spXOff1;
float spYOff2 = random(genSz/3)+spYOff1;
float spXOff3 = random(-8, 8)+spXOff2;
float spYOff3 = random(genSz/3)+spYOff2;
float spXOff4 = random(-8, 8)+spXOff3;
float spYOff4 = random(genSz/3)+spYOff3;
float spXOff5 = random(-8, 8)+spXOff4;
float spYOff5 = random(genSz/3)+spYOff4;
void setup() {
size(800, 600, OPENGL);
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");
}
void keyPressed() {
if (key == CODED) {
if (keyCode == UP) {
//Create an entirely new character.
//For Eyes
lEyeX1 = sin(sz*0) + random(genSz);
lEyeY1 = cos(sz*0) + random(genSz);
rEyeX1 = sin(sz*0) + random(genSz);
rEyeY1 = cos(sz*0) + random(genSz);
lEyeX2 = sin(sz*1) + random(genSz);
lEyeY2 = cos(sz*1) + random(genSz);
rEyeX2 = sin(sz*1) + random(genSz);
rEyeY2 = cos(sz*1) + random(genSz);
ranREye = random(7, 9);
ranLEye = random(7, 9);
//For Mouth
mthX = cos(sz) + random(genSz);
mthY = sin(sz) + random(genSz);
ranM = random(-0.1, 1.5);
//For Spine
spineSz = random(genSz/2);
spXOff1 = random(-8, 8);
spYOff1 = hdOffset + random(genSz/3);
spXOff2 = random(-8, 8) + spXOff1;
spYOff2 = random(genSz/3) + spYOff1;
spXOff3 = random(-8, 8) + spXOff2;
spYOff3 = random(genSz/3) + spYOff2;
spXOff4 = random(-8, 8) + spXOff3;
spYOff4 = random(genSz/3) + spYOff3;
spXOff5 = random(-8, 8) + spXOff4;
spYOff5 = random(genSz/3) + spYOff4;
//For Head
hdX = cos(sz) + random(genSz, 3*genSz);
hdY = sin(sz) + random(genSz, 3*genSz);
rotAngle = random(-rotInt,rotInt);
//For Colors
R = random(255);
G = random(255);
B = random(255);
draw();
}
}
}
void draw() {
background(0);
strokeWeight(1);
noFill();
if(found != 0) {
pushMatrix();
translate(posePosition.x, posePosition.y);
//Scales head and allows for rotations
scale(poseScale*2);
rotateY(0 - poseOrientation.y);
rotateX(0 - poseOrientation.x);
rotateZ(poseOrientation.z);
rotate(radians(rotAngle));
ellipse(0,0, hdX,hdY);
popMatrix();
//FACE
translate(posePosition.x, posePosition.y);
scale(poseScale);
noFill();
//Eyes
float eyeFac = 1;
float eyeBL = eyebrowLeft * 2;
float eyeBR = eyebrowRight * 2;
ellipse(-20,eyeLeft * -ranLEye, lEyeX1*eyeFac + eyeBL,lEyeY1*eyeFac + eyeBL);
ellipse(20,eyeRight * -ranREye, rEyeX1*eyeFac + eyeBR,rEyeY1*eyeFac + eyeBR);
ellipse(-20,eyeLeft * -ranLEye, lEyeX2*eyeFac + eyeBL,lEyeY2*eyeFac + eyeBL);
ellipse(20,eyeRight * -ranREye, rEyeX2*eyeFac + eyeBR,rEyeY2*eyeFac + eyeBR);
//Mouth
ellipse(0, 20*ranM, mouthWidth* mthX/3, mouthHeight * mthY);
//BODY/BUBBLES
stroke(R,G,B);
ellipse(spXOff1,spYOff1, spineSz,spineSz);
ellipse(spXOff2,spYOff2, spineSz,spineSz);
ellipse(spXOff3,spYOff3, spineSz,spineSz);
ellipse(spXOff4,spYOff4, spineSz,spineSz);
ellipse(spXOff5,spYOff5, spineSz,spineSz);
}
}
// 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);
}
}
'''