00001
00002 #include <ros/ros.h>
00003 #include <ros/package.h>
00004 #include <std_msgs/UInt8.h>
00005 #include <tf/transform_broadcaster.h>
00006
00007 #include <XnOpenNI.h>
00008 #include <XnCppWrapper.h>
00009 #include <XnHash.h>
00010 #include <XnLog.h>
00011
00012
00013 #include <XnVNite.h>
00014 #include <XnVPointControl.h>
00015 using std::string;
00016 xn::Context g_Context;
00017 xn::DepthGenerator g_DepthGenerator;
00018 xn::HandsGenerator g_HandsGenerator;
00019
00020
00021 XnVSessionManager *g_pSessionManager;
00022 XnVFlowRouter *g_pFlowRouter;
00023
00024
00025 ros::Publisher hand_point_pub_;
00026 ros::Publisher hand_point_status_pub_;
00027
00028 typedef enum
00029 {
00030 IN_SESSION,
00031 NOT_IN_SESSION,
00032 QUICK_REFOCUS
00033 } SessionState;
00034
00035 #define CHECK_RC(nRetVal, what) \
00036 if (nRetVal != XN_STATUS_OK){ \
00037 printf ("%s failed: %s\n", what, xnGetStatusString (nRetVal)); \
00038 return nRetVal; \
00039 }
00040
00041 SessionState g_SessionState = NOT_IN_SESSION;
00042
00043
00044 void XN_CALLBACK_TYPE FocusProgress (const XnChar * strFocus, const XnPoint3D & ptPosition, XnFloat fProgress,
00045 void *UserCxt)
00046 {
00047
00048 }
00049
00050
00051 void XN_CALLBACK_TYPE SessionStarting (const XnPoint3D & ptPosition, void *UserCxt)
00052 {
00053 printf ("Session start: (%f,%f,%f)\n", ptPosition.X, ptPosition.Y, ptPosition.Z);
00054 g_SessionState = IN_SESSION;
00055 }
00056
00057
00058 void XN_CALLBACK_TYPE SessionEnding (void *UserCxt)
00059 {
00060 printf ("Session end\n");
00061 g_SessionState = NOT_IN_SESSION;
00062 }
00063
00064 void XN_CALLBACK_TYPE NoHands (void *UserCxt)
00065 {
00066 printf ("Quick refocus\n");
00067 g_SessionState = QUICK_REFOCUS;
00068 }
00069
00070 class XnVPointPublisher : public XnVPointControl
00071 {
00072 public:
00073 XnVPointPublisher(xn::DepthGenerator depthGenerator): XnVPointControl("XnVPointPublisher"), m_DepthGenerator(depthGenerator)
00074 {
00075 }
00076
00077 virtual ~XnVPointPublisher()
00078 {
00079 std::map<XnUInt32, std::vector<XnPoint3D> >::iterator iter;
00080 for (iter = m_Position.begin(); iter != m_Position.end(); ++iter)
00081 {
00082 iter->second.clear();
00083 }
00084 m_Position.clear();
00085 }
00086
00090 void OnPointCreate(const XnVHandPointContext* cxt)
00091 {
00092 printf("** %d\n", cxt->nID);
00093 m_Position[cxt->nID].resize(2);
00094 OnPointUpdate(cxt);
00095 }
00096
00097
00098 void OnPointDestroy(XnUInt32 nID)
00099 {
00100
00101 m_Position.erase(nID);
00102 }
00106 void OnPointUpdate(const XnVHandPointContext* cxt)
00107 {
00108
00109 XnPoint3D ptPosition(cxt->ptPosition);
00110 XnPoint3D ptProjective(cxt->ptPosition);
00111 m_DepthGenerator.ConvertRealWorldToProjective(1, &ptProjective, &ptProjective);
00112 printf ("%d (%f,%f,%f) ", cxt->nID, cxt->ptPosition.X, cxt->ptPosition.Y, cxt->ptPosition.Z);
00113 printf (" -> (%f,%f,%f)\n", ptProjective.X, ptProjective.Y, ptProjective.Z);
00114
00115
00116 m_Position[cxt->nID][0]=ptPosition;
00117 m_Position[cxt->nID][1]=ptProjective;
00118 }
00119
00120
00125 void Update(XnVMessage* pMessage) {
00126
00127 XnVPointControl::Update(pMessage);
00128
00129 string frame_id("openni_depth_frame");
00130 string child_frame_id("hand_position");
00131
00132
00133 if ( m_Position.size() > 0 ) {
00134 XnUInt32 Id = m_Position.begin()->first;
00135 XnPoint3D Position = m_Position.begin()->second[0];
00136 XnPoint3D Projection = m_Position.begin()->second[1];
00137
00138 static tf::TransformBroadcaster br;
00139 tf::Transform transform;
00140 transform.setOrigin(tf::Vector3(Position.X/1000.0, Position.Y/1000.0, Position.Z/1000.0));
00141 transform.setRotation(tf::Quaternion(0,0,0,1));
00142 br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), frame_id, child_frame_id));
00143
00144 geometry_msgs::PointStamped msg;
00145 msg.point.x = Projection.X;
00146 msg.point.y = Projection.Y;
00147 msg.header.stamp = ros::Time::now();
00148 hand_point_pub_.publish(msg);
00149 }
00150
00151 std::map<XnUInt32, std::vector<XnPoint3D> >::const_iterator PointIterator;
00152
00153 for (PointIterator = m_Position.begin();
00154 PointIterator != m_Position.end();
00155 ++PointIterator)
00156 {
00157 XnUInt32 Id = PointIterator->first;
00158 string child_frame_id("hand_position");
00159 child_frame_id = child_frame_id + ((char)('0'+Id));
00160
00161
00162 XnPoint3D Position = PointIterator->second[0];
00163 XnPoint3D Projection = PointIterator->second[1];
00164
00165 static tf::TransformBroadcaster br;
00166 tf::Transform transform;
00167 transform.setOrigin(tf::Vector3(Position.X/1000.0, Position.Y/1000.0, Position.Z/1000.0));
00168 transform.setRotation(tf::Quaternion(0,0,0,1));
00169 br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), frame_id, child_frame_id));
00170 }
00171 }
00172
00173 protected:
00174
00175 xn::DepthGenerator m_DepthGenerator;
00176
00177 std::map<XnUInt32, std::vector<XnPoint3D> > m_Position;
00178 };
00179
00180
00181 XnVPointPublisher* g_pPublisher;
00182
00183 int main (int argc, char **argv)
00184 {
00185 ros::init (argc, argv, "openni_pointer");
00186 ros::NodeHandle nh;
00187
00188 hand_point_pub_ = nh.advertise<geometry_msgs::PointStamped>("hand_position",10);
00189 hand_point_status_pub_ = nh.advertise<std_msgs::UInt8>("hand_position/status",10);
00190
00191
00192 string configFilename = ros::package::getPath ("openni_pointer") + "/openni_pointer.xml";
00193 XnStatus nRetVal = g_Context.InitFromXmlFile (configFilename.c_str ());
00194 CHECK_RC (nRetVal, "InitFromXml");
00195 nRetVal = g_Context.FindExistingNode (XN_NODE_TYPE_DEPTH, g_DepthGenerator);
00196 CHECK_RC (nRetVal, "Find depth generator");
00197 nRetVal = g_Context.FindExistingNode (XN_NODE_TYPE_HANDS, g_HandsGenerator);
00198 CHECK_RC (nRetVal, "Find hands generator");
00199
00200
00201 g_pSessionManager = new XnVSessionManager;
00202 nRetVal = g_pSessionManager->Initialize (&g_Context, "Click,Wave", "RaiseHand");
00203 CHECK_RC (nRetVal, "SessionManager::Initialize");
00204 g_pSessionManager->RegisterSession (NULL, SessionStarting, SessionEnding, FocusProgress);
00205
00206 g_pPublisher = new XnVPointPublisher(g_DepthGenerator);
00207 g_pFlowRouter = new XnVFlowRouter;
00208 g_pFlowRouter->SetActive(g_pPublisher);
00209
00210
00211 g_pSessionManager->AddListener (g_pFlowRouter);
00212
00213 g_pPublisher->RegisterNoPoints(NULL, NoHands);
00214
00215
00216 nRetVal = g_Context.StartGeneratingAll ();
00217 CHECK_RC (nRetVal, "StartGenerating");
00218 ros::Rate r (30);
00219 while (ros::ok ())
00220 {
00221 g_Context.WaitAndUpdateAll ();
00222
00223
00224 g_pSessionManager->Update (&g_Context);
00225 switch (g_SessionState)
00226
00227 {
00228 case IN_SESSION:
00229 ROS_INFO ("Tracking hands");
00230 break;
00231 case NOT_IN_SESSION:
00232 ROS_INFO ("Perform click or wave gestures to track hand");
00233 break;
00234 case QUICK_REFOCUS:
00235 ROS_INFO ("Raise your hand for it to be identified, or perform click or wave gestures");
00236 break;
00237 }
00238 std_msgs::UInt8 msg;
00239 msg.data = g_SessionState;
00240 hand_point_status_pub_.publish(msg);
00241
00242
00243 r.sleep ();
00244 }
00245 g_Context.Shutdown ();
00246 return 0;
00247 }