www.pudn.com > reacTIVision-1.3.rar > FidtrackFinder.cpp


/*  reacTIVision fiducial tracking framework
    FidtrackFinder.cpp
    Copyright (C) 2006 Martin Kaltenbrunner 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "FidtrackFinder.h"

bool FidtrackFinder::init(int w, int h, int sb, int db) {
	
	FiducialFinder::init(w,h,sb,db);
	
	if (db!=1) {
		printf("target buffer must be grayscale\n");
		return false;
	}
	
	if (strcmp(tree_config,"none")!=0) {
		initialize_treeidmap_from_file( &treeidmap, tree_config );
	} else initialize_treeidmap( &treeidmap );

	initialize_fidtrackerX( &fidtrackerx, &treeidmap, dmap);
	initialize_segmenter( &segmenter, width, height, treeidmap.max_adjacencies );
	return true;
}

void FidtrackFinder::process(unsigned char *src, unsigned char *dest) {

	// segmentation
	step_segmenter( &segmenter, dest, width, height );
	// fiducial recognition
	int count = find_fiducialsX( fiducials, MAX_FIDUCIAL_COUNT,  &fidtrackerx , &segmenter, width, height);	

	// process found symbols
	for(int i=0;i< count;i++) {
	
		// tracking the objects first
		if(fiducials[i].id!=FINGER_ID) {	
			FiducialObject *existing_fiducial = NULL;
	
			// update objects we had in the last frame
			// also check if we have an ID/position conflict
			// or correct an INVALID_FIDUCIAL_ID if we had an ID in the last frame
			for (fiducial = fiducialList.begin(); fiducial!=fiducialList.end(); fiducial++) {
	
				float distance = fiducial->distance(fiducials[i].x,fiducials[i].y);
	
				if (fiducials[i].id==fiducial->fiducial_id)  {
					// find and match a fiducial we had last frame already ...
					if(!existing_fiducial) {
						existing_fiducial = &(*fiducial);
						for (int j=0;jdistance(fiducials[j].x,fiducials[j].y)distance(fiducials[i].x,fiducials[i].y)) {
							existing_fiducial = &(*fiducial);
							// is this still necessary?
					}

				} else if (distancegetAngle());
                                                fiducials[i].angle=fiducial->getAngle();
                                                //printf("corrected invalid ID to %d at %d %d\n", fiducial->fiducial_id,(int)fiducial$
                                                fiducials[i].id=fiducial->fiducial_id;
                                        } else if (fiducials[i].id!=fiducial->fiducial_id) {

                                                if (!fiducial->checkIdConflict(session_id,fiducials[i].id)) {
                                                        //printf("corrected wrong ID from %d to %d at %d %d\n", fiducials[i].id,fiduc$
                                                        fiducials[i].id=fiducial->fiducial_id;
                                                } else session_id++;
                                        }
                                        existing_fiducial = &(*fiducial);
                                        break;
				}
			}
		
			if  (existing_fiducial!=NULL) {
				// just update the fiducial from last frame ...
				existing_fiducial->update(fiducials[i].x,fiducials[i].y,fiducials[i].angle);
			} else if  (fiducials[i].id!=INVALID_FIDUCIAL_ID) {
				// add the newly found object
				FiducialObject addFiducial(session_id, fiducials[i].id, width, height);
				addFiducial.update(fiducials[i].x,fiducials[i].y,fiducials[i].angle);
				fiducialList.push_back(addFiducial);
				if (mserver!=NULL) mserver->sendAddMessage(fiducials[i].id);
				if (msg_listener) {
					char add_message[16];
					sprintf(add_message,"add obj %ld %d",session_id,fiducials[i].id);
					msg_listener->setMessage(std::string(add_message));
				}
				session_id++;
			}
	
			if(fiducials[i].id!=INVALID_FIDUCIAL_ID && msg_listener)
				msg_listener->setObject(fiducials[i].id,(int)(fiducials[i].x),(int)(fiducials[i].y),fiducials[i].angle );
	
		// now the finger fiducials
		} else {
			FingerObject *existing_finger = NULL;
			for (std::list::iterator finger = fingerList.begin(); finger!=fingerList.end(); finger++) {
		
				float distance = finger->distance(fiducials[i].x,fiducials[i].y);
				if (distance<24.0f) {
					existing_finger = &(*finger);
					for (int j=0;jdistance(fiducials[j].x,fiducials[j].y)distance(fiducials[j].x,fiducials[j].y)<24.0f)) {
							existing_finger->reset();
							existing_finger = NULL;
							//printf("discarded existing finger\n");
							break;
						}
					}	
				}
				if (existing_finger) break;
			}

			bool add_finger = true;
			for (fiducial = fiducialList.begin(); fiducial!=fiducialList.end(); fiducial++) {
				if (fiducial->distance(fiducials[i].x,fiducials[i].y)<24) { add_finger = false; break; }
			}

			
			if  (existing_finger!=NULL) {
				// just update the finger from last frame ...
				if (add_finger) existing_finger->update(fiducials[i].x,fiducials[i].y);
				else existing_finger->reset();
			} else {
				// add the newly found cursor
				if (add_finger) {
					FingerObject addFinger(width, height);
					addFinger.update(fiducials[i].x,fiducials[i].y);
					fingerList.push_back(addFinger);
				}
			}
	
			if(msg_listener) msg_listener->setObject(FINGER_ID,(int)(fiducials[i].x),(int)(fiducials[i].y),0);	
		}

	}

	if (tserver!=NULL) {
		sendTuioMessages();
		sendCursorMessages();
	} else if (mserver!=NULL) sendMidiMessages();
	
	drawGrid(src,dest);
}

void FidtrackFinder::sendCursorMessages() {

	// get the current set of objects on the table
	// we do not only use the raw objects retrieved from the frame
	// but also the remaining (filtered) objects from our fiducialObject list
	bool sendAliveMessage = false;
	int aliveSize = 0;
	long *aliveList = new long[fingerList.size()];
		
	for(std::list::iterator finger = fingerList.begin(); finger!=fingerList.end(); ) {

		char message[16];
		int finger_status = finger->checkStatus(session_id);
		switch (finger_status) {
			case FINGER_ADDED: {
				aliveList[aliveSize]=finger->session_id;
				aliveSize++;
				session_id++;
				if(msg_listener) {
					sprintf(message,"add cur %ld",finger->session_id);
					msg_listener->setMessage(std::string(message));
				}
				finger++;
				break;
			}
			case FINGER_REMOVED: {
				if(msg_listener) {
					sprintf(message,"del cur %ld",finger->session_id);
					msg_listener->setMessage(std::string(message));
				}
				finger = fingerList.erase(finger);
				sendAliveMessage = true;
				break;
			}
			case FINGER_ALIVE: {
				aliveList[aliveSize]=finger->session_id;
				aliveSize++;
				finger++;
				break;
			}
			case FINGER_EXPIRED: {
				finger = fingerList.erase(finger);
				break;
			}
			case FINGER_CANDIDATE: {
				finger++;
				break;
			}
		}
				
	}
		
	// after a certain number of frames we should send the redundant alive message	
	if ((aliveSize>0) || (totalframes%30==0)) sendAliveMessage = true;
		
	// add the alive message
	if (sendAliveMessage) {
		tserver->addCurAlive(aliveList, aliveSize);
		
		char unsent = 0;
		// send a set message (in case anything changed compared to the last frame)
		for(std::list::iterator finger = fingerList.begin(); finger!=fingerList.end(); finger++) {
			if (!tserver->freeCurSpace()) {
				tserver->addCurSeq(totalframes);
				tserver->sendCurMessages();
			}
				
			char *set_message = finger->addSetMessage(tserver);
			if(set_message && msg_listener) msg_listener->setMessage(std::string(set_message));
		
			if (finger->unsent>unsent) unsent = finger->unsent;
		}
	
		// fill the rest of the packet with unchanged objects
		// sending the least sent ones first
		while (unsent>0) {
			for(std::list::iterator finger = fingerList.begin(); finger!=fingerList.end(); finger++) {
				if ((finger->alive) && (finger->unsent==unsent)) {
					if (tserver->freeCurSpace()) { 
						finger->redundantSetMessage(tserver);
					} else goto send;
				}
			}
			unsent--;
		}
	
		send:
		// finally send the packet
		tserver->addCurSeq(totalframes);
		tserver->sendCurMessages();
	}
	delete[] aliveList;
}