Mercurial > hg > grouptrack
diff src/testApp.cpp @ 0:2aa8ba4db20e
Initial check in.
author | samer |
---|---|
date | Sat, 21 Jan 2012 12:15:29 +0000 |
parents | |
children | 6c8f4c5fdb5c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testApp.cpp Sat Jan 21 12:15:29 2012 +0000 @@ -0,0 +1,334 @@ +#include "testApp.h" + +#define IMGWIDTH 640 +#define IMGHEIGHT 480 + +static int Colors[6][3] = { + 255, 0, 0, + 0, 200, 0, + 0, 0, 255, + 200, 175, 0, + 0, 200, 255, + 255, 0, 255 +}; + + +/* Not using these for the time being +// Callback: A user was found +void XN_CALLBACK_TYPE NewUserDetected(UserGenerator& rGenerator,XnUserID nID ,void* pCookie) { + printf("New User %d\n", nID); + send_osc_i(((testApp*)pCookie)->sender),"/birth",nID); +} + +// Callback: An existing user was lost +void XN_CALLBACK_TYPE UserLostDetected(UserGenerator& rGenerator ,XnUserID nID ,void* pCookie) { + printf("Lost user %d\n", nID); + send_osc_i(((testApp*)pCookie)->sender),"/death",nID); +} +*/ + +static void inline send_osc_i(ofxOscSender& sender, const char *path, int arg) { + ofxOscMessage msg; + msg.setAddress(path); + msg.addIntArg(arg); + sender.sendMessage(msg); +} + +static inline void check_rc(XnStatus rc, const char *tag){ + if (rc != XN_STATUS_OK) { + printf("FAILURE: %s - %s\n",tag,xnGetStatusString(rc)); + OF_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++; + } + +}; + + +//-------------------------------------------------------------- + +testApp::testApp(const char *host, int port, int FPS) { + ofSetupOpenGL(&window, IMGWIDTH,IMGHEIGHT, OF_WINDOW); + ofSetWindowTitle("Idyom Installation Tracker"); + ofSetFrameRate(FPS); + + // initialise OSC sender + printf("OSC target: %s:%d.\n",host,port); + printf("Will run at %d frames per second.\n",FPS); + sender.setup(host, port); + draw_image=2; +} + +static XnMapOutputMode fps_map_mode(int fps) { + XnMapOutputMode mapMode; + + mapMode.nXRes = IMGWIDTH; + mapMode.nYRes = IMGHEIGHT; + mapMode.nFPS = fps; + return mapMode; +} + +void testApp::setup() { + + font.loadFont("frabk.ttf", 12); + 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); + + imagePixels = new unsigned char[IMGWIDTH*IMGHEIGHT]; + userImage.allocate(IMGWIDTH, IMGHEIGHT, OF_IMAGE_GRAYSCALE); + for(int i=0;i<MAX_USERS;i++) users[i].present=false; + ofBackground(255, 255, 255); + + printf("Ready to start generating.\n"); + check_rc( context.StartGeneratingAll(), "start generating"); +} + + +//-------------------------------------------------------------- +void testApp::update() { + if (check_nonfatal(context.WaitOneUpdateAll(depthGenerator),"update")) return; + + timestamp = depthGenerator.GetTimestamp(); + 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); + } + + const XnDepthPixel *depthMap = depthGenerator.GetDepthMap(); + + // maybe transfer depth map to image + if (draw_image==2) + for (int i=0; i<IMGWIDTH*IMGHEIGHT; i++) + imagePixels[i] = (255*depthMap[i])/max_depth; + + // get pixels for all users, for each compute centroid and bounding rectangle + { + UserStats stats[MAX_USERS]; + + userGenerator.GetUserPixels(0, sceneMetaData); // 0 for all users + unsigned short *userRawPixels = (unsigned short*)sceneMetaData.Data(); + + if (draw_image==1) { + for (int i=0, y=0; y<IMGHEIGHT; y++) { + for (int x=0; x<IMGWIDTH; x++, i++) { + int id=userRawPixels[i]; + if (id>0) { + stats[id-1].accum(x,y,depthMap[i]); + imagePixels[i]=(128/MAX_USERS)*id; + } else imagePixels[i] = 255; + } + } + } else { + for (int i=0, y=0; y<IMGHEIGHT; y++) { + for (int x=0; x<IMGWIDTH; x++, i++) { + int id=userRawPixels[i]; + if (id>0) 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) { + send_osc_i(sender,"/birth",id0+1); + users[id0].present=true; + } + update_user(id0+1,stats[id0],&users[id0]); + } else { + if (users[id0].present) { + send_osc_i(sender,"/death",id0+1); + users[id0].present=false; + } + } + } + + } + if (draw_image) { + userImage.setFromPixels(imagePixels, IMGWIDTH, IMGHEIGHT, OF_IMAGE_GRAYSCALE); + } +} + +void testApp::update_user(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) { + ofxOscMessage m; + 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; + + m.setAddress("/track"); + m.addIntArg(id); + + m.addFloatArg(on_floor.X); + // m.addFloatArg(on_floor.Y); // not interesting + m.addFloatArg(on_floor.Z); + + { // distances to edges of bounding box + // corrected for perspective + float z=coors[2]; // depth + m.addIntArg(z*(coors[0]-coors[3])); + m.addIntArg(z*(coors[4]-coors[0])); + m.addIntArg(z*(coors[1]-coors[5])); + m.addIntArg(z*(coors[6]-coors[1])); + // area, corrected for perspective + m.addIntArg(z*sqrt(stats.area())); + } + + sender.sendMessage(m); + } +} + +//-------------------------------------------------------------- +static inline void draw_rect(float x1, float x2, float y1, float y2){ + ofLine(x1,y1,x1,y2); + ofLine(x1,y1,x2,y1); + ofLine(x1,y2,x2,y2); + ofLine(x2,y1,x2,y2); +} + + +void testApp::draw(){ + char buf[64]; + ofSetColor(255,255,255); + + if (draw_image) userImage.draw(0, 0, IMGWIDTH, IMGHEIGHT); + // ofSetColor(0); + // ofLine(IMGWIDTH,0,IMGWIDTH,IMGHEIGHT); + + if (draw_time) { + ofSetColor(180,0,0); + sprintf(buf,"%llu",timestamp); + font.drawString(buf,0,IMGHEIGHT-8); + } + + for(int k=0; k<MAX_USERS; k++) { + if (users[k].present) { + int *coors=users[k].plot_coors; // pointer to coors for this user + int *color=Colors[k%6]; + + ofSetColor(color[0],color[1],color[2]); + ofRect(coors[0],coors[1],10,10); + font.drawString(ofToString(k+1), coors[0]-10, coors[1]-10); + draw_rect(coors[3],coors[4],coors[5],coors[6]); + // ofRect(coors[0]+IMGWIDTH, (IMGHEIGHT*coors[2])/max_depth, 10, 10); + } + } + if (!got_floor) { //ofSetColor(0,200,0); + ofSetColor(255,0,0); + ofRect(16,16,16,16); + } +} + +void testApp::keyPressed(int key){ + switch (key) { + case 'd': draw_image = (draw_image+1)%3; break; + case 'f': + printf("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); + break; + case 't': draw_time = !draw_time; break; + } +} + +void testApp::keyReleased(int key) {} +void testApp::mouseMoved(int x, int y ) {} +void testApp::mouseDragged(int x, int y, int button) {} +void testApp::mousePressed(int x, int y, int button) {} +void testApp::mouseReleased(int x, int y, int button) {} +void testApp::windowResized(int w, int h) {} +