00001 /*!@file INVT/neovision2.C Neovision2 integrated demo */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/INVT/neovision2.C $ 00035 // $Id: neovision2.C 14376 2011-01-11 02:44:34Z pez $ 00036 // 00037 00038 #include "Image/OpenCVUtil.H" // must be first to avoid conflicting defs of int64, uint64 00039 00040 #include "Component/GlobalOpts.H" 00041 #include "Component/ModelManager.H" 00042 #include "Component/ModelOptionDef.H" 00043 #include "Component/ModelParam.H" 00044 #include "Component/ModelParamBatch.H" 00045 #include "Devices/DeviceOpts.H" 00046 #include "Devices/IEEE1394grabber.H" 00047 #include "GUI/ImageDisplayStream.H" 00048 #include "GUI/PrefsWindow.H" 00049 #include "GUI/XWinManaged.H" 00050 #include "Image/ColorOps.H" 00051 #include "Image/CutPaste.H" 00052 #include "Image/DrawOps.H" 00053 #include "Image/FilterOps.H" 00054 #include "Image/Image.H" 00055 #include "Image/ImageSet.H" 00056 #include "Image/Layout.H" 00057 #include "Image/MathOps.H" 00058 #include "Image/Pixels.H" 00059 #include "Image/PyramidOps.H" 00060 #include "Image/ShapeOps.H" 00061 #include "Image/Transforms.H" 00062 #include "Media/FrameSeries.H" 00063 #include "Media/MediaOpts.H" 00064 #include "NeovisionII/Nv2LabelReader.H" 00065 #include "NeovisionII/nv2_common.h" 00066 #include "Neuro/NeoBrain.H" 00067 #include "Neuro/EnvInferoTemporal.H" 00068 #include "Neuro/EnvSaliencyMap.H" 00069 #include "Neuro/EnvSegmenterConfigurator.H" 00070 #include "Neuro/EnvVisualCortex.H" 00071 #include "Raster/GenericFrame.H" 00072 #include "Raster/Raster.H" 00073 #include "Transport/FrameInfo.H" 00074 #include "Transport/TransportOpts.H" 00075 #include "Util/FpsTimer.H" 00076 #include "Util/Pause.H" 00077 #include "Util/StringConversions.H" 00078 #include "Util/StringUtil.H" 00079 #include "Util/SyncJobServer.H" 00080 #include "Util/SysInfo.H" 00081 #include "Util/TextLog.H" 00082 #include "Util/WorkThreadServer.H" 00083 #include "Util/csignals.H" 00084 #include "rutz/shared_ptr.h" 00085 #include "rutz/trace.h" 00086 00087 #include <ctype.h> 00088 #include <deque> 00089 #include <iterator> 00090 #include <limits> 00091 #include <stdlib.h> // for atoi(), malloc(), free() 00092 #include <string.h> 00093 #include <sys/resource.h> 00094 #include <signal.h> 00095 #include <time.h> 00096 #include <vector> 00097 00098 const size_t PREFERRED_TEXT_LENGTH = 42; 00099 00100 // ###################################################################### 00101 class EnvSimulationViewer : public ModelComponent 00102 { 00103 public: 00104 EnvSimulationViewer(OptionManager& mgr); 00105 00106 virtual ~EnvSimulationViewer(); 00107 00108 virtual void paramChanged(ModelParamBase* const param, const bool valueChanged, ParamClient::ChangeStatus* status); 00109 00110 bool shouldQuit() const { return itsDoQuit; } 00111 00112 OModelParam<Dims> itsInputDims; 00113 OModelParam<bool> optAsyncUi; 00114 OModelParam<uint> optAsyncUiQueueSize; 00115 OModelParam<bool> optFlushUiQueue; 00116 OModelParam<bool> itsNeovision2Gui; 00117 OModelParam<bool> optCompactDisplay; 00118 OModelParam<byte> optExtendedDisplay; 00119 OModelParam<size_t> optDispZoom; 00120 OModelParam<size_t> optInputReduce; 00121 OModelParam<std::string> optMainwinTitle; 00122 OModelParam<bool> itsSaveVcx; 00123 OModelParam<bool> itsSaveSm; 00124 00125 bool itsDoQuit; 00126 }; 00127 00128 00129 // ###################################################################### 00130 static const ModelOptionDef OPT_AsyncUi = 00131 { MODOPT_FLAG, "AsyncUi", &MOC_OUTPUT, OPTEXP_CORE, 00132 "Whether to run the UI asynchronously in a background thread. " 00133 "This will give lower latencies and better framerates on a multi-core " 00134 "system, but will also allow frames to be dropped in order to maintain " 00135 "real-time responsiveness. Use --noasync-ui when it is critical that " 00136 "all frames be processed through the ui queue even if it cannot be done " 00137 "in real time.", 00138 "async-ui", '\0', "", "true" }; 00139 00140 static const ModelOptionDef OPT_AsyncUiQueueSize = 00141 { MODOPT_ARG(uint), "AsyncUiQueueSize", &MOC_OUTPUT, OPTEXP_CORE, 00142 "How many frames to hold in the asynchronous UI queue before " 00143 "we start dropping old frames", 00144 "async-ui-qsize", '\0', "<uint>", "2" }; 00145 00146 static const ModelOptionDef OPT_FlushUiQueue = 00147 { MODOPT_FLAG, "FlushUiQueue", &MOC_OUTPUT, OPTEXP_CORE, 00148 "Whether to flush UI frames that are left in the queue " 00149 "when the main loop exits", 00150 "flush-ui-queue", '\0', "", "false" }; 00151 00152 static const ModelOptionDef OPT_Neovision2Gui = 00153 { MODOPT_FLAG, "Neovision2Gui", &MOC_OUTPUT, OPTEXP_CORE, 00154 "Whether to show/save the neovision2 GUI", 00155 "neovision2-gui", '\0', "", "true" }; 00156 00157 static const ModelOptionDef OPT_CompactDisplay = 00158 { MODOPT_FLAG, "EsvCompactDisplay", &MOC_OUTPUT, OPTEXP_CORE, 00159 "Whether to start the GUI in compact display mode", 00160 "compact-display", '\0', "", "true" }; 00161 00162 static const ModelOptionDef OPT_ExtendedDisplay = 00163 { MODOPT_ARG(byte), "EsvExtendedDisplay", &MOC_OUTPUT, OPTEXP_CORE, 00164 "Amount of extra info to display in the GUI:\n" 00165 " level 0: just input + saliency map\n" 00166 " level 1: add meters underneath input+salmap\n" 00167 " level 2: add single row of small internal maps\n" 00168 " level 3: add double row of medium-sized internal maps", 00169 "extended-display", '\0', "<int>", "2" }; 00170 00171 static const ModelOptionDef OPT_DispZoom = 00172 { MODOPT_ARG(size_t), "EsvDispZoom", &MOC_OUTPUT, OPTEXP_CORE, 00173 "Number of octaves to zoom in on the small maps", 00174 "disp-zoom", '\0', "size_t", "4" }; 00175 00176 static const ModelOptionDef OPT_InputReduce = 00177 { MODOPT_ARG(size_t), "EsvInputReduce", &MOC_OUTPUT, OPTEXP_CORE, 00178 "Number of octaves to reduce the input by, for display purposes only", 00179 "input-reduce", '\0', "size_t", "0" }; 00180 00181 static const ModelOptionDef OPT_MainwinTitle = 00182 { MODOPT_ARG_STRING, "MainwinTitle", &MOC_OUTPUT, OPTEXP_CORE, 00183 "Title to use for main output window", 00184 "mainwin-title", '\0', "<string>", "neovision2" }; 00185 00186 static const ModelOptionDef OPT_SaveVcx = 00187 { MODOPT_FLAG, "SaveVcx", &MOC_OUTPUT, OPTEXP_CORE, 00188 "Whether to save the VisualCortex (VCX) output", 00189 "save-vcx", '\0', "", "false" }; 00190 00191 static const ModelOptionDef OPT_SaveSm = 00192 { MODOPT_FLAG, "SaveSm", &MOC_OUTPUT, OPTEXP_CORE, 00193 "Whether to save the SaliencyMap (Sm) output", 00194 "save-sm", '\0', "", "false" }; 00195 00196 // ###################################################################### 00197 EnvSimulationViewer::EnvSimulationViewer(OptionManager& mgr) : 00198 ModelComponent(mgr, "Embeddable Simulation Viewer", "EnvSimulationViewer"), 00199 itsInputDims(&OPT_InputFrameDims, this), 00200 optAsyncUi(&OPT_AsyncUi, this), 00201 optAsyncUiQueueSize(&OPT_AsyncUiQueueSize, this), 00202 optFlushUiQueue(&OPT_FlushUiQueue, this), 00203 itsNeovision2Gui(&OPT_Neovision2Gui, this), 00204 optCompactDisplay(&OPT_CompactDisplay, this, ALLOW_ONLINE_CHANGES), 00205 optExtendedDisplay(&OPT_ExtendedDisplay, this, ALLOW_ONLINE_CHANGES), 00206 optDispZoom(&OPT_DispZoom, this, ALLOW_ONLINE_CHANGES), 00207 optInputReduce(&OPT_InputReduce, this, ALLOW_ONLINE_CHANGES), 00208 optMainwinTitle(&OPT_MainwinTitle, this), 00209 itsSaveVcx(&OPT_SaveVcx, this), 00210 itsSaveSm(&OPT_SaveSm, this), 00211 itsDoQuit(false) 00212 { } 00213 00214 EnvSimulationViewer::~EnvSimulationViewer() 00215 { } 00216 00217 void EnvSimulationViewer::paramChanged(ModelParamBase* const param, const bool valueChanged, 00218 ParamClient::ChangeStatus* status) 00219 { 00220 if (param == &itsInputDims) { 00221 const size_t excess_size = size_t(0.5 * log2(itsInputDims.getVal().sz() / 1000000.0)); 00222 if (excess_size > optInputReduce.getVal()) optInputReduce.setVal(excess_size); 00223 } else if (param == &optInputReduce) { 00224 const size_t val = optInputReduce.getVal(); 00225 const Dims d = itsInputDims.getVal(); 00226 00227 if (val > 16) *status = ParamClient::CHANGE_REJECTED; 00228 else if (d.isNonEmpty() && val > 0 && ((d.w() / (1 << val)) < 32 || (d.h() / (1 << val)) < 32)) 00229 *status = ParamClient::CHANGE_REJECTED; 00230 } 00231 } 00232 00233 // ###################################################################### 00234 struct Nv2UiData 00235 { 00236 Nv2UiData(const int map_zoom_) : 00237 accepted_training_label(), 00238 remote_command(), 00239 map_zoom(map_zoom_), 00240 targetLoc(-1,-1), 00241 ncpu(numCpus()), 00242 text_log_file("") 00243 { } 00244 00245 FpsTimer::State time_state; 00246 std::string accepted_training_label; 00247 std::string remote_command; 00248 const int map_zoom; 00249 Point2D<int> targetLoc; 00250 const int ncpu; 00251 std::string text_log_file; 00252 }; 00253 00254 // ###################################################################### 00255 class Nv2UiJob : public JobServer::Job 00256 { 00257 public: 00258 Nv2UiJob(OutputFrameSeries* ofs_, 00259 EnvSimulationViewer* esv_, 00260 EnvInferoTemporal* eit_, 00261 const Nv2UiData& uidata_, 00262 EnvSaliencyMap* sm_, 00263 EnvSegmenter* ese_, 00264 NeoBrain* nb_, 00265 Image<PixRGB<byte> > rgbin_, 00266 Image<byte> vcxmap_ 00267 , Image<byte> Imap_ 00268 , Image<byte> Cmap_ 00269 , Image<byte> Omap_ 00270 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00271 , Image<byte> Fmap_ 00272 , Image<byte> Mmap_ 00273 #endif 00274 ) : 00275 ofs(ofs_), esv(esv_), eit(eit_), uidata(uidata_), sm(sm_), ese(ese_), neoBrain(nb_), rgbin(rgbin_), 00276 vcxmap(vcxmap_), Imap(Imap_), Cmap(Cmap_), Omap(Omap_), 00277 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00278 Fmap(Fmap_), Mmap(Mmap_), 00279 #endif 00280 m_dispzoom(1 << esv->optDispZoom.getVal()), m_inputreduce(esv->optInputReduce.getVal()) 00281 { } 00282 00283 // #################### 00284 unsigned int getHalfZoom() const 00285 { 00286 const int div = (esv->optExtendedDisplay.getVal() >= 4 && esv->optExtendedDisplay.getVal() < 10) ? 2 : 4; 00287 return std::max(size_t(1), m_dispzoom/div); 00288 } 00289 00290 // #################### 00291 Layout<PixRGB<byte> > makeInputMarkup(const Rectangle& foa, const Image<byte>& foamask, 00292 const EnvSaliencyMap::State& smstate, const uint32_t patch_id) const 00293 { 00294 Image<PixRGB<byte> > markup = rgbin; 00295 00296 if (foa.isValid()) drawRectSquareCorners(markup, foa, PixRGB<byte>(255, 255, 0), 3 << m_inputreduce); 00297 00298 if (uidata.targetLoc.isValid()) 00299 drawCircle(markup, uidata.targetLoc, 3, PixRGB<byte>(60, 220, 255), 3 << m_inputreduce); 00300 00301 // draw the first most salient loc: 00302 drawRectSquareCorners(markup, 00303 Rectangle(smstate.fullres_maxpos - uidata.map_zoom/2, Dims(uidata.map_zoom, uidata.map_zoom)), 00304 PixRGB<byte>(255, 0, 0), 3 << m_inputreduce); 00305 00306 // draw the next n most salient loc: 00307 for (uint i = 1; i < smstate.nMostSalientLoc.size(); ++i) 00308 { 00309 const EnvSaliencyMap::LocInfo locInfo = smstate.nMostSalientLoc[i]; 00310 drawRectSquareCorners(markup, Rectangle(locInfo.fullres_maxpos - uidata.map_zoom/2, 00311 Dims(uidata.map_zoom, uidata.map_zoom)), 00312 PixRGB<byte>(150, 0, 0), 3 << m_inputreduce); 00313 } 00314 00315 for (size_t i = 0; i < m_inputreduce; ++i) markup = decXY(markup); 00316 00317 if (foamask.initialized()) drawContour2D(rescaleNI(foamask, markup.getDims()), markup, PixRGB<byte>(0,255,0), 2); 00318 00319 const std::string lines[2] = { 00320 sformat("peak %3d in %3dx%3d foa @ (%3d,%3d)", int(smstate.maxval), 00321 foa.isValid() ? foa.width() : -1, foa.isValid() ? foa.height() : -1, 00322 smstate.fullres_maxpos.i, smstate.fullres_maxpos.j), 00323 sformat("%s #%06u [%5.2ffps, %5.1f%%CPU]", convertToString(uidata.time_state.elapsed_time).c_str(), 00324 (unsigned int) patch_id, uidata.time_state.recent_fps, uidata.time_state.recent_cpu_usage*100.0) 00325 }; 00326 00327 const Image<PixRGB<byte> > textarea = 00328 makeMultilineTextBox(markup.getWidth(), &lines[0], 2, 00329 PixRGB<byte>(255, 255, 0), PixRGB<byte>(0,0,0), PREFERRED_TEXT_LENGTH); 00330 00331 return vcat(markup, textarea); 00332 } 00333 00334 // #################### 00335 Layout<PixRGB<byte> > 00336 makeSalmapMarkup(const EnvSaliencyMap::State& smstate) const 00337 { 00338 Image<PixRGB<byte> > zoomedsm = zoomXY(smstate.salmap, m_dispzoom, m_dispzoom); 00339 00340 // draw the first most salient loc: 00341 drawRectSquareCorners(zoomedsm, Rectangle(smstate.lowres_maxpos * m_dispzoom, Dims(m_dispzoom, m_dispzoom)), 00342 PixRGB<byte>(255, 0, 0), 3); 00343 00344 // draw the next n most salient locs: 00345 for (uint i = 1; i < smstate.nMostSalientLoc.size(); ++i) 00346 { 00347 const EnvSaliencyMap::LocInfo locInfo = smstate.nMostSalientLoc[i]; 00348 drawRectSquareCorners(zoomedsm, Rectangle(locInfo.lowres_maxpos * m_dispzoom, Dims(m_dispzoom, m_dispzoom)), 00349 PixRGB<byte>(150, 0, 0), 3); 00350 } 00351 00352 const std::string valstring = sformat("%d", int(smstate.maxval)); 00353 00354 const SimpleFont font = SimpleFont::fixedMaxWidth(zoomedsm.getWidth() / 30); 00355 00356 Point2D<int> textpos = smstate.lowres_maxpos * m_dispzoom; 00357 textpos.j -= font.h() + 2; if (textpos.j < 0) textpos.j += m_dispzoom + 2; 00358 00359 writeText(zoomedsm, textpos, valstring.c_str(), 00360 PixRGB<byte>(255, 0, 0), PixRGB<byte>(0, 0, 0), font, true); 00361 00362 #ifdef VSS_DEMO 00363 Image<PixRGB<byte> > histo = 00364 neoBrain->getSaliencyHisto(Dims(zoomedsm.getWidth(), 62), PixRGB<byte>(0,0,0), PixRGB<byte>(180,180,180)); 00365 return vcat(zoomedsm, histo); 00366 #else 00367 return zoomedsm; 00368 #endif 00369 } 00370 00371 // #################### 00372 Layout<PixRGB<byte> > makeCmapsMarkup() const 00373 { 00374 unsigned int halfzoom = this->getHalfZoom(); 00375 if (esv->optExtendedDisplay.getVal() == 10) halfzoom /= 2; 00376 00377 Image<PixRGB<byte> > cmaps[] = { 00378 zoomXY(Imap, halfzoom, halfzoom), 00379 zoomXY(Cmap, halfzoom, halfzoom), 00380 zoomXY(Omap, halfzoom, halfzoom), 00381 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00382 zoomXY(Fmap, halfzoom, halfzoom), 00383 zoomXY(Mmap, halfzoom, halfzoom), 00384 #endif 00385 zoomXY(vcxmap, halfzoom, halfzoom) 00386 }; 00387 00388 const char* labels[] = { 00389 "I", "C", "O", 00390 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00391 "F", "M", 00392 #endif 00393 "VC" 00394 }; 00395 00396 for (size_t i = 0; i < sizeof(labels) / sizeof(labels[0]); ++i) { 00397 const SimpleFont font = SimpleFont::fixedMaxWidth(cmaps[i].getWidth() / 20); 00398 writeText(cmaps[i], Point2D<int>(1,1), labels[i], PixRGB<byte>(0), PixRGB<byte>(255), font); 00399 drawLine(cmaps[i], Point2D<int>(0,0), Point2D<int>(cmaps[i].getWidth()-1,0), PixRGB<byte>(255), 1); 00400 drawLine(cmaps[i], Point2D<int>(0,0), Point2D<int>(0,cmaps[i].getHeight()-1), PixRGB<byte>(255), 1); 00401 } 00402 00403 const size_t nrows = esv->optExtendedDisplay.getVal() >= 4 ? 2 : 1; 00404 00405 return arrcat(&cmaps[0], sizeof(cmaps) / sizeof(cmaps[0]), (sizeof(cmaps) / sizeof(cmaps[0]) + (nrows-1)) / nrows); 00406 } 00407 00408 // #################### 00409 Image<PixRGB<byte> > makeInhibitionMarkup() const 00410 { 00411 Image<byte> inh = sm->getInhibmap(); 00412 if (!inh.initialized()) inh = Image<byte>(vcxmap.getDims(), ZEROS); 00413 00414 Image<byte> inr = Image<byte>(sm->getInertiaMap()); 00415 if (!inr.initialized()) inr = Image<byte>(vcxmap.getDims(), ZEROS); 00416 00417 Image<PixRGB<byte> > rgb(vcxmap.getDims(), NO_INIT); 00418 Image<PixRGB<byte> >::iterator aptr = rgb.beginw(); 00419 Image<PixRGB<byte> >::iterator stop = rgb.endw(); 00420 00421 Image<byte>::const_iterator rptr = inh.begin(); 00422 Image<byte>::const_iterator gptr = inr.begin(); 00423 00424 while (aptr != stop) *aptr++ = PixRGB<byte>(*rptr++, *gptr++, 0); 00425 00426 return zoomXY(rgb, esv->optExtendedDisplay.getVal() == 10 ? getHalfZoom() / 2 : getHalfZoom()); 00427 } 00428 00429 // #################### 00430 Image<PixRGB<byte> > makeMeters(const size_t nx, const Dims& meterdims) const 00431 { 00432 const double maxcpu = uidata.ncpu <= 0 ? 100.0 : uidata.ncpu * 100.0; 00433 00434 const double nothresh = std::numeric_limits<double>::max(); 00435 00436 const MeterInfo infos[] = { 00437 { "dvcx/dt", sm->getVcxFlicker(), 1.0, nothresh, PixRGB<byte>(0, 255, 0) }, 00438 { "dfactor", sm->getDynamicFactor(), 1.0, nothresh, PixRGB<byte>(128, 0, 255) }, 00439 #ifdef VSS_DEMO 00440 { "boringness", neoBrain->getBoringness(), 128.0, nothresh, PixRGB<byte>(192, 255, 0) }, 00441 { "excitement", neoBrain->getExcitementLevel(), 256.0, nothresh, PixRGB<byte>(255, 0, 32) }, 00442 { "sleepiness", neoBrain->getSleepLevel(), 1000.0, nothresh, PixRGB<byte>(255, 0, 32) }, 00443 #endif 00444 { "confidence", eit->getMaxConfidence(), 1.0, eit->getConfidenceThresh(), PixRGB<byte>(0, 255, 128) }, 00445 { "cpu%", uidata.time_state.recent_cpu_usage*100.0, maxcpu, nothresh, PixRGB<byte>(255, 165, 0) }, 00446 { "fps", uidata.time_state.recent_fps, 60.0, nothresh, PixRGB<byte>(0, 128, 255) } 00447 }; 00448 00449 return drawMeters(&infos[0], sizeof(infos) / sizeof(infos[0]), nx, meterdims); 00450 } 00451 00452 // #################### 00453 virtual void run() 00454 { 00455 Point2D<int> scaled_maxpos(-1,-1); 00456 00457 const nub::soft_ref<ImageDisplayStream> ids = ofs->findFrameDestType<ImageDisplayStream>(); 00458 00459 const rutz::shared_ptr<XWinManaged> uiwin = ids.is_valid() ? 00460 ids->getWindow(esv->optCompactDisplay.getVal() ? esv->optMainwinTitle.getVal() : "input") 00461 : rutz::shared_ptr<XWinManaged>(); 00462 00463 Point2D<int> forceTrackLocation(-1,-1); 00464 00465 if (uiwin.is_valid()) { 00466 XButtonEvent ev; 00467 if (uiwin->getLastButtonEvent(&ev) && ev.button == 1) forceTrackLocation = Point2D<int>(ev.x, ev.y); 00468 } 00469 00470 if (forceTrackLocation.isValid()) { 00471 const Point2D<int> candidate = forceTrackLocation * (1 << m_inputreduce) + (1 << m_inputreduce) / 2; 00472 00473 if (rgbin.coordsOk(candidate)) { 00474 scaled_maxpos = candidate; 00475 neoBrain->setTarget(scaled_maxpos, rgbin, -1, false, true); 00476 //neoBrain->setKeepTracking(true); 00477 } 00478 } else if (uidata.targetLoc.isValid()) { 00479 scaled_maxpos = uidata.targetLoc; 00480 ASSERT(rgbin.coordsOk(scaled_maxpos)); 00481 } 00482 00483 const EnvSaliencyMap::State smstate = sm->getSalmap(vcxmap, scaled_maxpos); 00484 00485 #ifdef VSS_DEMO 00486 neoBrain->updateBoringness(smstate.salmap, smstate.maxval); 00487 neoBrain->updateExcitement(sm->getVcxFlicker()); 00488 #endif 00489 00490 Image<byte> foamask; 00491 Image<PixRGB<byte> > segmentdisp; 00492 00493 // Send the first most salient locations to be identified 00494 const Rectangle foa = ese->getFoa(rgbin, smstate.fullres_maxpos, &foamask, &segmentdisp); 00495 00496 //if (foa.isValid()) { 00497 // const Point2D<int> objCenter = Point2D<int>(foa.topLeft().i + foa.width()/2, foa.topLeft().j + foa.height()/2); 00498 // neoBrain->setTarget(objCenter, rgbin, smstate.maxval); 00499 //} else if (!uidata.targetLoc.isValid()) 00500 // neoBrain->setTarget(smstate.fullres_maxpos, rgbin, smstate.maxval); 00501 if (!uidata.targetLoc.isValid()) 00502 neoBrain->setTarget(smstate.fullres_maxpos, rgbin, smstate.maxval); 00503 00504 const uint32_t patch_id = uidata.time_state.frame_number; 00505 00506 eit->sendPatch(patch_id, rgbin, foa, 00507 uidata.time_state.elapsed_time, 00508 uidata.accepted_training_label.length() > 0, 00509 uidata.accepted_training_label, 00510 uidata.remote_command, 00511 smstate.fullres_maxpos); 00512 00513 // Send the next N most salient locations to be identified: 00514 for (uint i = 1; i < smstate.nMostSalientLoc.size(); ++i) { 00515 Image<byte> nextFoamask; 00516 Image<PixRGB<byte> > nextSegmentdisp; 00517 00518 const EnvSaliencyMap::LocInfo locInfo = smstate.nMostSalientLoc[i]; 00519 const Rectangle nextFoa = ese->getFoa(rgbin, locInfo.fullres_maxpos, &nextFoamask, &nextSegmentdisp); 00520 00521 eit->sendPatch(patch_id, rgbin, nextFoa, 00522 uidata.time_state.elapsed_time, 00523 uidata.accepted_training_label.length() > 0, 00524 uidata.accepted_training_label, 00525 uidata.remote_command, 00526 locInfo.fullres_maxpos); 00527 } 00528 00529 // log various bits of info (these calls will do nothing if the log filename is empty): 00530 textLog(uidata.text_log_file, "FOAbox", convertToString(foa)); 00531 00532 const FrameState os = ofs->updateNext(); 00533 00534 // save maps if requested: 00535 if (esv->itsSaveVcx.getVal()) ofs->writeGray(vcxmap, "VCO", FrameInfo("VisualCortex output map", SRC_POS)); 00536 00537 if (esv->itsSaveSm.getVal()) ofs->writeGray(smstate.salmap, "SM", FrameInfo("SaliencyMap output map", SRC_POS)); 00538 00539 // ##### compact displays 00540 if (esv->itsNeovision2Gui.getVal() && esv->optCompactDisplay.getVal()) { 00541 ofs->closeStream("input"); 00542 ofs->closeStream("salmap"); 00543 ofs->closeStream("cmaps"); 00544 ofs->closeStream("inhibition,inertia"); 00545 ofs->closeStream("segmentation"); 00546 ofs->closeStream("meters"); 00547 00548 Layout<PixRGB<byte> > img; 00549 00550 // ##### mode 10 displays (for display on HD monitor) 00551 if (esv->optExtendedDisplay.getVal() == 10) { 00552 // let's start with an HD display of the input + markups: 00553 Image<PixRGB<byte> > markup = rgbin; 00554 if (foa.isValid()) drawRectSquareCorners(markup, foa, PixRGB<byte>(255, 255, 0), 3 << m_inputreduce); 00555 00556 if (uidata.targetLoc.isValid()) 00557 drawCircle(markup, uidata.targetLoc, 3, PixRGB<byte>(60, 220, 255), 3 << m_inputreduce); 00558 00559 // draw the first most salient loc 00560 drawRectSquareCorners(markup, 00561 Rectangle(smstate.fullres_maxpos - uidata.map_zoom/2, 00562 Dims(uidata.map_zoom, uidata.map_zoom)), 00563 PixRGB<byte>(255, 0, 0), 3 << m_inputreduce); 00564 00565 // draw the next n most salient locs: 00566 for (uint i = 1; i < smstate.nMostSalientLoc.size(); ++i) { 00567 const EnvSaliencyMap::LocInfo locInfo = smstate.nMostSalientLoc[i]; 00568 drawRectSquareCorners(markup, 00569 Rectangle(locInfo.fullres_maxpos - uidata.map_zoom/2, 00570 Dims(uidata.map_zoom, uidata.map_zoom)), PixRGB<byte>(150, 0, 0), 3 << m_inputreduce); 00571 } 00572 00573 for (size_t i = 0; i < m_inputreduce; ++i) markup = decXY(markup); 00574 00575 if (foamask.initialized()) drawContour2D(rescaleNI(foamask,markup.getDims()), markup, PixRGB<byte>(0,255,0), 2); 00576 00577 // that's it for this window, let's send it out to display: 00578 ofs->writeRGB(markup, esv->optMainwinTitle.getVal(), FrameInfo("copy of input", SRC_POS)); 00579 00580 // the salmap: 00581 const unsigned int halfzoom = 8; 00582 Image<PixRGB<byte> > zoomedsm = zoomXY(smstate.salmap, halfzoom, halfzoom); 00583 00584 drawRectSquareCorners(zoomedsm, Rectangle(smstate.lowres_maxpos * halfzoom, Dims(halfzoom, halfzoom)), 00585 PixRGB<byte>(255, 0, 0), 3); 00586 00587 const std::string valstring = sformat("%d", int(smstate.maxval)); 00588 const SimpleFont font = SimpleFont::fixedMaxWidth(zoomedsm.getWidth() / 30); 00589 Point2D<int> textpos = smstate.lowres_maxpos * halfzoom; 00590 textpos.j -= font.h() + 2; if (textpos.j < 0) textpos.j += halfzoom + 2; 00591 writeText(zoomedsm, textpos, valstring.c_str(), PixRGB<byte>(255, 0, 0), PixRGB<byte>(0, 0, 0), font, true); 00592 00593 Image<PixRGB<byte> > inh = this->makeInhibitionMarkup(); 00594 drawLine(inh, Point2D<int>(0,0), Point2D<int>(inh.getWidth()-1,0), PixRGB<byte>(255, 255, 255), 1); 00595 drawLine(inh, Point2D<int>(0,0), Point2D<int>(0,inh.getHeight()-1), PixRGB<byte>(255, 255, 255), 1); 00596 00597 if (!segmentdisp.initialized()) 00598 segmentdisp = Image<PixRGB<byte> >(inh.getDims(), ZEROS); 00599 else { 00600 segmentdisp = rescaleNI(segmentdisp, inh.getDims()); 00601 drawContour2D(rescaleNI(foamask, inh.getDims()), segmentdisp, PixRGB<byte>(0,255,0), 2); 00602 } 00603 drawLine(segmentdisp, Point2D<int>(0,0), Point2D<int>(inh.getWidth()-1,0), 00604 PixRGB<byte>(255, 255, 255), 1); 00605 drawLine(segmentdisp, Point2D<int>(0,0), Point2D<int>(0,inh.getHeight()-1), 00606 PixRGB<byte>(255, 255, 255), 1); 00607 Layout<PixRGB<byte> > inl = vcat(inh, segmentdisp); 00608 00609 img = vcat(zoomedsm, this->makeMeters(2, Dims(zoomedsm.getDims().w() / 2, 13))); 00610 00611 // now some info: 00612 const std::string lines[1] = 00613 { 00614 sformat("peak %3d in %3dx%3d foa @ (%4d,%4d) %04dx%04d %s #%06u [%3.2ffps, %4.1f%%CPU]", 00615 int(smstate.maxval), 00616 foa.isValid() ? foa.width() : -1, 00617 foa.isValid() ? foa.height() : -1, 00618 smstate.fullres_maxpos.i, 00619 smstate.fullres_maxpos.j, 00620 rgbin.getWidth(), rgbin.getHeight(), 00621 convertToString(uidata.time_state.elapsed_time).c_str(), 00622 (unsigned int) patch_id, 00623 uidata.time_state.recent_fps, 00624 uidata.time_state.recent_cpu_usage*100.0) 00625 }; 00626 00627 const Image<PixRGB<byte> > textarea = 00628 makeMultilineTextBox(img.getWidth(), &lines[0], 1, PixRGB<byte>(255, 255, 0), PixRGB<byte>(0,0,0), 00629 PREFERRED_TEXT_LENGTH, 10); 00630 img = vcat(img, textarea); 00631 00632 // now the cmaps and friends: 00633 const Layout<PixRGB<byte> > cmaps = this->makeCmapsMarkup(); 00634 inl = hcat(cmaps, inl); 00635 img = vcat(img, inl); 00636 00637 ofs->writeRgbLayout(img, "control-panel", FrameInfo("copy of input", SRC_POS)); 00638 //////////////////////////////// 00639 } else { 00640 img = hcat(this->makeInputMarkup(foa, foamask, smstate, patch_id), this->makeSalmapMarkup(smstate)); 00641 00642 if (esv->optExtendedDisplay.getVal() > 0) { 00643 // ##### mode 2+ displays 00644 if (esv->optExtendedDisplay.getVal() >= 2) 00645 { 00646 const Layout<PixRGB<byte> > cmaps = this->makeCmapsMarkup(); 00647 Image<PixRGB<byte> > inh = this->makeInhibitionMarkup(); 00648 drawLine(inh, Point2D<int>(0,0), Point2D<int>(inh.getWidth()-1,0), PixRGB<byte>(255, 255, 255), 1); 00649 drawLine(inh, Point2D<int>(0,0), Point2D<int>(0,inh.getHeight()-1), PixRGB<byte>(255, 255, 255), 1); 00650 00651 const SimpleFont font = SimpleFont::fixedMaxWidth(inh.getWidth() / 20); 00652 writeText(inh, Point2D<int>(1,1), "INH", PixRGB<byte>(0), PixRGB<byte>(255), font); 00653 00654 if (!segmentdisp.initialized()) 00655 segmentdisp = Image<PixRGB<byte> >(inh.getDims(), ZEROS); 00656 else { 00657 segmentdisp = rescaleNI(segmentdisp, inh.getDims()); 00658 00659 drawContour2D(rescaleNI(foamask, inh.getDims()), segmentdisp, PixRGB<byte>(0,255,0), 2); 00660 writeText(segmentdisp, Point2D<int>(1,1), "SEG", PixRGB<byte>(0), PixRGB<byte>(255), font); 00661 } 00662 drawLine(segmentdisp, Point2D<int>(0,0), Point2D<int>(inh.getWidth()-1,0), 00663 PixRGB<byte>(255, 255, 255), 1); 00664 drawLine(segmentdisp, Point2D<int>(0,0), Point2D<int>(0,inh.getHeight()-1), 00665 PixRGB<byte>(255, 255, 255), 1); 00666 00667 if (esv->optExtendedDisplay.getVal() >= 4) 00668 img = vcat(img, hcat(cmaps, vcat(inh,segmentdisp))); 00669 else 00670 img = vcat(img, hcat(cmaps, hcat(inh,segmentdisp))); 00671 } 00672 00673 img = vcat(img, this->makeMeters(2, Dims(img.getDims().w() / 2, 13))); 00674 00675 // ##### mode 3+ displays 00676 if (esv->optExtendedDisplay.getVal() >= 3) 00677 { 00678 NeoBrain::Stats stats = neoBrain->getStats(); 00679 00680 const std::string lines[5] = { 00681 sformat(" track error #frames %04lu (%04lu) | target track #frames %04lu (%04lu)", 00682 stats.bigerrframes, stats.bigerrframes_thresh, stats.targetframes, stats.targetframes_thresh), 00683 sformat(" non-motion #frames %04lu (%04lu) | stop track #frames %04lu (%04lu)", 00684 stats.nomoveframes, stats.nomoveframes_thresh, stats.stopframes, stats.stopframes_thresh), 00685 "", 00686 sformat(" track err = %.3f = %.3f+%.3f (%.3f, %.3f)", 00687 stats.last_err, stats.last_xerr, stats.last_yerr, stats.err_tol, stats.dist_tol), 00688 sformat(" leftEyeTilt = %.3f leftEyePan = %.3f headPan = %.3f", 00689 stats.leftEyeTiltPos, stats.leftEyePanPos, stats.headPanPos) 00690 }; 00691 00692 const Image<PixRGB<byte> > textarea = 00693 makeMultilineTextBox(img.getDims().w(), &lines[0], 5, 00694 PixRGB<byte>(128, 180, 255), PixRGB<byte>(0,0,0), 150); 00695 img = vcat(img, textarea); 00696 } 00697 } 00698 ofs->writeRgbLayout(img, esv->optMainwinTitle.getVal(), FrameInfo("copy of input", SRC_POS)); 00699 } 00700 } else if (esv->itsNeovision2Gui.getVal()) { 00701 // ##### multiwindow displays 00702 ofs->closeStream(esv->optMainwinTitle.getVal()); 00703 00704 ofs->writeRgbLayout(this->makeInputMarkup(foa, foamask, smstate, patch_id), 00705 "input", FrameInfo("copy of input", SRC_POS)); 00706 00707 ofs->writeRgbLayout(this->makeSalmapMarkup(smstate), "salmap", FrameInfo("saliency map", SRC_POS)); 00708 00709 if (esv->optExtendedDisplay.getVal()) { 00710 ofs->writeRgbLayout(this->makeCmapsMarkup(), "cmaps", FrameInfo("channel conspicuity maps", SRC_POS)); 00711 00712 ofs->writeRGB(this->makeInhibitionMarkup(), "inhibition,inertia", 00713 FrameInfo("inertia and inhibition of return", SRC_POS)); 00714 00715 ofs->writeRGB(this->makeMeters(1, Dims(400, 13)), "meters"); 00716 } else { 00717 ofs->closeStream("cmaps"); 00718 ofs->closeStream("inhibition,inertia"); 00719 ofs->closeStream("meters"); 00720 } 00721 00722 if (segmentdisp.initialized()) { 00723 segmentdisp = zoomXY(segmentdisp, m_dispzoom); 00724 drawContour2D(zoomXY(foamask, m_dispzoom), segmentdisp, PixRGB<byte>(0,255,0), 2); 00725 ofs->writeRGB(segmentdisp, "segmentation"); 00726 } else ofs->closeStream("segmentation"); 00727 } 00728 00729 std::vector<Nv2LabelReader::LabeledImage> images = eit->getLabeledImages(PREFERRED_TEXT_LENGTH); 00730 00731 for (size_t i = 0; i < images.size(); ++i) 00732 { 00733 ofs->writeRGB(images[i].img, images[i].ident, FrameInfo("object-labeled image", SRC_POS)); 00734 #ifdef VSS_DEMO 00735 neoBrain->sayObjectLabel(images[i].label, /*confidence = */ 0, true); 00736 #endif 00737 } 00738 00739 if (os == FRAME_FINAL) esv->itsDoQuit = true; 00740 } 00741 00742 // #################### 00743 virtual const char* jobType() const { return "Nv2UiJob"; } 00744 00745 private: 00746 OutputFrameSeries* const ofs; 00747 EnvSimulationViewer* const esv; 00748 EnvInferoTemporal* const eit; 00749 const Nv2UiData uidata; 00750 EnvSaliencyMap* const sm; 00751 EnvSegmenter* const ese; 00752 NeoBrain* const neoBrain; 00753 Image<PixRGB<byte> > rgbin; 00754 const Image<byte> vcxmap; 00755 const Image<byte> Imap; 00756 const Image<byte> Cmap; 00757 const Image<byte> Omap; 00758 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00759 const Image<byte> Fmap; 00760 const Image<byte> Mmap; 00761 #endif 00762 const size_t m_dispzoom; 00763 const size_t m_inputreduce; 00764 }; 00765 00766 // ###################################################################### 00767 static const ModelOptionDef OPT_WithObjrecMode = 00768 { MODOPT_FLAG, "WithObjrecMode", &MOC_OUTPUT, OPTEXP_CORE, 00769 "Whether to include an 'objrec' mode which toggles parameters " 00770 "to values suitable for object recognition training.", 00771 "with-objrec-mode", '\0', "", "false" }; 00772 00773 static const ModelOptionDef OPT_ALIASheadDemo = 00774 { MODOPT_ALIAS, "ALIASheadDemo", &MOC_ALIAS, OPTEXP_CORE, 00775 "Set parameters for the head demo", 00776 "head-demo", '\0', "", 00777 "--in=V4L2 " 00778 "--framegrabber-dims=320x240 " 00779 "--framegrabber-mode=RGB24 " 00780 "--framegrabber-chan=0 " 00781 "--framegrabber-dev=/dev/video1 " 00782 "--evc-type=I:0.75C:0.75O:0.75F:0.75M:1.0 " 00783 "--mainwin-title=Sal " 00784 "--neobrain-speak-saliency " 00785 "--neobrain-speak-objects " 00786 "--with-objrec-mode " 00787 }; 00788 00789 static const ModelOptionDef OPT_ALIASheadDemo21 = 00790 { MODOPT_ALIAS, "ALIASheadDemo21", &MOC_ALIAS, OPTEXP_CORE, 00791 "Set parameters for the head demo on ilab21", 00792 "head-demo21", '\0', "", 00793 "--in=v4l2 " 00794 "--framegrabber-dims=720x480 " 00795 "--framegrabber-mode=HM12 " 00796 "--framegrabber-chan=2 " 00797 "--framegrabber-dev=/dev/video32 " 00798 "--evc-type=I:0.75C:0.75O:0.75F:0.75M:1.0 " 00799 "--mainwin-title=Sal " 00800 "--with-objrec-mode " 00801 "--neobrain-speak-saliency " 00802 "--evc-multithreaded " 00803 }; 00804 00805 static const ModelOptionDef OPT_ALIASheadDemo3 = 00806 { MODOPT_ALIAS, "ALIASheadDemo3", &MOC_ALIAS, OPTEXP_CORE, 00807 "Set parameters for the head demo on ilab3", 00808 "head-demo3", '\0', "", 00809 "--in=v4l2 " 00810 "--evc-type=I:0.75C:0.75O:0.75F:0.75M:1.0 " 00811 "--mainwin-title=Sal " 00812 "--with-objrec-mode " 00813 "--neobrain-speak-saliency " 00814 "--evc-multithreaded " 00815 }; 00816 00817 static const ModelOptionDef OPT_ALIASflea2Demo = 00818 { MODOPT_ALIAS, "ALIASflea2Demo", &MOC_ALIAS, OPTEXP_CORE, 00819 "Set parameters for the Flea2 demo", 00820 "flea2-demo", '\0', "", 00821 "--in=dc1394v2 " 00822 "--framegrabber-dims=1024x768 " 00823 "--framegrabber-mode=RGB24 " 00824 "--framegrabber-fps=15 " 00825 "--evc-multithreaded " 00826 "--noneobrain-speech " 00827 "--disp-zoom=4 " 00828 }; 00829 00830 static const ModelOptionDef OPT_ALIASHDDemo = 00831 { MODOPT_ALIAS, "ALIASHDDemo", &MOC_ALIAS, OPTEXP_CORE, 00832 "Set parameters for the hd camera on ilab24", 00833 "hd-demo", '\0', "", 00834 "--in=XC " 00835 "--framegrabber-dims=1024x768 " 00836 "--patch-reader=192.168.0.229:9930 " 00837 "--disp-zoom=3 " 00838 "--evc-multithreaded " 00839 }; 00840 00841 // ###################################################################### 00842 int submain(int argc, const char** argv) 00843 { 00844 volatile int signum = 0; 00845 signal(SIGPIPE, SIG_IGN); 00846 catchsignals(&signum); 00847 00848 // Instantiate our various ModelComponents: 00849 00850 ModelManager manager("Nv2"); 00851 00852 OModelParam<bool> optWithObjrecMode(&OPT_WithObjrecMode, &manager); 00853 OModelParam<std::string> optTextLogFile(&OPT_TextLogFile, &manager); 00854 00855 nub::ref<EnvSimulationViewer> esv(new EnvSimulationViewer(manager)); 00856 manager.addSubComponent(esv); 00857 00858 nub::ref<InputFrameSeries> ifs(new InputFrameSeries(manager)); 00859 manager.addSubComponent(ifs); 00860 00861 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager)); 00862 manager.addSubComponent(ofs); 00863 00864 nub::ref<EnvVisualCortex> evc(new EnvVisualCortex(manager)); 00865 manager.addSubComponent(evc); 00866 00867 nub::ref<EnvSaliencyMap> esm(new EnvSaliencyMap(manager)); 00868 manager.addSubComponent(esm); 00869 00870 nub::ref<EnvSegmenterConfigurator> esec(new EnvSegmenterConfigurator(manager)); 00871 manager.addSubComponent(esec); 00872 00873 nub::ref<EnvInferoTemporal> eit(new EnvInferoTemporal(manager)); 00874 manager.addSubComponent(eit); 00875 00876 nub::ref<NeoBrain> neoBrain(new NeoBrain(manager)); 00877 manager.addSubComponent(neoBrain); 00878 00879 manager.requestOptionAlias(&OPT_ALIASheadDemo); 00880 manager.requestOptionAlias(&OPT_ALIASheadDemo3); 00881 manager.requestOptionAlias(&OPT_ALIASheadDemo21); 00882 manager.requestOptionAlias(&OPT_ALIASflea2Demo); 00883 manager.requestOptionAlias(&OPT_ALIASHDDemo); 00884 00885 manager.exportOptions(MC_RECURSE); 00886 00887 #if defined(HAVE_IEEE1394) 00888 // input comes from firewire camera 640x480/rgb/15fps by default 00889 manager.setOptionValString(&OPT_InputFrameSource, "ieee1394"); 00890 manager.setOptionValString(&OPT_FrameGrabberMode, "RGB24"); 00891 manager.setOptionValString(&OPT_FrameGrabberDims, "640x480"); 00892 manager.setOptionValString(&OPT_FrameGrabberFPS, "15"); 00893 #elif defined(HAVE_QUICKTIME_QUICKTIME_H) 00894 manager.setOptionValString(&OPT_InputFrameSource, "qtgrab"); 00895 manager.setOptionValString(&OPT_FrameGrabberDims, "640x480"); 00896 #endif 00897 00898 // output goes to the screen by default 00899 manager.setOptionValString(&OPT_OutputFrameSink, "display"); 00900 00901 // change some default values 00902 manager.setOptionValString(&OPT_EvcColorSmoothing, "true"); 00903 manager.setOptionValString(&OPT_EsmInertiaHalfLife, "60"); 00904 manager.setOptionValString(&OPT_EsmIorStrength, "8.0"); 00905 00906 if (manager.parseCommandLine(argc, argv, "<ip1:port1,ip2:port2,...>", 0, 1) == false) return(1); 00907 00908 eit->initReaders(manager.numExtraArgs() > 0 ? manager.getExtraArg(0) : ""); 00909 00910 manager.start(); 00911 00912 neoBrain->init(ifs->peekDims()); 00913 00914 Nv2UiData uidata(1 << evc->getMapLevel()); 00915 uidata.text_log_file = optTextLogFile.getVal(); 00916 00917 PrefsWindow pwin("control panel", SimpleFont::FIXED(8)); 00918 pwin.setValueNumChars(16); 00919 00920 pwin.addPrefsForComponent(esv.get()); 00921 pwin.addPrefsForComponent(esm.get()); 00922 pwin.addPrefsForComponent(esec->getSeg().get()); 00923 pwin.addPrefsForComponent(eit.get()); 00924 pwin.addPrefsForComponent(neoBrain.get(), true); 00925 pwin.addPrefsForComponent(evc.get()); 00926 00927 PrefItemBln prefPause(&pwin, "pause", false); 00928 PrefItemStr prefRemoteCommand(&pwin, "remote command", uidata.remote_command); 00929 PrefItemBln prefInTrainingMode(&pwin, "in training mode", false); 00930 PrefItemBln prefInObjRecMode(optWithObjrecMode.getVal() ? &pwin : 0, "in ObjRec mode", false); 00931 PrefItemBln prefDoGrabFrame(&pwin, "grab frame", true); 00932 PrefItemBln prefCommitTrainingImage(&pwin, "commit training image", false); 00933 PrefItemBln prefCommitTrainingImageConfirm(&pwin, "confirm commit ??", false); 00934 PrefItemStr prefTrainingLabel(&pwin, "training label", ""); 00935 PrefItemByt prefFontSize(&pwin, "font size", 6); 00936 00937 PrefsWindow inputprefs; 00938 inputprefs.addPrefsForComponent(ifs->getFrameSource().get()); 00939 pwin.setFont(SimpleFont::fixedMaxWidth(prefFontSize.get())); 00940 inputprefs.setFont(SimpleFont::fixedMaxWidth(prefFontSize.get())); 00941 00942 PauseWaiter p; 00943 00944 int retval = 0; 00945 00946 rutz::shared_ptr<JobServer> uiq; 00947 if (esv->optAsyncUi.getVal()) { 00948 // set up a background job server with one worker thread to 00949 // handle the ui jobs: 00950 rutz::shared_ptr<WorkThreadServer> tsrv(new WorkThreadServer("neovision2-ui", 1)); 00951 00952 // keep max latency low, and if we get bogged down, then drop 00953 // old frames rather than new ones 00954 tsrv->setMaxQueueSize(esv->optAsyncUiQueueSize.getVal()); 00955 tsrv->setDropPolicy(WorkThreadServer::DROP_OLDEST); 00956 tsrv->setFlushBeforeStopping(esv->optFlushUiQueue.getVal()); 00957 uiq = tsrv; 00958 } else { 00959 // set up a synchronous job server that will run all ui jobs in 00960 // the foreground 00961 uiq.reset(new SyncJobServer); 00962 } 00963 00964 ASSERT(uiq.get() != 0); 00965 00966 ifs->startStream(); 00967 00968 // const GenericFrameSpec fspec = ifs->peekFrameSpec(); 00969 00970 FpsTimer fps_timer; 00971 00972 bool previous_training_mode = prefInTrainingMode.get(); 00973 bool previous_do_fixed = esm->getUseFixed(); 00974 Image<PixRGB<byte> > rgbin_last; 00975 00976 ModelParamBatch objrecParams; 00977 objrecParams.addParamValue("EseDynamicFoa", false); 00978 objrecParams.addParamValue("EseFoaSize", 80); 00979 objrecParams.addParamValue("NeobrainBoringnessThresh", 2000); 00980 objrecParams.addParamValue("NeobrainTargetFramesThresh", (unsigned long) 2000); 00981 objrecParams.addParamValue("NeobrainNoMoveFramesThresh", (unsigned long) 2000); 00982 00983 bool previous_objrec_mode = prefInObjRecMode.get(); 00984 00985 while (true) 00986 { 00987 if (signum != 0) { 00988 LINFO("quitting because %s was caught", signame(signum)); 00989 retval = -1; 00990 break; 00991 } 00992 00993 if (ofs->becameVoid()) { 00994 LINFO("quitting because output stream was closed or became void"); 00995 break; 00996 } 00997 00998 if (esv->shouldQuit()) break; 00999 01000 // 01001 // update preferences window and uidata 01002 // 01003 01004 pwin.update(); // handle pending preference window events 01005 01006 setPause(prefPause.get()); 01007 uidata.remote_command = prefRemoteCommand.get(); 01008 01009 prefCommitTrainingImage.setDisabled(!prefInTrainingMode.get()); 01010 prefCommitTrainingImageConfirm.setDisabled(!prefInTrainingMode.get()); 01011 prefTrainingLabel.setDisabled(!prefInTrainingMode.get()); 01012 01013 pwin.setFont(SimpleFont::fixedMaxWidth(prefFontSize.get())); 01014 01015 inputprefs.setFont(SimpleFont::fixedMaxWidth(prefFontSize.get())); 01016 inputprefs.update(); 01017 01018 if (prefInObjRecMode.get()) { 01019 if (!previous_objrec_mode) objrecParams.installValues(&manager); // save previous values 01020 } else { 01021 if (previous_objrec_mode) objrecParams.restoreValues(&manager); //restore values 01022 } 01023 01024 previous_objrec_mode = prefInObjRecMode.get(); 01025 01026 // This code enforces the "training mode" logic 01027 // .. i.e., certain combinations of preferences are not possible. 01028 uidata.accepted_training_label = ""; 01029 01030 if (prefInTrainingMode.get()) { 01031 if (!previous_training_mode) previous_do_fixed = esm->getUseFixed(); 01032 01033 esm->setUseFixed(true); 01034 01035 if (prefCommitTrainingImageConfirm.get()) { 01036 if (!prefCommitTrainingImage.get()) 01037 prefCommitTrainingImageConfirm.set(false); 01038 else if (prefTrainingLabel.get().length() <= 3) { 01039 prefCommitTrainingImage.set(false); 01040 prefCommitTrainingImageConfirm.set(false); 01041 prefTrainingLabel.set(""); 01042 01043 LERROR("invalid training label %s (too short)", prefTrainingLabel.get().c_str()); 01044 } else { 01045 // OK, we accept the training label as a valid one 01046 // and send it off to the labelers: 01047 uidata.accepted_training_label = prefTrainingLabel.get(); 01048 } 01049 } 01050 } else { 01051 // training mode is off, certain settings not possible 01052 prefDoGrabFrame.set(true); 01053 prefCommitTrainingImage.set(false); 01054 prefCommitTrainingImageConfirm.set(false); 01055 prefTrainingLabel.set(""); 01056 01057 // this just handles unfixing window when training is first toggled off 01058 if (previous_training_mode) esm->setUseFixed(previous_do_fixed); 01059 } 01060 01061 previous_training_mode = prefInTrainingMode.get(); 01062 01063 if (p.checkPause()) continue; 01064 01065 // 01066 // get the next frame from our input source 01067 // 01068 01069 const FrameState is = ifs->updateNext(); 01070 if (is == FRAME_COMPLETE) break; 01071 01072 GenericFrame input = ifs->readFrame(); 01073 if (!input.initialized()) break; 01074 01075 // only read in from camera if do_grab_frame 01076 const Image<PixRGB<byte> > rgbin = prefDoGrabFrame.get() ? input.asRgb() : rgbin_last; 01077 01078 rgbin_last = rgbin; 01079 01080 if (eit->belowConfidenceThresh()) uidata.targetLoc = neoBrain->trackObject(rgbin); 01081 else uidata.targetLoc = Point2D<int>(-1,-1); 01082 01083 // 01084 // send the frame to the EnvVisualCortex and get the vcx output 01085 // 01086 01087 evc->input(rgbin); 01088 01089 fps_timer.nextFrame(); 01090 uidata.time_state = fps_timer.getState(); 01091 01092 if (uidata.time_state.frame_number % 50 == 0) 01093 LINFO("frame %u: %.2f fps", uidata.time_state.frame_number, uidata.time_state.recent_fps); 01094 01095 const Image<byte> vcxmap = evc->getVCXmap(); 01096 01097 // 01098 // build a ui job to run in the background to display update the 01099 // saliency map the input frame, the vcx maps, 01100 // 01101 01102 uiq->enqueueJob(rutz::make_shared 01103 (new Nv2UiJob 01104 (ofs.get(), 01105 esv.get(), 01106 eit.get(), 01107 uidata, 01108 esm.get(), 01109 esec->getSeg().get(), 01110 neoBrain.get(), 01111 rgbin, vcxmap 01112 , evc->getImap() 01113 , evc->getCmap() 01114 , evc->getOmap() 01115 #ifdef ENV_WITH_DYNAMIC_CHANNELS 01116 , evc->getFmap() 01117 , evc->getMmap() 01118 #endif 01119 ))); 01120 } 01121 01122 // destroy the ui queue so that we force it to shut down now 01123 uiq.reset(0); 01124 01125 manager.stop(); 01126 01127 return retval; 01128 } 01129 01130 // ###################################################################### 01131 int main(int argc, const char** argv) 01132 { 01133 try { 01134 return submain(argc, argv); 01135 } catch (...) { 01136 REPORT_CURRENT_EXCEPTION; 01137 } 01138 } 01139 01140 // ###################################################################### 01141 /* So things look consistent in everyone's emacs... */ 01142 /* Local Variables: */ 01143 /* mode: c++ */ 01144 /* indent-tabs-mode: nil */ 01145 /* End: */