view src/testApp.cpp @ 2:c265c6b3b98d

Added bin/data/
author samer
date Thu, 09 Feb 2012 17:27:14 +0000
parents 2aa8ba4db20e
children 6c8f4c5fdb5c
line wrap: on
line source
#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) {}