|
1 /* |
|
2 * Projet : KINECT PROJECTS |
|
3 * Module : MIDDLEWARE |
|
4 * Sous-Module : Tracking |
|
5 * Classe : KinectMain |
|
6 * |
|
7 * Auteur : alexandre.bastien@iri.centrepompidou.fr |
|
8 * |
|
9 * Fonctionnalités : Récupère les trames de données de la Kinect, les squelettes détectés via le SDK 1.0 de Microsoft. |
|
10 * Interprète ces trames de façon à afficher le flux vidéo couleurs, et récupérer la distance de l'utilisateur et les |
|
11 * noeuds de son squelette. Lance des événements lorsque la main gauche/droite entre dans/quitte le champ. |
|
12 * Envoie des données au sous-module de debug de manière a afficher un retour visuel sur la position de l'utilisateur, |
|
13 * son squelette, la détection de ses mains. |
|
14 */ |
|
15 |
|
16 using System; |
|
17 using System.Collections.Generic; |
|
18 using System.Linq; |
|
19 using System.Text; |
|
20 using System.Windows; |
|
21 using System.Windows.Controls; |
|
22 using System.Windows.Data; |
|
23 using System.Windows.Documents; |
|
24 using System.Windows.Input; |
|
25 using System.Windows.Media; |
|
26 using System.Windows.Media.Imaging; |
|
27 using System.Windows.Navigation; |
|
28 using System.Windows.Shapes; |
|
29 using System.Drawing; |
|
30 using System.Windows.Media.Media3D; |
|
31 using Microsoft.Kinect; |
|
32 |
|
33 using Coding4Fun.Kinect.Wpf; |
|
34 using System.ComponentModel; |
|
35 |
|
36 using Trakers.Debug; |
|
37 using Tuio; |
|
38 using Trakers.Communication; |
|
39 using System.IO; |
|
40 using Trakers.Tracking.Gestures; |
|
41 using Trakers.Tracking.Events; |
|
42 using System.Configuration; |
|
43 using Kinect.Toolbox; |
|
44 |
|
45 namespace Trakers.Tracking |
|
46 { |
|
47 //Il s'agit des fonctions permettant d'appeler les fonctions des événements Main droite/gauche entre/quitte le champ. |
|
48 public delegate void LeftHandTrackedHandler(object o, LeftHandTrackedEventArgs e); |
|
49 public delegate void RightHandTrackedHandler(object o, RightHandTrackedEventArgs e); |
|
50 public delegate void LeftHandQuitHandler(object o, LeftHandQuitEventArgs e); |
|
51 public delegate void RightHandQuitHandler(object o, RightHandQuitEventArgs e); |
|
52 //Il s'agit des fonctions permettant d'appeler les fonctions des événements Swipe left/right/up/down. |
|
53 public delegate void SwipeHandler(object o, SwipeEventArgs e); |
|
54 |
|
55 public class KinectMain |
|
56 { |
|
57 //Fenêtre de debug. |
|
58 private Debug.DebugWindow debug; |
|
59 //Squelettes (Il y en a 6 par défaut). |
|
60 private Skeleton[] skeletons; |
|
61 //Caméra infrarouge (sensor) de la Kinect. |
|
62 private KinectSensor kinectSensor; |
|
63 |
|
64 //Détecteur de gestes. |
|
65 private SwipeDetector swipeDetector; |
|
66 |
|
67 //Distances min/max délimitant le champ de recherche. |
|
68 private float minDistHands; |
|
69 private float maxDistHands; |
|
70 |
|
71 //Serveur TUIO pour la connexion du Middleware vers le Front Atelier. |
|
72 private Server server; |
|
73 |
|
74 //Les événements des mains pour la recherche. |
|
75 public static event LeftHandTrackedHandler LeftHandTrackedEvent; |
|
76 public static event RightHandTrackedHandler RightHandTrackedEvent; |
|
77 public static event LeftHandQuitHandler LeftHandQuitEvent; |
|
78 public static event RightHandQuitHandler RightHandQuitEvent; |
|
79 //Les événements swipe. |
|
80 public static event SwipeHandler SwipeEvent; |
|
81 |
|
82 //Voici les ID des noeuds d'un squelette. |
|
83 private int hipCenterID = 0, spineID = 1, shoulderCenterID = 2, headID = 3; |
|
84 private int shoulderLeftID = 4, elbowLeftID = 5, wristLeftID = 6, handLeftID = 7; |
|
85 private int shoulderRightID = 8, elbowRightID = 9, wristRightID = 10, handRightID = 11; |
|
86 private int hipLeftID = 12, kneeLeftID = 13, ankleLeftID = 14, footLeftID = 15; |
|
87 private int hipRightID = 16, kneeRightID = 17, ankleRightID = 18, footRightID = 19; |
|
88 |
|
89 /* |
|
90 * Initialisation de la classe principale. |
|
91 * Affiche l'écran de debug dans lequel on voit la distance à la Kinect, |
|
92 * les mains détectées et le squelette de l'utilisateur. |
|
93 */ |
|
94 public KinectMain() |
|
95 { |
|
96 //On crée la fenêtre de debug. |
|
97 debug = new Debug.DebugWindow(this); |
|
98 |
|
99 //On crée le détecteur de gestes. |
|
100 swipeDetector = new SwipeDetector(); |
|
101 |
|
102 //On tente de charger les paramètres du fichier params.ini. |
|
103 //Si on n'y arrive pas, on affiche une erreur et on charge les paramètres par défaut. |
|
104 if (!loadParameters()) |
|
105 { |
|
106 debug.ExceptionLbl.Content = "Impossible de charger les paramètres. Paramètres par défaut."; |
|
107 //Distances de détection des mains par défaut pour la recherche (ici de 1m à 2m de la Kinect). |
|
108 minDistHands = (float)1.0; |
|
109 maxDistHands = (float)1.5; |
|
110 } |
|
111 else if (maxDistHands <= 0 || minDistHands <= 0 || maxDistHands > 4 || minDistHands > 4 || minDistHands >= maxDistHands) |
|
112 { |
|
113 debug.ExceptionLbl.Content = "Paramètres incorrects. Paramètres par défaut."; |
|
114 //Distances de détection des mains par défaut pour la recherche (ici de 1m à 2m de la Kinect). |
|
115 minDistHands = (float)1.0; |
|
116 maxDistHands = (float)1.5; |
|
117 } |
|
118 |
|
119 //On affiche la fenêtre de debug. |
|
120 try |
|
121 { |
|
122 debug.ShowDialog(); |
|
123 } |
|
124 catch(Exception){} |
|
125 } |
|
126 |
|
127 /* |
|
128 * Initialisation du sensor de la Kinect. |
|
129 */ |
|
130 public void KinectInitialization() |
|
131 { |
|
132 try |
|
133 { |
|
134 //On sélectionne la première kinect détectée. |
|
135 kinectSensor = KinectSensor.KinectSensors.FirstOrDefault(s => s.Status == KinectStatus.Connected); |
|
136 //La caméra couleur est activée avec une résolution 640x480 et un framerate de 30 FPS. |
|
137 kinectSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30); |
|
138 //La caméra de profondeur est activée. |
|
139 kinectSensor.DepthStream.Enable(); |
|
140 //Le squelette est activé. |
|
141 kinectSensor.SkeletonStream.Enable(); |
|
142 |
|
143 //Quand le Middleware reçoit des trames de la Kinect, on va dans cette fonction. |
|
144 kinectSensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(AllFramesReady); |
|
145 |
|
146 //On démarre la Kinect. |
|
147 kinectSensor.Start(); |
|
148 debug.ExceptionLbl.Content = ""; |
|
149 } |
|
150 catch (System.Exception) |
|
151 { |
|
152 debug.ExceptionLbl.Content = "Kinect non connectée."; |
|
153 } |
|
154 |
|
155 //Pour les événements main gauche/droite entre dans/quitte le champ, on a 4 listeners. |
|
156 //Fonction appelée lorsque la main gauche entre dans le champ de recherche. |
|
157 LeftHandTrackedListener leftHandTrackedListener = new LeftHandTrackedListener(); |
|
158 LeftHandTrackedEvent += new LeftHandTrackedHandler(leftHandTrackedListener.ShowOnScreen); |
|
159 |
|
160 //Fonction appelée lorsque la main droite entre dans le champ de recherche. |
|
161 RightHandTrackedListener rightHandTrackedListener = new RightHandTrackedListener(); |
|
162 RightHandTrackedEvent += new RightHandTrackedHandler(rightHandTrackedListener.ShowOnScreen); |
|
163 |
|
164 //Fonction appelée lorsque la main gauche quitte le champ de recherche. |
|
165 LeftHandQuitListener leftHandQuitListener = new LeftHandQuitListener(); |
|
166 LeftHandQuitEvent += new LeftHandQuitHandler(leftHandQuitListener.ShowOnScreen); |
|
167 |
|
168 //Fonction appelée lorsque la main droite quitte le champ de recherche. |
|
169 RightHandQuitListener rightHandQuitListener = new RightHandQuitListener(); |
|
170 RightHandQuitEvent += new RightHandQuitHandler(rightHandQuitListener.ShowOnScreen); |
|
171 |
|
172 //Fonction appelée lorsque l'utilisateur effectue un swipe right. |
|
173 SwipeEventListener swipeListener = new SwipeEventListener(); |
|
174 SwipeEvent += new SwipeHandler(swipeListener.ShowOnScreen); |
|
175 |
|
176 //On connecte le serveur à l'adresse locale sur le port 80. |
|
177 server = new Server("127.0.0.1", 80); |
|
178 } |
|
179 |
|
180 /* |
|
181 * Fermeture du sensor de la Kinect. |
|
182 */ |
|
183 public void KinectClose() |
|
184 { |
|
185 try |
|
186 { |
|
187 //On stoppe la Kinect. |
|
188 kinectSensor.Stop(); |
|
189 //On met a zero l'image d'affichage et le serveur. |
|
190 debug.DebugImage.Source = null; |
|
191 //server = null; |
|
192 debug.ExceptionLbl.Content = ""; |
|
193 } |
|
194 catch (System.Exception) |
|
195 { |
|
196 debug.ExceptionLbl.Content = "Kinect non connectée."; |
|
197 } |
|
198 } |
|
199 |
|
200 /* |
|
201 * Récupère le premier squelette. |
|
202 */ |
|
203 Skeleton GetFirstSkeleton(AllFramesReadyEventArgs e) |
|
204 { |
|
205 using (SkeletonFrame skeletonFrameData = e.OpenSkeletonFrame()) |
|
206 { |
|
207 if (skeletonFrameData == null) |
|
208 return null; |
|
209 if ((skeletons == null) || (skeletons.Length != skeletonFrameData.SkeletonArrayLength)) |
|
210 skeletons = new Skeleton[skeletonFrameData.SkeletonArrayLength]; |
|
211 skeletonFrameData.CopySkeletonDataTo(skeletons); |
|
212 |
|
213 //On obtient le premier skelette. |
|
214 Skeleton first = (from s in skeletons where s.TrackingState == SkeletonTrackingState.Tracked select s).FirstOrDefault(); |
|
215 |
|
216 return first; |
|
217 } |
|
218 } |
|
219 |
|
220 /* |
|
221 * Récupère le squelette le plus proche. |
|
222 */ |
|
223 Skeleton GetNearestSkeleton(AllFramesReadyEventArgs e) |
|
224 { |
|
225 using (SkeletonFrame skeletonFrameData = e.OpenSkeletonFrame()) |
|
226 { |
|
227 if (skeletonFrameData == null) |
|
228 return null; |
|
229 if ((skeletons == null) || (skeletons.Length != skeletonFrameData.SkeletonArrayLength)) |
|
230 skeletons = new Skeleton[skeletonFrameData.SkeletonArrayLength]; |
|
231 skeletonFrameData.CopySkeletonDataTo(skeletons); |
|
232 |
|
233 Skeleton s; |
|
234 float minDist = (float)-1.0; |
|
235 int minID = 0; |
|
236 |
|
237 //Pour tous les squelettes. |
|
238 for(int i = 0 ; i < skeletons.Count() ; i++) |
|
239 { |
|
240 s = skeletons.ElementAt(i); |
|
241 //S'il est tracké. |
|
242 if(s.TrackingState == SkeletonTrackingState.Tracked) |
|
243 { |
|
244 //On récupère sa position et on obtient la distance min et l'ID du squelette qui est à la distance min. |
|
245 float dist = skeletons.ElementAt(i).Position.Z; |
|
246 if (minDist == -1) |
|
247 { |
|
248 minDist = dist; |
|
249 minID = i; |
|
250 } |
|
251 else if(minDist > dist) |
|
252 { |
|
253 minDist = dist; |
|
254 minID = i; |
|
255 } |
|
256 } |
|
257 } |
|
258 |
|
259 //On renvoie le skelette le plus proche. |
|
260 return skeletons.ElementAt(minID); |
|
261 } |
|
262 } |
|
263 |
|
264 /* |
|
265 * Récupère le squelette le plus proche. |
|
266 */ |
|
267 private void AllFramesReady(object sender, AllFramesReadyEventArgs e) |
|
268 { |
|
269 //On ne calcule rien si la fenêtre de debug se ferme. |
|
270 if (debug.isClosing()) |
|
271 return; |
|
272 |
|
273 //On met à jour la vidéo de debug. |
|
274 debug.RefreshVideo(e); |
|
275 //On récupère le premier squelette tracké. |
|
276 //Skeleton first = GetFirstSkeleton(e); |
|
277 //On récupère le plus proche squelette tracké. |
|
278 Skeleton first = GetNearestSkeleton(e); |
|
279 //Si celui-ci n’est pas nul |
|
280 if (first == null) |
|
281 return; |
|
282 |
|
283 //Si ce squelette est tracké (donc suivi et reconnu par la camera) |
|
284 if (first.TrackingState == SkeletonTrackingState.Tracked) |
|
285 { |
|
286 //Ensemble des noeuds du squelette. |
|
287 Joint hipCenter = getJoint(first, hipCenterID), spine = getJoint(first, spineID), shoulderCenter = getJoint(first, shoulderCenterID), head = getJoint(first, headID); |
|
288 Joint shoulderLeft = getJoint(first, shoulderLeftID), elbowLeft = getJoint(first, elbowLeftID), wristLeft = getJoint(first, wristLeftID), handLeft = getJoint(first, handLeftID); |
|
289 Joint shoulderRight = getJoint(first, shoulderRightID), elbowRight = getJoint(first, elbowRightID), wristRight = getJoint(first, wristRightID), handRight = getJoint(first, handRightID); |
|
290 Joint hipLeft = getJoint(first, hipLeftID), kneeLeft = getJoint(first, kneeLeftID), ankleLeft = getJoint(first, ankleLeftID), footLeft = getJoint(first, footLeftID); |
|
291 Joint hipRight = getJoint(first, hipRightID), kneeRight = getJoint(first, kneeRightID), ankleRight = getJoint(first, ankleRightID), footRight = getJoint(first, footRightID); |
|
292 |
|
293 //On construit l'historique des postures. |
|
294 /*List<Joint> joints = new List<Joint>(); |
|
295 joints.Clear(); |
|
296 joints.Add(footRight); |
|
297 joints.Add(ankleRight); |
|
298 joints.Add(kneeRight); |
|
299 joints.Add(hipRight); |
|
300 joints.Add(footLeft); |
|
301 joints.Add(ankleLeft); |
|
302 joints.Add(kneeLeft); |
|
303 joints.Add(hipLeft); |
|
304 joints.Add(handRight); |
|
305 joints.Add(wristRight); |
|
306 joints.Add(elbowRight); |
|
307 joints.Add(shoulderRight); |
|
308 joints.Add(handLeft); |
|
309 joints.Add(wristLeft); |
|
310 joints.Add(elbowLeft); |
|
311 joints.Add(shoulderLeft); |
|
312 joints.Add(head); |
|
313 joints.Add(shoulderCenter); |
|
314 joints.Add(spine); |
|
315 joints.Add(hipCenter); |
|
316 swipeDetector.UpdateSkeletonHistory(joints);*/ |
|
317 |
|
318 SkeletonDisplayManager sdm = new SkeletonDisplayManager(kinectSensor, debug.DebugCanvas); |
|
319 //sdm.Draw(); |
|
320 |
|
321 //On obtient sa distance à la Kinect. |
|
322 float distance = first.Position.Z; |
|
323 |
|
324 //On affiche la distance dans le debug. |
|
325 debug.showDistance(distance); |
|
326 |
|
327 //Si la main gauche est dans le champ, on lance l'événement approprié. |
|
328 if (handLeft.Position.Z < maxDistHands && handLeft.Position.Z > minDistHands) |
|
329 { |
|
330 LeftHandTrackedEventArgs leftHandTrackedEvent = new LeftHandTrackedEventArgs(handLeft, handLeft.Position.Z, debug, server); |
|
331 OnLeftHandTrackedEvent(leftHandTrackedEvent); |
|
332 } |
|
333 //Si la main gauche quitte le champ, on lance l'événement approprié. |
|
334 else |
|
335 { |
|
336 LeftHandQuitEventArgs leftHandQuitEvent = new LeftHandQuitEventArgs(handLeft, handLeft.Position.Z, debug, server); |
|
337 OnLeftHandQuitEvent(leftHandQuitEvent); |
|
338 } |
|
339 //Si la main droite est dans le champ, on lance l'événement approprié. |
|
340 if (handRight.Position.Z < maxDistHands && handRight.Position.Z > minDistHands) |
|
341 { |
|
342 RightHandTrackedEventArgs rightHandTrackedEvent = new RightHandTrackedEventArgs(handRight, handRight.Position.Z, debug, server); |
|
343 OnRightHandTrackedEvent(rightHandTrackedEvent); |
|
344 } |
|
345 //Si la main droite quitte le champ, on lance l'événement approprié. |
|
346 else |
|
347 { |
|
348 RightHandQuitEventArgs rightHandQuitEvent = new RightHandQuitEventArgs(handRight, handRight.Position.Z, debug, server); |
|
349 OnRightHandQuitEvent(rightHandQuitEvent); |
|
350 } |
|
351 |
|
352 //Si l'utilisateur effectue un swipe left. |
|
353 if (swipeDetector.CheckForSwipeLeft()) |
|
354 { |
|
355 SwipeEventArgs swipeEvent = new SwipeEventArgs(debug, server, SwipeDetector.Direction.LEFT); |
|
356 OnSwipeEvent(swipeEvent); |
|
357 } |
|
358 |
|
359 |
|
360 //Dessine le squelette dans le debug. |
|
361 //debug.drawJoints(first.Joints, first); |
|
362 //debug.showSkeleton(hipCenter, spine, shoulderCenter, head, shoulderLeft, elbowLeft, wristLeft, handLeft, shoulderRight, elbowRight, wristRight, handRight, hipLeft, kneeLeft, ankleLeft, footLeft, hipRight, kneeRight, ankleRight, footRight); |
|
363 } |
|
364 } |
|
365 |
|
366 /* |
|
367 * Change l'échelle des coordonnées d'un noeud pour qu'en X et Y il corresponde à la résolution et en Z à la distance à la Kinect. |
|
368 */ |
|
369 public Joint getJoint(Skeleton ske, int jointID) |
|
370 { |
|
371 return Coding4Fun.Kinect.Wpf.SkeletalExtensions.ScaleTo(ske.Joints.ElementAt(jointID), 600, 400, 0.75f, 0.75f); |
|
372 } |
|
373 |
|
374 /* |
|
375 * Initialise l'événement et fait appel aux fonctions du listener quand la main gauche entre dans le champ. |
|
376 */ |
|
377 public static void OnLeftHandTrackedEvent(LeftHandTrackedEventArgs e) |
|
378 { |
|
379 if (LeftHandTrackedEvent != null) |
|
380 LeftHandTrackedEvent(new object(), e); |
|
381 } |
|
382 |
|
383 /* |
|
384 * Initialise l'événement et fait appel aux fonctions du listener quand la main droite entre dans le champ. |
|
385 */ |
|
386 public static void OnRightHandTrackedEvent(RightHandTrackedEventArgs e) |
|
387 { |
|
388 if (RightHandTrackedEvent != null) |
|
389 RightHandTrackedEvent(new object(), e); |
|
390 } |
|
391 |
|
392 /* |
|
393 * Initialise l'événement et fait appel aux fonctions du listener quand la main gauche quitte le champ. |
|
394 */ |
|
395 public static void OnLeftHandQuitEvent(LeftHandQuitEventArgs e) |
|
396 { |
|
397 if (LeftHandQuitEvent != null) |
|
398 LeftHandQuitEvent(new object(), e); |
|
399 } |
|
400 |
|
401 /* |
|
402 * Initialise l'événement et fait appel aux fonctions du listener quand la main droite quitte le champ. |
|
403 */ |
|
404 public static void OnRightHandQuitEvent(RightHandQuitEventArgs e) |
|
405 { |
|
406 if (RightHandQuitEvent != null) |
|
407 RightHandQuitEvent(new object(), e); |
|
408 } |
|
409 |
|
410 /* |
|
411 * Initialise l'événement et fait appel aux fonctions du listener quand l'utilisateur effectue un swipe right. |
|
412 */ |
|
413 public static void OnSwipeEvent(SwipeEventArgs e) |
|
414 { |
|
415 if (SwipeEvent != null) |
|
416 SwipeEvent(new object(), e); |
|
417 } |
|
418 |
|
419 /* |
|
420 * Initialise l'événement et fait appel aux fonctions du listener quand l'utilisateur effectue un swipe up. |
|
421 */ |
|
422 /*public static void OnSwipeUpEvent(SwipeUpEventArgs e) |
|
423 { |
|
424 if (SwipeUpEvent != null) |
|
425 SwipeUpEvent(new object(), e); |
|
426 }*/ |
|
427 |
|
428 /* |
|
429 * Initialise l'événement et fait appel aux fonctions du listener quand l'utilisateur effectue un swipe down. |
|
430 */ |
|
431 /*public static void OnSwipeDownEvent(SwipeDownEventArgs e) |
|
432 { |
|
433 if (SwipeDownEvent != null) |
|
434 SwipeDownEvent(new object(), e); |
|
435 }*/ |
|
436 |
|
437 /* |
|
438 * Méthode de chargement des paramètres (position du champ de recherche...). |
|
439 */ |
|
440 public bool loadParameters() |
|
441 { |
|
442 try |
|
443 { |
|
444 minDistHands = float.Parse(ConfigurationManager.AppSettings["searchMinDistance"]); |
|
445 maxDistHands = float.Parse(ConfigurationManager.AppSettings["searchMaxDistance"]); |
|
446 } |
|
447 catch (Exception) |
|
448 { |
|
449 return false; |
|
450 } |
|
451 |
|
452 return true; |
|
453 } |
|
454 } |
|
455 } |