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