Buenas,
en estos días de fiestas, cuando se te juntan al lado 2 enanos con ganas de jugar, tenes el kinect conectado al PC y el SDK que te extraña, pues lo menos que te sale es algo como lo siguiente:
¡¡¡ Una aplicación que para cada persona que aparece en la WebCam le pone un gorro de Santa Claus !!!
Disclaimer: como pueden ver en el screenshot, además de la vista de la WebCam estoy mostrando el skeleton, pero como justo le dió un rayo de sol a mi enana en el brazo, pues no lo reconoció !!!
Pues bien, después de varios post sobre Kinect, hoy el desafío consistía en lo siguiente
- identificar el joint específico de la cabeza de cada skeleton
- calcular las coordenadas relativas de ese joint frente a la imagen de la webcam
- pintar un Santa Hat en la webcam
El primer punto se soluciona fácilmente, ya que una vez que iteramos por los skeletons reconocidos en modo Trackeable (líneas 6 a 9), podemos iterar entre los Joints del skeleton y verificar que el mismo sea el de la cabeza comparando con [JointID.Head] (línea 17).
Una vez identificado el Joint de la cabeza pasamos al 2do punto que es un poco más complicado. La función GetDisplayPosition() (línea 27), es la encargada de realizar la conversión de la posición del Joint a la ubicación relativa en la imagen. Para esto se utilizan las siguientes capacidades del SDK
– SkeletonEngine.SkeletonToDepthImage() utilizando esta función podemos conocer la ubicación relativa en “depth” de un joint.
– NuiCamera.GetColorPixelCoordinatesFromDepthPixel() utilizando esta función, podemos descubrir la posición en coordenadas X/Y a partir del depth que obtuvimos antes.
En ambos casos, hay que hacer algunos ajustes ya que por un lado la imagen de la webcam está en resolución de 640*480 y la capacidad de depth es solo de 320*240. Pero bueno, con estas pocas líneas ya podemos definir la ubicación específica de nuestra cabeza y pintar un SantaHat en el mismo.
1: void KinectSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
2: {
3: canvasSkeleton.Children.Clear();
4: this.HideImageHats();
5: var skeletonId = 0;
6: foreach (var skeleton in e.SkeletonFrame.Skeletons.Where
7: (skeleton =>
8: SkeletonTrackingState.Tracked == skeleton.TrackingState))
9: {
10: skeletonId++;
11: this.DisplayImageHats(skeletonId);
12: PaintBones(skeleton);
13: PaintJoints(skeleton);
14:
15: foreach (Joint joint in skeleton.Joints)
16: {
17: if (joint.ID != JointID.Head)
18: {
19: continue;
20: }
21: var newPosition = this.GetDisplayPosition(joint);
22: this.MoveImageHats(newPosition, skeletonId);
23: }
24: }
25: }
26:
27: private Point GetDisplayPosition(Joint joint)
28: {
29: float depthX, depthY;
30: kinect.SkeletonEngine.SkeletonToDepthImage(joint.Position, out depthX, out depthY);
31: depthX = Math.Max(0, Math.Min(depthX * 320, 320));
32: depthY = Math.Max(0, Math.Min(depthY * 240, 240));
33: int colorX, colorY;
34: var iv = new ImageViewArea();
35: kinect.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(ImageResolution.Resolution640x480, iv, (int)depthX, (int)depthY, (short)0, out colorX, out colorY);
36: var newX = (int)(CameraViewer.ActualWidth * colorX / 640.0) - 30;
37: var intY = (int)(CameraViewer.ActualHeight * colorY / 480) - 30;
38: return new Point(newX, intY);
39: }
Saludos @ Home y Merry Christmas
El Bruno
Referencias:
- Kinect References
https://elbruno.com/category/msn-microsoft/kinect/ - CodePlext Project
http://kinectmerrychristmas.codeplex.com/ - CodePlex ClickOnce Publising
http://geeks.ms/blogs/elbruno/archive/2010/12/06/vs2010-publicando-aplicaciones-con-clickonce-en-codeplex-sistema-de-distribuci-243-n-gratis-como-el-aire.aspx

Leave a comment