annotate src/testApp.cpp @ 16:79de93763a94 tip

Removed termapp, which now has it's own project (mtri-termtrack)
author samer
date Mon, 27 Feb 2012 20:38:12 +0000
parents 584ef20184f6
children
rev   line source
samer@0 1 #include "testApp.h"
samer@0 2
samer@0 3 #define IMGWIDTH 640
samer@0 4 #define IMGHEIGHT 480
samer@0 5
samer@0 6 static int Colors[6][3] = {
samer@0 7 255, 0, 0,
samer@0 8 0, 200, 0,
samer@0 9 0, 0, 255,
samer@0 10 200, 175, 0,
samer@0 11 0, 200, 255,
samer@0 12 255, 0, 255
samer@0 13 };
samer@0 14
samer@0 15
samer@0 16 /* Not using these for the time being
samer@0 17 // Callback: A user was found
samer@0 18 void XN_CALLBACK_TYPE NewUserDetected(UserGenerator& rGenerator,XnUserID nID ,void* pCookie) {
samer@0 19 printf("New User %d\n", nID);
samer@0 20 send_osc_i(((testApp*)pCookie)->sender),"/birth",nID);
samer@0 21 }
samer@0 22
samer@0 23 // Callback: An existing user was lost
samer@0 24 void XN_CALLBACK_TYPE UserLostDetected(UserGenerator& rGenerator ,XnUserID nID ,void* pCookie) {
samer@0 25 printf("Lost user %d\n", nID);
samer@0 26 send_osc_i(((testApp*)pCookie)->sender),"/death",nID);
samer@0 27 }
samer@0 28 */
samer@0 29
samer@0 30 static void inline send_osc_i(ofxOscSender& sender, const char *path, int arg) {
samer@0 31 ofxOscMessage msg;
samer@0 32 msg.setAddress(path);
samer@0 33 msg.addIntArg(arg);
samer@0 34 sender.sendMessage(msg);
samer@0 35 }
samer@0 36
samer@0 37 static inline void check_rc(XnStatus rc, const char *tag){
samer@0 38 if (rc != XN_STATUS_OK) {
samer@0 39 printf("FAILURE: %s - %s\n",tag,xnGetStatusString(rc));
samer@0 40 OF_EXIT_APP(0);
samer@0 41 }
samer@0 42 }
samer@0 43
samer@0 44 static inline int check_nonfatal(XnStatus rc, const char *tag){
samer@0 45 if (rc != XN_STATUS_OK) {
samer@0 46 printf("WARNING: %s - %s\n",tag,xnGetStatusString(rc));
samer@0 47 return 1;
samer@0 48 } else return 0;
samer@0 49 }
samer@0 50
samer@0 51 //--------------------------------------------------------------
samer@0 52
samer@0 53 class int3d {
samer@0 54 public:
samer@0 55 int X, Y, Z;
samer@0 56 inline void set(int x, int y, int z) { X=x; Y=y; Z=z; }
samer@0 57 inline void add(int x, int y, int z) { X+=x; Y+=y; Z+=z; }
samer@0 58 inline void div(float d, XnVector3D *p) { p->X=X/d; p->Y=Y/d; p->Z=Z/d; }
samer@0 59 inline void cpy(XnVector3D *p) { p->X=X; p->Y=Y; p->Z=Z; }
samer@0 60 };
samer@0 61
samer@0 62 static void project_into_plane(XnPlane3D& plane, XnVector3D& r, XnVector3D *q) {
samer@0 63 float l = (r.X-plane.ptPoint.X)*plane.vNormal.X
samer@0 64 + (r.Y-plane.ptPoint.Y)*plane.vNormal.Y
samer@0 65 + (r.Z-plane.ptPoint.Z)*plane.vNormal.Z;
samer@0 66
samer@0 67 q->X = r.X - l*plane.vNormal.X;
samer@0 68 q->Y = r.Y - l*plane.vNormal.Y;
samer@0 69 q->Z = r.Z - l*plane.vNormal.Z;
samer@0 70 }
samer@0 71
samer@0 72 class UserStats {
samer@0 73 public:
samer@0 74 struct int3d left, right, top, bottom, sum;
samer@0 75 int numPixels;
samer@0 76
samer@0 77 UserStats() {
samer@0 78 left.X=IMGWIDTH;
samer@0 79 top.Y=IMGHEIGHT;
samer@0 80 right.X=bottom.Y=0;
samer@0 81 sum.X=sum.Y=sum.Z=0;
samer@0 82 numPixels=0;
samer@0 83 }
samer@0 84
samer@0 85 inline int area() { return numPixels; }
samer@0 86 inline void centroid(XnVector3D *p) { sum.div(numPixels,p); }
samer@0 87 inline void accum(int x, int y, int z) {
samer@0 88 if (x<left.X) left.set(x,y,z);
samer@0 89 if (x>right.X) right.set(x,y,z);
samer@0 90 if (y<top.Y) top.set(x,y,z);
samer@0 91 if (y>bottom.Y) bottom.set(x,y,z);
samer@0 92 sum.add(x,y,z);
samer@0 93 numPixels++;
samer@0 94 }
samer@0 95
samer@0 96 };
samer@0 97
samer@0 98
samer@0 99 //--------------------------------------------------------------
samer@0 100
samer@0 101 testApp::testApp(const char *host, int port, int FPS) {
samer@0 102 ofSetupOpenGL(&window, IMGWIDTH,IMGHEIGHT, OF_WINDOW);
samer@8 103 ofSetWindowTitle("Melody Triangle Tracker");
samer@0 104 ofSetFrameRate(FPS);
samer@0 105
samer@0 106 // initialise OSC sender
samer@0 107 printf("OSC target: %s:%d.\n",host,port);
samer@0 108 printf("Will run at %d frames per second.\n",FPS);
samer@0 109 sender.setup(host, port);
samer@0 110 draw_image=2;
samer@0 111 }
samer@0 112
samer@0 113 static XnMapOutputMode fps_map_mode(int fps) {
samer@0 114 XnMapOutputMode mapMode;
samer@0 115
samer@0 116 mapMode.nXRes = IMGWIDTH;
samer@0 117 mapMode.nYRes = IMGHEIGHT;
samer@0 118 mapMode.nFPS = fps;
samer@0 119 return mapMode;
samer@0 120 }
samer@0 121
samer@0 122 void testApp::setup() {
samer@0 123
samer@0 124 font.loadFont("frabk.ttf", 12);
samer@0 125 check_rc(context.Init(),"initialise context");
samer@0 126
samer@0 127 {
samer@0 128 XnLicense license;
samer@0 129 strcpy(license.strVendor,"PrimeSense");
samer@0 130 strcpy(license.strKey,"0KOIk2JeIBYClPWVnMoRKn5cdY4=");
samer@0 131 check_rc(context.AddLicense(license),"add license");
samer@0 132 }
samer@0 133
samer@0 134 check_rc(depthGenerator.Create(context),"create depth generator");
samer@0 135 check_rc(depthGenerator.SetMapOutputMode(fps_map_mode(30)),"config depth generator");
samer@0 136 check_rc(sceneAnalyzer.Create(context),"create scene analyzer");
samer@0 137 check_rc(sceneAnalyzer.SetMapOutputMode(fps_map_mode(30)),"config scene analyzer");
samer@0 138 check_rc(userGenerator.Create(context),"create user generator");
samer@0 139
samer@0 140 //XnCallbackHandle user_cb_handle;
samer@0 141 //userGenerator.RegisterUserCallbacks(NewUserDetected,UserLostDetected,this,user_cb_handle);
samer@0 142
samer@0 143 max_depth = depthGenerator.GetDeviceMaxDepth();
samer@0 144 printf("Depth generator max depth=%d.\n",max_depth);
samer@0 145
samer@0 146 imagePixels = new unsigned char[IMGWIDTH*IMGHEIGHT];
samer@0 147 userImage.allocate(IMGWIDTH, IMGHEIGHT, OF_IMAGE_GRAYSCALE);
samer@0 148 for(int i=0;i<MAX_USERS;i++) users[i].present=false;
samer@0 149 ofBackground(255, 255, 255);
samer@0 150
samer@0 151 printf("Ready to start generating.\n");
samer@0 152 check_rc( context.StartGeneratingAll(), "start generating");
samer@0 153 }
samer@0 154
samer@0 155
samer@0 156 //--------------------------------------------------------------
samer@0 157 void testApp::update() {
samer@0 158 if (check_nonfatal(context.WaitOneUpdateAll(depthGenerator),"update")) return;
samer@0 159
samer@0 160 timestamp = depthGenerator.GetTimestamp();
samer@0 161 got_floor = (sceneAnalyzer.GetFloor(floor_pie)==XN_STATUS_OK);
samer@0 162 if (got_floor) { // project camera onto floor
samer@0 163 XnVector3D origin = {0,0,0};
samer@0 164 project_into_plane(floor_pie, origin, &floor_offset);
samer@0 165 }
samer@0 166
samer@0 167 const XnDepthPixel *depthMap = depthGenerator.GetDepthMap();
samer@0 168
samer@0 169 // maybe transfer depth map to image
samer@0 170 if (draw_image==2)
samer@0 171 for (int i=0; i<IMGWIDTH*IMGHEIGHT; i++)
samer@0 172 imagePixels[i] = (255*depthMap[i])/max_depth;
samer@0 173
samer@0 174 // get pixels for all users, for each compute centroid and bounding rectangle
samer@0 175 {
samer@0 176 UserStats stats[MAX_USERS];
samer@0 177
samer@0 178 userGenerator.GetUserPixels(0, sceneMetaData); // 0 for all users
samer@0 179 unsigned short *userRawPixels = (unsigned short*)sceneMetaData.Data();
samer@0 180
samer@0 181 if (draw_image==1) {
samer@0 182 for (int i=0, y=0; y<IMGHEIGHT; y++) {
samer@0 183 for (int x=0; x<IMGWIDTH; x++, i++) {
samer@0 184 int id=userRawPixels[i];
samer@8 185 if (id>0 && id<=MAX_USERS) {
samer@0 186 stats[id-1].accum(x,y,depthMap[i]);
samer@0 187 imagePixels[i]=(128/MAX_USERS)*id;
samer@0 188 } else imagePixels[i] = 255;
samer@0 189 }
samer@0 190 }
samer@0 191 } else {
samer@0 192 for (int i=0, y=0; y<IMGHEIGHT; y++) {
samer@0 193 for (int x=0; x<IMGWIDTH; x++, i++) {
samer@0 194 int id=userRawPixels[i];
samer@8 195 if (id>0 && id<=MAX_USERS) {
samer@8 196 stats[id-1].accum(x,y,depthMap[i]);
samer@8 197 }
samer@0 198 }
samer@0 199 }
samer@0 200 }
samer@0 201
samer@0 202 for (int id0=0; id0<MAX_USERS; id0++) {
samer@0 203 if (stats[id0].area()>0) {
samer@0 204 if (!users[id0].present) {
samer@0 205 send_osc_i(sender,"/birth",id0+1);
samer@8 206 send_osc_i(sender,"/randinit",id0+1);
hekeus@5 207 send_osc_i(sender,"/start",id0+1);
samer@0 208 users[id0].present=true;
samer@0 209 }
samer@0 210 update_user(id0+1,stats[id0],&users[id0]);
samer@0 211 } else {
samer@0 212 if (users[id0].present) {
samer@0 213 send_osc_i(sender,"/death",id0+1);
samer@0 214 users[id0].present=false;
samer@0 215 }
samer@0 216 }
samer@0 217 }
samer@0 218
samer@0 219 }
samer@0 220 if (draw_image) {
samer@0 221 userImage.setFromPixels(imagePixels, IMGWIDTH, IMGHEIGHT, OF_IMAGE_GRAYSCALE);
samer@0 222 }
samer@0 223 }
samer@0 224
samer@0 225 void testApp::update_user(int id, UserStats& stats, UserData *user) {
samer@0 226 XnVector3D proj[3], real[3];
samer@0 227 int *coors=user->plot_coors;
samer@0 228
samer@0 229 stats.centroid(&proj[0]); // centroid in device coordinate
samer@0 230 stats.left.cpy(&proj[1]); // left edge in device coordinates
samer@0 231 stats.right.cpy(&proj[2]); // right edge in device coordinates
samer@0 232
samer@0 233 // save values required for drawing later
samer@0 234 coors[0]=floor(proj[0].X);
samer@0 235 coors[1]=floor(proj[0].Y);
samer@0 236 coors[2]=floor(proj[0].Z);
samer@0 237 coors[3]=stats.left.X;
samer@0 238 coors[4]=stats.right.X;
samer@0 239 coors[5]=stats.top.Y;
samer@0 240 coors[6]=stats.bottom.Y;
samer@0 241
samer@0 242 if (got_floor) {
samer@0 243 ofxOscMessage m;
samer@0 244 XnVector3D on_floor;
samer@0 245
samer@0 246 // convert to camera-centric world coordinates
samer@0 247 depthGenerator.ConvertProjectiveToRealWorld(3,proj,real);
samer@0 248
samer@0 249 // projection of centroid onto floor...
samer@0 250 project_into_plane(floor_pie,real[0],&on_floor);
samer@0 251
samer@0 252 // ...relative to projection of camera on floor
samer@0 253 on_floor.X -= floor_offset.X;
samer@0 254 on_floor.Y -= floor_offset.Y;
samer@0 255 on_floor.Z -= floor_offset.Z;
samer@0 256
samer@0 257 m.setAddress("/track");
samer@0 258 m.addIntArg(id);
samer@0 259
samer@0 260 m.addFloatArg(on_floor.X);
samer@0 261 // m.addFloatArg(on_floor.Y); // not interesting
samer@0 262 m.addFloatArg(on_floor.Z);
samer@0 263
samer@0 264 { // distances to edges of bounding box
samer@0 265 // corrected for perspective
samer@0 266 float z=coors[2]; // depth
samer@0 267 m.addIntArg(z*(coors[0]-coors[3]));
samer@0 268 m.addIntArg(z*(coors[4]-coors[0]));
samer@0 269 m.addIntArg(z*(coors[1]-coors[5]));
samer@0 270 m.addIntArg(z*(coors[6]-coors[1]));
samer@0 271 // area, corrected for perspective
samer@0 272 m.addIntArg(z*sqrt(stats.area()));
samer@0 273 }
samer@0 274
samer@0 275 sender.sendMessage(m);
samer@0 276 }
samer@0 277 }
samer@0 278
samer@0 279 //--------------------------------------------------------------
samer@0 280 static inline void draw_rect(float x1, float x2, float y1, float y2){
samer@0 281 ofLine(x1,y1,x1,y2);
samer@0 282 ofLine(x1,y1,x2,y1);
samer@0 283 ofLine(x1,y2,x2,y2);
samer@0 284 ofLine(x2,y1,x2,y2);
samer@0 285 }
samer@0 286
samer@0 287
samer@0 288 void testApp::draw(){
samer@0 289 char buf[64];
samer@0 290 ofSetColor(255,255,255);
samer@8 291 ofScale(ofGetWidth()/(float)IMGWIDTH,ofGetHeight()/(float)IMGHEIGHT);
samer@0 292
samer@0 293 if (draw_image) userImage.draw(0, 0, IMGWIDTH, IMGHEIGHT);
samer@0 294 // ofSetColor(0);
samer@0 295 // ofLine(IMGWIDTH,0,IMGWIDTH,IMGHEIGHT);
samer@0 296
samer@0 297 if (draw_time) {
samer@0 298 ofSetColor(180,0,0);
samer@0 299 sprintf(buf,"%llu",timestamp);
samer@0 300 font.drawString(buf,0,IMGHEIGHT-8);
samer@0 301 }
samer@0 302
samer@0 303 for(int k=0; k<MAX_USERS; k++) {
samer@0 304 if (users[k].present) {
samer@0 305 int *coors=users[k].plot_coors; // pointer to coors for this user
samer@0 306 int *color=Colors[k%6];
samer@0 307
samer@0 308 ofSetColor(color[0],color[1],color[2]);
samer@0 309 ofRect(coors[0],coors[1],10,10);
samer@0 310 font.drawString(ofToString(k+1), coors[0]-10, coors[1]-10);
samer@0 311 draw_rect(coors[3],coors[4],coors[5],coors[6]);
samer@0 312 // ofRect(coors[0]+IMGWIDTH, (IMGHEIGHT*coors[2])/max_depth, 10, 10);
samer@0 313 }
samer@0 314 }
samer@8 315 if (!got_floor) {
samer@0 316 ofSetColor(255,0,0);
samer@0 317 ofRect(16,16,16,16);
samer@0 318 }
samer@0 319 }
samer@0 320
samer@0 321 void testApp::keyPressed(int key){
samer@0 322 switch (key) {
samer@0 323 case 'd': draw_image = (draw_image+1)%3; break;
samer@0 324 case 'f':
samer@0 325 printf("floor plane: (%f,%f,%f), <%f,%f,%f>\n",
samer@0 326 floor_pie.ptPoint.X, floor_pie.ptPoint.Y, floor_pie.ptPoint.Z,
samer@0 327 floor_pie.vNormal.X, floor_pie.vNormal.Y, floor_pie.vNormal.Z);
samer@0 328 break;
samer@0 329 case 't': draw_time = !draw_time; break;
samer@8 330 case 'F': ofToggleFullscreen(); break;
samer@0 331 }
samer@0 332 }
samer@0 333
samer@0 334 void testApp::keyReleased(int key) {}
samer@0 335 void testApp::mouseMoved(int x, int y ) {}
samer@0 336 void testApp::mouseDragged(int x, int y, int button) {}
samer@0 337 void testApp::mousePressed(int x, int y, int button) {}
samer@0 338 void testApp::mouseReleased(int x, int y, int button) {}
samer@0 339 void testApp::windowResized(int w, int h) {}
samer@0 340