/* dtkVrTrackerKinect_p.cpp --- * * Author: Julien Wintz * Copyright (C) 2008-2011 - Julien Wintz, Inria. * Created: Wed Apr 25 17:16:28 2012 (+0200) * Version: $Id: 03f302e02758bb771c65e6af9ad9242570b3790f $ * Last-Updated: Wed Apr 25 17:31:45 2012 (+0200) * By: Julien Wintz * Update #: 13 */ /* Commentary: * */ /* Change log: * */ #include "dtkVrTrackerKinect_p.h" #include #include #include #include #include #include #include #include #include #include // ///////////////////////////////////////////////////////////////// // // ///////////////////////////////////////////////////////////////// #define KNCT_CHECK_RC(rc, what) \ if (rc != XN_STATUS_OK) { \ printf("%s failed: %s\n", what, xnGetStatusString(rc)); \ } #define KNCT_CHECK_ERRORS(rc, errors, what) \ if (rc == XN_STATUS_NO_NODE_PRESENT) { \ XnChar strError[1024]; \ errors.ToString(strError, 1024); \ printf("%s\n", strError); \ } // ///////////////////////////////////////////////////////////////// // // ///////////////////////////////////////////////////////////////// class dtkVrTrackerKinectPrivateThread : public QThread { public: enum SessionState { IN_SESSION, NOT_IN_SESSION, QUICK_REFOCUS }; public: void run(void); void stop(void); public: static void XN_CALLBACK_TYPE SessionStarting(const XnPoint3D& ptPosition, void *UserCxt); static void XN_CALLBACK_TYPE SessionEnding(void *UserCxt); static void XN_CALLBACK_TYPE FocusProgress(const XnChar *strFocus, const XnPoint3D& ptPosition, XnFloat fProgress, void *UserCxt); static void XN_CALLBACK_TYPE NewUser(xn::UserGenerator& generator, XnUserID user, void *cookie); static void XN_CALLBACK_TYPE LostUser(xn::UserGenerator& generator, XnUserID user, void *cookie); static void XN_CALLBACK_TYPE CalibrationStarted(xn::SkeletonCapability& skeleton, XnUserID user, void *cxt); static void XN_CALLBACK_TYPE CalibrationEnded(xn::SkeletonCapability& skeleton, XnUserID user, XnBool bSuccess, void *cxt); static void XN_CALLBACK_TYPE PoseDetected(xn::PoseDetectionCapability& pose, const XnChar *strPose, XnUserID user, void *cxt); public: bool assignUser(XnUserID user); void findUser(void); public: xn::Context context; xn::DepthGenerator depth_generator; xn::HandsGenerator hands_generator; xn::UserGenerator users_generator; public: XnVSessionManager *session_manager; XnVFlowRouter *flow_router; public: SessionState session_state; public: XnUserID user_id; public: bool running; bool calibrated; public: static dtkVrTrackerKinectPrivateThread *self; public: dtkVrTrackerKinectPrivate *q; public: // -- head dtkVector3D position; dtkQuaternion orientation; public: // -- right hand dtkVector3D hand_position; }; void dtkVrTrackerKinectPrivateThread::run(void) { while (this->running) { this->context.WaitAndUpdateAll(); this->session_manager->Update(&this->context); if (this->user_id != 0) { // -- head position XnSkeletonJointPosition head_position; this->users_generator.GetSkeletonCap().GetSkeletonJointPosition(this->user_id, XN_SKEL_HEAD, head_position); if (head_position.fConfidence > 0.5) this->position = dtkVector3D(head_position.position.X, head_position.position.Y, head_position.position.Z); // q->emit moved(head_position.position.X/10.0, head_position.position.Y/10.0, head_position.position.Z/10.0 - 100); // -- right hand position XnSkeletonJointPosition hand_position; this->users_generator.GetSkeletonCap().GetSkeletonJointPosition(this->user_id, XN_SKEL_RIGHT_HAND, hand_position); if (hand_position.fConfidence > 0.5) this->hand_position = dtkVector3D(hand_position.position.X, hand_position.position.Y, hand_position.position.Z); // -- head orientation XnSkeletonJointOrientation head_orientation; this->users_generator.GetSkeletonCap().GetSkeletonJointOrientation(this->user_id, XN_SKEL_HEAD, head_orientation); if (head_orientation.fConfidence > 0.5) { dtkMatrixSquared matrix(3); matrix[0][0] = head_orientation.orientation.elements[0]; matrix[0][1] = head_orientation.orientation.elements[3]; matrix[0][2] = head_orientation.orientation.elements[6]; matrix[1][0] = head_orientation.orientation.elements[1]; matrix[1][1] = head_orientation.orientation.elements[4]; matrix[1][2] = head_orientation.orientation.elements[7]; matrix[2][0] = head_orientation.orientation.elements[2]; matrix[2][1] = head_orientation.orientation.elements[5]; matrix[2][2] = head_orientation.orientation.elements[8]; this->orientation = dtkQuaternionFromMatSquared(matrix); } XnPoint3D com; this->users_generator.GetCoM(this->user_id, com); if (com.Z == 0) { this->user_id = 0; this->findUser(); } } this->usleep(100000); } } void dtkVrTrackerKinectPrivateThread::stop(void) { this->running = false; } // ///////////////////////////////////////////////////////////////// void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::SessionStarting(const XnPoint3D& ptPosition, void *UserCxt) { printf("Session start: (%f,%f,%f)\n", ptPosition.X, ptPosition.Y, ptPosition.Z); self->session_state = IN_SESSION; } void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::SessionEnding(void *UserCxt) { printf("Session end\n"); self->session_state = NOT_IN_SESSION; } void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::FocusProgress(const XnChar *strFocus, const XnPoint3D& ptPosition, XnFloat fProgress, void *UserCxt) { printf("Focus progress: %s @(%f,%f,%f): %f\n", strFocus, ptPosition.X, ptPosition.Y, ptPosition.Z, fProgress); } // ///////////////////////////////////////////////////////////////// void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::NewUser(xn::UserGenerator& generator, XnUserID user, void *cookie) { if (!self->calibrated) { printf("Look for pose\n"); self->users_generator.GetPoseDetectionCap().StartPoseDetection("Psi", user); return; } self->assignUser(user); } void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::LostUser(xn::UserGenerator& generator, XnUserID user, void *cookie) { printf("Lost user %d\n", user); if (self->user_id == user) { self->user_id = 0; self->findUser(); } } void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::CalibrationStarted(xn::SkeletonCapability& skeleton, XnUserID user, void *cxt) { qDebug() << Q_FUNC_INFO; } void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::CalibrationEnded(xn::SkeletonCapability& skeleton, XnUserID user, XnBool bSuccess, void *cxt) { printf("Calibration done [%d] %ssuccessfully\n", user, bSuccess ? "" : "un"); if (bSuccess) { if (!self->calibrated) { self->users_generator.GetSkeletonCap().SaveCalibrationData(user, 0); self->user_id = user; self->users_generator.GetSkeletonCap().StartTracking(user); self->calibrated = true; } XnUserID aUsers[10]; XnUInt16 nUsers = 10; self->users_generator.GetUsers(aUsers, nUsers); for (int i = 0; i < nUsers; ++i) self->users_generator.GetPoseDetectionCap().StopPoseDetection(aUsers[i]); } } void XN_CALLBACK_TYPE dtkVrTrackerKinectPrivateThread::PoseDetected(xn::PoseDetectionCapability& pose, const XnChar *strPose, XnUserID user, void *cxt) { printf("Found pose \"%s\" for user %d\n", strPose, user); self->users_generator.GetSkeletonCap().RequestCalibration(user, true); self->users_generator.GetPoseDetectionCap().StopPoseDetection(user); } // ///////////////////////////////////////////////////////////////// bool dtkVrTrackerKinectPrivateThread::assignUser(XnUserID user) { qDebug << Q_FUNC_INFO; if (this->user_id) return false; XnPoint3D com; this->users_generator.GetCoM(user, com); if (com.Z == 0) return false; printf("Matching for existing calibration\n"); this->users_generator.GetSkeletonCap().LoadCalibrationData(user, 0); this->users_generator.GetSkeletonCap().StartTracking(user); this->user_id = user; return true; } void dtkVrTrackerKinectPrivateThread::findUser(void) { qDebug() << Q_FUNC_INFO; if (this->user_id != 0) return; XnUserID aUsers[20]; XnUInt16 nUsers = 20; this->users_generator.GetUsers(aUsers, nUsers); for (int i = 0; i < nUsers; ++i) if (this->assignUser(aUsers[i])) return; } // ///////////////////////////////////////////////////////////////// dtkVrTrackerKinectPrivateThread *dtkVrTrackerKinectPrivateThread::self = NULL; // ///////////////////////////////////////////////////////////////// // // ///////////////////////////////////////////////////////////////// dtkVrTrackerKinectPrivate::dtkVrTrackerKinectPrivate(void) : QObject(), d(new dtkVrTrackerKinectPrivateThread) { d->flow_router = NULL; d->user_id = 0; d->running = false; d->calibrated = false; d->q = this; d->self = d; } dtkVrTrackerKinectPrivate::~dtkVrTrackerKinectPrivate(void) { delete d; d = NULL; } void *dtkVrTrackerKinectPrivate::depthGenerator(void) { return &(d->depth_generator); } void *dtkVrTrackerKinectPrivate::handsGenerator(void) { return &(d->hands_generator); } void *dtkVrTrackerKinectPrivate::usersGenerator(void) { return &(d->users_generator); } void dtkVrTrackerKinectPrivate::initialize(void) { XnStatus rc = XN_STATUS_OK; xn::EnumerationErrors errors; rc = d->context.InitFromXmlFile(DTKVRTRACKERKINECT_XML_PATH, &errors); KNCT_CHECK_ERRORS(rc, errors, "InitFromXmlFile"); KNCT_CHECK_RC(rc, "InitFromXmlFile"); rc = d->context.FindExistingNode(XN_NODE_TYPE_DEPTH, d->depth_generator); KNCT_CHECK_RC(rc, "Find depth generator"); rc = d->context.FindExistingNode(XN_NODE_TYPE_HANDS, d->hands_generator); KNCT_CHECK_RC(rc, "Find hands generator"); rc = d->context.FindExistingNode(XN_NODE_TYPE_USER, d->users_generator); KNCT_CHECK_RC(rc, "Find user generator"); if (!d->users_generator.IsCapabilitySupported(XN_CAPABILITY_SKELETON) || !d->users_generator.IsCapabilitySupported(XN_CAPABILITY_POSE_DETECTION)) { printf("User generator doesn't support either skeleton or pose detection.\n"); } d->users_generator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL); d->session_manager = new XnVSessionManager; rc = d->session_manager->Initialize(&d->context, "Click,Wave", "RaiseHand"); KNCT_CHECK_RC(rc, "SessionManager::Initialize"); d->session_manager->RegisterSession(NULL, dtkVrTrackerKinectPrivateThread::SessionStarting, dtkVrTrackerKinectPrivateThread::SessionEnding, dtkVrTrackerKinectPrivateThread::FocusProgress); d->flow_router = new XnVFlowRouter; d->session_manager->AddListener(d->flow_router); rc = d->context.StartGeneratingAll(); KNCT_CHECK_RC(rc, "StartGenerating"); XnCallbackHandle handle_user_callbacks; XnCallbackHandle handle_calibration_callbacks; XnCallbackHandle handle_pose_callbacks; d->users_generator.RegisterUserCallbacks( dtkVrTrackerKinectPrivateThread::NewUser, dtkVrTrackerKinectPrivateThread::LostUser, NULL, handle_user_callbacks); d->users_generator.GetSkeletonCap().RegisterCalibrationCallbacks( dtkVrTrackerKinectPrivateThread::CalibrationStarted, dtkVrTrackerKinectPrivateThread::CalibrationEnded, NULL, handle_calibration_callbacks); d->users_generator.GetPoseDetectionCap().RegisterToPoseCallbacks( dtkVrTrackerKinectPrivateThread::PoseDetected, NULL, NULL, handle_pose_callbacks); d->running = true; d->start(); } void dtkVrTrackerKinectPrivate::uninitialize(void) { d->stop(); } void dtkVrTrackerKinectPrivate::rotate(int angle) { XN_USB_DEV_HANDLE m_dev; open: const XnUSBConnectionString *paths; XnUInt32 count; XnStatus res; res = xnUSBEnumerateDevices(0x045E /* VendorID */, 0x02B0 /*ProductID*/, &paths, &count); if (res != XN_STATUS_OK) { xnPrintError(res, "xnUSBEnumerateDevices failed"); } res = xnUSBOpenDeviceByPath(paths[0], &m_dev); if (res != XN_STATUS_OK) { xnPrintError(res, "xnUSBOpenDeviceByPath failed"); } res = xnUSBSendControl(m_dev, XN_USB_CONTROL_TYPE_VENDOR, 0x06, 0x01, 0x00, NULL, 0, 0); if (res != XN_STATUS_OK) { xnPrintError(res, "xnUSBSendControl 2 failed"); goto close; } rotate: res = xnUSBSendControl(m_dev, XN_USB_CONTROL_TYPE_VENDOR, 0x31, angle, 0x00, NULL, 0, 0); if (res != XN_STATUS_OK) { xnPrintError(res, "xnUSBSendControl failed"); } close: xnUSBCloseDevice(m_dev); } void dtkVrTrackerKinectPrivate::setActive(void *listener) { if (d->flow_router) d->flow_router->SetActive(static_cast(listener)); } dtkVector3D dtkVrTrackerKinectPrivate::hand(void) { return d->hand_position; } dtkVector3D dtkVrTrackerKinectPrivate::position(void) { return d->position; } dtkQuaternion dtkVrTrackerKinectPrivate::orientation(void) { return d->orientation; }