OpenNi: Es una especie de framework/driver liberado por la empresa PrimeSense (involucrada con el desarrollo del hardware de kinect) que entre otras cosas nos permite tener acceso al sensor de profundidad.
Nite: Una extensión de OpenNi que nos permite reconocer gestos (movimientos) y realizar \"skeleton tracker\".
de momento no nos centraremos en como se instalan estas herramientas, mas bien en su uso, sobre la instalación: http://www.beta2k.es/instalar-driver-de ... penninite/
aquí unos vídeos de lo que se vio en la conferencia de \"Hacking kinect\" que di en enli, pronto subiré mas.
[youtube=425,350]http://www.youtube.com/watch?v=iwboC-akMlY[/youtube] (este vídeo demuestra lo que se vera en esta introducción)
[youtube=425,350]http://www.youtube.com/watch?v=pnGtkImPdW8[/youtube]
(como podrán ver para cualquier persona esta clase de control es completamente natural... incluyendo los niños).
ya que se tenga funcionando las librerías vamos a comenzar a trabajar con los movimientos, en mi caso reutilice parte del código escrito por Oz Magal para \"facilitar\" un poco este ejemplo, pero próximamente terminaremos el plugin para blender.
Tuvimos un problema con blender al utilizar hilos y actualizar la ventana (debido a que kinect trabaja a 30 frames por segundo blender simplemente desbordaba, aunque quizás también se debía a la incompatibilidad con la tarjeta gráfica que utilizamos).
Para comenzar se requiere tener instalado OpenNi y Nite (y sensor), vamos a realizar este ejemplo en base al código de Oz Magal (que se encuentra en los ejemplos de Nite) llamado \"Players\", únicamente editaremos el archivo SceneDrawer.cpp (para trabajar con OpenNi/Nite se requiere saber un poco de c/c++), de momento este ejemplo lo realizaremos para trabajar sobre X11, pero próximamente subiremos el código para otras plataformas que no lo soportan.
Una vez cumplidos los requisitos previos continuemos:
En este ejemplo se mostrara como mover objetos en blender con la mano derecha (como \"mouse\") e izquierda (para tomar objetos).
Para localizar la ubicación de algún punto del usuario sincronizado (posición \"Psi\") podemos realizar lo siguiente:
Código: Seleccionar todo
XnPoint3D getpost(XnUserID player, XnSkeletonJoint eJoint1) {
XnSkeletonJointPosition joint1;
g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(player, eJoint1, joint1);
return joint1.position;
}
Nombre del punto/Valor int
XN_SKEL_HEAD/1
XN_SKEL_NECK/2
XN_SKEL_TORSO/3
XN_SKEL_LEFT_SHOULDER/6
XN_SKEL_LEFT_ELBOW/7
XN_SKEL_LEFT_HAND/9
XN_SKEL_RIGHT_SHOULDER/12
XN_SKEL_RIGHT_ELBOW/13
XN_SKEL_RIGHT_HAND/15
XN_SKEL_LEFT_HIP/17
XN_SKEL_LEFT_KNEE/18
XN_SKEL_LEFT_FOOT/20
XN_SKEL_RIGHT_HIP/21
XN_SKEL_RIGHT_KNEE/22
XN_SKEL_RIGHT_FOOT/24
el tipo XnUserID es de tipo int y sera el id del usuario del cual queremos que nos retorne sus coordenadas (se pueden sincronizar los usuarios que sean (siempre y cuando el espacio lo permita...), solo se requiere hacer algunas pequeñas ediciones en el código).
Código: Seleccionar todo
FILE *datos = fopen(\"skeleto.txt\",\"w\"); // abrimos el archivo donde guardaremos los datos
XnPoint3D cabeza = getpost(player, XN_SKEL_HEAD);
XnPoint3D hombrod = getpost(player, XN_SKEL_RIGHT_SHOULDER);
XnPoint3D hombroi = getpost(player, XN_SKEL_LEFT_SHOULDER);
XnPoint3D caderecha = getpost(player, XN_SKEL_RIGHT_HIP);
XnPoint3D manod = getpost(player, XN_SKEL_RIGHT_HAND);
XnPoint3D manoi = getpost(player, XN_SKEL_LEFT_HAND);
if(sizebrazo < 1) { // si no tenemos el tamaño del brazo lo establecemos
cabezainicial = cabeza.Z;
sizebrazo = (manod.Y-hombrod.Y)/2;
printf(\"Taño brazo: %f\\n\",sizebrazo);
}
float centrox = (hombrod.X+hombroi.X)/2; // el centro X
float centroy = (hombrod.Y+hombroi.Y)/2;
float x;
float y;
float zoom = 50-(cabeza.Z-cabezainicial)/((sizebrazo*2)/50); // según que tan cerca esta la cabeza del usuario calculamos el zoom de la cámara que seria 50 maximo.
if(abs(manod.X-centrox) > (sizebrazo*2) || (abs(manod.Y-centroy) > (sizebrazo*2))) { // si la mano derecha del usuario se paso del limite de la pantalla establecida para blender
if((abs(manod.Y-centroy) > (sizebrazo*2))) { // si es en y entonces 20
y = 20;
} else x = 20; // si es en x igual
} else { // de lo contrario esta en los limites y podemos calcular la medida para blender
x = abs(manod.X-centrox)/(sizebrazo/20);
y = abs(manod.Y-centroy)/(sizebrazo/20);
if(x > 20) x = 20; // algo fallo
if(y > 20) y = 20; // algo fallo
if(manod.X < centrox) x = x-(x*2);
if(manod.Y < centroy) y = y-(y*2);
}
int estado = 0;
if(manoi.Z < (hombroi.Z-(sizebrazo))) estado = 1; // esto seria cuando se tiene la izquierda enfrente, es decir se quiere mover algun objeto
ablender(datos,\"DERECHA\",y,x,estado,zoom); // guardamos en el archivo
tecla(XK_A); // esta tecla solo se envia para decirle a blender que tiene que actualizar (por el bug con hilos)
Código: Seleccionar todo
import Blender
from Blender import *
import threading
from threading import Thread
class kinect(Thread):
def __init__ (self):
threading.Thread.__init__(self)
self.bucle = 1
def stop(self):
self.bucle = 0
def run(self):
global Blender
ob = Blender.Object.Get(\'Sphere\') # tomamos a la esfera como \"puntero\"
ob.LocX = 0
ob.LocY = 0
ob.LocZ = 0
while(self.bucle):
f = open(\"/tmp/skeleto.txt\") # direccion del archivo de coordenadas
t = f.read()
lineas = t.split(\'\\n\')
t = \"\"
linea = \"\"
anteriorx = 0
anteriory = 0
for linea in lineas:
if linea != \"\":
d = linea.split(\'|\')
if(d[0] == \"DERECHA\"):
ob.LocX = float(d[1])
ob.LocY = float(d[2])
anteriorx = ob.LocX
anteriory = ob.LocY
estado = int(d[3])
objetos = Blender.Object.Get()
camara = Blender.Camera.Get(\"Camera\")
if(estado == 1):
for objeto in objetos:
ob.LocZ = 0
if(objeto != ob and objeto != camara and abs(objeto.LocX-ob.LocX) < 2 and abs(ob.LocY-objeto.LocY) < 2):
objeto.LocX = ob.LocX
objeto.LocY = ob.LocY
print \'clicked \',objeto.name,\'!\'
zoom = float(d[4])
camara.lens = zoom
print \'Hilo finalizado!\'
k = kinect()
k.start()
def draw():
Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
Blender.Draw.String(\"Hacking Kinect By Los Caballeros! ... Blender PoC 1\", 1, 300, 300, 350, 30, \"\", 2)
def event(evt,val):
if evt == Blender.Draw.AKEY:
# leemos la tecla A
Blender.Window.Redraw()
# actualizamos...
if evt == Blender.Draw.ESCKEY:
# entonces salimos con escape
k.stop()
# finalizamos el hilo
Blender.Draw.Exit()
return
def button(evt):
if evt == 1:
Blender.Window.Redraw()
Blender.Draw.Register(draw,event,button)
adjunto los códigos.