Mercurial > hg > grouptrack
view termapp/termapp.cpp @ 14:34156549d423
termapp handles signals and termination a bit better.
author | samer |
---|---|
date | Mon, 20 Feb 2012 15:38:16 +0000 |
parents | b82da07b6800 |
children |
line wrap: on
line source
#include <XnCppWrapper.h> #include <lo/lo.h> #include <math.h> #include <stdlib.h> #include <signal.h> #include <string.h> #include <sys/select.h> #include <termios.h> #include <stdio.h> #define IMGWIDTH 640 #define IMGHEIGHT 480 #define MAX_USERS 16 #define HOST "localhost" #define PORT "7770" #define EXIT_APP(rc) exit(rc) using namespace xn; class UserStats; class termapp { private: Context context; DepthGenerator depthGenerator; UserGenerator userGenerator; SceneAnalyzer sceneAnalyzer; SceneMetaData sceneMetaData; XnDepthPixel max_depth; XnUInt64 timestamp; XnPlane3D floor_pie; lo_address target; bool got_floor; XnVector3D floor_offset; class UserData { public: bool present; int plot_coors[7]; }; UserData users[MAX_USERS]; void update_user(lo_bundle bundle, int id, UserStats& stats, UserData *user); static void append_msg_i(lo_bundle bundle, const char *path, int arg); static void append_track(lo_bundle bundle, int id, float x, float y, int *coors, float area); public: termapp(const char *host, const char *port, int fps); ~termapp() { lo_address_free(target); printf("Shutting down OpenNI...\n"); context.Shutdown(); }; void setup(); void update(); void draw(); void keyPressed(int); }; static inline void check_rc(XnStatus rc, const char *tag){ if (rc != XN_STATUS_OK) { printf("FAILURE: %s - %s\n",tag,xnGetStatusString(rc)); EXIT_APP(0); } } static inline int check_nonfatal(XnStatus rc, const char *tag){ if (rc != XN_STATUS_OK) { printf("WARNING: %s - %s\n",tag,xnGetStatusString(rc)); return 1; } else return 0; } //-------------------------------------------------------------- class int3d { public: int X, Y, Z; inline void set(int x, int y, int z) { X=x; Y=y; Z=z; } inline void add(int x, int y, int z) { X+=x; Y+=y; Z+=z; } inline void div(float d, XnVector3D *p) { p->X=X/d; p->Y=Y/d; p->Z=Z/d; } inline void cpy(XnVector3D *p) { p->X=X; p->Y=Y; p->Z=Z; } }; static void project_into_plane(XnPlane3D& plane, XnVector3D& r, XnVector3D *q) { float l = (r.X-plane.ptPoint.X)*plane.vNormal.X + (r.Y-plane.ptPoint.Y)*plane.vNormal.Y + (r.Z-plane.ptPoint.Z)*plane.vNormal.Z; q->X = r.X - l*plane.vNormal.X; q->Y = r.Y - l*plane.vNormal.Y; q->Z = r.Z - l*plane.vNormal.Z; } class UserStats { public: struct int3d left, right, top, bottom, sum; int numPixels; UserStats() { left.X=IMGWIDTH; top.Y=IMGHEIGHT; right.X=bottom.Y=0; sum.X=sum.Y=sum.Z=0; numPixels=0; } inline int area() { return numPixels; } inline void centroid(XnVector3D *p) { sum.div(numPixels,p); } inline void accum(int x, int y, int z) { if (x<left.X) left.set(x,y,z); if (x>right.X) right.set(x,y,z); if (y<top.Y) top.set(x,y,z); if (y>bottom.Y) bottom.set(x,y,z); sum.add(x,y,z); numPixels++; } }; //-------------------------------------------------------------- termapp::termapp(const char *host, const char *port, int FPS) { // initialise OSC sender printf("OSC target is %s:%s.\n",host,port); // printf("Will run at %d frames per second.\n",FPS); target = lo_address_new(host,port); } static XnMapOutputMode fps_map_mode(int fps) { XnMapOutputMode mapMode; mapMode.nXRes = IMGWIDTH; mapMode.nYRes = IMGHEIGHT; mapMode.nFPS = fps; return mapMode; } void termapp::setup() { check_rc(context.Init(),"initialise context"); { XnLicense license; strcpy(license.strVendor,"PrimeSense"); strcpy(license.strKey,"0KOIk2JeIBYClPWVnMoRKn5cdY4="); check_rc(context.AddLicense(license),"add license"); } check_rc(depthGenerator.Create(context),"create depth generator"); check_rc(depthGenerator.SetMapOutputMode(fps_map_mode(30)),"config depth generator"); check_rc(sceneAnalyzer.Create(context),"create scene analyzer"); check_rc(sceneAnalyzer.SetMapOutputMode(fps_map_mode(30)),"config scene analyzer"); check_rc(userGenerator.Create(context),"create user generator"); //XnCallbackHandle user_cb_handle; //userGenerator.RegisterUserCallbacks(NewUserDetected,UserLostDetected,this,user_cb_handle); max_depth = depthGenerator.GetDeviceMaxDepth(); printf("Depth generator max depth=%d.\n",max_depth); for(int i=0;i<MAX_USERS;i++) users[i].present=false; printf("Ready to start generating.\n"); check_rc( context.StartGeneratingAll(), "start generating"); } //-------------------------------------------------------------- void termapp::update() { lo_timetag now; if (check_nonfatal(context.WaitOneUpdateAll(depthGenerator),"update")) return; lo_timetag_now(&now); userGenerator.GetUserPixels(0, sceneMetaData); // 0 for all users timestamp = sceneMetaData.Timestamp(); got_floor = (sceneAnalyzer.GetFloor(floor_pie)==XN_STATUS_OK); if (got_floor) { // project camera onto floor XnVector3D origin = {0,0,0}; project_into_plane(floor_pie, origin, &floor_offset); } // get pixels for all users, for each compute centroid and bounding rectangle { const XnDepthPixel *depthMap = depthGenerator.GetDepthMap(); unsigned short *userRawPixels = (unsigned short*)sceneMetaData.Data(); UserStats stats[MAX_USERS]; lo_bundle bundle=lo_bundle_new(now); for (int i=0, y=0; y<IMGHEIGHT; y++) { for (int x=0; x<IMGWIDTH; x++, i++) { int id=userRawPixels[i]; if (id>0 && id<=MAX_USERS) { stats[id-1].accum(x,y,depthMap[i]); } } } for (int id0=0; id0<MAX_USERS; id0++) { if (stats[id0].area()>0) { if (!users[id0].present) { append_msg_i(bundle,"/birth",id0+1); append_msg_i(bundle,"/randinit",id0+1); append_msg_i(bundle,"/start",id0+1); users[id0].present=true; } update_user(bundle,id0+1,stats[id0],&users[id0]); } else { if (users[id0].present) { append_msg_i(bundle,"/death",id0+1); users[id0].present=false; } } } lo_send_bundle(target,bundle); lo_bundle_free_messages(bundle); } } void termapp::update_user(lo_bundle bundle, int id, UserStats& stats, UserData *user) { XnVector3D proj[3], real[3]; int *coors=user->plot_coors; stats.centroid(&proj[0]); // centroid in device coordinate stats.left.cpy(&proj[1]); // left edge in device coordinates stats.right.cpy(&proj[2]); // right edge in device coordinates // save values required for drawing later coors[0]=floor(proj[0].X); coors[1]=floor(proj[0].Y); coors[2]=floor(proj[0].Z); coors[3]=stats.left.X; coors[4]=stats.right.X; coors[5]=stats.top.Y; coors[6]=stats.bottom.Y; if (got_floor) { XnVector3D on_floor; // convert to camera-centric world coordinates depthGenerator.ConvertProjectiveToRealWorld(3,proj,real); // projection of centroid onto floor... project_into_plane(floor_pie,real[0],&on_floor); // ...relative to projection of camera on floor on_floor.X -= floor_offset.X; on_floor.Y -= floor_offset.Y; on_floor.Z -= floor_offset.Z; append_track(bundle,id, on_floor.X, on_floor.Y, coors, stats.area()); } } void termapp::draw(){ printf(" % 6.2lf s floor[%s] users[",((double)timestamp)/1000000, got_floor ? "*" : "."); for (int id0=0; id0<MAX_USERS; id0++) putchar( users[id0].present ? '*' : '.'); printf("] \r"); fflush(stdout); } void termapp::keyPressed(int key){ switch (key) { case 'f': printf("\n floor plane: (%f,%f,%f), <%f,%f,%f>\n", floor_pie.ptPoint.X, floor_pie.ptPoint.Y, floor_pie.ptPoint.Z, floor_pie.vNormal.X, floor_pie.vNormal.Y, floor_pie.vNormal.Z); fflush(stdout); break; } } void termapp::append_msg_i(lo_bundle bundle, const char *path, int arg) { lo_message msg=lo_message_new(); lo_message_add_int32(msg,arg); lo_bundle_add_message(bundle,path,msg); } void termapp::append_track(lo_bundle bundle, int id, float x, float y, int *coors, float area) { lo_message m=lo_message_new(); float z=coors[2]; // depth lo_message_add_int32(m,id); lo_message_add_float(m,x); lo_message_add_float(m,z); // distances to edges of bounding box // corrected for perspective lo_message_add_int32(m,z*(coors[0]-coors[3])); lo_message_add_int32(m,z*(coors[4]-coors[0])); lo_message_add_int32(m,z*(coors[1]-coors[5])); lo_message_add_int32(m,z*(coors[6]-coors[1])); // area, corrected for perspective lo_message_add_int32(m,z*sqrt(area)); lo_bundle_add_message(bundle,"/track",m); } static bool Continue=true; //======================================================================== struct termios orig_termios; void reset_terminal_mode() { printf("Resetting terminal...\n"); tcsetattr(0, TCSANOW, &orig_termios); } void set_conio_terminal_mode() { struct termios new_termios; /* take two copies - one for now, one for later */ tcgetattr(0, &orig_termios); memcpy(&new_termios, &orig_termios, sizeof(new_termios)); new_termios.c_lflag &= ~ECHO; new_termios.c_lflag &= ~ICANON; tcsetattr(0, TCSANOW, &new_termios); } int kbhit() { struct timeval tv = { 0L, 0L }; fd_set fds; FD_ZERO(&fds); FD_SET(0, &fds); return select(1, &fds, NULL, NULL, &tv); } int getch() { unsigned char c; int r=read(0, &c, sizeof(c)); return (r<0) ? r : c; } static bool InHandler=false; static void signal_handler(int sig) { if (InHandler) { reset_terminal_mode(); exit(0); } else InHandler=true; printf("\nCaught signal %d - will exit cleanly.\n", sig); Continue=false; } int main(int argc, const char **argv) { int i,ch; termapp app( argc>1 ? argv[1] : HOST, argc>2 ? argv[2] : PORT, argc>3 ? atoi(argv[3]) : 15); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGKILL, signal_handler); printf("Setting up...\n"); app.setup(); printf("Running...\n"); set_conio_terminal_mode(); while (Continue) { app.update(); app.draw(); while (kbhit()) { ch = getch(); if (ch=='q') Continue=false; else if (ch>0) app.keyPressed(ch); } } printf("\n"); reset_terminal_mode(); }