app-ScorbotMultiGrabImagize.C

00001 #include <iomanip>
00002 #include <vector>
00003 #include <pthread.h>
00004 #include <signal.h>
00005 #include <fstream>
00006 #include <boost/lexical_cast.hpp>
00007 #include <boost/algorithm/string.hpp>
00008 #include <list>
00009 
00010 #include "Devices/V4L2grabber.H"
00011 #include "Devices/XCgrabber.H"
00012 #include "Util/WorkThreadServer.H"
00013 #include "Raster/Raster.H"
00014 #include "Component/ModelManager.H"
00015 #include "Media/FrameSeries.H"
00016 #include "Raster/GenericFrame.H"
00017 #include "Transport/FrameInfo.H"
00018 #include "Image/Image.H"
00019 #include "Image/DrawOps.H"
00020 #include "GUI/PrefsWindow.H"
00021 #include "Devices/DeviceOpts.H"
00022 #include "Devices/Serial.H"
00023 #include "Image/DrawOps.H"
00024 #include "GUI/XWinManaged.H"
00025 #include "GUI/ImageDisplayStream.H"
00026 #include "GUI/PrefsWindow.H"
00027 #include "GUI/DebugWin.H"
00028 #include "GUI/PrefsWindow.H"
00029 #include "Util/StringUtil.H"
00030 #include "rutz/time.h"
00031 #include "Util/csignals.H"
00032 
00033 class ScorbotSimple;
00034 
00035 const char* dataDir = "/home2/robotscenes";
00036 std::string sceneDir = "";
00037 int pathID = 0;
00038 int sceneID = 0;
00039 
00040 nub::soft_ref<OutputFrameSeries> ofs;
00041 nub::soft_ref<ScorbotSimple> scorbot;
00042 XWinManaged *userInteractiveWindow = NULL;
00043 volatile bool record = false;
00044 volatile bool keepgoing = true;
00045 volatile bool dolivedisplay = false;
00046 
00047 // 'volatile' because we will modify this from signal handlers
00048 volatile int signum = 0;
00049 
00050 Image< PixRGB<byte> > inputImage;
00051 volatile unsigned long currentVideoFrameNumber = 0;
00052 pthread_mutex_t imgMutex = PTHREAD_MUTEX_INITIALIZER;
00053 
00054 rutz::time epoch = rutz::time::wall_clock_now();
00055 
00056 const int focusval[4] = { 10, 6, 7, 8 };
00057 
00058 // number of cameras
00059 #define NUMCAMS 2
00060 
00061 // ######################################################################
00062 //! An Async Image Writer which works on a separate thread 
00063 class WriteJob : public JobServer::Job
00064 {
00065 public:
00066   WriteJob(const Image< PixRGB<byte> > img_, const std::string fname_) :
00067     img(img_), fname(fname_) { }
00068 
00069   virtual ~WriteJob() { }
00070 
00071   virtual void run() { Raster::WriteRGB(img, fname); }
00072 
00073   virtual const char* jobType() const { return "WriteJob"; }
00074 
00075 private:
00076   const Image< PixRGB<byte> > img;
00077   const std::string fname;
00078 };
00079 
00080 WorkThreadServer writer("Write Server", 5, false); // write several files at once since png compression is bottleneck
00081 
00082 void AsyncWriteImage(const Image< PixRGB<byte> > img, size_t cameraID, unsigned long frameNumber)
00083 {
00084   const std::string fname = sformat("%s/RobotScene-s%04d-p%02d/RobotScene-s%04d-p%02d-c%02zu-f%06lu.ppm", 
00085                                     dataDir, sceneID, pathID, sceneID, pathID, cameraID, frameNumber);
00086   writer.enqueueJob(rutz::make_shared(new WriteJob(img, fname)));
00087 }
00088 
00089 // ######################################################################
00090 // grabber devices
00091 std::vector< nub::ref<FrameIstream> > grabbers;
00092 
00093 //! A grab job (we grab from all cameras in parallel)
00094 class GrabJob : public JobServer::Job
00095 {
00096 public:
00097   GrabJob(const size_t cameraID_) :
00098     cameraID(cameraID_),
00099     frameNumber(0)
00100   {
00101     ASSERT(cameraID < grabbers.size());
00102   }
00103 
00104   virtual ~GrabJob() {}
00105 
00106   virtual void run() 
00107   {
00108     nub::ref<FrameIstream> grabber = grabbers[cameraID];
00109     bool recording = false;
00110 
00111     while(keepgoing) {
00112       // let's grab an image:
00113       GenericFrame frame = grabber->readFrame();
00114       Image< PixRGB<byte> > img;
00115 
00116       if (record) {
00117         if (recording == false) { LINFO("Start recording camera %"ZU" at %fms...", cameraID, (rutz::time::wall_clock_now() - epoch).msec()); recording = true; }
00118         img = frame.asRgb();
00119         AsyncWriteImage(img, cameraID, frameNumber);
00120         ++frameNumber;
00121         if ((frameNumber % 10) == 0) LINFO("Camera %"ZU" got frame %"ZU" at %fms", cameraID, frameNumber, (rutz::time::wall_clock_now() - epoch).msec());
00122       } else {
00123         if (recording == true) { LINFO("Stop recording camera %"ZU" frame %"ZU" at %fms...", cameraID, frameNumber, (rutz::time::wall_clock_now() - epoch).msec()); recording = false; }
00124         frameNumber = 0;
00125       }
00126 
00127       // pass the current frame to the display thread
00128       if (cameraID == 0 && record == false) {
00129         if (img.initialized() == false) img = frame.asRgb();
00130         pthread_mutex_lock(&imgMutex);
00131         inputImage = img;
00132         ++currentVideoFrameNumber;
00133         pthread_mutex_unlock(&imgMutex);
00134       }
00135     }
00136   }
00137 
00138   virtual const char* jobType() const { return "GrabJob"; }
00139 
00140 private:
00141   const size_t cameraID;
00142   unsigned long frameNumber;
00143 };
00144 
00145 WorkThreadServer grabberThreadServer("Grab Server", NUMCAMS, false); // number of parallel grab jobs
00146 
00147 void setupGrabbers(ModelManager& manager)
00148 {
00149   size_t cameraID = 0;
00150   while(true)
00151   {
00152     std::string dev = sformat("/dev/video%"ZU, grabbers.size());
00153     LINFO("Trying to open %s", dev.c_str());
00154     int fd = open(dev.c_str(), O_RDONLY);
00155     if (fd == -1) { LINFO("%s not found -- Skipping.", dev.c_str()); break; } else close(fd);
00156 
00157     // instantiate and configure a grabber:
00158     nub::ref<V4L2grabber> grabber(new V4L2grabber(manager, dev, dev));
00159     
00160     // do not export any command-line option to avoid clashes among grabber instances:
00161     grabber->forgetExports();
00162 
00163     // let's set everything by hand here to ensure consistency:
00164     grabber->setModelParamVal("FrameGrabberDevice", dev);
00165 
00166     grabber->setModelParamVal("FrameGrabberNbuf", 2);
00167     grabber->setModelParamVal("FrameGrabberStreaming", true); 
00168     grabber->setModelParamVal("FrameGrabberByteSwap", false);
00169     grabber->setModelParamVal("FrameGrabberDims", Dims(1280,720));
00170     grabber->setModelParamVal("FrameGrabberMode", VIDFMT_YUYV);
00171     grabber->setModelParamVal("FrameGrabberChannel", 0);
00172 
00173     // to make sure we will force the hardware to set its values, first set some trash values, then set the real values:
00174     // turn all auto controls to on:
00175     grabber->setModelParamVal("FrameGrabberWhiteBalTempAuto", true);
00176     grabber->setModelParamVal("FrameGrabberPowerLineFreq", 2);
00177     grabber->setModelParamVal("FrameGrabberBacklightComp", 1);
00178     grabber->setModelParamVal("FrameGrabberFocusAuto", true);
00179  
00180     // now turn all auto controls to off:
00181     grabber->setModelParamVal("FrameGrabberWhiteBalTempAuto", false);
00182     grabber->setModelParamVal("FrameGrabberPowerLineFreq", 0);
00183     grabber->setModelParamVal("FrameGrabberBacklightComp", 0);
00184     grabber->setModelParamVal("FrameGrabberExposureAuto", 3); // that's still auto
00185     grabber->setModelParamVal("FrameGrabberFocusAuto", false);
00186     grabber->setModelParamVal("FrameGrabberExposureAuto", 1); // now we are full manual for exposure
00187  
00188     // set all manual settings 1-off from what we want:
00189     grabber->setModelParamVal("FrameGrabberBrightness", 134);
00190     grabber->setModelParamVal("FrameGrabberContrast", 6);
00191     grabber->setModelParamVal("FrameGrabberSaturation", 84);
00192     grabber->setModelParamVal("FrameGrabberWhiteBalTemp", 3101);
00193     grabber->setModelParamVal("FrameGrabberExposureAbs", 39);
00194     grabber->setModelParamVal("FrameGrabberSharpness", 26);
00195     grabber->setModelParamVal("FrameGrabberFocus", focusval[cameraID] + 1);
00196     grabber->setModelParamVal("FrameGrabberZoom", 1);
00197  
00198     // and now the real values:
00199     grabber->setModelParamVal("FrameGrabberPowerLineFreq", 0); // should be set already but just in case...
00200     grabber->setModelParamVal("FrameGrabberBacklightComp", 0);
00201     grabber->setModelParamVal("FrameGrabberExposureAuto", 1);
00202     grabber->setModelParamVal("FrameGrabberWhiteBalTempAuto", false);
00203  
00204     grabber->setModelParamVal("FrameGrabberBrightness", 133);
00205     grabber->setModelParamVal("FrameGrabberContrast", 5);
00206     grabber->setModelParamVal("FrameGrabberSaturation", 83);
00207     grabber->setModelParamVal("FrameGrabberWhiteBalTemp", 3100);
00208     grabber->setModelParamVal("FrameGrabberSharpness", 25);
00209     grabber->setModelParamVal("FrameGrabberExposureAbs", 156);
00210     grabber->setModelParamVal("FrameGrabberFocusAuto", false);
00211     grabber->setModelParamVal("FrameGrabberFocus", focusval[cameraID]);
00212     grabber->setModelParamVal("FrameGrabberZoom", 0);
00213     
00214     // keep track of it:
00215     manager.addSubComponent(grabber);
00216     grabbers.push_back(grabber);
00217     LINFO("Added V4L2grabber for %s", dev.c_str());
00218 
00219     ++cameraID;
00220   }
00221 
00222   // Now look for the Imagize cam:
00223 
00224   // instantiate and configure a grabber:
00225   nub::ref<XCgrabber> grabber(new XCgrabber(manager, "Imagize", "Imagize"));
00226     
00227   // do not export any command-line option to avoid clashes among grabber instances:
00228   grabber->forgetExports();
00229 
00230   // let's set everything by hand here to ensure consistency:
00231   grabber->setModelParamString("XCGrabberFormatFile", "/home/ilab24/xcap/data/imagize-works.xsetup");
00232     grabber->setModelParamVal("FrameGrabberMode", VIDFMT_RGB24);
00233   grabber->setModelParamVal("FrameGrabberNbuf", 2);
00234   grabber->setModelParamVal("FrameGrabberDims", Dims(1280,1024));
00235 
00236   // keep track of it:
00237   manager.addSubComponent(grabber);
00238   grabbers.push_back(grabber);
00239   LINFO("Added XCgrabber for Imagize camera");
00240 }
00241 
00242 // ######################################################################
00243 struct SceneSetup
00244 {
00245   struct Object
00246   {
00247     std::string trayFileName;
00248     std::string trayName;
00249     int trayColumn;
00250     int trayRow;
00251     float trayX;
00252     float trayY;
00253     std::vector< Point2D<int> > outline;
00254   };
00255 
00256   std::string setupPath;
00257   int setupNum;
00258   int backgroundIdx;
00259   std::string backgroundFileName;
00260   std::vector<int> pathIndex;
00261   
00262   std::vector<SceneSetup::Object> objects;
00263 };
00264 
00265 // ######################################################################
00266 // Parse the scene setup file found in the given path
00267 SceneSetup loadSceneSetup(const int id)
00268 {
00269   SceneSetup setup;
00270   setup.setupPath = sceneDir;
00271 
00272   std::string setupFileName = setup.setupPath + "/" + sformat("%04d.txt", id);
00273   std::ifstream setupFile(setupFileName.c_str());
00274 
00275   if (!setupFile.is_open()) LFATAL("Could not open setup file: %s", setupFileName.c_str());
00276 
00277   std::string line;
00278 
00279   try
00280   {
00281     //SetupNumber
00282     getline(setupFile, line);
00283     setup.setupNum = boost::lexical_cast<int>(line.substr(line.find("=")+1));
00284 
00285     //BackgroundIndex
00286     getline(setupFile, line);
00287     setup.backgroundIdx = boost::lexical_cast<int>(line.substr(line.find("=")+1));
00288 
00289     //BackgroundFileName
00290     getline(setupFile, line);
00291     setup.backgroundFileName = line.substr(line.find("=")+1);
00292     
00293     //PathIndex
00294     getline(setupFile, line);
00295     std::vector<std::string> tok;
00296     split(line.substr(line.find("=")+1), ",", std::back_inserter(tok));
00297     for (size_t ii = 0; ii < tok.size(); ++ii)
00298       setup.pathIndex.push_back(boost::lexical_cast<int>(tok[ii]));
00299 
00300     //NumberOfObjects
00301     getline(setupFile, line);
00302     int numObjects = boost::lexical_cast<int>(line.substr(line.find("=")+1));
00303 
00304     for(int i=0; i<numObjects; ++i)
00305     {
00306       SceneSetup::Object obj;
00307 
00308       //TrayFileName
00309       getline(setupFile, line);
00310       obj.trayFileName = line.substr(line.find("=")+1);
00311 
00312       //TrayName
00313       size_t s = obj.trayFileName.find_last_of('/');
00314       size_t e = obj.trayFileName.find_last_of('.');
00315       obj.trayName = obj.trayFileName.substr(s+1, e-s-1);
00316 
00317       //TrayColumn
00318       getline(setupFile, line);
00319       obj.trayColumn = boost::lexical_cast<int>(line.substr(line.find("=")+1));
00320 
00321       //TrayRow
00322       getline(setupFile, line);
00323       obj.trayRow = boost::lexical_cast<int>(line.substr(line.find("=")+1));
00324 
00325       //XOnTray
00326       getline(setupFile, line);
00327       obj.trayX = boost::lexical_cast<float>(line.substr(line.find("=")+1));
00328 
00329       //YOnTray
00330       getline(setupFile, line);
00331       obj.trayY = boost::lexical_cast<float>(line.substr(line.find("=")+1));
00332 
00333       setup.objects.push_back(obj);
00334     }
00335   }
00336   catch(boost::bad_lexical_cast& e)
00337   {
00338     LFATAL("Error Parsing Setup File (%s) [%s] -- Offending Line: %s", setupFileName.c_str(), e.what(), line.c_str());
00339   }
00340 
00341   return setup;
00342 }
00343 
00344 // ######################################################################
00345 // Display the image and prompts to the user
00346 void *displayThreadMethod(void*)
00347 {
00348   // this is disabled for now...
00349 
00350   /*
00351   unsigned long frameNumber = 0;
00352   while(true)
00353   {
00354     Image< PixRGB<byte> > img;
00355     pthread_mutex_lock(&imgMutex);
00356     if (frameNumber != currentVideoFrameNumber) {
00357       img = inputImage;
00358       frameNumber = currentVideoFrameNumber;
00359     }
00360     pthread_mutex_unlock(&imgMutex);
00361 
00362     if (dolivedisplay && img.initialized()) {
00363       //      img = rescale(img, img.getDims() / 2);
00364       ofs->writeRGB(img, "Live Video from Main Camera");
00365       ofs->updateNext();
00366     }
00367 
00368     // go easy on the CPU:
00369     usleep(30000);
00370   }
00371   */
00372 
00373   return NULL;
00374 }
00375 
00376 // ######################################################################
00377 class ScorbotSimple: public ModelComponent
00378 {
00379   public:
00380     ScorbotSimple(OptionManager& mgr, 
00381         const std::string& descrName = "",
00382         const std::string& tagName = "") :
00383       ModelComponent(mgr, descrName, tagName),
00384       itsSerial(new Serial(mgr)) 
00385     {
00386       addSubComponent(itsSerial);
00387       itsSerial->configure("/dev/ttyUSB0", 115200, "8N1", false, false, 10000);
00388     }
00389 
00390     bool getBusyState()
00391     {
00392       char cmd = 'B';
00393       itsSerial->write(&cmd, 1);
00394       usleep(5000);
00395 
00396       char retVal = '?';
00397       itsSerial->read(&retVal, 1);
00398       //if (retVal == '?') LERROR("Serial Comminucation failed");
00399       return (retVal == '1');
00400     }
00401 
00402     bool getHomeState()
00403     {
00404       char cmd = 'H';
00405       itsSerial->write(&cmd, 1);
00406       usleep(5000);
00407 
00408       char retVal = '?';
00409       itsSerial->read(&retVal, 1);
00410       //if (retVal == '?') LERROR("Serial Comminucation failed");
00411       return (retVal == '1');
00412     }
00413     
00414     void emptyBuffer()
00415     {
00416        while(true)
00417        {
00418            usleep(10000);
00419            char retVal = '?';
00420            itsSerial->read(&retVal, 1);
00421            if(retVal == '?') break;
00422        }
00423     }
00424   
00425     void setPathNum(int pathnum)
00426     {
00427       //LINFO("Executing Path %i", pathnum);
00428       char cmd[2] = { 'P', pathnum };
00429       itsSerial->write(&cmd, 2);
00430     }
00431 
00432   private:
00433     nub::ref<Serial> itsSerial;
00434 };
00435 
00436 // ######################################################################
00437 // Run the robot arm along the given path, blocking until it is finished
00438 void executePath(int pathnum)
00439 {
00440   LINFO("Waiting for Robot HOME ...");
00441   while(!scorbot->getHomeState())
00442   {
00443      if(signum != 0) { record = false; return; }
00444      usleep(10000);
00445   }
00446   LINFO("Going To Path %d", pathnum);
00447   scorbot->setPathNum(pathnum++);
00448   LINFO("Waiting for Robot BUSY ...");
00449   while(!scorbot->getBusyState())
00450   {
00451      if(signum != 0) { record = false; return; }
00452      usleep(10000);
00453   }
00454   epoch = rutz::time::wall_clock_now();
00455   usleep(1000000); // trash old frame in camera buffer
00456   LINFO("Camera recording on.");
00457   record = true;
00458   LINFO("Waiting for Robot ~BUSY ...");
00459   while(scorbot->getBusyState())
00460   {
00461      if(signum != 0) { record = false; return; }
00462      usleep(10000);
00463   }
00464   record = false;
00465   LINFO("Camera recording off.");
00466 
00467   scorbot->emptyBuffer();
00468 }
00469 
00470 // ######################################################################
00471 // Prompt the user to place an object from a tray onto the table, and 
00472 // then present them with an interface to outline that object
00473 std::vector< Point2D<int> > promptPlaceObjectOnScene(SceneSetup const & setup, int objIdx)
00474 {
00475   LINFO("Place object %d onto table. Follow instructions in User Interactive window...", objIdx);
00476 
00477   const SceneSetup::Object &obj = setup.objects[objIdx];
00478 
00479   Image< PixRGB<byte> > trayImg = Raster::ReadRGB(setup.setupPath + "/" + obj.trayFileName);
00480   trayImg = rescale(trayImg, trayImg.getDims()/2);
00481 
00482   Point2D<int> objPos(obj.trayX*trayImg.getWidth(), obj.trayY*trayImg.getHeight());
00483 
00484   drawCircle(trayImg, objPos, trayImg.getWidth()/12, PixRGB<byte>(255, 0, 0), 2);
00485   drawCross(trayImg, objPos, PixRGB<byte>(255, 0, 0), trayImg.getWidth()/8, 2);
00486 
00487   std::ostringstream ss;
00488   ss << "Place Tray " << obj.trayName << 
00489     " (row " << obj.trayRow << 
00490     ", col " << obj.trayColumn << 
00491     ") on table and ENTER";
00492   writeText(trayImg, Point2D<int>(0, 0), ss.str().c_str());
00493 
00494   userInteractiveWindow->drawImage(trayImg, 0, 0, true);
00495   while(userInteractiveWindow->getLastKeyPress() != 36) usleep(100000);
00496   
00497   pthread_mutex_lock(&imgMutex);
00498   Image<PixRGB<byte> > cameraImg = inputImage;
00499   pthread_mutex_unlock(&imgMutex);
00500   userInteractiveWindow->drawImage(cameraImg, 0, 0, true);
00501   std::vector< Point2D<int> > poly;
00502   std::string msg = "Outline new object using 4 points. ESCAPE to undo point. SPACE to refresh image. ENTER when finished.";
00503 
00504   // eat all previous mouse clicks and key presses, just in case:
00505   while (userInteractiveWindow->getLastMouseClick() != Point2D<int>(-1, -1)) { }
00506   while (userInteractiveWindow->getLastKeyPress() != -1) { }
00507 
00508   bool finished = false;
00509   while(!finished) {
00510     Point2D<int> mouseClick = userInteractiveWindow->getLastMouseClick();
00511     if(mouseClick != Point2D<int>(-1, -1) && poly.size() < 4)
00512       poly.push_back(mouseClick);
00513 
00514     int lastKeyPress = userInteractiveWindow->getLastKeyPress();
00515     switch(lastKeyPress) {
00516     case -1: // No Key
00517       break;
00518     case 9:  // ESCAPE
00519       if(poly.size()) poly.erase(poly.end()-1);
00520       break;
00521     case 36: // ENTER
00522       if(poly.size() == 4) finished = true;
00523       break;
00524     case 65: // SPACE
00525       pthread_mutex_lock(&imgMutex);
00526       cameraImg = inputImage;
00527       pthread_mutex_unlock(&imgMutex);
00528       userInteractiveWindow->drawImage(cameraImg, 0, 0, true);
00529       break;
00530     default:
00531       LINFO("Key Pressed: %d", lastKeyPress);
00532       break;
00533     }
00534 
00535     Image< PixRGB<byte> > dispImage = cameraImg;
00536     for(size_t i=0; i<poly.size(); ++i) drawCircle(dispImage, poly[i], 5, PixRGB<byte>(255, 0, 0), 3);
00537     drawOutlinedPolygon(dispImage, poly, PixRGB<byte>(0, 0, 255), Point2D<int>(0,0),0,1,0,0,3);
00538     writeText(dispImage, Point2D<int>(0,0), msg.c_str());
00539     userInteractiveWindow->drawImage(dispImage, 0, 0, true);
00540 
00541     usleep(100000);
00542   }
00543 
00544   LINFO("Done placing object %d onto table.", objIdx);
00545 
00546   return poly;
00547 }
00548 
00549 // ######################################################################
00550 // Prompt the user to return the object back to the tray place an object
00551 void promptReturnObjectToTray(SceneSetup const & setup, int objIdx)
00552 {
00553   LINFO("Placing back object %d into its tray. Follow instructions in User Interactive window...", objIdx);
00554   const SceneSetup::Object &obj = setup.objects[objIdx];
00555 
00556   Image< PixRGB<byte> > trayImg = Raster::ReadRGB(setup.setupPath + "/" + obj.trayFileName);
00557   trayImg = rescale(trayImg, trayImg.getDims()/2);
00558 
00559   Point2D<int> objPos(obj.trayX*trayImg.getWidth(), obj.trayY*trayImg.getHeight());
00560 
00561   drawCircle(trayImg, objPos, trayImg.getWidth()/12, PixRGB<byte>(255, 0, 0), 2);
00562   drawCross(trayImg, objPos, PixRGB<byte>(255, 0, 0), trayImg.getWidth()/8, 2);
00563 
00564   std::ostringstream ss;
00565   ss << "Place back Obj(" <<
00566     "row " << obj.trayRow << 
00567     ", col " << obj.trayColumn << 
00568     ") into tray " << obj.trayName << 
00569     " and ENTER";
00570   writeText(trayImg, Point2D<int>(0, 0), ss.str().c_str());
00571   
00572   userInteractiveWindow->drawImage(trayImg, 0, 0, true);
00573 
00574   // eat all previous mouse clicks and key presses, just in case:
00575   while (userInteractiveWindow->getLastMouseClick() != Point2D<int>(-1, -1)) { }
00576   while (userInteractiveWindow->getLastKeyPress() != -1) { }
00577 
00578   // wait for ENTER:
00579   while (userInteractiveWindow->getLastKeyPress() != 36) usleep(100000);
00580 
00581   LINFO("Done placing back object %d into its tray.", objIdx);
00582 }
00583 
00584 // ######################################################################
00585 //! Get/confirm an int value:
00586 void getInt(const char *msg, int& val)
00587 {
00588   printf("%s [%d]: ", msg, val); fflush(stdout);
00589   char input[1000]; while(gets(input) == NULL) LERROR("Invalid input, try again");
00590 
00591   if (strlen(input) > 0) val = atoi(input); // updated the value
00592 };
00593 
00594 // ######################################################################
00595 int submain(const int argc, const char** argv)
00596 {
00597   // catch signals and redirect them for a clean exit (in particular, this gives us a chance to do useful things like
00598   // flush and close output files that would otherwise be left in a bogus state, like mpeg output files):
00599   catchsignals(&signum);
00600 
00601   LINFO("#############################################STARTING##############################################");
00602 
00603   ModelManager mgr("App Scorbot MultiGrab");
00604 
00605   scorbot.reset(new ScorbotSimple(mgr));
00606   mgr.addSubComponent(scorbot);
00607 
00608   setupGrabbers(mgr);
00609 
00610   ofs.reset(new OutputFrameSeries(mgr));
00611   mgr.addSubComponent(ofs);
00612 
00613   if(mgr.parseCommandLine(argc, argv, "FilePrefix SceneID", 2, 2) == false) return -1;
00614   mgr.start();
00615 
00616   if (grabbers.size() < NUMCAMS) LFATAL("Only found %"ZU" cameras instead of %d. Reboot your machine and try again.", grabbers.size(), NUMCAMS);
00617 
00618   // get our grabbers to start grabbing:  
00619   for (size_t cameraID = 0; cameraID < grabbers.size(); ++cameraID)
00620     grabberThreadServer.enqueueJob(rutz::make_shared(new GrabJob(cameraID)));
00621 
00622   sceneDir = mgr.getExtraArg(0);
00623   sceneID = boost::lexical_cast<int>(mgr.getExtraArg(1));
00624 
00625   pthread_t displayThread;
00626   pthread_create(&displayThread, NULL, &displayThreadMethod, NULL);
00627 
00628   // Create the interactive window
00629   userInteractiveWindow = new XWinManaged(Dims(640,480), -1, -1, "User Interactive");
00630   userInteractiveWindow->setVisible(false);
00631   userInteractiveWindow->setPosition(0, 0);
00632 
00633   // Main loop:
00634   int runnumber = 0;
00635   while(true) {
00636     if(signum != 0) break;
00637 
00638     // home the robot once in a while:
00639     if ((runnumber % 5) == 0) {
00640       int gogo = 0; getInt("Perform robot homing sequence and press ENTER", gogo);
00641     }
00642 
00643     // select the scene:
00644     getInt("Enter scene ID (-1 to exit):", sceneID);
00645 
00646     if (sceneID == -1) break; // abort on scene -1
00647 
00648     // STEP 1. Load the scene file
00649     SceneSetup setup = loadSceneSetup(sceneID);
00650 
00651     // STEP 2. Show the interactive window:
00652     userInteractiveWindow->setVisible(true);
00653 
00654     // STEP 3. Display background image and ask the user to place it on the scene
00655     Image< PixRGB<byte> > backgroundImage = Raster::ReadRGB(setup.setupPath + "/" + setup.backgroundFileName);
00656     backgroundImage = rescale(backgroundImage, Dims(640, 480));
00657     writeText(backgroundImage, Point2D<int>(0, 0), "Please place this background on the scene and press ENTER.");
00658     userInteractiveWindow->drawImage(backgroundImage, 0, 0, true);
00659     LINFO("Place background map on scene and add houses, trees, and other background objects. See User Interactive window for instructions...");
00660     // eat all previous mouse clicks and key presses, just in case:
00661     while (userInteractiveWindow->getLastMouseClick() != Point2D<int>(-1, -1)) { }
00662     while (userInteractiveWindow->getLastKeyPress() != -1) { }
00663     // wait for ENTER:
00664     while(userInteractiveWindow->getLastKeyPress() != 36) usleep(100000);
00665     LINFO("Background map done. Make sure you have built a nice scene.");
00666 
00667     // STEP 4. Display each object and ask user to put on the scene and specify its bounding box
00668     for (size_t i = 0; i < setup.objects.size(); ++i)
00669       setup.objects[i].outline = promptPlaceObjectOnScene(setup, i);
00670 
00671     // STEP 5. Hide the interactive window
00672     userInteractiveWindow->setVisible(false);
00673 
00674     // STEP 6. Write out outlines to a file
00675     {
00676       std::string objectFileName = sformat("%s/RobotScene-s%04d-polygons.txt", dataDir, sceneID);
00677       std::ofstream objectFile(objectFileName.c_str());
00678 
00679       LINFO("Saving the object bounding boxes into: %s", objectFileName.c_str());
00680  
00681       for(size_t i=0; i<setup.objects.size(); ++i)
00682         {
00683           for(size_t j=0; j<setup.objects[i].outline.size(); ++j)
00684             {
00685               Point2D<int> &pnt = setup.objects[i].outline[j];
00686               if(j != 0) objectFile << ',';
00687               objectFile << pnt.i << ',' << pnt.j;
00688             }
00689           objectFile << std::endl;
00690         }
00691     }
00692 
00693     // STEP 7. Execute the path and record the videos
00694     for (pathID = 0; pathID < int(setup.pathIndex.size()); ++pathID) {
00695       if(signum != 0) break;
00696       // create a directory for this scene / light:
00697       const std::string dir = sformat("%s/RobotScene-s%04d-p%02d", dataDir, sceneID, pathID);
00698       const std::string cmd = sformat("/bin/mkdir -p %s", dir.c_str());
00699       if (system(cmd.c_str()) == -1) PLFATAL("Could not create directory %s", dir.c_str());
00700 
00701       int gogo = pathID; getInt("Set light and press ENTER to start video recording", gogo);
00702 
00703       // make sure we don't have too many pending disk writes:
00704       while(writer.size() > 1000) {
00705         LINFO("Waiting for image writer thread, queue size = %"ZU"...", writer.size());
00706         usleep(1000000);
00707       }
00708 
00709       LINFO("Running Scene %04d Path %02d ...", sceneID, setup.pathIndex[pathID]);
00710 
00711       executePath(setup.pathIndex[pathID]);
00712     }
00713     if(signum != 0) break;
00714 
00715     // STEP 8. Instruct users to place the objects back into the bins
00716     userInteractiveWindow->setVisible(true);
00717     userInteractiveWindow->setPosition(0, 0);
00718     for(size_t i=0; i<setup.objects.size(); ++i) promptReturnObjectToTray(setup, i);
00719     userInteractiveWindow->setVisible(false);
00720 
00721     // STEP 9. Ready for next scene
00722     ++sceneID;
00723     ++runnumber;
00724   }
00725 
00726   // stop grabbing:
00727   keepgoing = false;
00728 
00729   // wait for all pics to be written (note: this just waits until the queue of pending jobs is empty, the writer's
00730   // destructor will wait until all jobs are complete):
00731   while(writer.size()) {
00732     LINFO("Waiting for image writer thread, queue size = %"ZU"...", writer.size());
00733     usleep(500000);
00734   }
00735   writer.flushQueue(250000, true);
00736 
00737   // make sure all is done
00738   LINFO("Cleaning up... Stand by...");
00739   usleep(2000000);
00740 
00741   // stop all our ModelComponents
00742   mgr.stop();
00743 
00744   LINFO("Finished.");
00745 
00746   return 0;
00747 }
00748 
00749 // ######################################################################
00750 int main(int argc, const char** argv)
00751 {
00752   int ret = -1;
00753 
00754   try { ret = submain(argc, argv); }
00755   catch(...) { REPORT_CURRENT_EXCEPTION; }
00756 
00757   return ret;
00758 }
Generated on Sun May 8 08:05:56 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3