00001 /*!@file INVT/neovision2-hd.C Neovision demo for HD streams and 1080p display*/ 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-hd.C $ 00035 // $Id: neovision2-hd.C 12782 2010-02-05 22:14:30Z irock $ 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/BufferedInputFrameSeries.H" 00063 #include "Media/FrameSeries.H" 00064 #include "Media/MediaOpts.H" 00065 #include "NeovisionII/Nv2LabelReader.H" 00066 #include "NeovisionII/nv2_common.h" 00067 #include "Neuro/NeoBrain.H" 00068 #include "Neuro/EnvInferoTemporal.H" 00069 #include "Neuro/EnvSaliencyMap.H" 00070 #include "Neuro/EnvSegmenterConfigurator.H" 00071 #include "Neuro/EnvVisualCortex.H" 00072 #include "Raster/GenericFrame.H" 00073 #include "Raster/Raster.H" 00074 #include "Transport/FrameInfo.H" 00075 #include "Transport/TransportOpts.H" 00076 #include "Util/FpsTimer.H" 00077 #include "Util/Pause.H" 00078 #include "Util/StringConversions.H" 00079 #include "Util/StringUtil.H" 00080 #include "Util/SyncJobServer.H" 00081 #include "Util/SysInfo.H" 00082 #include "Util/TextLog.H" 00083 #include "Util/WorkThreadServer.H" 00084 #include "Util/csignals.H" 00085 #include "rutz/shared_ptr.h" 00086 #include "rutz/trace.h" 00087 00088 #include <ctype.h> 00089 #include <deque> 00090 #include <iterator> 00091 #include <limits> 00092 #include <stdlib.h> // for atoi(), malloc(), free() 00093 #include <string.h> 00094 #include <sys/resource.h> 00095 #include <signal.h> 00096 #include <time.h> 00097 #include <vector> 00098 00099 #define PREFERRED_TEXT_LENGTH 42 00100 00101 struct Nv2UiData 00102 { 00103 Nv2UiData(const int map_zoom_) : 00104 map_zoom(map_zoom_), ncpu(numCpus()) 00105 {} 00106 00107 FpsTimer::State time_state; 00108 const int map_zoom; 00109 const int ncpu; 00110 }; 00111 00112 std::string time2str(const rutz::time& t) 00113 { 00114 const double s = t.sec(); 00115 00116 const int hpart = int(s/(60.0*60.0)); 00117 const int mpart = int((s-hpart*60*60)/60.0); 00118 const double spart = s - hpart*60*60 - mpart*60; 00119 00120 return sformat("%02d:%02d:%06.3f", hpart, mpart, spart); 00121 } 00122 00123 class Nv2UiJob : public JobServer::Job 00124 { 00125 public: 00126 Nv2UiJob(OutputFrameSeries* ofs_, const Nv2UiData& uidata_, 00127 Image<PixRGB<byte> > rgbin_, Image<byte> vcxmap_, 00128 Image<byte> Imap_, Image<byte> Cmap_, Image<byte> Omap_ 00129 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00130 , Image<byte> Fmap_, Image<byte> Mmap_ 00131 #endif 00132 ) : 00133 ofs(ofs_), uidata(uidata_), rgbin(rgbin_), vcxmap(vcxmap_), 00134 Imap(Imap_), Cmap(Cmap_), Omap(Omap_) 00135 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00136 , Fmap(Fmap_), Mmap(Mmap_) 00137 #endif 00138 { } 00139 00140 virtual void run() 00141 { 00142 ofs->updateNext(); 00143 00144 Point2D<int> win; byte winval; 00145 findMax(vcxmap, win, winval); 00146 win = win * uidata.map_zoom; 00147 00148 // do a markup on the input images: 00149 Image<PixRGB<byte> > markup = rgbin; 00150 drawCircle(markup, win, 3, PixRGB<byte>(60, 220, 255), 3); 00151 00152 // do the saliency map: 00153 Image<byte> sm = vcxmap; // for now 00154 Image<PixRGB<byte> > smc = 00155 zoomXY(sm, uidata.map_zoom / 2, uidata.map_zoom / 2); 00156 drawCircle(smc, win/2, 3, PixRGB<byte>(60, 220, 255), 3); 00157 00158 const std::string lines[2] = 00159 { 00160 sformat("peak %3d @ (%3d,%3d)", 00161 winval, win.i, win.j), 00162 sformat("%s [%5.2ffps, %5.1f%%CPU]", 00163 time2str(uidata.time_state.elapsed_time).c_str(), 00164 uidata.time_state.recent_fps, 00165 uidata.time_state.recent_cpu_usage*100.0) 00166 }; 00167 00168 const Image<PixRGB<byte> > textarea = 00169 makeMultilineTextBox(smc.getWidth(), &lines[0], 2, 00170 PixRGB<byte>(255, 255, 0), PixRGB<byte>(0,0,0), 00171 PREFERRED_TEXT_LENGTH); 00172 00173 Layout<PixRGB<byte> > disp = vcat(smc, textarea); 00174 00175 // ofs->writeRgbLayout(disp, "neovision2-HD Control", 00176 // FrameInfo("copy of input", SRC_POS)); 00177 ofs->writeRGB(markup, "neovision2-HD", 00178 FrameInfo("copy of input", SRC_POS)); 00179 } 00180 00181 virtual const char* jobType() const { return "Nv2UiJob"; } 00182 00183 private: 00184 OutputFrameSeries* const ofs; 00185 const Nv2UiData uidata; 00186 Image<PixRGB<byte> > rgbin; 00187 const Image<byte> vcxmap; 00188 const Image<byte> Imap; 00189 const Image<byte> Cmap; 00190 const Image<byte> Omap; 00191 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00192 const Image<byte> Fmap; 00193 const Image<byte> Mmap; 00194 #endif 00195 }; 00196 00197 // ###################################################################### 00198 int submain(int argc, const char** argv) 00199 { 00200 volatile int signum = 0; 00201 signal(SIGPIPE, SIG_IGN); 00202 catchsignals(&signum); 00203 00204 // Instantiate our various ModelComponents: 00205 00206 ModelManager manager("Nv2hd"); 00207 00208 nub::ref<BufferedInputFrameSeries> 00209 ifs(new BufferedInputFrameSeries(manager, 50, true)); 00210 manager.addSubComponent(ifs); 00211 00212 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager)); 00213 manager.addSubComponent(ofs); 00214 00215 nub::ref<EnvVisualCortex> evc(new EnvVisualCortex(manager)); 00216 manager.addSubComponent(evc); 00217 00218 manager.exportOptions(MC_RECURSE); 00219 00220 #if defined(HAVE_IEEE1394) 00221 // input comes from firewire camera 640x480/rgb/30fps by default 00222 manager.setOptionValString(&OPT_InputFrameSource, "ieee1394"); 00223 manager.setOptionValString(&OPT_FrameGrabberMode, "RGB24"); 00224 manager.setOptionValString(&OPT_FrameGrabberDims, "640x480"); 00225 manager.setOptionValString(&OPT_FrameGrabberFPS, "30"); 00226 #elif defined(HAVE_QUICKTIME_QUICKTIME_H) 00227 manager.setOptionValString(&OPT_InputFrameSource, "qtgrab"); 00228 manager.setOptionValString(&OPT_FrameGrabberDims, "640x480"); 00229 #endif 00230 00231 // output goes to the screen by default 00232 manager.setOptionValString(&OPT_OutputFrameSink, "display"); 00233 00234 // change some default values 00235 manager.setOptionValString(&OPT_EvcColorSmoothing, "true"); 00236 00237 if (manager.parseCommandLine(argc, argv, 00238 "<ip1:port1,ip2:port2,...>", 00239 0, 1) == false) 00240 return(1); 00241 00242 manager.start(); 00243 00244 Nv2UiData uidata(1 << evc->getMapLevel()); 00245 00246 // set up a background job server with one worker thread to 00247 // handle the ui jobs: 00248 rutz::shared_ptr<WorkThreadServer> tsrv 00249 (new WorkThreadServer("neovision2-ui", 1)); 00250 00251 // keep max latency low, and if we get bogged down, then drop 00252 // old frames rather than new ones 00253 tsrv->setMaxQueueSize(3); 00254 tsrv->setDropPolicy(WorkThreadServer::DROP_OLDEST); 00255 tsrv->setFlushBeforeStopping(true); 00256 rutz::shared_ptr<JobServer> uiq = tsrv; 00257 00258 ///////////// ifs->startStream(); 00259 00260 const GenericFrameSpec fspec = ifs->peekFrameSpec(); 00261 Image<PixRGB<byte> > rgbin_last(fspec.dims, ZEROS); 00262 FpsTimer fps_timer; 00263 00264 int retval = 0; bool toggle = true; Image<byte> vcxmap; 00265 while (true) 00266 { 00267 if (signum != 0) 00268 { 00269 LINFO("quitting because %s was caught", signame(signum)); 00270 retval = -1; 00271 break; 00272 } 00273 00274 if (ofs->becameVoid()) 00275 { 00276 LINFO("quitting because output stream was closed or became void"); 00277 break; 00278 } 00279 00280 // 00281 // get the next frame from our input source 00282 // 00283 bool underflowed; 00284 Image<PixRGB<byte> > rgbin; 00285 GenericFrame input = ifs->get(&underflowed); 00286 if (!input.initialized()) 00287 { 00288 if (underflowed) { LINFO("Input underflow!"); rgbin = rgbin_last; } 00289 else break; // end of stream or error 00290 } 00291 else 00292 rgbin = input.asRgb(); 00293 00294 rgbin_last = rgbin; 00295 00296 // 00297 // send the frame to the EnvVisualCortex and get the vcx output 00298 // 00299 if (toggle) 00300 { 00301 evc->input(rgbin); 00302 vcxmap = evc->getVCXmap(); 00303 } 00304 00305 toggle = !toggle; 00306 00307 fps_timer.nextFrame(); 00308 uidata.time_state = fps_timer.getState(); 00309 00310 if (uidata.time_state.frame_number % 50 == 0) 00311 LINFO("frame %u: %.2f fps", 00312 uidata.time_state.frame_number, 00313 uidata.time_state.recent_fps); 00314 00315 // 00316 // build a ui job to run in the background to display update the 00317 // saliency map the input frame, the vcx maps, 00318 // 00319 uiq->enqueueJob(rutz::make_shared 00320 (new Nv2UiJob 00321 (ofs.get(), uidata, rgbin, vcxmap, evc->getImap(), 00322 evc->getCmap(), evc->getOmap() 00323 #ifdef ENV_WITH_DYNAMIC_CHANNELS 00324 , evc->getFmap(), evc->getMmap() 00325 #endif 00326 ))); 00327 } 00328 00329 // destroy the ui queue so that we force it to shut down now 00330 uiq.reset(0); 00331 00332 manager.stop(); 00333 00334 return retval; 00335 } 00336 00337 // ###################################################################### 00338 int main(int argc, const char** argv) 00339 { 00340 try 00341 { 00342 return submain(argc, argv); 00343 } 00344 catch (...) 00345 { 00346 REPORT_CURRENT_EXCEPTION; 00347 } 00348 } 00349 00350 // ###################################################################### 00351 /* So things look consistent in everyone's emacs... */ 00352 /* Local Variables: */ 00353 /* mode: c++ */ 00354 /* indent-tabs-mode: nil */ 00355 /* End: */