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