00001 
00002 #include "Events/EventRouter.h"
00003 #include "Events/TextMsgEvent.h"
00004 #include "Events/LookoutEvents.h"
00005 #include "Motion/HeadPointerMC.h"
00006 #include "Motion/Kinematics.h"
00007 #include "Shared/mathutils.h"
00008 #include "Shared/Measures.h"
00009 #include "Shared/Config.h"
00010 #include "Shared/MarkScope.h"
00011 
00012 #include "DualCoding/ShapeRoot.h"
00013 #include "DualCoding/ShapeLine.h"
00014 #include "DualCoding/ShapeEllipse.h"
00015 #include "DualCoding/ShapeBlob.h"
00016 #include "DualCoding/ShapeCylinder.h"
00017 #include "DualCoding/ShapePolygon.h"
00018 #include "DualCoding/ShapeSphere.h"
00019 #include "DualCoding/ShapeTarget.h"
00020 #include "DualCoding/ShapeMarker.h"
00021 #include "DualCoding/ShapeSift.h"
00022 #include "DualCoding/ShapeAprilTag.h"
00023 #include "DualCoding/ShapeDomino.h"
00024 #include "DualCoding/ShapeNaught.h"
00025 #include "DualCoding/ShapeCross.h"
00026 #include "DualCoding/Sketch.h"    
00027 #include "DualCoding/visops.h"
00028 #include "DualCoding/VRmixin.h"
00029 
00030 #include "Crew/LookoutRequests.h"
00031 #include "Crew/Lookout.h"
00032 #include "Crew/MapBuilder.h"
00033 
00034 #include "Vision/SIFT/API/SiftTekkotsu.h"
00035 #include "Vision/AprilTags/TagDetector.h"
00036 #include "Vision/AprilTags/TagDetection.h"
00037 
00038 using namespace std;
00039 
00040 namespace DualCoding {
00041 
00042 inline float distSq(const fmat::Column<4>& vec) {
00043   return vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2];
00044 }
00045 
00046 MapBuilder::MapBuilder() : 
00047   BehaviorBase("MapBuilder"),
00048   camSkS(VRmixin::getCamSkS()), camShS(camSkS.getDualSpace()),
00049   groundShS(VRmixin::getGroundShS()),
00050   localSkS(VRmixin::getLocalSkS()), localShS(localSkS.getDualSpace()),
00051   worldSkS(VRmixin::getWorldSkS()), worldShS(worldSkS.getDualSpace()),
00052   xres(camSkS.getWidth()), yres(camSkS.getHeight()), 
00053   ground_plane(),
00054   theAgent(VRmixin::theAgent),
00055   localToWorldMatrix(fmat::Transform::identity()),
00056   worldToLocalMatrix(fmat::Transform::identity()), 
00057   badGazePoints(), 
00058   requests(), curReq(NULL), idCounter(0), maxDistSq(0), siftMatchers(),
00059   pointAtID(Lookout::invalid_LO_ID), scanID(Lookout::invalid_LO_ID),
00060   nextGazePoint() {}
00061 
00062 void MapBuilder::preStart() {
00063   BehaviorBase::preStart();
00064   if ( verbosity & MBVstart )
00065     cout << "MapBuilder::start()\n";
00066 
00067   camSkS.clear(); camShS.clear();
00068   groundShS.clear();
00069   localSkS.clear(); localShS.clear();
00070   worldSkS.clear(); worldShS.clear();
00071   badGazePoints.clear();
00072 
00073   erouter->addListener(this,EventBase::textmsgEGID);  
00074   erouter->addListener(this,EventBase::lookoutEGID);  
00075 }
00076 
00077 bool MapBuilder::retain = true;
00078 
00079 MapBuilder::MapBuilderVerbosity_t MapBuilder::verbosity =
00080   (-1U & ~(MBVevents | MBVcomplete
00081 #ifdef TGT_HAS_WHEELS
00082            | MBVgroundPlane
00083 #endif
00084            | MBVgazePointQueue | MBVskipShape));
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 void MapBuilder::stop() {
00094   cout << "MapBuilder::stop()\n";
00095   while(!requests.empty()) {
00096     delete requests.front();
00097     requests.pop();
00098   }
00099   curReq = NULL;
00100   BehaviorBase::stop();
00101 }
00102 
00103 void MapBuilder::executeRequest(BehaviorBase *requestingBehavior, const MapBuilderRequest &req) {
00104   MapBuilderRequest newreq(req);
00105   newreq.requestingBehavior = requestingBehavior;
00106   executeRequest(newreq);
00107 }
00108 
00109 unsigned int MapBuilder::executeRequest(const MapBuilderRequest& req, unsigned int *req_id) {
00110   VRmixin::requireCrew("MapBuilder");
00111   MapBuilderRequest *newreq = new MapBuilderRequest(req);
00112   if ( !newreq->validateRequest() ) {
00113     cout << "*** Request rejected by MapBuilder" << endl;
00114     return 0;
00115   }
00116   const unsigned int this_request  = ++idCounter;
00117   newreq->requestID = this_request;
00118   if ( req_id != NULL ) *req_id = this_request;
00119   requests.push(newreq);
00120   executeRequest();
00121   return this_request;
00122 }
00123 
00124 void MapBuilder::executeRequest() {
00125   if ( curReq != NULL || requests.empty() ) return;
00126   curReq = requests.front();
00127   curReq->verbosity = (verbosity & ~curReq->clearVerbosity) | curReq->setVerbosity;
00128   if ( curReq->verbosity & MBVexecute )
00129     cout << "MapBuilder::executeRequest: execute " << curReq->requestID << endl;
00130   erouter->postEvent(EventBase::mapbuilderEGID, curReq->requestID, EventBase::activateETID,0);  
00131 
00132   calculateGroundPlane();
00133   maxDistSq = curReq->maxDist*curReq->maxDist;
00134   badGazePoints.clear();
00135  
00136   if ( curReq->clearCamera && ! curReq->ignoreCamera) {
00137     camShS.clear();
00138     camSkS.clear();
00139     curReq->gazePts.clear();
00140     curReq->baseToCamMats.clear();
00141   }
00142   if ( curReq->clearLocal ) {
00143     localShS.clear();
00144     localSkS.clear();
00145   }
00146   if ( curReq->clearWorld ) {
00147     worldShS.clear();
00148     worldSkS.clear();
00149   }
00150 
00151   if ( curReq->immediateRequest )
00152     grabCameraImageAndGo();
00153   else if ( ! curReq->searchArea.isValid() && curReq->worldTargets.size() == 0 )
00154     storeImage(false);
00155   else {
00156     setInitialGazePts();
00157     if ( curReq->doScan == true )
00158       return; 
00159     else if ( curReq->worldTargets.size() > 0 )
00160       doNextSearch();
00161     else if ( determineNextGazePoint() )
00162       moveToNextGazePoint();
00163     else
00164       requestComplete();
00165   }
00166 }
00167   
00168 
00169 
00170 
00171 
00172 
00173 
00174 
00175 
00176 
00177 
00178 
00179 
00180 
00181 
00182 
00183 
00184 void MapBuilder::doEvent() {
00185   if ( curReq == NULL) return;
00186   if ( curReq->verbosity & MBVevents )
00187     cout << "MapBuilder got event " << event->getName() << endl;
00188 
00189   switch ( event->getGeneratorID() ) {
00190   case EventBase::textmsgEGID:
00191     if ( strcmp(dynamic_cast<const TextMsgEvent&>(*event).getText().c_str(),"MoveHead") == 0 )
00192       moveToNextGazePoint(true);
00193     break;
00194 
00195   case EventBase::lookoutEGID:
00196     if ( event->getSourceID() == pointAtID )
00197       processImage(dynamic_cast<const LookoutSketchEvent&>(*event));
00198     else if ( event->getSourceID() == scanID ) {
00199       const vector<Point>& pts = dynamic_cast<const LookoutScanEvent*>(event)->getTasks().front()->data;
00200       cout << " doScan found " << pts.size() << " interest points." << endl;
00201       for (vector<Point>::const_iterator it = pts.begin(); it != pts.end(); it++)
00202         curReq->gazePts.push_back(GazePoint(GazePoint::visible, *it));
00203     }
00204     else {
00205       cout << "MapBuilder: unexpected Lookout event " << event->getDescription()
00206            << ",   current pointAtID=" << pointAtID << ", scanID=" << scanID << endl;
00207       return;
00208     }
00209     
00210     if ( requestExitTest() )
00211       requestComplete();
00212     else if ( curReq->worldTargets.size() > 0 )
00213       doNextSearch();
00214     else if ( determineNextGazePoint() )
00215       moveToNextGazePoint();
00216     else
00217       requestComplete();
00218     break;
00219 
00220   default:
00221     cout << "MapBuilder received unexpected event: " << event->getDescription() << endl;
00222   }
00223 }
00224 
00225 void MapBuilder::processImage(const LookoutSketchEvent &e) {
00226   const fmat::Transform& camToBase = curReq->baseTransform * e.toBaseMatrix;
00227   const fmat::Transform baseToCam = camToBase.rigidInverse();
00228   if ( ! curReq->ignoreCamera ) {
00229     if ( curReq->clearCamera ) {
00230       camSkS.clear(false); 
00231       camShS.clear();
00232     }
00233     if ( curReq->rawY ) {
00234       NEW_SKETCH(rawY, uchar, VRmixin::sketchFromRawY());
00235     }
00236     NEW_SKETCH(camFrame, uchar, e.getSketch());
00237     if (curReq->userImageProcessing != NULL) (*curReq->userImageProcessing)();
00238     getCameraShapes(camFrame);
00239     if (curReq->userCamProcessing != NULL) (*curReq->userCamProcessing)();
00240     if (curReq->getRequestType() > MapBuilderRequest::cameraMap) {
00241       projectToGround(camToBase);
00242       if (curReq->userGroundProcessing != NULL) (*curReq->userGroundProcessing)();
00243       filterGroundShapes(baseToCam);
00244     }
00245   }
00246   switch ( curReq->getRequestType() ) {
00247   case MapBuilderRequest::cameraMap:
00248   case MapBuilderRequest::groundMap:
00249     break;
00250   case MapBuilderRequest::localMap:
00251     if ( ! curReq->ignoreCamera )
00252       extendLocal(baseToCam);
00253     if (curReq->userLocalProcessing != NULL) (*curReq->userLocalProcessing)();
00254     break;
00255   case MapBuilderRequest::worldMap:
00256     if ( ! curReq->ignoreCamera )
00257       extendLocal(baseToCam);
00258     if (curReq->userLocalProcessing != NULL) (*curReq->userLocalProcessing)();
00259     extendWorld(baseToCam);
00260     if (curReq->userWorldProcessing != NULL) (*curReq->userWorldProcessing)();
00261   }
00262 }
00263 
00264 bool MapBuilder::determineNextGazePoint() {
00265   if ( (curReq->verbosity & MBVgazePointQueue) ) {
00266     std::cout << "GazePoint queue: ";
00267     if ( curReq->gazePts.empty() )
00268       std::cout << "empty";
00269     else
00270       for (std::vector<GazePoint>::const_iterator it = curReq->gazePts.begin();
00271            it != curReq->gazePts.end(); it++ )
00272         std::cout << " " << it->point;
00273     std::cout << std::endl;
00274   }
00275   if (curReq->getRequestType() == MapBuilderRequest::worldMap) {
00276     
00277     worldShS.applyTransform(worldToLocalMatrix,egocentric);
00278     bool b = determineNextGazePoint(worldShS.allShapes()) || determineNextGazePoint(curReq->gazePts);
00279     worldShS.applyTransform(localToWorldMatrix,allocentric); 
00280     return b;
00281   }
00282   else 
00283     return determineNextGazePoint(localShS.allShapes()) || determineNextGazePoint(curReq->gazePts);
00284 }
00285 
00286   
00287 bool MapBuilder::determineNextGazePoint(const vector<ShapeRoot>& shapes) {
00288   if ( ! curReq->pursueShapes )
00289     return false;
00290   HeadPointerMC headpointer_mc;
00291   for (vector<ShapeRoot>::const_iterator it = shapes.begin();
00292        it != shapes.end(); it++) {
00293     
00294     if ((*it)->isType(lineDataType) || (*it)->isType(polygonDataType)) {
00295       const Shape<LineData>& ld = ShapeRootTypeConst(*it,LineData);
00296       const Shape<PolygonData>& pd = ShapeRootTypeConst(*it,PolygonData);
00297       bool isLine = (*it)->isType(lineDataType);
00298       EndPoint p[2] = { isLine ? ld->end1Pt(): pd->end1Pt(), isLine ? ld->end2Pt() : pd->end2Pt()};
00299       for (int i = 0; i < 2; i++) {
00300         if ( !p[i].isValid() && !isBadGazePoint(p[i]) ) {
00301           cout << "Next gazepoint at endpoint" << (i+1) << " of shape id " 
00302                << (*it)->getId() << " at " << p[i] << endl;
00303           if ( !headpointer_mc.lookAtPoint(p[i].coordX(),p[i].coordY(),p[i].coordZ()) ) {
00304             if ( curReq->verbosity & MBVbadGazePoint )
00305               cout << "MapBuilder noting unreachable gaze point " << (Point)p[i] << endl;
00306             badGazePoints.push_back((Point)p[i]);
00307           }
00308           nextGazePoint = p[i];
00309           return true;
00310         }
00311       }
00312     }
00313     
00314     if ( (*it)->isType(blobDataType) ) {
00315       const Shape<BlobData>& bd = ShapeRootTypeConst(*it,BlobData);
00316       if ( ! (bd->bottomValid && bd->topValid && bd->leftValid && bd->rightValid) ) {
00317         Point bcentroid = bd->getCentroid();
00318         if ( ! isBadGazePoint(bcentroid) &&
00319              badGazePoints.end() == find(badGazePoints.begin(), badGazePoints.end(), bcentroid)) {
00320           
00321           badGazePoints.push_back(bcentroid);
00322           cout << "Next gazepoint for blob at " << bcentroid << endl;
00323           nextGazePoint = bcentroid;
00324           return true;
00325         }
00326       }
00327     }
00328     
00329     
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340 
00341 
00342 
00343 
00344 
00345     
00346     if ( curReq->verbosity & MBVskipShape )
00347       cout << "Skipping shape " << (*it)
00348            << " (confidence level: " << (*it)->getConfidence() << ")" << endl;      
00349   }
00350   return false;
00351 }
00352 
00353 
00354 
00355 bool MapBuilder::determineNextGazePoint(vector<GazePoint>& gazePts) {
00356   if ( ! gazePts.empty() && (curReq->verbosity & MBVgazePointQueue) )
00357     std::cout << "Gazepoint queue has " << gazePts.size() << " entries." << std::endl;
00358   for ( vector<GazePoint>::iterator it = gazePts.begin();
00359         it != gazePts.end();  it = gazePts.erase(it) ) {
00360     if (it->point.getRefFrameType() == DualCoding::allocentric) {
00361       it->point.applyTransform(worldToLocalMatrix,egocentric);
00362       it->point.setRefFrameType(egocentric);
00363     }
00364     if ( ! isBadGazePoint(it->point) ) {
00365       nextGazePoint = it->point;
00366       gazePts.erase(it);
00367       badGazePoints.push_back(nextGazePoint);
00368       return true;
00369     }
00370   }
00371   return false;
00372 }
00373 
00374 void MapBuilder::moveToNextGazePoint(const bool manualOverride) {
00375   if ( curReq == NULL ) {
00376     cout << "curReq == NULL in moveToNextGazePoint!" << endl;
00377     return;
00378   }
00379   if ( (curReq->verbosity & MBVnextGazePoint) || (curReq->manualHeadMotion && manualOverride==false) )
00380     cout << "moveToNextGazePoint " << nextGazePoint << endl;
00381   if ( curReq->manualHeadMotion && manualOverride==false ) {
00382     cout << "To proceed to this gaze point:  !msg MoveHead" << endl;
00383     return;
00384   }
00385   else
00386     storeImage(true);
00387 }
00388 
00389 
00390 void MapBuilder::doNextSearch() {
00391   LookoutSearchRequest *curLSR = curReq->worldTargets.front();
00392   curReq->worldTargets.pop();
00393   pointAtID = VRmixin::lookout->executeRequest(*curLSR);
00394 }
00395 
00396 bool MapBuilder::isBadGazePoint(const Point& pt) const {
00397   const coordinate_t x = pt.coordX();
00398   const coordinate_t y = pt.coordY();
00399   if ( x*x + y*y > maxDistSq )
00400     return true;
00401   float const badGazePointRadiusSq = 100;
00402   for ( vector<Point>::const_iterator it = badGazePoints.begin();
00403         it != badGazePoints.end(); it++ )
00404     if ( ((x-it->coordX())*(x-it->coordX()) + (y-it->coordY())*(y-it->coordY())) < badGazePointRadiusSq )
00405       return true;
00406   return false;
00407 }
00408 
00409 void MapBuilder::storeImage(bool useNextGazePoint) {
00410   LookoutPointRequest lreq;
00411   lreq.motionSettleTime = curReq->motionSettleTime;
00412   lreq.numSamples = curReq->numSamples;
00413   lreq.sampleInterval = curReq->sampleInterval;
00414   if ( useNextGazePoint )
00415     lreq.setTarget(nextGazePoint);
00416   else
00417     lreq.setHeadMotionType(LookoutRequestBase::noMotion);
00418   pointAtID = VRmixin::lookout->executeRequest(lreq);
00419 }
00420 
00421 void MapBuilder::grabCameraImageAndGo() {
00422   
00423   
00424   
00425   
00426   pointAtID = 0;
00427   Sketch<uchar> camFrame(VRmixin::sketchFromSeg());
00428 #ifdef TGT_HAS_CAMERA
00429   const fmat::Transform camToBase = kine->linkToBase(CameraFrameOffset);
00430 #else
00431   const fmat::Transform &camToBase = fmat::Transform::identity();
00432 #endif
00433   LookoutSketchEvent dummy(true, camFrame, camToBase,
00434                            EventBase::lookoutEGID, pointAtID, EventBase::deactivateETID);
00435   processImage(dummy);
00436   requestComplete();
00437 }
00438 
00439 void MapBuilder::scanForGazePts() {
00440   LookoutScanRequest lreq;
00441   lreq.searchArea = curReq->searchArea;
00442   lreq.motionSettleTime = curReq->motionSettleTime;
00443   set<color_index> colors;  
00444   for (map<ShapeType_t,set<color_index> >::const_iterator it1 = curReq->objectColors.begin();
00445        it1 != curReq->objectColors.end(); it1++)
00446     for (set<color_index>::const_iterator it2 = it1->second.begin();
00447          it2 != it1->second.end(); it2++)
00448       colors.insert(*it2);
00449   lreq.addTask(LookoutScanRequest::VisionRegionTask(colors,curReq->dTheta));
00450   scanID = VRmixin::lookout->executeRequest(lreq);
00451 }
00452 
00453 void MapBuilder::extendLocal(const fmat::Transform& baseToCam) {
00454   vector<ShapeRoot> all = localShS.allShapes();
00455   removeNoise(localShS, baseToCam);
00456   matchSrcToDst(groundShS,localShS,curReq->objectColors[polygonDataType]);
00457   
00458   
00459   
00460   
00461   curReq->baseToCamMats.push_back(baseToCam);
00462 }
00463 
00464 void MapBuilder::extendWorld(const fmat::Transform& baseToCam) {
00465   worldShS.applyTransform(worldToLocalMatrix,egocentric);
00466   removeNoise(worldShS, baseToCam);
00467   matchSrcToDst(localShS,worldShS,curReq->objectColors[polygonDataType]);
00468   worldShS.applyTransform(localToWorldMatrix,allocentric);
00469   removeGazePts(curReq->gazePts,baseToCam);
00470   curReq->baseToCamMats.push_back(baseToCam);
00471 }
00472 
00473 bool MapBuilder::requestExitTest() {
00474   if ( curReq->exitTest == NULL )
00475     return false;
00476   else
00477     return (*curReq->exitTest)();
00478 }
00479 
00480 void MapBuilder::requestComplete() {
00481   const size_t reqID = curReq->requestID;
00482   if ( curReq->verbosity & MBVcomplete )
00483     cout << "MapBuilderRequest " << reqID << " complete\n";
00484   BehaviorBase* reqbeh = curReq->requestingBehavior;
00485   delete curReq;
00486   curReq = NULL;
00487   requests.pop();
00488   if ( reqbeh )
00489     erouter->postEvent(EventBase::mapbuilderEGID, (size_t)reqbeh, EventBase::statusETID,0);
00490   else {
00491     erouter->postEvent(EventBase::mapbuilderEGID, reqID, EventBase::statusETID,0);
00492     erouter->postEvent(EventBase::mapbuilderEGID, reqID, EventBase::deactivateETID,0);
00493   }
00494   if ( requests.empty() )
00495     VRmixin::lookout->relax();
00496   else
00497     executeRequest(); 
00498 }
00499 
00500 void MapBuilder::setAgent(const Point &worldLocation, const AngTwoPi worldHeading, bool quiet) {
00501   if ( !quiet && ((curReq==NULL ? verbosity : curReq->verbosity) & MBVsetAgent) )
00502     cout << "Agent now at " << worldLocation << " hdg " << worldHeading 
00503          << " (= " << float(worldHeading)*180/M_PI << " deg.)" << endl;
00504   theAgent->setCentroidPt(worldLocation);
00505   theAgent->setOrientation(worldHeading);
00506   const coordinate_t dx = worldLocation.coordX();
00507   const coordinate_t dy = worldLocation.coordY();
00508   const coordinate_t dz = worldLocation.coordZ();
00509   float const c = cos(worldHeading);
00510   float const s = sin(worldHeading);
00511   float localToWorld[] =
00512     {c, -s, 0, dx,
00513      s,  c, 0, dy, 
00514      0,  0, 1, dz};
00515   localToWorldMatrix = fmat::Matrix<4,3>(localToWorld).transpose();;
00516   worldToLocalMatrix = localToWorldMatrix.inverse();
00517 }
00518 
00519 void MapBuilder::moveAgent(coordinate_t const local_dx, coordinate_t const local_dy, coordinate_t const local_dz, AngSignPi dtheta) {
00520   Point const agentLoc = theAgent->getCentroid();
00521   AngTwoPi const heading = theAgent->getOrientation();
00522   float const c = cos(heading);
00523   float const s = sin(heading);
00524   float const dx = local_dx*c + local_dy*-s;
00525   float const dy = local_dx*s + local_dy*c;
00526   setAgent(agentLoc + Point(dx,dy,local_dz,allocentric), heading+dtheta);
00527 }
00528 
00529 void MapBuilder::importLocalToWorld() {
00530   worldShS.applyTransform(worldToLocalMatrix,egocentric);
00531   matchSrcToDst(localShS,worldShS);
00532   worldShS.applyTransform(localToWorldMatrix,allocentric);
00533 }
00534 
00535 ShapeRoot MapBuilder::importLocalShapeToWorld(const ShapeRoot &localShape) {
00536   ShapeRoot worldShape(worldShS.importShape(localShape));
00537   worldShape->applyTransform(localToWorldMatrix, allocentric);
00538   return worldShape;
00539 }
00540 
00541 ShapeRoot MapBuilder::importWorldToLocal(const ShapeRoot &worldShape) {
00542   ShapeRoot localShape(localShS.importShape(worldShape));
00543   localShape->applyTransform(worldToLocalMatrix,egocentric);
00544   return localShape;
00545 }
00546 
00547 bool MapBuilder::isPointVisible(const Point &pt, const fmat::Transform& baseToCam, float maxDistanceSq) {
00548   fmat::Column<3> camCoords = baseToCam*fmat::pack(pt.coordX(),pt.coordY(),pt.coordZ());
00549   
00550   if ( fmat::SubVector<2>(camCoords).sumSq() >= maxDistanceSq )
00551     return false;
00552   float normX,normY; 
00553   config->vision.computePixel(camCoords[0],camCoords[1],camCoords[2],normX,normY);
00554   return (fabs(normX) < 0.9f && fabs(normY) < config->vision.aspectRatio*.9f); 
00555 }
00556 
00557 bool MapBuilder::isLineVisible(const LineData& ln, const fmat::Transform& baseToCam) {
00558   float normX1,normX2,normY1,normY2;
00559   fmat::Column<3> camCoords;
00560   Point pt = ln.end1Pt();
00561   camCoords = baseToCam*fmat::pack(pt.coordX(),pt.coordY(),pt.coordZ());
00562   config->vision.computePixel(camCoords[0],camCoords[1],camCoords[2],normX1,normY1);
00563   pt = ln.end2Pt();
00564   camCoords = baseToCam*fmat::pack(pt.coordX(),pt.coordY(),pt.coordZ());
00565   config->vision.computePixel(camCoords[0],camCoords[1],camCoords[2],normX2,normY2);
00566   const float xRange = 0.9f;
00567   const float yRange = config->vision.aspectRatio*.9f; 
00568   const bool end1Pt_visible = fabs(normX1) < xRange && fabs(normY1) < yRange;
00569   const bool end2Pt_visible = fabs(normX2) < xRange && fabs(normY2) < yRange;
00570   if (end1Pt_visible && end2Pt_visible)
00571     return true;
00572   LineData lnCam(VRmixin::groundShS, Point(normX1,normY1), Point(normX2,normY2));
00573   
00574   LineData camBounds[] = {LineData(VRmixin::groundShS, Point( xRange, yRange), Point( xRange,-yRange)),
00575                           LineData(VRmixin::groundShS, Point( xRange,-yRange), Point(-xRange,-yRange)),
00576                           LineData(VRmixin::groundShS, Point(-xRange,-yRange), Point(-xRange, yRange)),
00577                           LineData(VRmixin::groundShS, Point(-xRange, yRange), Point( xRange, yRange))};
00578   unsigned int ptCount = 0;
00579   Point p[2];
00580   
00581   if (end1Pt_visible) p[ptCount++].setCoords(normX1,normY1,0); 
00582   else if (end2Pt_visible) p[ptCount++].setCoords(normX2,normY2,0); 
00583   for (int i = 0; i < 4; i++)
00584     if (camBounds[i].intersectsLine(lnCam)) {
00585       p[ptCount++].setCoords(lnCam.intersectionWithLine(camBounds[i]));
00586       
00587       if (ptCount > 1)
00588         return p[0].distanceFrom(p[1]) > 0.1; 
00589     }
00590   return false;
00591 }
00592 
00593 bool MapBuilder::isShapeVisible(const ShapeRoot &ground_shape, const fmat::Transform& baseToCam,
00594                                 float maxDistanceSq) {
00595   if (ground_shape->isType(lineDataType))
00596     return isLineVisible(ShapeRootTypeConst(ground_shape,LineData).getData(), baseToCam);
00597   else if (ground_shape->isType(polygonDataType)) {
00598     const Shape<PolygonData>& polygon = ShapeRootTypeConst(ground_shape,PolygonData);
00599     for (vector<LineData>::const_iterator edge_it = polygon->getEdges().begin();
00600          edge_it != polygon->getEdges().end(); edge_it++)
00601       if (isLineVisible(*edge_it,baseToCam))
00602         return true;
00603     return false;
00604   }
00605   else 
00606     return isPointVisible(ground_shape->getCentroid(), baseToCam, maxDistanceSq);
00607 }
00608 
00609 
00610 
00611 
00612 
00613 void MapBuilder::filterGroundShapes(const fmat::Transform& baseToCam) {
00614   
00615   vector<ShapeRoot> ground_shapes = groundShS.allShapes();
00616 
00617   for (vector<ShapeRoot>::iterator ground_it = ground_shapes.begin();
00618        ground_it != ground_shapes.end(); ground_it++ ) {
00619     const coordinate_t cenX = (*ground_it)->getCentroid().coordX();
00620     const coordinate_t cenY = (*ground_it)->getCentroid().coordY();
00621     if (cenX*cenX + cenY*cenY > maxDistSq) { 
00622       if ( curReq->verbosity & MBVnotAdmissible )
00623         cout << "ground shape " << (*ground_it)->getId() << " (lastMatch " 
00624              << (*ground_it)->getLastMatchId() << ") too far, delete\n";
00625       ground_it->deleteShape();
00626     }
00627     fmat::Column<3> coords = Kinematics::pack(cenX,cenY,(*ground_it)->getCentroid().coordZ());
00628     coords = baseToCam*coords;
00629     if (coords[2] < 0) { 
00630       if ( curReq->verbosity & MBVprojectionFailed )
00631         cout << "Projection failed for ground shape " << (*ground_it)->getId()
00632              << ": " << coords
00633              << " (lastMatch " << (*ground_it)->getLastMatchId() << "): deleting\n";
00634       ground_it->deleteShape();
00635     }
00636     
00637     else if ((*ground_it)->isType(lineDataType)) {
00638       Shape<LineData>& line = ShapeRootType(*ground_it,LineData);
00639       const coordinate_t e1x = line->end1Pt().coordX();
00640       const coordinate_t e1y = line->end1Pt().coordY();
00641       const coordinate_t e2x = line->end2Pt().coordX();
00642       const coordinate_t e2y = line->end2Pt().coordY();
00643       if (e1x*e1x + e1y*e1y > maxDistSq && e2x*e2x + e2y*e2y > maxDistSq)
00644         ground_it->deleteShape();
00645       else if (e1x*e1x + e1y*e1y > maxDistSq || e2x*e2x + e2y*e2y > maxDistSq) {
00646         
00647         
00648         vector<float> line_abc = line->lineEquation_abc();
00649         Point pt;
00650         const EndPoint* far_ept = (e1x*e1x + e1y*e1y > maxDistSq) ? &line->end1Pt() : &line->end2Pt(); 
00651         if (line_abc[1] == 0.0) {
00652           const coordinate_t y_abs = sqrt(maxDistSq - line_abc[2]*line_abc[2]);
00653           if (fabs(far_ept->coordY()-y_abs) < fabs(far_ept->coordY()+y_abs))
00654             pt.setCoords(e1x, y_abs, far_ept->coordZ());
00655           else
00656             pt.setCoords(e1x, -y_abs, far_ept->coordZ());
00657         }
00658         else {
00659           const float a = - line_abc[0]/line_abc[1];
00660           const float b = line_abc[2]/line_abc[1];
00661           const coordinate_t x1 = (std::sqrt((a*a+1)*maxDistSq-b*b)-a*b)/(a*a+1);
00662           const coordinate_t x2 = (-std::sqrt((a*a+1)*maxDistSq-b*b)-a*b)/(a*a+1);
00663           if (std::abs(far_ept->coordX()-x1) < std::abs(far_ept->coordX()-x2))
00664             pt.setCoords(x1, a*x1+b, far_ept->coordZ());
00665           else
00666             pt.setCoords(x2, a*x2+b, far_ept->coordZ());
00667         }
00668         EndPoint temp_endPt(pt);
00669         temp_endPt.setValid(false);
00670         
00671         
00672         if (e1x*e1x + e1y*e1y > maxDistSq)
00673           line->setEndPts(temp_endPt, line->end2Pt());
00674         else
00675           line->setEndPts(line->end1Pt(), temp_endPt);
00676         badGazePoints.push_back(pt);
00677       }
00678     }
00679   }
00680 }
00681 
00682 void MapBuilder::calculateGroundPlane() {
00683   switch(curReq->groundPlaneAssumption) {
00684   case MapBuilderRequest::onLegs:
00685     ground_plane = kine->calculateGroundPlane(); 
00686     if ( curReq->verbosity & MBVgroundPlane ) 
00687       cout << "Calculated ground plane: " << ground_plane << endl;
00688     break;
00689   case MapBuilderRequest::onStand:
00690 #if defined(TGT_ERS210) || defined(TGT_ERS220) || defined(TGT_ERS2xx)
00691     ground_plane = PlaneEquation(0,0,-1,200);
00692 #else
00693     ground_plane = PlaneEquation(0,0,-1,170);
00694 #endif
00695     
00696     break;
00697   case MapBuilderRequest::onWheel:
00698 #ifdef TGT_REGIS1
00699     std::cout << "Target Regis 1 Mapping";
00700     ground_plane = fmat::pack<float>(0,0,(-1/85.0),1);
00701 #endif
00702     break;    
00703   case MapBuilderRequest::custom:
00704     ground_plane = curReq->customGroundPlane;
00705   }
00706 }
00707 
00708 void MapBuilder::projectToGround(const fmat::Transform& camToBase) {
00709   VRmixin::projectToGround(camToBase, ground_plane);
00710 }
00711 
00712 ShapeRoot MapBuilder::projectToLocal(ShapeRoot &shape) {
00713 #ifdef TGT_HAS_CAMERA
00714   fmat::Transform camToBase = kine->linkToBase(CameraFrameOffset);
00715 #else
00716   fmat::Transform camToBase = fmat::Transform::identity();
00717 #endif
00718   ground_plane = kine->calculateGroundPlane();
00719   
00720   groundShS.importShape(shape);
00721   ShapeRoot &newShape = groundShS.allShapes().back();
00722   newShape->projectToGround(camToBase, ground_plane);
00723   localShS.importShape(newShape);
00724   return localShS.allShapes().back();
00725 }
00726   
00727 void MapBuilder::matchSrcToDst(ShapeSpace &srcShS, ShapeSpace &dstShS,
00728                                set<color_index> polCols, bool mergeSrc, bool mergeDst) {
00729   vector<ShapeRoot> src_shapes = srcShS.allShapes();
00730   vector<ShapeRoot> dst_shapes = dstShS.allShapes();
00731   vector<LineData> polygon_edges;
00732   
00733   
00734   std::set<int> markedForDeletion;
00735   vector<ShapeRoot> cleaned_src;
00736   for (vector<ShapeRoot>::iterator src_it = src_shapes.begin();
00737        src_it != src_shapes.end(); src_it++ ) {
00738     
00739     if (!(*src_it)->isAdmissible()) {
00740       if (curReq && curReq->verbosity & MBVnotAdmissible )
00741         cout << "shape " << (*src_it)->getId() << " (lastMatch " 
00742              << (*src_it)->getLastMatchId() << ") is not admissible." << endl;
00743       
00744       markedForDeletion.insert((*src_it)->getId());
00745     }
00746     else if ((*src_it)->isType(polygonDataType) && (*src_it)->getParentId() != 0) {
00747       const vector<LineData>& edges = ShapeRootTypeConst(*src_it, PolygonData)->getEdges();
00748       
00749       
00750       
00751       polygon_edges.insert(polygon_edges.end(), edges.begin(), edges.end());
00752       markedForDeletion.insert((*src_it)->getId());
00753     }
00754     else if ((*src_it)->isType(lineDataType)) {
00755       
00756       
00757       const color_index colorIndex = ProjectInterface::getColorIndex((*src_it)->getColor());
00758       if ( polCols.end() != find(polCols.begin(), polCols.end(), colorIndex)) {
00759         polygon_edges.push_back(ShapeRootTypeConst(*src_it, LineData).getData());
00760         markedForDeletion.insert((*src_it)->getId());
00761       }
00762     }
00763   }
00764   
00765   for ( vector<ShapeRoot>::iterator it = src_shapes.begin();
00766         it != src_shapes.end(); it++ )
00767     if ( markedForDeletion.find((*it)->getId()) == markedForDeletion.end() )
00768       cleaned_src.push_back(*it);
00769   src_shapes = cleaned_src;
00770 
00771   
00772   if (mergeSrc) {
00773     markedForDeletion.clear();
00774     cleaned_src.clear();
00775     for ( vector<ShapeRoot>::iterator it = src_shapes.begin();
00776           it != src_shapes.end(); it++ )
00777       for ( vector<ShapeRoot>::iterator it2 = it+1;
00778             it2 != src_shapes.end(); it2++)
00779         if ((*it2)->isMatchFor(*it) && (*it)->updateParams(*it2)) {
00780           if (curReq && curReq->verbosity & MBVshapesMerge )
00781             cout << "merging shape " << (*it)->getId() << " (from " << (*it)->getLastMatchId()
00782                  << ") and shape " << (*it2)->getId() << " (from " << (*it2)->getLastMatchId() << ")" << endl;
00783           markedForDeletion.insert((*it2)->getId());
00784         }
00785     
00786     for ( vector<ShapeRoot>::iterator it = src_shapes.begin();
00787           it != src_shapes.end(); it++ )
00788       if ( markedForDeletion.find((*it)->getId()) == markedForDeletion.end() )
00789         cleaned_src.push_back(*it);
00790     src_shapes = cleaned_src;
00791   }
00792 
00793   
00794   markedForDeletion.clear();
00795   cleaned_src.clear();
00796   std::set<int> markedForDeletionDst;
00797   vector<Shape<PolygonData> > existingPolygons;
00798   for (vector<ShapeRoot>::iterator dst_it = dst_shapes.begin();
00799        dst_it != dst_shapes.end(); dst_it++ ) {
00800     
00801     if ( (*dst_it)->isType(polygonDataType) && (*dst_it)->getParentId() != 0 ) {
00802       existingPolygons.push_back(ShapeRootType(*dst_it,PolygonData));
00803       continue;
00804     }
00805     if ( (*dst_it)->isType(localizationParticleDataType) )
00806       continue;
00807     for (vector<ShapeRoot>::iterator src_it = src_shapes.begin();
00808          src_it != src_shapes.end(); src_it++)
00809       if ((*dst_it)->isMatchFor(*src_it) && (*dst_it)->updateParams((*src_it))) {
00810         (*dst_it)->increaseConfidence(2);  
00811         (*dst_it)->setLastMatchId((*src_it)->getId());
00812         if (curReq && curReq->verbosity & MBVshapeMatch )
00813           cout << "Matched src shape " << *src_it << " (lastMatch " << (*src_it)->getLastMatchId()
00814                << ") to dst shape " << (*dst_it)->getId() << endl;
00815         markedForDeletion.insert((*src_it)->getId());
00816       } else if((*dst_it)->getType() == agentDataType && (*src_it)->getType() == agentDataType &&
00817                 (*dst_it)->getName() == (*src_it)->getName()) {
00818         
00819         
00820         
00821         
00822         markedForDeletionDst.insert((*dst_it)->getId());
00823         break;
00824       }
00825   }
00826 
00827   
00828   for ( vector<ShapeRoot>::iterator it = src_shapes.begin();
00829         it != src_shapes.end(); it++ )
00830     if ( markedForDeletion.find((*it)->getId()) == markedForDeletion.end() ) {
00831       cleaned_src.push_back(*it);
00832       if((*it)->getType() == agentDataType) {
00833         const Shape<AgentData> &a = ShapeRootTypeConst(*it, AgentData);
00834         cout << a->getName() << ", " << a->getId() << ": " << a->getCentroid() << ", " << a->getOrientation() << endl;
00835       }
00836     }
00837   src_shapes = cleaned_src;
00838   for(vector<ShapeRoot>::iterator it = dst_shapes.begin();
00839             it != dst_shapes.end(); ++it) {
00840     if(markedForDeletionDst.find((*it)->getId()) != markedForDeletionDst.end()) {
00841       dstShS.deleteShape(*it);
00842     }
00843   }
00844   
00845   
00846   vector<Shape<PolygonData> > deletedPolygons;
00847   vector<ShapeRoot> newPolygons = PolygonData::rebuildPolygons(polygon_edges,existingPolygons,deletedPolygons);
00848   for (vector<Shape<PolygonData> >::iterator delete_it = deletedPolygons.begin();
00849        delete_it != deletedPolygons.end(); delete_it++) {
00850     delete_it->deleteShape();
00851   }
00852   dstShS.importShapes(newPolygons);
00853   dstShS.importShapes(src_shapes);
00854   if (curReq && curReq->verbosity & MBVimportShapes ) {
00855     std::map<ShapeType_t,int> shapeCounts;
00856     if ( ! newPolygons.empty() )
00857       shapeCounts[polygonDataType] += newPolygons.size();
00858     for (std::vector<ShapeRoot>::iterator it = src_shapes.begin();
00859          it != src_shapes.end(); it++)
00860       ++shapeCounts[(*it)->getType()];
00861     cout << dstShS.name << "ShS imported";
00862     int comma = 0;
00863     if ( src_shapes.empty() && newPolygons.empty() )
00864       cout << " nothing";
00865     else
00866       for (std::map<ShapeType_t,int>::const_iterator it = shapeCounts.begin();
00867            it != shapeCounts.end(); it++)
00868         cout << (comma++ ? "," : "") << " " << it->second << " " << data_name(it->first);
00869     cout << endl;
00870   }
00871   
00872   
00873   if (mergeDst) {
00874     dst_shapes = dstShS.allShapes();
00875     for ( vector<ShapeRoot>::iterator it = dst_shapes.begin();
00876           it != dst_shapes.end(); it++ ) {
00877       if ( (*it)->isType(localizationParticleDataType) || (*it)->isType(agentDataType) )
00878         continue;
00879       for ( vector<ShapeRoot>::iterator it2 = it+1;
00880             it2 < dst_shapes.end(); it2++)
00881         if ((*it2)->isMatchFor(*it) && (*it)->updateParams(*it2,true)) {
00882           cout << "Matched src shape " << *it << " (lastMatch " 
00883                << (*it)->getLastMatchId()<< ") is a match for " 
00884                << *it2 << " (lastMatch " << (*it2)->getLastMatchId()
00885                << "), delete " << (*it2)->getId() << endl;;
00886           (*it)->setLastMatchId((*it2)->getLastMatchId());
00887           it2->deleteShape();
00888         }
00889     }
00890   }
00891 }
00892 
00893 
00894 
00895 void MapBuilder::removeNoise(ShapeSpace& ShS, const fmat::Transform& baseToCam) {
00896   
00897   vector<ShapeRoot> shapes = ShS.allShapes();
00898   for (vector<ShapeRoot>::iterator it = shapes.begin();
00899        it != shapes.end(); it++ ) {
00900     
00901     
00902     if (curReq->objectColors[(*it)->getType()].find(ProjectInterface::getColorIndex((*it)->getColor())) ==
00903         curReq->objectColors[(*it)->getType()].end())
00904       continue; 
00905     
00906     
00907     if ( (*it)->isType(polygonDataType) && (*it)->getParentId() != 0 ) {
00908       Shape<PolygonData>& polygon = ShapeRootType(*it,PolygonData);
00909       vector<LineData>& edges = polygon->getEdgesRW();
00910       unsigned int edge_index = 0;
00911       for (vector<LineData>::iterator edge_it = edges.begin();
00912            edge_it != edges.end(); edge_it++, edge_index++) {
00913         if (isLineVisible(*edge_it, baseToCam)) {
00914           
00915           
00916           
00917           edge_it->decreaseConfidence();
00918         }
00919       }
00920       vector<ShapeRoot> brokenPolygons = polygon->updateState();
00921       ShS.importShapes(brokenPolygons);
00922       if (!polygon->isAdmissible()) {
00923         if ( curReq->verbosity & MBVdeleteShape )
00924           cout << "delete polygon " << (*it)->getId() << " from map" << endl;
00925         it->deleteShape();
00926       }
00927     }
00928     else if ((!(*it)->isType(agentDataType)) && isShapeVisible(*it, baseToCam, maxDistSq)) {
00929       if ((*it)->getConfidence() < 0 ) {
00930         if ( curReq->verbosity & MBVshouldSee )
00931           cout << "shape " << (*it)->getId() << "(confidence: " << (*it)->getConfidence() 
00932                << ") should be visible in this frame; delete it" << endl;
00933         it->deleteShape();
00934       }
00935       else  
00936         (*it)->decreaseConfidence(); 
00937     }
00938   }
00939 }
00940 
00941 
00942 
00943 void MapBuilder::setInitialGazePts() {
00944   const ShapeRoot &sArea = curReq->searchArea;
00945   if ( ! sArea.isValid() )
00946     return;
00947   else if ( curReq->doScan == true )
00948     scanForGazePts();
00949   else
00950     switch ( sArea->getType() ) {
00951 
00952     case pointDataType:
00953       curReq->gazePts.push_back(GazePoint(GazePoint::centered,sArea->getCentroid()));
00954       break;
00955 
00956     case lineDataType: {
00957       static const float meshSize=50;
00958       const Shape<LineData>& line = ShapeRootTypeConst(sArea,LineData);
00959       if ( curReq->doScan == true )
00960         scanForGazePts();
00961       else {
00962         int numIntervals = (int) (line->getLength()/meshSize);
00963         const EndPoint& ep1 = line->end1Pt();
00964         const EndPoint& ep2 = line->end2Pt();
00965         curReq->gazePts.push_back(GazePoint(GazePoint::centered,ep1));
00966         for (int i = 1; i < numIntervals; i++)
00967           curReq->gazePts.push_back(GazePoint(GazePoint::centered,(ep1*i + ep2*(numIntervals-i))/numIntervals));
00968         curReq->gazePts.push_back(GazePoint(GazePoint::centered,ep2));
00969       }
00970     }
00971       break;
00972 
00973     case polygonDataType:
00974       if ( curReq->doScan == true )
00975         scanForGazePts();
00976       else {
00977         const Shape<PolygonData> &poly = ShapeRootTypeConst(sArea,PolygonData);
00978         const vector<Point> &verts = poly->getVertices();
00979         for (std::vector<Point>::const_iterator it = verts.begin(); it != verts.end(); it++)
00980           curReq->gazePts.push_back(GazePoint(GazePoint::centered,*it));
00981       }
00982       break;
00983 
00984     default:
00985       cerr << "ERROR MapBuilder::setInitialGazePts: Supported searchArea shapes are Point, Line, and Polygon\n";
00986       requestComplete();
00987       break;
00988     }
00989 }
00990 
00991 void MapBuilder::removeGazePts(vector<GazePoint> &gazePts, const fmat::Transform& baseToCam) {
00992   if (curReq->removePts) {
00993     int num_points_seen = 0;
00994     for ( vector<GazePoint>::iterator it = gazePts.begin();
00995           it != gazePts.end(); it++ ) {
00996       if ( it->point == nextGazePoint || 
00997            (it->type == GazePoint::visible && isPointVisible(it->point,baseToCam,maxDistSq)) ) {
00998         if ( it->point != nextGazePoint )
00999           cout << "Removing already-visible gaze point " << it->point << endl;
01000         num_points_seen++;
01001         gazePts.erase(it--);
01002       }
01003     }
01004     
01005     
01006   }
01007 }
01008 
01009 
01010 
01011 
01012 
01013 void MapBuilder::printShS(ShapeSpace &ShS) const {
01014   cout << "MapBuilder::printShS()" << endl;
01015   unsigned int line_count = 0;
01016   vector<ShapeRoot> shapes = ShS.allShapes();
01017   for (vector<ShapeRoot>::const_iterator it = shapes.begin();
01018        it != shapes.end(); it++) {
01019     if ((*it)->isType(lineDataType)) {
01020       const Shape<LineData>& ld = ShapeRootTypeConst(*it,LineData);
01021       cout << (*it)->getId() << " " << lineDataType << " " 
01022            << ProjectInterface::getColorIndex((*it)->getColor()) 
01023            << " " << ld->end1Pt().coordX()  << " " << ld->end1Pt().coordY()
01024            << " " << ++line_count << " " << ld->getLength() << " " << ld->end1Pt().isValid() << endl; 
01025       cout << (*it)->getId() << " " << lineDataType << " " 
01026            << ProjectInterface::getColorIndex((*it)->getColor()) 
01027            << " " << ld->end2Pt().coordX()  << " " << ld->end2Pt().coordY()
01028            << " " << line_count << " " << ld->getLength() << " " << ld->end2Pt().isValid() << endl;
01029     }
01030     else {
01031       cout << (*it)->getId() << " " << (*it)->getType() << " " 
01032            << ProjectInterface::getColorIndex((*it)->getColor()) 
01033            << " " << (*it)->getCentroid().coordX()  << " " << (*it)->getCentroid().coordY() << endl;
01034     }
01035   }
01036 }
01037 
01038 
01039 
01040 
01041 void MapBuilder::getCameraShapes(const Sketch<uchar>& camFrame) { 
01042   getCamLines(camFrame, curReq->objectColors[lineDataType], curReq->occluderColors[lineDataType]);
01043   getCamEllipses(camFrame, curReq->objectColors[ellipseDataType], curReq->occluderColors[ellipseDataType]);
01044   getCamPolygons(camFrame, curReq->objectColors[polygonDataType], curReq->occluderColors[polygonDataType]);
01045   getCamSpheres(camFrame, curReq->objectColors[sphereDataType], curReq->occluderColors[sphereDataType]);
01046   getCamCylinders(camFrame, curReq->objectColors[cylinderDataType], curReq->assumedCylinderHeights, curReq->minBlobAreas);
01047   getCamWalls(camFrame, curReq->floorColor);
01048   if ( curReq->numSamples == 1 && !curReq->searchArea.isValid() && 
01049        !curReq->objectColors[blobDataType].empty() && curReq->userImageProcessing == NULL )  
01050     getCamBlobs(curReq->objectColors[blobDataType]);
01051   else
01052     getCamBlobs(camFrame, curReq->objectColors[blobDataType], curReq->minBlobAreas, curReq->blobOrientations, curReq->assumedBlobHeights);
01053   getCamTargets(camFrame, curReq->objectColors[targetDataType], curReq->occluderColors[targetDataType]);
01054   getCamMarkers(camFrame, curReq->objectColors[markerDataType], curReq->occluderColors[markerDataType],
01055                 curReq->markerTypes);
01056   getCamDominoes(camFrame, curReq->objectColors[dominoDataType], curReq->secondColors[dominoDataType]);
01057 
01058   getCamNaughts(camFrame, curReq->objectColors[naughtDataType], curReq->naughtDimensions);
01059   getCamCrosses(camFrame, curReq->objectColors[crossDataType]);
01060 
01061   
01062   if ( !curReq->siftDatabasePath.empty() || curReq->aprilTagFamily.first != 0) {
01063     NEW_SKETCH_N(rawY, uchar, VRmixin::sketchFromRawY());
01064     getCamSiftObjects(rawY, curReq->siftDatabasePath, curReq->siftObjectNames);
01065     getCamAprilTags(rawY);
01066   }
01067   if ( ! curReq->objectColors[agentDataType].empty() ) {
01068     NEW_SKETCH_N(camFrameYUV, yuv, VRmixin::sketchFromYUV());
01069     getCamAgents(camFrame, camFrameYUV, curReq->objectColors[agentDataType]);
01070   }
01071 }
01072 
01073 vector<Shape<LineData> > MapBuilder::getCamLines(const Sketch<uchar> &camFrame, const set<color_index>& objectColors, 
01074                                                  const set<color_index>& occluderColors) const {
01075   vector<Shape<LineData> > linesReturned;
01076   if ( objectColors.empty() ) 
01077     return linesReturned;
01078   if ( curReq->verbosity & MBVshapeSearch )
01079     cout << "*** Find the lines ***" << endl;
01080   NEW_SKETCH_N(occluders,bool,visops::zeros(camFrame));
01081   for ( set<color_index>::const_iterator it = occluderColors.begin();
01082         it != occluderColors.end(); it++ )
01083     occluders |= visops::minArea(visops::colormask(camFrame,*it));
01084 
01085   for (set<color_index>::const_iterator it = objectColors.begin();
01086        it != objectColors.end(); it++) {
01087     NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,*it));
01088     NEW_SKETCH_N(cleancolor,bool,visops::minArea(colormask));
01089     NEW_SKETCH_N(fatmask,bool,visops::fillin(cleancolor,1,2,8));
01090     NEW_SKETCH_N(skel,bool,visops::skel(fatmask));
01091     vector<Shape<LineData> > line_shapes(LineData::extractLines(skel,cleancolor|occluders));
01092     linesReturned.insert(linesReturned.end(), line_shapes.begin(), line_shapes.end());
01093     if ( curReq->verbosity & MBVshapesFound )
01094       cout << "Found " << line_shapes.size() << " " 
01095            << ProjectInterface::getColorName(*it) << " lines." << endl;
01096   }
01097   return linesReturned;
01098 }
01099 
01100 vector<Shape<EllipseData> > 
01101 MapBuilder::getCamEllipses(const Sketch<uchar> &camFrame,
01102                            const set<color_index>& objectColors, const set<color_index>& ) const {
01103   vector<Shape<EllipseData> > ellipses;
01104   if (objectColors.empty())
01105     return ellipses;
01106   if ( curReq->verbosity & MBVshapeSearch )
01107     cout << "*** Find the ellipses ***" << endl;
01108   for (set<color_index>::const_iterator it = objectColors.begin();
01109        it !=objectColors.end(); it++) {
01110     NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,*it));
01111     vector<Shape<EllipseData> > ellipse_shapes = EllipseData::extractEllipses(colormask);
01112     ellipses.insert(ellipses.end(), ellipse_shapes.begin(),ellipse_shapes.end());
01113     if ( curReq->verbosity & MBVshapesFound )
01114       cout << "Found " << ellipse_shapes.size() << " "
01115            << ProjectInterface::getColorName(*it) << " ellipses." << endl;
01116   }
01117   return ellipses;
01118 }
01119 
01120 void MapBuilder::getCamPolygons(const Sketch<uchar> &camFrame,
01121                                 const set<color_index>& objectColors,
01122                                 const set<color_index>& occluderColors) const {
01123   if ( objectColors.empty() ) 
01124     return;
01125   if ( curReq->verbosity & MBVshapeSearch )
01126     cout << "*** Find the polygons ***" << endl;
01127   NEW_SKETCH_N(occluders,bool,visops::zeros(camFrame));
01128   for ( set<color_index>::const_iterator it = occluderColors.begin();
01129         it !=occluderColors.end(); it++ )
01130     occluders |= visops::colormask(camFrame,*it);
01131   
01132   for (set<color_index>::const_iterator it = objectColors.begin();
01133        it !=objectColors.end(); it++) {
01134     NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,*it));
01135     NEW_SKETCH_N(fatmask,bool,visops::fillin(colormask,1,2,8));
01136     NEW_SKETCH_N(skel,bool,visops::skel(fatmask));
01137     NEW_SKETCH_N(fatskel,bool,visops::fillin(skel,1,2,8));
01138     
01139     vector<Shape<LineData> > pLines = LineData::extractLines(fatskel,fatmask|occluders);
01140     vector<LineData> polygonLines;
01141     for ( vector<Shape<LineData> >::iterator ln_it = pLines.begin();
01142           ln_it != pLines.end(); ln_it++ ) {
01143       polygonLines.push_back(ln_it->getData());
01144       
01145       ln_it->deleteShape();
01146     }
01147     vector<ShapeRoot> polygons = PolygonData::formPolygons(polygonLines);
01148     if ( curReq->verbosity & MBVshapesFound )
01149       cout << "Found " << polygons.size() << " polygons." << endl;
01150   }
01151 }
01152 
01153 void MapBuilder::getCamSpheres(const Sketch<uchar> &camFrame,
01154                                const set<color_index>& objectColors, const set<color_index>& ) const {
01155   vector<Shape<SphereData> > spheres;
01156   if ( objectColors.empty() )
01157     return;
01158   if ( curReq->verbosity & MBVshapeSearch )
01159     cout << "*** Find the spheres ***" << endl;
01160   for (set<color_index>::const_iterator it = objectColors.begin();
01161        it !=objectColors.end(); it++) {
01162     NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,*it));
01163     vector<Shape<SphereData> > sphere_shapes = SphereData::extractSpheres(colormask);
01164     spheres.insert(spheres.end(), spheres.begin(), spheres.end());
01165     if ( curReq->verbosity & MBVshapesFound )
01166       cout << "Found " << sphere_shapes.size() << " spheres." << endl;
01167   }
01168 }
01169 
01170 void MapBuilder::getCamCylinders(const Sketch<uchar>& camFrame,
01171                                  const set<color_index>& colors,
01172                                  const map<color_index,coordinate_t>& assumedHeights,
01173                                  const map<color_index,int>& minCylinderAreas) {
01174   if ( colors.empty() )
01175     return;
01176   if ( curReq->verbosity & MBVshapeSearch )
01177     cout << "*** Find the cylinders ***" << endl;
01178   int const maxcylinders = 50;
01179   vector<GazePoint> addGazePts;
01180   vector<Shape<CylinderData> > result(CylinderData::extractCylinders(camFrame, colors, assumedHeights, 
01181                                                                      minCylinderAreas, maxcylinders, addGazePts));
01182   if ( curReq->verbosity & MBVshapesFound )
01183     if ( !result.empty() )
01184       cout << "Found " << result.size() << " cylinders." << endl;
01185   if ( ! addGazePts.empty() ) {
01186     const fmat::Transform camToBase = kine->linkToBase(CameraFrameOffset);
01187     for ( std::vector<GazePoint>::iterator it = addGazePts.begin();
01188           it != addGazePts.end(); it++ ) {
01189       it->point.projectToGround(camToBase,ground_plane);
01190       
01191       std::cout << "Blob not valid; would have added gazepoint at " << it->point << std::endl;
01192     }
01193   }
01194 }
01195   
01196 vector<Shape<LineData> > 
01197 MapBuilder::getCamWalls(const Sketch<uchar> &camFrame, unsigned int floorColor) const {
01198   if (floorColor == 0)
01199     return vector<Shape<LineData> >();
01200   if ( curReq->verbosity & MBVshapeSearch )
01201     cout << "*** Find the walls ***" << endl;
01202   const int camFrame_offset = 8;
01203   
01204   NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,floorColor));
01205   NEW_SKETCH_N(fillinmask ,bool,visops::fillin(colormask, 1, 6, 8)); 
01206   NEW_SKETCH_N(fillinmask2 ,bool,visops::fillin(fillinmask, 2, 3, 8)); 
01207   NEW_SKETCH_N(edgemask ,bool,visops::fillin(fillinmask2, 1, 5, 7)); 
01208   NEW_SKETCH_N(edgemask2 ,bool,visops::non_bounds(edgemask, camFrame_offset)); 
01209 
01210   NEW_SKETCH_N(occluders_floor, bool, (camFrame != uchar(0)) & (camFrame != uchar(floorColor)));
01211   NEW_SKETCH_N(occ_mask ,bool,visops::fillin(occluders_floor, 1, 8, 8)); 
01212   usint const clear_dist = 15;
01213   Sketch<bool> not_too_close = (visops::mdist(occ_mask) >= clear_dist); 
01214   edgemask2 &= not_too_close; 
01215   
01216   NEW_SKETCH_N(fatmask ,bool,visops::fillin(edgemask2,2,2,8)); 
01217   NEW_SKETCH_N(skel,bool,visops::skel(fatmask));
01218   NEW_SKETCH_N(fatskel,bool,visops::fillin(skel,1,2,8));
01219   
01220   vector<Shape<LineData> > wall_bounds = PolygonData::extractPolygonEdges(fatskel,fatmask|occluders_floor);
01221 
01222   
01223   
01224   for (vector<Shape<LineData> >::iterator it = wall_bounds.begin();
01225        it != wall_bounds.end(); it++) {
01226     if (((*it)->end1Pt().coordX() < camFrame_offset*2.0 || (*it)->end1Pt().coordX() > xres - camFrame_offset*2.0
01227          || (*it)->end1Pt().coordY() < camFrame_offset*2.0 || (*it)->end1Pt().coordY() > yres - camFrame_offset*2.0)
01228         && (*it)->end1Pt().isValid())
01229       (*it)->end1Pt().setValid(false);
01230     if (((*it)->end2Pt().coordX() < camFrame_offset*2.0 || (*it)->end2Pt().coordX() > xres - camFrame_offset*2.0
01231          || (*it)->end2Pt().coordY() < camFrame_offset*2.0 || (*it)->end2Pt().coordY() > yres - camFrame_offset*2.0)
01232         && (*it)->end2Pt().isValid())
01233       (*it)->end2Pt().setValid(false);
01234   }
01235   
01236   if ( curReq->verbosity & MBVshapesFound )
01237     cout << "Found " << wall_bounds.size() << " wall boundary lines" << endl;
01238   return wall_bounds;
01239 }
01240 
01241 void MapBuilder::getCamBlobs(const Sketch<uchar>& camFrame,
01242                              const set<color_index>& colors,
01243                              const map<color_index,int>& minBlobAreas,
01244                              const map<color_index, BlobData::BlobOrientation_t>& blobOrientations,
01245                              const map<color_index,coordinate_t>& assumedBlobHeights) {
01246   if ( colors.empty() )
01247     return;
01248   int const maxblobs = 50;
01249   vector<Shape<BlobData> > result(BlobData::extractBlobs(camFrame, colors, minBlobAreas, blobOrientations, assumedBlobHeights, maxblobs));
01250   if ( curReq->verbosity & MBVshapesFound )
01251     if ( !result.empty() )
01252       cout << "Found " << result.size() << " blobs." << endl;
01253 }
01254 
01255 
01256 
01257 void MapBuilder::getCamBlobs(const set<color_index>& colors, int defMinBlobArea) {
01258   
01259   if ( curReq->verbosity & MBVshapeSearch )
01260     cout << "*** Find the blobs ***" << endl;
01261   for (set<color_index>::const_iterator it = colors.begin();
01262        it != colors.end(); it++) {
01263     int const minarea = (curReq->minBlobAreas.find(*it)==curReq->minBlobAreas.end()) ? 
01264       defMinBlobArea : curReq->minBlobAreas[*it];
01265     BlobData::BlobOrientation_t const orient = (curReq->blobOrientations.find(*it)==curReq->blobOrientations.end()) ? 
01266       BlobData::groundplane : curReq->blobOrientations[*it];
01267     coordinate_t const height = (curReq->assumedBlobHeights.find(*it)==curReq->assumedBlobHeights.end()) ? 
01268       0 : curReq->assumedBlobHeights[*it];
01269     vector<Shape<BlobData> > blob_shapes(VRmixin::getBlobsFromRegionGenerator(*it,minarea,orient,height));
01270     if ( curReq->verbosity & MBVshapesFound )
01271       if ( !blob_shapes.empty() )
01272         cout << "Found " << blob_shapes.size() << " "
01273              << ProjectInterface::getColorName(*it) << " region generator blobs." << endl;
01274   }
01275 }
01276 
01277 void MapBuilder::getCamTargets(const Sketch<uchar> &camFrame, const set<color_index>& objectColors, const set<color_index>& occluderColors) const {
01278   vector<Shape<TargetData> > targets;
01279   if (objectColors.empty())
01280     return;
01281   if ( curReq->verbosity & MBVshapeSearch )
01282     cout << "*** Find the targets ***" << endl;
01283   
01284   NEW_SKETCH_N(occluders,bool,visops::zeros(camFrame));
01285   for (set<color_index>::const_iterator it = occluderColors.begin();
01286        it != occluderColors.end(); it++)
01287     occluders |= visops::minArea(visops::colormask(camFrame,*it));
01288   
01289   
01290   for (set<color_index>::const_iterator it = objectColors.begin();
01291        it != objectColors.end(); it++) {
01292     NEW_SKETCH_N(front_colormask, bool, visops::colormask(camFrame,*it));
01293     it++;
01294     if (it == objectColors.end()) {
01295       it--;
01296     }
01297     NEW_SKETCH_N(back_colormask, bool, visops::colormask(camFrame,*it));
01298     it++;
01299     if (it == objectColors.end()) {
01300       it--;
01301     }
01302     NEW_SKETCH_N(right_colormask, bool, visops::colormask(camFrame,*it));
01303     Shape<TargetData> target = TargetData::extractLineTarget(front_colormask, back_colormask, right_colormask, occluders);
01304     if (target.isValid()) {
01305       targets.insert(targets.end(), target);
01306     }
01307     if ( curReq->verbosity & MBVshapesFound )
01308       cout << "Found " << (target.isValid() ? 1 : 0) << " targets." << endl;
01309   }
01310 }
01311 
01312 vector<Shape<MarkerData> > 
01313 MapBuilder::getCamMarkers(const Sketch<uchar> &camFrame, const set<color_index>& objectColors,
01314                           const set<color_index>&, const set<MarkerType_t>& markerTypes) const
01315 {
01316   vector<Shape<MarkerData> > markers;
01317   if (objectColors.empty() || markerTypes.empty())
01318     return markers;
01319 
01320   if ( curReq->verbosity & MBVshapeSearch )
01321     cout << "*** Find the markers ***" << endl;
01322 
01323   
01324 
01325 
01326 
01327 
01328 
01329 
01330 
01331 
01332   for (set<MarkerType_t>::const_iterator it = markerTypes.begin();
01333        it != markerTypes.end(); it++) {
01334     vector<Shape<MarkerData> > single_type = MarkerData::extractMarkers(camFrame, *it, *curReq);
01335     markers.insert(markers.end(), single_type.begin(), single_type.end());
01336   }
01337 
01338   if ( curReq->verbosity & MBVshapesFound )
01339     cout << "Found " << markers.size() << " markers." << endl;
01340             
01341   return markers;
01342 }
01343 
01344 void MapBuilder::getCamSiftObjects(const Sketch<uchar> &rawY, const std::string &siftDatabasePath, 
01345                                    const std::set<std::string> &siftObjectNames) {
01346   if ( siftDatabasePath.empty() ) return;
01347   SiftTekkotsu *matcher = siftMatchers[siftDatabasePath];
01348   if ( matcher == NULL ) {
01349     matcher = new SiftTekkotsu;
01350     matcher->loadFile(siftDatabasePath);
01351     matcher->setParameter("probOfMatch", 0.8);
01352     siftMatchers[siftDatabasePath] = matcher;
01353   }
01354   ImageBuffer buff = matcher->sketchToBuffer(rawY);
01355   vector<SiftMatch*> results;
01356   if ( siftObjectNames.empty() )
01357     matcher->findAllObjectsInImage(buff, results);
01358   else
01359     for ( std::set<std::string>::const_iterator it = siftObjectNames.begin();
01360           it != siftObjectNames.end(); it++ ) {
01361       int id = matcher->getObjectID(*it);
01362       matcher->findObjectInImage(id, buff, results);
01363     };
01364   if ( curReq->verbosity & MBVshapesFound )
01365     cout << "Found " << results.size() << " sift objects." << endl;
01366   for ( vector<SiftMatch*>::const_iterator it = results.begin();
01367         it != results.end(); it++ ) {
01368     NEW_SHAPE(siftobj, SiftData, new SiftData(VRmixin::camShS, *it));
01369   }
01370 }
01371     
01372 void MapBuilder::newSiftMatcher(const std::string &siftDatabasePath) {
01373   if ( siftDatabasePath.empty() ) return;
01374   SiftTekkotsu *matcher = siftMatchers[siftDatabasePath];
01375   if ( matcher == NULL ) {
01376     matcher = new SiftTekkotsu;
01377     
01378     matcher->setParameter("probOfMatch", 0.8);
01379     siftMatchers[siftDatabasePath] = matcher;
01380   }
01381 }
01382 
01383 void MapBuilder::getCamAprilTags(const Sketch<uchar> &rawY) {
01384   std::map<std::pair<int,int>,AprilTags::TagFamily*>::const_iterator registryEntry =
01385     AprilTags::TagFamily::tagFamilyRegistry.find(curReq->aprilTagFamily);
01386   if ( registryEntry == AprilTags::TagFamily::tagFamilyRegistry.end() )
01387     return;
01388   AprilTags::TagFamily *tagFamily = registryEntry->second;
01389   std::vector<Shape<AprilTagData> > results = AprilTagData::extractAprilTags(rawY, *tagFamily);
01390   
01391   coordinate_t markerHeight = MapBuilderRequest::defaultMarkerHeight;
01392   for ( std::vector<Shape<AprilTagData> >::iterator it = results.begin();
01393         it != results.end(); it++ ) {
01394     Point c = (*it)->getCentroid();
01395     MarkerData::calculateCameraDistance(c, markerHeight);
01396     (*it)->setCentroid(c);
01397   }
01398 }
01399 
01400 void MapBuilder::getCamDominoes(const Sketch<uchar> &camFrame,
01401                                 const std::set<color_index>& objectColors,
01402                                 const std::set<color_index>& secondColors) {
01403   if ( objectColors.empty() ) 
01404     return;
01405   if ( curReq->verbosity & MBVshapeSearch )
01406     cout << "*** Find the dominoes ***" << endl;
01407 
01408   float saveMinLineLength = curReq->minLineLength;
01409   curReq->minLineLength = 35; 
01410   vector<Shape<LineData> > camLines;
01411   
01412   const set<color_index> &lineColors = (! secondColors.empty()) ? secondColors : objectColors;
01413   for (set<color_index>::const_iterator it = lineColors.begin();
01414        it != lineColors.end(); it++) {
01415     NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,*it));
01416     NEW_SKETCH_N(fatmask,bool,visops::fillin(colormask,1,2,8));
01417     NEW_SKETCH_N(skel,bool,visops::skel(fatmask));
01418     NEW_SKETCH_N(fatskel,bool,visops::fillin(skel,1,2,8));
01419     fatskel->retain(); fatmask->retain();
01420     vector<Shape<LineData> > newLines = LineData::extractLines(fatskel,fatmask);
01421     camLines.insert(camLines.end(),newLines.begin(),newLines.end());
01422   }
01423   curReq->minLineLength = saveMinLineLength;
01424 
01425   float saveMinEllipseSemiMajor = curReq->minEllipseSemiMajor;
01426   curReq->minEllipseSemiMajor = 3; 
01427   vector<Shape<EllipseData> > camEllipses;
01428   for (set<color_index>::const_iterator it = objectColors.begin();
01429        it != objectColors.end(); it++) {
01430     NEW_SKETCH_N(dotcolormask,bool,visops::colormask(camFrame,*it));
01431     vector<Shape<EllipseData> > ellipse_shapes = EllipseData::extractEllipses(dotcolormask);
01432     camEllipses.insert(camEllipses.end(), ellipse_shapes.begin(),ellipse_shapes.end());
01433   }
01434   curReq->minEllipseSemiMajor = saveMinEllipseSemiMajor;
01435 
01436   if ( camLines.empty() || camEllipses.empty() ) {
01437     if ( curReq->verbosity & MBVshapesFound )
01438       cout << "Found " << camLines.size() << " lines and "
01439            << camEllipses.size() << " ellipses in camera space; no dominoes." << endl;
01440     SHAPEVEC_ITERATE(camLines, LineData, line) {
01441       line.deleteShape();
01442     } END_ITERATE;
01443     SHAPEVEC_ITERATE(camEllipses, EllipseData, ellipse) {
01444       ellipse.deleteShape();
01445     } END_ITERATE;
01446     return;
01447   }
01448 
01449 # ifdef TGT_HAS_CAMERA
01450     fmat::Transform camToBase = kine->linkToBase(CameraFrameOffset);
01451 # else
01452     fmat::Transform camToBase = fmat::Transform::identity();
01453 # endif
01454   PlaneEquation groundPlane(fmat::pack(0,0,1), curReq->dominoDimensions[2]); 
01455 
01456   std::vector<Shape<LineData> > localLines;
01457   float minlen = curReq->dominoDimensions[1] * 0.65; 
01458   float maxlen = curReq->dominoDimensions[1] * 1.1;
01459   SHAPEVEC_ITERATE(camLines, LineData, line) {
01460     line->projectToGround(camToBase, groundPlane);
01461     float len = line->getLength();
01462     if ( len >= minlen && len <= maxlen )
01463       localLines.push_back(line);
01464   } END_ITERATE;
01465 
01466   std::vector<Shape<EllipseData> > localEllipses;
01467   SHAPEVEC_ITERATE(camEllipses, EllipseData, ellipse) {
01468     ellipse->projectToGround(camToBase, groundPlane);
01469     if ( ellipse->getSemimajor() < maxlen/6 ) 
01470       localEllipses.push_back(ellipse);
01471   } END_ITERATE;
01472 
01473   int dominoesFound = 0;
01474   if ( localLines.size() > 0 && localEllipses.size() > 0 ) {
01475     fmat::Column<3> halfdims = fmat::pack(curReq->dominoDimensions[0]/2,
01476                                           curReq->dominoDimensions[1]/2,
01477                                           curReq->dominoDimensions[2]/2);
01478     SHAPEVEC_ITERATE(localLines, LineData, line) {
01479       NEW_SHAPE(domino, DominoData,
01480                 new DominoData(localShS, 0, 0,
01481                                fmat::pack(line->getCentroid().coordX(),
01482                                           line->getCentroid().coordY(),
01483                                           halfdims[2]),
01484                                halfdims, 
01485                                fmat::rotationZ(AngPi(line->getOrientation() + (AngPi)(M_PI/2)))));
01486       domino->setColor(localEllipses[0]->getColor());
01487       domino->setLineColor(line->getColor());
01488       domino->increaseConfidence(5); 
01489       LineData line1(localShS, domino->getTFL(), domino->getTFR());
01490       LineData line2(localShS, domino->getTBL(), domino->getTBR());
01491       std::vector<Point> points1, points2;
01492       points1.push_back(line1.getCentroid());
01493       points1.push_back(domino->getTFL());
01494       points1.push_back(domino->getTBL());
01495       points1.push_back(line2.getCentroid());
01496       points2.push_back(line1.getCentroid());
01497       points2.push_back(domino->getTFR());
01498       points2.push_back(domino->getTBR());
01499       points2.push_back(line2.getCentroid());
01500       PolygonData poly1(localShS, points1, true);
01501       PolygonData poly2(localShS, points2, true);
01502       int count1 = 0, count2 = 0;
01503       SHAPEVEC_ITERATE(localEllipses, EllipseData, ellipse) {
01504         if ( poly1.isInside(ellipse->getCentroid()) ) count1++;
01505         else if ( poly2.isInside(ellipse->getCentroid()) ) count2++;
01506       } END_ITERATE; 
01507       if ( count1 > 0 && count2 > 0 ) {
01508         domino->setValues(min(count1,count2), max(count1,count2));
01509         if ( domino->getLowValue() != count1 )
01510           domino->flipLeftRight();
01511         ++dominoesFound;
01512       }
01513       else
01514         domino.deleteShape();
01515     } END_ITERATE; 
01516   }
01517   if ( curReq->verbosity & MBVshapesFound ) {
01518     cout << "Built " << dominoesFound << " local dominoes from " << localLines.size()
01519          << " local lines and " << localEllipses.size() << " local ellipses";
01520     if ( camLines.size() != localLines.size() || camEllipses.size() != localEllipses.size() )
01521       cout << " (" << camLines.size() << " camera lines, " << camEllipses.size() << " camera ellipses)";
01522     cout << endl;
01523   }
01524 
01525   
01526   SHAPEVEC_ITERATE(camLines, LineData, line) {
01527     line.deleteShape();
01528   } END_ITERATE;
01529   SHAPEVEC_ITERATE(camEllipses, EllipseData, ellipse) {
01530     ellipse.deleteShape();
01531   } END_ITERATE;
01532 }
01533 
01534 void MapBuilder::getCamNaughts(const Sketch<uchar> &camFrame, 
01535                                const set<color_index>& objectColors, 
01536                                const fmat::Column<3>& dimensions) const {
01537   vector<Shape<NaughtData> > naughts;
01538   if (objectColors.empty())
01539     return;
01540   if ( curReq->verbosity & MBVshapeSearch )
01541     cout << "*** Find the naughts ***" << endl;
01542   for (set<color_index>::const_iterator it = objectColors.begin();
01543        it !=objectColors.end(); it++) {
01544     NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,*it));
01545     vector<Shape<NaughtData> > naught_shapes = 
01546       NaughtData::extractNaughts(colormask, dimensions);
01547     naughts.insert(naughts.end(), naught_shapes.begin(),naught_shapes.end());
01548     if ( curReq->verbosity & MBVshapesFound )
01549       cout << "Found " << naught_shapes.size() << " "
01550            << ProjectInterface::getColorName(*it) << " naughts." << endl;
01551   }
01552 }
01553 
01554 void MapBuilder::getCamCrosses(const Sketch<uchar> &camFrame, const set<color_index>& objectColors) const {
01555   cout << "Entering getCamCrosses\n";
01556   if ( objectColors.empty() ) 
01557     return;
01558   if ( curReq->verbosity & MBVshapeSearch )
01559     cout << "*** Find the crosses ***" << endl;
01560 
01561   float saveMinLineLength = curReq->minLineLength;
01562   curReq->minLineLength = 10; 
01563   vector<Shape<LineData> > camLines;
01564   for (set<color_index>::const_iterator it = objectColors.begin();
01565        it != objectColors.end(); it++) {
01566     NEW_SKETCH_N(colormask,bool,visops::colormask(camFrame,*it));
01567     NEW_SKETCH_N(cleancolor,bool,visops::minArea(colormask));
01568     NEW_SKETCH_N(fatmask,bool,visops::fillin(cleancolor,1,2,8));
01569     NEW_SKETCH_N(skel,bool,visops::skel(fatmask));
01570     skel->retain(); fatmask->retain();
01571     vector<Shape<LineData> > newLines = LineData::extractLines(skel,fatmask);
01572     camLines.insert(camLines.end(),newLines.begin(),newLines.end());
01573   }
01574   curReq->minLineLength = saveMinLineLength;
01575 
01576 
01577 # ifdef TGT_HAS_CAMERA
01578     fmat::Transform camToBase = kine->linkToBase(CameraFrameOffset);
01579 # else
01580     fmat::Transform camToBase = fmat::Transform::identity();
01581 # endif
01582   PlaneEquation groundPlane(fmat::pack(0,0,1), curReq->crossDimensions[2]); 
01583 
01584   
01585   std::vector<LineData> localLines;
01586   float minlen = curReq->crossDimensions[0] * 1.5; 
01587   float maxlen = curReq->crossDimensions[0] * 2.5;
01588   SHAPEVEC_ITERATE(camLines, LineData, camLine) {
01589     LineData localLine(camLine.getData());
01590     localLine.projectToGround(camToBase, groundPlane);
01591     float len = localLine.getLength();
01592     if ( len >= minlen && len <= maxlen ) {
01593       localLine.setSpace(&localShS);
01594       localLines.push_back(localLine);
01595     }
01596   } END_ITERATE;
01597 
01598   
01599   if (localLines.size() < 2) {
01600     cout << "Not enough lines found.\n";
01601   } else {
01602     vector<Shape<CrossData> > crosses;
01603 
01604     
01605     for (unsigned int i = 0; i < localLines.size()-1; i++) {
01606       for (unsigned int j = i+1; j < localLines.size(); j++) {
01607       Point intersection = localLines[i].intersectionWithLine(localLines[j]);
01608 
01609       
01610       
01611       if (localLines[i].pointOnLine(intersection) && localLines[j].pointOnLine(intersection))
01612         if (abs(localLines[i].getOrientation() - localLines[j].getOrientation()) > M_PI/9) { 
01613           Shape<CrossData> cross(new CrossData(localShS, localLines[i],
01614                                                localLines[j],
01615                                                curReq->crossDimensions));
01616           cross->setColor(localLines[i].getColor());
01617           cross->setViewable(true);
01618           crosses.push_back(cross);
01619         }
01620       }
01621     }
01622     cout << "Found " << localLines.size() << " lines and recognized "
01623          << crosses.size() << " cross" << (crosses.size()==1 ? "" : "es") << endl;
01624   }
01625   
01626   SHAPEVEC_ITERATE(camLines, LineData, line) {
01627     line.deleteShape();
01628   } END_ITERATE;
01629 }
01630 
01631 void MapBuilder::getCamAgents(const Sketch<uchar> &camFrame, const Sketch<yuv> &camFrameYUV,
01632                               const std::set<color_index>& objectColors) const {
01633   if ( objectColors.empty() ) return;
01634   if ( curReq->verbosity & MBVshapeSearch )
01635     cout << "*** Find the agents ***" << endl;
01636   AgentData::extractAgents(camFrame, camFrameYUV, objectColors);
01637 }
01638 
01639 void MapBuilder::saveSiftDatabase(const std::string &siftDatabasePath) {
01640   if ( siftDatabasePath.empty() ) return;
01641   SiftTekkotsu *matcher = siftMatchers[siftDatabasePath];
01642   if ( matcher == NULL )
01643     cout << "Error in saveSiftDatabase: no database named '" << siftDatabasePath << "' has been loaded." << endl;
01644   else {
01645     matcher->saveToFile(siftDatabasePath, false);
01646     cout << "Wrote SIFT database " << siftDatabasePath << endl;
01647   }
01648 }
01649 
01650 void MapBuilder::trainSiftObject(const std::string &siftDatabasePath,
01651                                  const std::string &objectName, const std::string &modelName) {
01652   NEW_SKETCH_N(rawY, uchar, VRmixin::sketchFromRawY());
01653   trainSiftObject(siftDatabasePath, rawY, objectName, modelName);
01654 }
01655 
01656 void MapBuilder::trainSiftObject(const std::string &siftDatabasePath, const Sketch<uchar> &sketch,
01657                                  const std::string &objectName, const std::string &modelName) {
01658   if ( siftDatabasePath.empty() ) return;
01659   SiftTekkotsu *matcher = siftMatchers[siftDatabasePath];
01660   if ( matcher == NULL ) {
01661     cout << "Error in trainSiftObject:: no database named '" << siftDatabasePath << "' has been loaded." << endl;
01662     return;
01663   }
01664   ImageBuffer buffer = SiftTekkotsu::sketchToBuffer(sketch);
01665   int id = matcher->getObjectID(objectName);
01666   if ( id == -1 ) {
01667     int new_id = matcher->train_addNewObject(buffer);
01668     matcher->setObjectName(new_id, objectName);
01669   } else {
01670     matcher->train_addToObject(id, buffer);
01671   }
01672 }
01673 
01674 } 
01675