Fawkes API  Fawkes Development Version
usertracker_thread.cpp
1 
2 /***************************************************************************
3  * usertracker_thread.cpp - OpenNI user tracker thread
4  *
5  * Created: Sun Feb 27 17:53:38 2011
6  * Copyright 2006-2011 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "usertracker_thread.h"
24 #include "utils/setup.h"
25 
26 #include <core/threading/mutex_locker.h>
27 #include <interfaces/HumanSkeletonInterface.h>
28 #include <interfaces/HumanSkeletonProjectionInterface.h>
29 #include <fvutils/ipc/shm_image.h>
30 
31 #include <memory>
32 
33 using namespace fawkes;
34 using namespace firevision;
35 
36 /** @class OpenNiUserTrackerThread "usertracker_thread.h"
37  * OpenNI User Tracker Thread.
38  * This thread requests a user tracker node from OpenNI and publishes the
39  * retrieved information via the blackboard.
40  *
41  * @author Tim Niemueller
42  */
43 
44 /** Constructor. */
46  : Thread("OpenNiUserTrackerThread", Thread::OPMODE_WAITFORWAKEUP),
47  BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_SENSOR_PROCESS)
48 {
49 }
50 
51 
52 /** Destructor. */
54 {
55 }
56 
57 
58 static void XN_CALLBACK_TYPE
59 cb_new_user(xn::UserGenerator &generator, XnUserID id, void *cookie)
60 {
61  OpenNiUserTrackerThread *t = static_cast<OpenNiUserTrackerThread *>(cookie);
62  t->new_user(id);
63 }
64 
65 static void XN_CALLBACK_TYPE
66 cb_lost_user(xn::UserGenerator &generator, XnUserID id, void *cookie)
67 {
68  OpenNiUserTrackerThread *t = static_cast<OpenNiUserTrackerThread *>(cookie);
69  t->lost_user(id);
70 }
71 
72 static void XN_CALLBACK_TYPE
73 cb_pose_start(xn::PoseDetectionCapability &capability,
74  const XnChar *pose_name, XnUserID id, void* cookie)
75 {
76  OpenNiUserTrackerThread *t = static_cast<OpenNiUserTrackerThread *>(cookie);
77  t->pose_start(id, pose_name);
78 }
79 
80 static void XN_CALLBACK_TYPE
81 cb_pose_end(xn::PoseDetectionCapability &capability,
82  const XnChar *pose_name, XnUserID id, void* cookie)
83 {
84  OpenNiUserTrackerThread *t = static_cast<OpenNiUserTrackerThread *>(cookie);
85  t->pose_end(id, pose_name);
86 }
87 
88 static void XN_CALLBACK_TYPE
89 cb_calibration_start(xn::SkeletonCapability &capability, XnUserID id, void *cookie)
90 {
91  OpenNiUserTrackerThread *t = static_cast<OpenNiUserTrackerThread *>(cookie);
92  t->calibration_start(id);
93 }
94 
95 #if XN_VERSION_GE(1,3,2,0)
96 static void XN_CALLBACK_TYPE
97 cb_calibration_complete(xn::SkeletonCapability &capability, XnUserID id,
98  XnCalibrationStatus status, void *cookie)
99 {
100  OpenNiUserTrackerThread *t = static_cast<OpenNiUserTrackerThread *>(cookie);
101  t->calibration_end(id, status == XN_CALIBRATION_STATUS_OK);
102 }
103 #else
104 static void XN_CALLBACK_TYPE
105 cb_calibration_end(xn::SkeletonCapability &capability, XnUserID id,
106  XnBool success, void *cookie)
107 {
108  OpenNiUserTrackerThread *t = static_cast<OpenNiUserTrackerThread *>(cookie);
109  t->calibration_end(id, success);
110 }
111 #endif
112 
113 
114 void
116 {
118 
119  __user_gen = new xn::UserGenerator();
120  std::auto_ptr<xn::UserGenerator> usergen_autoptr(__user_gen);
121 
122  __depth_gen = new xn::DepthGenerator();
123  std::auto_ptr<xn::DepthGenerator> depthgen_autoptr(__depth_gen);
124 
125  XnStatus st;
126 
127  fawkes::openni::find_or_create_node(openni, XN_NODE_TYPE_DEPTH, __depth_gen);
128  fawkes::openni::setup_map_generator(*__depth_gen, config);
129  fawkes::openni::find_or_create_node(openni, XN_NODE_TYPE_USER, __user_gen);
130 
131  if (!__user_gen->IsCapabilitySupported(XN_CAPABILITY_SKELETON)) {
132  throw Exception("User generator does not support skeleton capability");
133  }
134 
135  __scene_md = new xn::SceneMetaData();
136  std::auto_ptr<xn::SceneMetaData> scenemd_autoptr(__scene_md);
137  if ((st = __user_gen->GetUserPixels(0, *__scene_md)) != XN_STATUS_OK) {
138  throw Exception("Failed to get scene meta data (%s)", xnGetStatusString(st));
139  }
140 
141  st = __user_gen->RegisterUserCallbacks(cb_new_user, cb_lost_user,
142  this, __user_cb_handle);
143  if (st != XN_STATUS_OK) {
144  throw Exception("Failed to register user callbacks (%s)",
145  xnGetStatusString(st));
146  }
147 
148  __skelcap = new xn::SkeletonCapability(__user_gen->GetSkeletonCap());
149 
150 #if XN_VERSION_GE(1,3,2,0)
151  st = __skelcap->RegisterToCalibrationStart(cb_calibration_start,
152  this, __calib_start_cb_handle);
153  if (st != XN_STATUS_OK) {
154  throw Exception("Failed to register calibration start event (%s)",
155  xnGetStatusString(st));
156  }
157  st = __skelcap->RegisterToCalibrationComplete(cb_calibration_complete,
158  this, __calib_complete_cb_handle);
159 #else
160  st = __skelcap->RegisterCalibrationCallbacks(cb_calibration_start,
161  cb_calibration_end,
162  this, __calib_cb_handle);
163 #endif
164 
165  if (st != XN_STATUS_OK) {
166  throw Exception("Failed to register calibration callback (%s)",
167  xnGetStatusString(st));
168  }
169 
170  __skel_need_calib_pose = __skelcap->NeedPoseForCalibration();
171 
172  if (__skel_need_calib_pose) {
173  if (! __user_gen->IsCapabilitySupported(XN_CAPABILITY_POSE_DETECTION)) {
174  throw Exception("Calibration requires pose, but not supported by node");
175  }
176  __skelcap->GetCalibrationPose(__calib_pose_name);
177 
178  xn::PoseDetectionCapability posecap = __user_gen->GetPoseDetectionCap();
179 
180 #if XN_VERSION_GE(1,3,2,0)
181  st = posecap.RegisterToPoseDetected(cb_pose_start,
182  this, __pose_start_cb_handle);
183  if (st != XN_STATUS_OK) {
184  throw Exception("Failed to register pose detect event (%s)",
185  xnGetStatusString(st));
186  }
187  st = posecap.RegisterToOutOfPose(cb_pose_end,
188  this, __pose_end_cb_handle);
189 #else
190  st = posecap.RegisterToPoseCallbacks(cb_pose_start, cb_pose_end,
191  this, __pose_cb_handle);
192 #endif
193  if (st != XN_STATUS_OK) {
194  throw Exception("Failed to register pose callbacks (%s)", xnGetStatusString(st));
195  }
196  }
197 
198  __skelcap->SetSkeletonProfile(XN_SKEL_PROFILE_ALL);
199 
200  __depth_gen->StartGenerating();
201  __user_gen->StartGenerating();
202 
203  __label_buf = new SharedMemoryImageBuffer("openni-labels", RAW16,
204  __scene_md->XRes(),
205  __scene_md->YRes());
206  __label_bufsize = colorspace_buffer_size(RAW16,
207  __scene_md->XRes(), __scene_md->YRes());
208 
209  usergen_autoptr.release();
210  depthgen_autoptr.release();
211  scenemd_autoptr.release();
212 }
213 
214 
215 void
217 {
218  // we do not stop generating, we don't know if there is no other plugin
219  // using the node.
220  delete __user_gen;
221  delete __scene_md;
222  delete __skelcap;
223  delete __label_buf;
224 
225  UserMap::iterator i;
226  for (i = __users.begin(); i != __users.end(); ++i) {
227  blackboard->close(i->second.skel_if);
228  blackboard->close(i->second.proj_if);
229  }
230 }
231 
232 
233 void
235 {
236  // we do not lock here, we are only operating on our user generator copy
237  // and the update happens in a different main loop hook
238 
239  if (! __user_gen->IsDataNew()) return;
240 
241  UserMap::iterator i;
242  for (i = __users.begin(); i != __users.end(); ++i) {
243 
244  if (!i->second.valid) continue;
245 
246  bool needs_write = false;
247 
248  HumanSkeletonInterface::State new_state = i->second.skel_if->state();
249  if (__skelcap->IsTracking(i->first)) {
250  new_state = HumanSkeletonInterface::STATE_TRACKING;
251  } else if (__skelcap->IsCalibrating(i->first)) {
252  new_state = HumanSkeletonInterface::STATE_CALIBRATING;
253  } else {
254  new_state = HumanSkeletonInterface::STATE_DETECTING_POSE;
255  }
256 
257  if (new_state != i->second.skel_if->state()) {
258  i->second.skel_if->set_state(new_state);
259  needs_write = true;
260  }
261 
262  if (new_state == HumanSkeletonInterface::STATE_TRACKING) {
263  // update skeleton information
264  try {
265  update_user(i->first, i->second);
266  update_com(i->first, i->second);
267  needs_write = true;
268  } catch (Exception &e) {
269  logger->log_warn(name(), "Failed to update skeleton data for %u, "
270  "exception follows", i->first);
271  logger->log_warn(name(), e);
272  }
273  } else if (new_state == HumanSkeletonInterface::STATE_DETECTING_POSE) {
274  update_com(i->first, i->second);
275  needs_write = true;
276  } else if (new_state == HumanSkeletonInterface::STATE_CALIBRATING) {
277  update_com(i->first, i->second);
278  needs_write = true;
279  }
280 
281  if (needs_write) {
282  i->second.skel_if->write();
283  i->second.proj_if->write();
284  }
285  }
286 
287  if (__label_buf->num_attached() > 1) {
288  memcpy(__label_buf->buffer(), __scene_md->Data(), __label_bufsize);
289  }
290 
291 }
292 
293 
294 
295 
296 // Very noisy when added to st != XN_STATUS_OK case
297 //logger->log_warn(name(), "Failed to get joint transformation for "
298 // "%s joint (%s)",
299 // joint_name, xnGetStatusString(st));
300 
301 
302 // change from mm to m
303 // translating to Fawkes coordinates, empirically verified
304 // permute ori columns to match our coordinate system, empirically verified
305 #define SET_JTF(id, joint, joint_name, bbfield) \
306  st = __skelcap->GetSkeletonJoint(id, joint, jtf); \
307  if (st != XN_STATUS_OK) { \
308  ori[0] = ori[1] = ori[2] = ori[3] = ori[4] = ori[5] = 0.; \
309  ori[6] = ori[7] = ori[8] = ori_confidence = pos_confidence = 0.; \
310  proj[0] = proj[1] = 0; \
311  } else { \
312  pos[0] = jtf.position.position.Z * 0.001; \
313  pos[1] = -jtf.position.position.X * 0.001; \
314  pos[2] = jtf.position.position.Y * 0.001; \
315  pos_confidence = jtf.position.fConfidence; \
316  \
317  ori[0] = jtf.orientation.orientation.elements[2]; \
318  ori[1] = -jtf.orientation.orientation.elements[0]; \
319  ori[2] = jtf.orientation.orientation.elements[1]; \
320  ori[3] = jtf.orientation.orientation.elements[5]; \
321  ori[4] = -jtf.orientation.orientation.elements[3]; \
322  ori[5] = jtf.orientation.orientation.elements[4]; \
323  ori[6] = jtf.orientation.orientation.elements[8]; \
324  ori[7] = -jtf.orientation.orientation.elements[6]; \
325  ori[8] = jtf.orientation.orientation.elements[7]; \
326  ori_confidence = jtf.orientation.fConfidence; \
327  \
328  XnPoint3D pt; \
329  pt = jtf.position.position; \
330  __depth_gen->ConvertRealWorldToProjective(1, &pt, &pt); \
331  proj[0] = pt.X; \
332  proj[1] = pt.Y; \
333  } \
334  user.skel_if->set_pos_##bbfield(pos); \
335  user.skel_if->set_pos_##bbfield##_confidence(pos_confidence); \
336  user.skel_if->set_ori_##bbfield(ori); \
337  user.skel_if->set_ori_##bbfield##_confidence(ori_confidence); \
338  \
339  user.proj_if->set_proj_##bbfield(proj);
340 
341 
342 
343 void
344 OpenNiUserTrackerThread::update_user(XnUserID id, UserInfo &user)
345 {
346  XnSkeletonJointTransformation jtf;
347  XnStatus st;
348 
349  float pos[3], ori[9], proj[2], pos_confidence, ori_confidence;
350 
351  SET_JTF(id, XN_SKEL_HEAD, "head", head);
352  SET_JTF(id, XN_SKEL_NECK, "neck", neck);
353  SET_JTF(id, XN_SKEL_TORSO, "torso", torso);
354  SET_JTF(id, XN_SKEL_WAIST, "waist", waist);
355  SET_JTF(id, XN_SKEL_LEFT_COLLAR, "left collar", left_collar);
356  SET_JTF(id, XN_SKEL_LEFT_SHOULDER, "left shoulder", left_shoulder);
357  SET_JTF(id, XN_SKEL_LEFT_ELBOW, "left elbow", left_elbow);
358  SET_JTF(id, XN_SKEL_LEFT_WRIST, "left wrist", left_wrist);
359  SET_JTF(id, XN_SKEL_LEFT_HAND, "left hand", left_hand);
360  SET_JTF(id, XN_SKEL_LEFT_FINGERTIP, "left finger tip", left_fingertip);
361  SET_JTF(id, XN_SKEL_RIGHT_COLLAR, "right collar", right_collar);
362  SET_JTF(id, XN_SKEL_RIGHT_SHOULDER, "right shoulder", right_shoulder);
363  SET_JTF(id, XN_SKEL_RIGHT_ELBOW, "right elbow", right_elbow);
364  SET_JTF(id, XN_SKEL_RIGHT_WRIST, "right wrist", right_wrist);
365  SET_JTF(id, XN_SKEL_RIGHT_HAND, "right hand", right_hand);
366  SET_JTF(id, XN_SKEL_RIGHT_FINGERTIP, "right finger tip", right_fingertip);
367  SET_JTF(id, XN_SKEL_LEFT_HIP, "left hip", left_hip);
368  SET_JTF(id, XN_SKEL_LEFT_KNEE, "left knee", left_knee);
369  SET_JTF(id, XN_SKEL_LEFT_ANKLE, "left ankle", left_ankle);
370  SET_JTF(id, XN_SKEL_LEFT_FOOT, "left foot", left_foot);
371  SET_JTF(id, XN_SKEL_RIGHT_HIP, "right hip", right_hip);
372  SET_JTF(id, XN_SKEL_RIGHT_KNEE, "right knee", right_knee);
373  SET_JTF(id, XN_SKEL_RIGHT_ANKLE, "right ankle", right_ankle);
374  SET_JTF(id, XN_SKEL_RIGHT_FOOT, "right foot", right_foot);
375 
376 }
377 
378 
379 void
380 OpenNiUserTrackerThread::update_com(XnUserID id, UserInfo &user)
381 {
382  XnPoint3D compt, compt_proj;
383  XnStatus st;
384  float com[3], com_proj[2];
385  com[0] = com[1] = com[2] = com_proj[0] = com_proj[1] = 0.;
386  if ((st = __user_gen->GetCoM(id, compt)) == XN_STATUS_OK) {
387 
388  // translating to Fawkes coordinates, empirically verified
389  com[0] = compt.Z * 0.001;
390  com[1] = -compt.X * 0.001;
391  com[2] = compt.Y * 0.001;
392 
393  __depth_gen->ConvertRealWorldToProjective(1, &compt, &compt_proj);
394  com_proj[0] = compt_proj.X;
395  com_proj[1] = compt_proj.Y;
396  } else {
397  logger->log_warn(name(), "GetCoM failed: %s", xnGetStatusString(st));
398  }
399 
400  user.skel_if->set_com(com);
401  user.proj_if->set_proj_com(com_proj);
402 
403  int current_vishist = user.skel_if->visibility_history();
404  if ((com[0] == 0.) && (com[1] == 0.) && (com[2] == 0.)) {
405  if (current_vishist < 0) {
406  user.skel_if->set_visibility_history(--current_vishist);
407  } else {
408  user.skel_if->set_visibility_history(-1);
409  }
410  } else {
411  if (current_vishist > 0) {
412  user.skel_if->set_visibility_history(++current_vishist);
413  } else {
414  user.skel_if->set_visibility_history(1);
415  }
416  }
417 }
418 
419 /** Notify of new user.
420  * This is called by the OpenNI callback when a new user has been detected.
421  * @param id new user's ID
422  */
423 void
425 {
426  if (__users.find(id) != __users.end()) {
427  logger->log_error(name(), "New user ID %u, interface already exists", id);
428  } else {
429  char *ifid;
430  if (asprintf(&ifid, "OpenNI Human %u", id) == -1) {
431  logger->log_warn(name(), "New user ID %u, but cannot generate "
432  "interface ID", id);
433  return;
434  }
435  try {
436  logger->log_debug(name(), "Opening interface 'HumanSkeletonInterface::%s'", ifid);
437  __users[id].skel_if = blackboard->open_for_writing<HumanSkeletonInterface>(ifid);
438  __users[id].skel_if->set_user_id(id);
439  __users[id].skel_if->write();
440  } catch (Exception &e) {
441  logger->log_warn(name(), "Failed to open interface, exception follows");
442  logger->log_warn(name(), e);
443  }
444 
445  try {
446  logger->log_debug(name(), "Opening interface 'HumanSkeletonProjectionInterface::%s'", ifid);
447  __users[id].proj_if = blackboard->open_for_writing<HumanSkeletonProjectionInterface>(ifid);
448  XnFieldOfView fov;
449  XnStatus st;
450  if ((st = __depth_gen->GetFieldOfView(fov)) != XN_STATUS_OK) {
451  logger->log_error(name(), "Failed to get field of view, ignoring. (%s)",
452  xnGetStatusString(st));
453  } else {
454  __users[id].proj_if->set_horizontal_fov(fov.fHFOV);
455  __users[id].proj_if->set_vertical_fov(fov.fVFOV);
456  }
457 
458  xn::DepthMetaData dmd;
459  __depth_gen->GetMetaData(dmd);
460  __users[id].proj_if->set_res_x(dmd.XRes());
461  __users[id].proj_if->set_res_y(dmd.YRes());
462  __users[id].proj_if->set_max_depth(__depth_gen->GetDeviceMaxDepth());
463  __users[id].proj_if->write();
464  } catch (Exception &e) {
465  blackboard->close(__users[id].proj_if);
466  __users.erase(id);
467  logger->log_warn(name(), "Failed to open interface, exception follows");
468  logger->log_warn(name(), e);
469  }
470 
471  free(ifid);
472  }
473 
474  __users[id].valid = true;
475 
476  if (__skel_need_calib_pose) {
477  __user_gen->GetPoseDetectionCap().StartPoseDetection(__calib_pose_name, id);
478  } else {
479  __user_gen->GetSkeletonCap().RequestCalibration(id, TRUE);
480  }
481 }
482 
483 
484 /** Notify of lost user.
485  * This is called by the OpenNI callback when a user has been lost,
486  * i.e. it has not been visible for some time.
487  * @param id lost user's ID
488  */
489 void
491 {
492  if (__users.find(id) == __users.end()) {
493  logger->log_error(name(), "Lost user ID %u, but interface does not exist", id);
494  return;
495  }
496 
497  logger->log_error(name(), "Lost user ID %u, setting interface '%s' to invalid",
498  id, __users[id].skel_if->uid());
499  // write invalid, a reader might still be open
500  __users[id].skel_if->set_state(HumanSkeletonInterface::STATE_INVALID);
501  __users[id].skel_if->write();
502  __users[id].valid = false;
503  //blackboard->close(__users[id].skel_if);
504  //blackboard->close(__users[id].proj_if);
505  //__users.erase(id);
506 }
507 
508 
509 /** Notify of detected pose.
510  * This is called if a pose has been detected.
511  * @param id ID of user who is in the pose
512  * @param pose_name name of the detected pose
513  */
514 void
515 OpenNiUserTrackerThread::pose_start(XnUserID id, const char *pose_name)
516 {
517  if (__users.find(id) == __users.end()) {
518  logger->log_error(name(), "Pose start for user ID %u, "
519  "but interface does not exist", id);
520  return;
521  }
522 
523  logger->log_info(name(), "Pose %s detected for user %u", pose_name, id);
524 
525  __users[id].skel_if->set_pose(pose_name);
526  __user_gen->GetPoseDetectionCap().StopPoseDetection(id);
527  __user_gen->GetSkeletonCap().RequestCalibration(id, TRUE);
528 }
529 
530 /** Notify of pose detection end.
531  * This is called if a pose is no longer detected. The NITE middleware seems
532  * not to call this.
533  * @param id ID of user who is in the pose
534  * @param pose_name name of the no longer detected pose
535  */
536 void
537 OpenNiUserTrackerThread::pose_end(XnUserID id, const char *pose_name)
538 {
539  if (__users.find(id) == __users.end()) {
540  logger->log_error(name(), "Pose end for user ID %u, "
541  "but interface does not exist", id);
542  return;
543  }
544 
545  __users[id].skel_if->set_pose("");
546 }
547 
548 /** Notify of calibration start.
549  * This is called when tracking for a user has been started.
550  * @param id ID of user who is being calibrated.
551  */
552 void
554 {
555  if (__users.find(id) == __users.end()) {
556  logger->log_error(name(), "Pose end for user ID %u, "
557  "but interface does not exist", id);
558  return;
559  }
560 
561  logger->log_info(name(), "Calibration started for user %u", id);
562 }
563 
564 
565 /** Notify of calibration end.
566  * This is called when tracking for a user has finished.
567  * @param id ID of user who was being calibrated
568  * @param success true if the calibration was successful, false otherwise
569  */
570 void
572 {
573  if (__users.find(id) == __users.end()) {
574  logger->log_error(name(), "Pose end for user ID %u, "
575  "but interface does not exist", id);
576  return;
577  }
578 
579  __users[id].skel_if->set_pose("");
580 
581  if (success) {
582  logger->log_info(name(), "Calibration successful for user %u, "
583  "starting tracking", id);
584  __user_gen->GetSkeletonCap().StartTracking(id);
585  } else {
586  logger->log_info(name(), "Calibration failed for user %u, restarting", id);
587  if (__skel_need_calib_pose) {
588  __user_gen->GetPoseDetectionCap().StartPoseDetection(__calib_pose_name, id);
589  } else {
590  __user_gen->GetSkeletonCap().RequestCalibration(id, TRUE);
591  }
592  }
593 }
LockPtr< xn::Context > openni
Central OpenNI context.
Definition: openni.h:48
HumanSkeletonProjectionInterface Fawkes BlackBoard Interface.
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
virtual ~OpenNiUserTrackerThread()
Destructor.
void new_user(XnUserID id)
Notify of new user.
Fawkes library namespace.
Mutex * objmutex_ptr() const
Get object mutex.
Definition: lockptr.h:240
Mutex locking helper.
Definition: mutex_locker.h:33
Thread class encapsulation of pthreads.
Definition: thread.h:42
void calibration_end(XnUserID id, bool success)
Notify of calibration end.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:44
virtual Interface * open_for_writing(const char *interface_type, const char *identifier)=0
Open interface for writing.
void pose_end(XnUserID id, const char *pose_name)
Notify of pose detection end.
virtual void init()
Initialize the thread.
State
Current tracking state for the skeleton.
Thread aspect to use blocked timing.
virtual void finalize()
Finalize the thread.
Base class for exceptions in Fawkes.
Definition: exception.h:36
OpenNiUserTrackerThread()
Constructor.
Shared memory image buffer.
Definition: shm_image.h:135
unsigned char * buffer() const
Get image buffer.
Definition: shm_image.cpp:234
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
virtual void loop()
Code to execute in the thread.
const char * name() const
Get name of thread.
Definition: thread.h:95
void lost_user(XnUserID id)
Notify of lost user.
unsigned int num_attached() const
Get number of attached processes.
Definition: shm.cpp:714
OpenNI User Tracker Thread.
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
HumanSkeletonInterface Fawkes BlackBoard Interface.
void pose_start(XnUserID id, const char *pose_name)
Notify of detected pose.
void calibration_start(XnUserID id)
Notify of calibration start.
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:43
virtual void close(Interface *interface)=0
Close interface.