00001 /*!@file Neuro/SimulationViewerNerdCam.C entry interface between INVT and ASAC */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 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: T. Nathan Mundhenk <mundhenk@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/SimulationViewerNerdCam.C $ 00035 // $Id: SimulationViewerNerdCam.C 13065 2010-03-28 00:01:00Z itti $ 00036 // 00037 00038 #include "Neuro/SimulationViewerNerdCam.H" 00039 00040 #include "Channels/BlueYellowChannel.H" 00041 #include "Channels/ChannelBase.H" 00042 #include "Channels/ColorChannel.H" 00043 #include "Channels/DirectionChannel.H" 00044 #include "Channels/FlickerChannel.H" 00045 #include "Channels/GaborChannel.H" 00046 #include "Channels/IntensityChannel.H" 00047 #include "Channels/MotionChannel.H" 00048 #include "Channels/OrientationChannel.H" 00049 #include "Channels/RedGreenChannel.H" 00050 #include "Image/ColorOps.H" // for normalizeC() 00051 #include "Image/CutPaste.H" // for concatX() 00052 #include "Image/DrawOps.H" 00053 #include "Image/MathOps.H" // for takeMax() 00054 #include "Image/PyramidOps.H" 00055 #include "Image/ShapeOps.H" // for crop() 00056 #include "Image/Transforms.H" // for contour2D() 00057 #include "Image/LevelSpec.H" 00058 #include "Neuro/AttentionGuidanceMap.H" 00059 #include "Neuro/NeuroOpts.H" 00060 #include "Neuro/NeuroSimEvents.H" 00061 #include "Neuro/SaliencyMap.H" 00062 #include "Neuro/TaskRelevanceMap.H" 00063 #include "Raster/Raster.H" 00064 #include "Simulation/SimEventQueue.H" 00065 #include "Transport/FrameInfo.H" 00066 #include "Transport/FrameOstream.H" 00067 #include "Util/readConfig.H" 00068 #include <time.h> 00069 #include <stdio.h> 00070 00071 00072 00073 // ###################################################################### 00074 SimulationViewerNerdCam::SimulationViewerNerdCam(OptionManager& mgr, 00075 const std::string& descrName, 00076 const std::string& tagName) : 00077 SimulationViewer(mgr, descrName, tagName), 00078 SIMCALLBACK_INIT(SimEventInputFrame), 00079 SIMCALLBACK_INIT(SimEventClockTick), 00080 SIMCALLBACK_INIT(SimEventWTAwinner), 00081 SIMCALLBACK_INIT(SimEventSaveOutput), 00082 itsMetrics(new SpatialMetrics(mgr)), 00083 itsColorBoring("SVcolorBoring", this, PixRGB<byte>(127, 0, 0)), 00084 itsColorLink("SVcolorLink", this, PixRGB<byte>(255, 0, 0)), 00085 itsColorNormal("SVcolorNormal", this, PixRGB<byte>(255, 255, 0)), 00086 itsConfigFile(&OPT_NerdCamConfigFile, this), 00087 itsCropFOA(&OPT_SVcropFOA, this), 00088 itsDisplayAdditive(&OPT_SVdisplayAdditive, this), 00089 itsDisplayBoring(&OPT_SVdisplayBoring, this), 00090 itsDisplayFOA(&OPT_SVdisplayFOA, this), 00091 itsDisplayFOALinks(&OPT_SVdisplayFOALinks, this), 00092 itsDisplayHighlights(&OPT_SVdisplayHighlights, this), 00093 itsDisplayPatch(&OPT_SVdisplayPatch, this), 00094 itsDisplaySMmodulate(&OPT_SVdisplaySMmodulate, this), 00095 itsDisplayTime(&OPT_SVdisplayTime, this), 00096 itsFOApsiz("SVfoapsiz", this, 3), 00097 itsFOAthick("SVfoathick", this, 3), 00098 itsFOAlinkThick("SVfoalinkthick", this, 2), 00099 itsMegaCombo(&OPT_SVmegaCombo, this), 00100 itsWarp3Dpitch("SVwarp3DInitialPitch", this, -25.0F), 00101 itsWarp3Dyaw("SVwarp3DInitialYaw", this, -15.0F), 00102 itsWarp3DpitchRate("SVwarp3DpitchRate", this, 0.0F), 00103 itsWarp3DyawRate("SVwarp3DyawRate", this, 15.0F), 00104 itsWarp3DpitchMax("SVwarp3DpitchMax", this, 0.0F), 00105 itsWarp3DyawMax("SVwarp3DyawMax", this, 20.0F), 00106 itsUseLargerDrawings(&OPT_SVuseLargerDrawings, this), 00107 itsCumFOAmask(), 00108 itsCurrFOA(WTAwinner::NONE()), 00109 itsCurrFOAmask(), 00110 itsCurrTime(), 00111 itsDims3D(), 00112 itsMultiTraj(), 00113 itsPrevFOA(WTAwinner::NONE()), 00114 itsTraj(), 00115 itsPitch3D(-1.0e10F), 00116 itsYaw3D(-1.0e10F) 00117 { 00118 this->addSubComponent(itsMetrics); 00119 itsInit = false; 00120 nlog("INIT - Normal startup recognized"); 00121 } 00122 00123 // ###################################################################### 00124 SimulationViewerNerdCam::~SimulationViewerNerdCam() 00125 { 00126 nlog("SHUTDOWN - normal shutdown recognized"); 00127 } 00128 00129 // ###################################################################### 00130 void SimulationViewerNerdCam::init(const ushort baseSizeX, 00131 const ushort baseSizeY) 00132 { 00133 char base[100]; 00134 std::string logstr; 00135 00136 itsBaseSizeX = baseSizeX; 00137 itsBaseSizeY = baseSizeY; 00138 00139 const std::string configFile = itsConfigFile.getVal(); 00140 readConfig config(25); 00141 config.openFile(configFile.c_str(),false); 00142 00143 itsLogFile = config.getItemValueS("LogFile"); 00144 sprintf(base,"INIT - Config File %s",configFile.c_str()); 00145 logstr = base; nlog(logstr); 00146 00147 itsOutputMotionImage = config.getItemValueS("OutputMotionImage"); 00148 itsOutputSalMapImage = config.getItemValueS("OutputSalMapImage"); 00149 itsOutput3DImage = config.getItemValueS("Output3DImage"); 00150 itsOutputMegaImage = config.getItemValueS("OutputMegaImage"); 00151 itsOutputTrajImage = config.getItemValueS("OutputTrajImage"); 00152 itsWebPageFile = config.getItemValueS("WebPageFile"); 00153 itsStatusFile = config.getItemValueS("StatusFile"); 00154 itsStatusHeader = config.getItemValueS("StatusHeader"); 00155 itsStatusFooter = config.getItemValueS("StatusFooter"); 00156 itsChannelFile = config.getItemValueS("ChannelFile"); 00157 itsBaseURL = config.getItemValueS("BaseURL"); 00158 itsBaseName = config.getItemValueS("BaseName"); 00159 itsMotionThreshold = config.getItemValueF("MotionThreshold"); 00160 00161 sprintf(base,"INIT - Image %d x %d",itsBaseSizeX,itsBaseSizeY); 00162 logstr = base; nlog(logstr); 00163 nlog("INIT - Init complete"); 00164 itsInit = true; 00165 00166 // Get server Start Time 00167 time_t rawtime; struct tm * timeinfo; 00168 time ( &rawtime ); timeinfo = localtime ( &rawtime ); 00169 itsStartTime = asctime (timeinfo); 00170 itsTotalFrames = 0; 00171 } 00172 00173 // ###################################################################### 00174 void SimulationViewerNerdCam::reset1() 00175 { 00176 itsCurrFOA = WTAwinner::NONE(); 00177 itsCurrFOAmask.freeMem(); 00178 itsCurrTime = SimTime::ZERO(); 00179 itsCumFOAmask.freeMem(); 00180 itsDims3D = Dims(); 00181 itsHasNewInput = false; 00182 itsMultiTraj.reset(); 00183 itsPitch3D = -1.0e10F; 00184 itsPrevFOA = WTAwinner::NONE(); 00185 itsTraj.freeMem(); 00186 itsYaw3D = -1.0e10F; 00187 00188 SimulationViewer::reset1(); 00189 nlog("INIT - Model reset complete"); 00190 } 00191 00192 // ###################################################################### 00193 void SimulationViewerNerdCam::start2() 00194 { 00195 // do we wnat larger drawings? 00196 if (itsUseLargerDrawings.getVal()) 00197 { 00198 itsFOApsiz.setVal(5); 00199 } 00200 } 00201 00202 // ###################################################################### 00203 void SimulationViewerNerdCam:: 00204 onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e) 00205 { 00206 LINFO("Inputing to Nerd-cam"); 00207 // keep a copy of the image 00208 itsInput = e->frame().asRgb(); 00209 00210 if (!itsInit) init(itsInput.getWidth(), itsInput.getHeight()); 00211 00212 // erase old trajectory and replace it by fresh new input: 00213 itsTraj = itsInput; 00214 // we have a new input; this will force redrawing various things on 00215 // the trajectory in case people request it before a new shift of 00216 // attention or other event occurrs: 00217 itsHasNewInput = true; 00218 itsTotalFrames++; 00219 } 00220 00221 // ###################################################################### 00222 void SimulationViewerNerdCam:: 00223 onSimEventClockTick(SimEventQueue& q, rutz::shared_ptr<SimEventClockTick>& e) 00224 { 00225 const SimTime t = q.now(); 00226 00227 // do the 3D rotation: 00228 if (itsPitch3D == -1.0e10F) 00229 itsPitch3D = itsWarp3Dpitch.getVal(); 00230 if (itsYaw3D == -1.0e10F) 00231 itsYaw3D = itsWarp3Dyaw.getVal(); 00232 00233 itsPitch3D += itsWarp3DpitchRate.getVal() * (t - itsCurrTime).secs(); 00234 itsYaw3D += itsWarp3DyawRate.getVal() * (t - itsCurrTime).secs(); 00235 00236 if (itsYaw3D >= itsWarp3DyawMax.getVal() || 00237 itsYaw3D <= -itsWarp3DyawMax.getVal()) 00238 itsWarp3DyawRate.setVal(- itsWarp3DyawRate.getVal()); 00239 if (itsPitch3D >= itsWarp3DpitchMax.getVal() || 00240 itsPitch3D <= -itsWarp3DpitchMax.getVal()) 00241 itsWarp3DpitchRate.setVal(- itsWarp3DpitchRate.getVal()); 00242 00243 itsCurrTime = t; 00244 } 00245 00246 // ###################################################################### 00247 void SimulationViewerNerdCam:: 00248 onSimEventWTAwinner(SimEventQueue& q, rutz::shared_ptr<SimEventWTAwinner>& e) 00249 { 00250 // Any output from the ShapeEstimator? 00251 Image<byte> foaMask; 00252 if (SeC<SimEventShapeEstimatorOutput> ee = q.check<SimEventShapeEstimatorOutput>(this)) 00253 { 00254 foaMask = Image<byte>(ee->smoothMask() * 255.0F); 00255 if (foaMask.isSameSize(itsInput) == false) 00256 LFATAL("Dimensions of FOAmask must match those of input"); 00257 } 00258 00259 // check dims of mask: 00260 if (foaMask.initialized() && foaMask.isSameSize(itsInput) == false) 00261 LFATAL("Dimensions of FOAmask must match those of input"); 00262 00263 // update our internals: 00264 itsPrevFOA = itsCurrFOA; itsCurrFOA = e->winner(); 00265 if (foaMask.initialized()) 00266 itsCurrFOAmask = foaMask; // keep a copy of the FOA mask 00267 else 00268 { 00269 // draw a disk at current foa position: 00270 itsCurrFOAmask.resize(itsInput.getDims(), true); 00271 if (itsCurrFOA.isValid()) 00272 drawDisk(itsCurrFOAmask, itsCurrFOA.p, 00273 itsMetrics->getFOAradius(), byte(255)); 00274 } 00275 00276 // update cumulative FOA mask: 00277 if (itsDisplayAdditive.getVal() && // cumulative display? 00278 itsCumFOAmask.initialized() && // not first frame? 00279 itsCumFOAmask.isSameSize(itsCurrFOAmask)) // not changing frame dims? 00280 itsCumFOAmask = takeMax(itsCumFOAmask, itsCurrFOAmask); 00281 else 00282 itsCumFOAmask = itsCurrFOAmask; 00283 00284 // forget it if we don't have a traj yet: 00285 if (itsTraj.initialized() == false) return; 00286 00287 // draw the FOA: 00288 if (itsDisplayFOA.getVal() || itsDisplayPatch.getVal()) drawFOA(); 00289 00290 // link the last two FOAs: 00291 if (itsDisplayFOALinks.getVal()) linkFOAs(); 00292 } 00293 00294 // ###################################################################### 00295 Image< PixRGB<byte> > SimulationViewerNerdCam::getTraj(SimEventQueue& q) 00296 { 00297 //LINFO("Get Traj"); 00298 itsCurrTime = q.now(); bool redraw = false; 00299 if (itsTraj.initialized() == false) return itsTraj; 00300 00301 // ##### if not doing additive displays, clear traj and redraw only 00302 // ##### current foa/eye/head data: 00303 if (itsDisplayAdditive.getVal() == false) 00304 { itsTraj = itsInput; redraw = true; } 00305 00306 // ##### re-do a bunch of drawings if we destroyed the traj 00307 // ##### (foveation, highlights, etc). We only care about current 00308 // ##### attention/eye/head position and not about any previous ones 00309 // ##### or links: 00310 if (redraw || itsHasNewInput) 00311 { 00312 if (itsDisplayFOA.getVal() || itsDisplayPatch.getVal()) drawFOA(); 00313 itsHasNewInput = false; 00314 } 00315 00316 // ##### let's get ready to return the traj, but we may reshape it 00317 // ##### just before that, or return something that involves the 00318 // ##### traj plus some other maps in some combined display: 00319 Image< PixRGB<byte> > ret; 00320 00321 // if cropping let's crop now: 00322 // resizing and other normalizations are taken care of by FrameOstream 00323 if (itsCropFOA.getVal().isNonEmpty()) 00324 { 00325 Dims crop_dims = itsCropFOA.getVal(); 00326 Rectangle crect = 00327 Rectangle::tlbrI(itsCurrFOA.p.j - crop_dims.h() / 2, 00328 itsCurrFOA.p.i - crop_dims.w() / 2, 00329 itsCurrFOA.p.j + crop_dims.h() / 2 - 1, 00330 itsCurrFOA.p.i + crop_dims.w() / 2 - 1); 00331 ret = crop(itsTraj, crect, true); 00332 } 00333 else ret = itsTraj; 00334 00335 // ##### do a bunch of last-minute drawings: 00336 if (itsDisplayTime.getVal()) drawTime(ret); 00337 00338 return ret; 00339 } 00340 00341 // ###################################################################### 00342 void SimulationViewerNerdCam::saveResults(const nub::ref<FrameOstream>& ofs, 00343 SimEventQueue& q) 00344 { 00345 // update the trajectory: 00346 const Image< PixRGB<byte> > traj = getTraj(q); 00347 00348 const double msecs = itsCurrTime.msecs(); 00349 00350 LINFO("Running Nerd-cam on Sample Input time %f ms",msecs); 00351 Image<float> salMap = getMap(q); 00352 00353 // write out saliency map 00354 itsSalMap = rescale(salMap,itsBaseSizeX,itsBaseSizeY); 00355 00356 // write web status page 00357 00358 const Image<byte> bsal = itsSalMap; 00359 struct flock fl_smap; 00360 int fd_smap; 00361 lockFile(itsOutputSalMapImage,fd_smap,fl_smap); 00362 Raster::WriteRGB(bsal,itsOutputSalMapImage); 00363 00364 00365 nub::soft_ref<MotionChannel> mc; 00366 00367 LFATAL("FIXME I should derive from SimulationViewerStd"); 00368 /* 00369 if(vc->hasSubChan("motion")) 00370 dynCastWeakToFrom(mc, vc->subChan("motion")); 00371 else 00372 { 00373 nlog("FATAL - No motion channel supplied by brain"); 00374 LFATAL("No Motion Channel Supplied by Brain"); 00375 } 00376 */ 00377 if (mc.isInvalid()) 00378 { 00379 nlog("FATAL - Channel named 'motion' not a MotionChannel"); 00380 LFATAL("Channel named 'motion' not a MotionChannel"); 00381 } 00382 00383 int fd_traj, fd_mega; 00384 struct flock fl_traj; 00385 struct flock fl_mega; 00386 if(itsTraj.initialized()) 00387 { 00388 // draw simple trajectory image 00389 lockFile(itsOutputTrajImage,fd_traj,fl_traj); 00390 Raster::WriteRGB(traj,itsOutputTrajImage); 00391 // Draw a megacombo 00392 if(itsTotalFrames > 1) 00393 { 00394 const Image< PixRGB<byte> > meg = drawMegaCombo(q); 00395 lockFile(itsOutputMegaImage,fd_mega,fl_mega); 00396 Raster::WriteRGB(meg,itsOutputMegaImage); 00397 itsComboSizeX = meg.getWidth(); 00398 itsComboSizeY = meg.getHeight(); 00399 } 00400 } 00401 00402 float min = 0, max = 0, avg = 0; 00403 float div = 0; 00404 00405 bool doMotion = false; 00406 00407 for(ushort i = 0; i < mc->numChans(); i++) 00408 { 00409 float mi,ma,av; 00410 const Image<float> ftmp = mc->dirChan(i).getOutput(); 00411 getMinMaxAvg(ftmp,mi,ma,av); 00412 min += mi; max += ma; avg += av; 00413 div++; 00414 if(ma > itsMotionThreshold) 00415 doMotion = true; 00416 } 00417 min = min/div; max = max/div; avg = avg/div; 00418 00419 00420 // write an image, something is moving 00421 int fd_mot; 00422 struct flock fl_mot; 00423 if(doMotion) 00424 { 00425 LINFO("Drawing Motion Image"); 00426 const Image<PixRGB<byte> > bimg = itsInput; 00427 lockFile(itsOutputMotionImage,fd_mot,fl_mot); 00428 Raster::WriteRGB(bimg,itsOutputMotionImage); 00429 } 00430 00431 // draw nifty 3D saliency map 00432 Image< PixRGB<byte> > ret = itsInput; 00433 drawGrid(ret, ret.getWidth() / 6, ret.getHeight() / 6, 3, 3, 00434 itsColorNormal.getVal()); 00435 drawRect(ret, Rectangle::tlbrI(1, 1, ret.getHeight()-2, ret.getWidth()-2), 00436 itsColorNormal.getVal(), 3); 00437 ret = warp3Dmap(ret, getMap(q), itsPitch3D, itsYaw3D, itsDims3D); 00438 int fd_3d; 00439 struct flock fl_3d; 00440 lockFile(itsOutput3DImage,fd_3d,fl_3d); 00441 Raster::WriteRGB(ret,itsOutput3DImage); 00442 its3DSizeX = ret.getWidth(); 00443 its3DSizeY = ret.getHeight(); 00444 00445 writeStatusPage(); 00446 00447 if(itsTotalFrames > 1) 00448 { 00449 writeChannelPage(); 00450 } 00451 00452 // unlock all our image files 00453 if(avg > itsMotionThreshold) 00454 { 00455 unlockFile(itsOutputMotionImage,fd_mot,fl_mot); 00456 } 00457 if(itsTraj.initialized()) 00458 { 00459 unlockFile(itsOutputTrajImage,fd_traj,fl_traj); 00460 if(itsTotalFrames > 1) 00461 { 00462 unlockFile(itsOutputMegaImage,fd_mega,fl_mega); 00463 } 00464 } 00465 unlockFile(itsOutputSalMapImage,fd_smap,fl_smap); 00466 unlockFile(itsOutput3DImage,fd_3d,fl_3d); 00467 } 00468 00469 // ###################################################################### 00470 void SimulationViewerNerdCam:: 00471 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e) 00472 { 00473 this->save1(e->sinfo()); 00474 } 00475 00476 // ###################################################################### 00477 void SimulationViewerNerdCam::save1(const ModelComponentSaveInfo& sinfo) 00478 { 00479 // get the OFS to save to, assuming sinfo is of type 00480 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00481 nub::ref<FrameOstream> ofs = 00482 dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs; 00483 00484 // also get the SimEventQueue: 00485 SimEventQueue *q = dynamic_cast<const SimModuleSaveInfo&>(sinfo).q; 00486 00487 saveResults(ofs, *q); 00488 } 00489 00490 // ##################################################################### 00491 void SimulationViewerNerdCam::writeStatusPage() const 00492 { 00493 std::ifstream headFile(itsStatusHeader.c_str(),std::ios::in); 00494 std::ifstream footFile(itsStatusFooter.c_str(),std::ios::in); 00495 00496 // get min/max/avg and stdev and number of peaks: 00497 double peaksum; 00498 const double sdev = stdev(itsSalMap); 00499 float mi, ma, av; getMinMaxAvg(itsSalMap, mi, ma, av); 00500 const int npeaks = findPeaks(itsSalMap, 0.0f, 255.0f, peaksum); 00501 00502 // find the location of max in the salmap, at scale of original input: 00503 float maxval; Point2D<int> maxloc; 00504 findMax(itsSalMap, maxloc, maxval); 00505 const float scale = float(itsInput.getWidth()) / float(itsSalMap.getWidth()); 00506 maxloc.i = int(maxloc.i * scale + 0.4999F); 00507 maxloc.j = int(maxloc.j * scale + 0.4999F); 00508 00509 // find the location of min in the salmap, at scale of original input: 00510 float minval; Point2D<int> minloc; 00511 findMin(itsSalMap, minloc, minval); 00512 minloc.i = int(minloc.i * scale + 0.4999F); 00513 minloc.j = int(minloc.j * scale + 0.4999F); 00514 00515 int fd; struct flock fl; 00516 lockFile(itsStatusFile,fd,fl); 00517 std::ofstream statFile(itsStatusFile.c_str(),std::ios::out); 00518 00519 std::string in; 00520 while (headFile >> in) 00521 { 00522 if(!in.compare("\\")) 00523 statFile << "\n"; 00524 else 00525 statFile << in << " "; 00526 } 00527 statFile.flush(); 00528 statFile << "\n<!-- End Header File -->\n" 00529 << "<!--\n" 00530 << "Nerd Cam Daemon\n" 00531 << "T. Nathan Mundhenk and Laurent Itti\n" 00532 << "http://www.nerd-cam.com\n" 00533 << "-->\n" 00534 << "<a href=\"" << itsBaseURL << "\">" 00535 << "<H1>" << itsBaseName << "</a> " 00536 << "Detailed Server Status</H1>\n"; 00537 00538 time_t rawtime; struct tm * timeinfo; 00539 time ( &rawtime ); timeinfo = localtime ( &rawtime ); 00540 00541 // general server stats 00542 statFile << "<H2>Nerd-Cam Daemon Saliency Server Statistics </H2>\n" 00543 << "<table border=\"0\" width=\"800\">\n" 00544 << "<tr>\n" 00545 << "\t<td width=\"275\">\n" 00546 << "\t\t<H3>Current Time </H3>" 00547 << asctime (timeinfo) << "<br>\n" 00548 << "\t\t<H3>Server Start Time </H3>" 00549 << itsStartTime << "<br>\n" 00550 << "\t\t<H3>Total Frames Processed </H3>" 00551 << itsTotalFrames << "<br>\n" 00552 << "\t\t<p> </td>\n" 00553 << "\t<td width=\"525\" align=\"center\">\n" 00554 << "\t\t<h1>Last Nerd Spotted by Nerd-Cam</h1>\n" 00555 << "\t\t<p><img border=\"0\" src=\"nerd-cam.motion.png\" " 00556 << "width=\"320\" height=\"240\"></p>\n" 00557 << "\t</td>\n" 00558 << "</tr>\n" 00559 << "</table>\n"; 00560 00561 statFile.flush(); 00562 // save some stats for that location: 00563 statFile << "<H2>Current Saliency Map Statistics </H2>\n" 00564 << "<table border=0 cellpadding=0 width=800>\n" 00565 << "<tr>\n" 00566 << "\t<td width=275 valign=top>\n" 00567 << "\t\t<H3>Point of Maximum Saliency </H3>" 00568 << "(" << maxloc.i << "," << maxloc.j << ")<br>\n" 00569 << "\t\t<H3>Point of Minimum Saliency </H3>" 00570 << "(" << minloc.i << "," << minloc.j << ")<br>\n" 00571 << "\t\t<H3>Maximum Saliency Value </H3>" 00572 << ma << "<br>\n" 00573 << "\t\t<H3>Minimum Saliency Value </H3>" 00574 << mi << "<br>\n" 00575 << "\t\t<H3>Average Saliency Value </H3>" 00576 << av << "<br>\n" 00577 << "\t\t<H3>Standard Deviation </H3>" 00578 << sdev << "<br>\n" 00579 << "\t\t<H3>Number of Peaks </H3>" 00580 << npeaks << "<br>\n" 00581 << "\t\t<H3>Peak Sum </H3>" 00582 << peaksum << "<br>\n" 00583 << "\t</td>\n" 00584 << "\t<td width=525 valign=top align=\"center\">\n" 00585 << "\t\t<H1>Superimposed 3D Saliency Image</H1>\n" 00586 << "\t\t<img border=0 width=" 00587 << its3DSizeX 00588 << " height=" 00589 << its3DSizeY 00590 << " src=\"awesome.3d.image.png\" " 00591 << " alt=\"Awesome 3D Saliency Map " 00592 << "to shock and awe\"><br>\n" 00593 << "\t</td>\n" 00594 << "</tr>\n" 00595 << "</table>\n"; 00596 statFile.flush(); 00597 statFile << "<!-- Start Footer File -->\n"; 00598 while (footFile >> in) 00599 { 00600 if(!in.compare("\\")) 00601 statFile << "\n"; 00602 else 00603 statFile << in << " "; 00604 } 00605 00606 statFile.flush(); 00607 statFile.close(); 00608 while(statFile.is_open() != 0){} 00609 unlockFile(itsStatusFile,fd,fl); 00610 } 00611 00612 // ##################################################################### 00613 void SimulationViewerNerdCam::writeChannelPage() const 00614 { 00615 std::ifstream headFile(itsStatusHeader.c_str(),std::ios::in); 00616 std::ifstream footFile(itsStatusFooter.c_str(),std::ios::in); 00617 00618 int fd; struct flock fl; 00619 lockFile(itsChannelFile,fd,fl); 00620 std::ofstream statFile(itsChannelFile.c_str(),std::ios::out); 00621 00622 std::string in; 00623 while (headFile >> in) 00624 { 00625 if(!in.compare("\\")) 00626 statFile << "\n"; 00627 else 00628 statFile << in << " "; 00629 } 00630 statFile.flush(); 00631 statFile << "\n<!-- End Header File -->\n" 00632 << "<!--\n" 00633 << "Nerd Cam Daemon\n" 00634 << "T. Nathan Mundhenk and Laurent Itti\n" 00635 << "http://www.nerd-cam.com\n" 00636 << "-->\n" 00637 << "<a href=\"" << itsBaseURL << "\">" 00638 << "<H1>" << itsBaseName << "</a> " 00639 << "Detailed Channel Status</H1>\n" 00640 << "<H2>Mega Combo Saliency Image</H2>\n" 00641 << "<img border=0 width=" 00642 << itsComboSizeX 00643 << " height=" 00644 << itsComboSizeY 00645 << " src=\"mega.surprise.combo.png\" " 00646 << " alt=\"Mega Combo Saliency Map with all the topings " 00647 << "for your viewing pleasure\"><br>\n"; 00648 00649 statFile << "<H2>Current Saliency Map Statistics Per Channel</H2>\n" 00650 << "<table border=0 cellpadding=0 width=900>\n" 00651 << "<tr>\n" 00652 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00653 << "\t\t<H2>Channel Type</H2>\n" 00654 << "\t</td>\n" 00655 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00656 << "\t\t<H2>Maximum Saliency</H2>\n" 00657 << "\t</td>\n" 00658 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00659 << "\t\t<H2>Minimum Saliency</H2>\n" 00660 << "\t</td>\n" 00661 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00662 << "\t\t<H2>Average Saliency</H2>\n" 00663 << "\t</td>\n" 00664 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00665 << "\t\t<H2>Saliency Peaks</H2>\n" 00666 << "\t</td>\n" 00667 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00668 << "\t\t<H2>Saliency Peaks Sum</H2>\n" 00669 << "\t</td>\n" 00670 << "</tr>\n"; 00671 statFile.flush(); 00672 00673 LFATAL("FIXME I should derive from SimulationViewerStd"); 00674 /* 00675 00676 const nub::ref<VisualCortex> vc = itsBrain->getVC(); 00677 if (vc->hasSubChan("color")) 00678 { 00679 const Image<float> ftmp = vc->subChan("color")->getOutput(); 00680 double peaksum; 00681 float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av); 00682 const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum); 00683 statFile << "<tr>\n" 00684 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00685 << "\t\t<H2>Color Channel</H2>\n" 00686 << "\t</td>\n" 00687 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00688 << "\t\t<H3>" << ma << "</H3>\n" 00689 << "\t</td>\n" 00690 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00691 << "\t\t<H3>" << mi << "</H3>\n" 00692 << "\t</td>\n" 00693 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00694 << "\t\t<H3>" << av << "</H3>\n" 00695 << "\t</td>\n" 00696 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00697 << "\t\t<H3>" << npeaks << "</H3>\n" 00698 << "\t</td>\n" 00699 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00700 << "\t\t<H3>" << peaksum << "</H3>\n" 00701 << "\t</td>\n" 00702 << "</tr>\n"; 00703 } 00704 statFile.flush(); 00705 if (vc->hasSubChan("intensity")) 00706 { 00707 const Image<float> ftmp = vc->subChan("intensity")->getOutput(); 00708 double peaksum; 00709 float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av); 00710 const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum); 00711 statFile << "<tr>\n" 00712 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00713 << "\t\t<H2>Intensity Channel</H2>\n" 00714 << "\t</td>\n" 00715 << "\t<td width=\"150\">\n" 00716 << "\t\t<H3>" << ma << "</H3>\n" 00717 << "\t</td>\n" 00718 << "\t<td width=\"150\">\n" 00719 << "\t\t<H3>" << mi << "</H3>\n" 00720 << "\t</td>\n" 00721 << "\t<td width=\"150\">\n" 00722 << "\t\t<H3>" << av << "</H3>\n" 00723 << "\t</td>\n" 00724 << "\t<td width=\"150\">\n" 00725 << "\t\t<H3>" << npeaks << "</H3>\n" 00726 << "\t</td>\n" 00727 << "\t<td width=\"150\">\n" 00728 << "\t\t<H3>" << peaksum << "</H3>\n" 00729 << "\t</td>\n" 00730 << "</tr>\n"; 00731 00732 } 00733 statFile.flush(); 00734 if (vc->hasSubChan("orientation")) 00735 { 00736 const Image<float> ftmp = vc->subChan("orientation")->getOutput(); 00737 double peaksum; 00738 float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av); 00739 const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum); 00740 statFile << "<tr>\n" 00741 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00742 << "\t\t<H2>Orientation Channel</H2>\n" 00743 << "\t</td>\n" 00744 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00745 << "\t\t<H3>" << ma << "</H3>\n" 00746 << "\t</td>\n" 00747 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00748 << "\t\t<H3>" << mi << "</H3>\n" 00749 << "\t</td>\n" 00750 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00751 << "\t\t<H3>" << av << "</H3>\n" 00752 << "\t</td>\n" 00753 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00754 << "\t\t<H3>" << npeaks << "</H3>\n" 00755 << "\t</td>\n" 00756 << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n" 00757 << "\t\t<H3>" << peaksum << "</H3>\n" 00758 << "\t</td>\n" 00759 << "</tr>\n"; 00760 } 00761 statFile.flush(); 00762 if (vc->hasSubChan("flicker")) 00763 { 00764 const Image<float> ftmp = vc->subChan("flicker")->getOutput(); 00765 double peaksum; 00766 float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av); 00767 const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum); 00768 statFile << "<tr>\n" 00769 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00770 << "\t\t<H2>Flicker Channel</H2>\n" 00771 << "\t</td>\n" 00772 << "\t<td width=\"150\">\n" 00773 << "\t\t<H3>" << ma << "</H3>\n" 00774 << "\t</td>\n" 00775 << "\t<td width=\"150\">\n" 00776 << "\t\t<H3>" << mi << "</H3>\n" 00777 << "\t</td>\n" 00778 << "\t<td width=\"150\">\n" 00779 << "\t\t<H3>" << av << "</H3>\n" 00780 << "\t</td>\n" 00781 << "\t<td width=\"150\">\n" 00782 << "\t\t<H3>" << npeaks << "</H3>\n" 00783 << "\t</td>\n" 00784 << "\t<td width=\"150\">\n" 00785 << "\t\t<H3>" << peaksum << "</H3>\n" 00786 << "\t</td>\n" 00787 << "</tr>\n"; 00788 } 00789 statFile.flush(); 00790 if (vc->hasSubChan("motion")) 00791 { 00792 nub::soft_ref<MotionChannel> mc; dynCastWeakToFrom(mc, vc->subChan("motion")); 00793 if (mc.isInvalid()) 00794 { 00795 nlog(" FATAL- In writing channel page Channel named 'motion' not a MotionChannel"); 00796 LFATAL("Channel named 'motion' not a MotionChannel"); 00797 } 00798 for(uint i = 0; i < mc->numChans(); i++) 00799 { 00800 Image<float> ftmp = mc->dirChan(i).getOutput(); 00801 double peaksum; 00802 float mi, ma, av; getMinMaxAvg(ftmp, mi, ma, av); 00803 const int npeaks = findPeaks(ftmp, 0.0f, 255.0f, peaksum); 00804 statFile << "<tr>\n" 00805 << "\t<td width=\"150\" bgcolor=\"#AAD0F0\">\n" 00806 << "\t\t<H2>"; 00807 00808 if(i == 0) 00809 statFile << "MotionRight"; 00810 else if(i == 1) 00811 statFile << "MotionDown"; 00812 else if(i == 2) 00813 statFile << "MotionLeft"; 00814 else if(i == 3) 00815 statFile << "MotionUp"; 00816 else 00817 statFile << "Motion " << i; 00818 00819 statFile << "</H2>\n" 00820 << "\t</td>\n"; 00821 00822 if(i%2 == 0) 00823 statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"; 00824 else 00825 statFile << "\t<td width=\"150\">\n"; 00826 00827 statFile << "\t\t<H3>" << ma << "</H3>\n" 00828 << "\t</td>\n"; 00829 00830 if(i%2 == 0) 00831 statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"; 00832 else 00833 statFile << "\t<td width=\"150\">\n"; 00834 00835 statFile << "\t\t<H3>" << mi << "</H3>\n" 00836 << "\t</td>\n"; 00837 00838 if(i%2 == 0) 00839 statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"; 00840 else 00841 statFile << "\t<td width=\"150\">\n"; 00842 00843 statFile << "\t\t<H3>" << av << "</H3>\n" 00844 << "\t</td>\n"; 00845 00846 if(i%2 == 0) 00847 statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"; 00848 else 00849 statFile << "\t<td width=\"150\">\n"; 00850 00851 statFile << "\t\t<H3>" << npeaks << "</H3>\n" 00852 << "\t</td>\n"; 00853 00854 if(i%2 == 0) 00855 statFile << "\t<td width=\"150\" bgcolor=\"#C0C0C0\">\n"; 00856 else 00857 statFile << "\t<td width=\"150\">\n"; 00858 00859 statFile << "\t\t<H3>" << peaksum << "</H3>\n" 00860 << "\t</td>\n" 00861 << "</tr>\n"; 00862 } 00863 } 00864 statFile.flush(); 00865 */ 00866 00867 statFile << "</table>\n" 00868 << "<!-- Start Footer File -->\n"; 00869 while (footFile >> in) 00870 { 00871 if(!in.compare("\\")) 00872 statFile << "\n"; 00873 else 00874 statFile << in << " "; 00875 } 00876 00877 statFile.flush(); 00878 statFile.close(); 00879 while(statFile.is_open() != 0){} 00880 unlockFile(itsChannelFile,fd,fl); 00881 } 00882 00883 // ##################################################################### 00884 void SimulationViewerNerdCam::drawTime(Image<PixRGB<byte> >& image) const 00885 { 00886 char txt[20]; sprintf(txt, " %dms ", int(itsCurrTime.msecs() + 0.4999)); 00887 writeText(image, Point2D<int>(0, 0), txt); 00888 } 00889 00890 // ##################################################################### 00891 void SimulationViewerNerdCam::lockFile(const std::string fileName, 00892 int &fd, 00893 struct flock &fl) const 00894 { 00895 // lock file 00896 fd = open(fileName.c_str(), O_RDWR); 00897 if (fd < 0) 00898 { 00899 LINFO("lockFile: Open failure on file %s",fileName.c_str()); 00900 } 00901 else 00902 { 00903 fl.l_type = F_WRLCK; 00904 fl.l_whence = SEEK_SET; 00905 fl.l_start = 0; 00906 fl.l_len = 0; 00907 if (fcntl(fd, F_SETLK, &fl) == -1) 00908 { 00909 if (errno == EACCES || errno == EAGAIN) 00910 LINFO("'%s' Already locked by another process",fileName.c_str()); 00911 else if(errno == EBADF) 00912 LINFO("'%s' not a valid open file descriptor",fileName.c_str()); 00913 else if(errno == EINVAL) 00914 LINFO("'%s In a locking operation, fildes refers to a file with a type that does not support locking, or the struct flock pointed to by the third argument has an incorrect form",fileName.c_str()); 00915 else if(errno == EMFILE) 00916 LINFO("'%s' process has already reached its maximum number of file descriptors",fileName.c_str()); 00917 else 00918 LINFO("Cannot lock file '%s' Error code '%d'",fileName.c_str(),errno); 00919 } 00920 } 00921 } 00922 00923 // ##################################################################### 00924 void SimulationViewerNerdCam::unlockFile(const std::string fileName, 00925 const int fd, 00926 struct flock &fl) const 00927 { 00928 // unlockfile 00929 fl.l_type = F_UNLCK; 00930 fl.l_whence = SEEK_SET; 00931 fl.l_start = 0; 00932 fl.l_len = 0; 00933 if (fcntl(fd, F_SETLK, &fl) == -1) 00934 { 00935 LINFO("Cannot unlock file '%s'",fileName.c_str()); 00936 } 00937 close(fd); 00938 } 00939 00940 // ##################################################################### 00941 void SimulationViewerNerdCam::nlog(const std::string logData) const 00942 { 00943 time_t rawtime; struct tm * timeinfo; 00944 time ( &rawtime ); timeinfo = localtime ( &rawtime ); 00945 00946 int fd; struct flock fl; 00947 lockFile(itsLogFile,fd,fl); 00948 std::ofstream logFile(itsLogFile.c_str(),std::ios::app); 00949 00950 logFile << asctime (timeinfo) << " - " << logData << "\n"; 00951 00952 logFile.close(); 00953 unlockFile(itsLogFile,fd,fl); 00954 } 00955 00956 // ##################################################################### 00957 void SimulationViewerNerdCam::drawDateTime(Image<PixRGB<byte> >& image) const 00958 { 00959 time_t rawtime; struct tm * timeinfo; 00960 time ( &rawtime ); timeinfo = localtime ( &rawtime ); 00961 00962 writeText(image, Point2D<int>(0, 0), asctime (timeinfo)); 00963 } 00964 00965 // ###################################################################### 00966 void SimulationViewerNerdCam::drawFOA() 00967 { 00968 if (itsCurrFOA.isValid() == false) return; 00969 00970 // select a drawing color: 00971 PixRGB<byte> col(itsColorNormal.getVal()); 00972 if (itsCurrFOA.boring) col -= itsColorBoring.getVal(); 00973 00974 // draw patch at current eye position: 00975 drawPatch(itsTraj, itsCurrFOA.p, itsFOApsiz.getVal(), col); 00976 00977 // display focus of attention, possibly object-shaped: 00978 if (itsDisplayFOA.getVal()) 00979 drawMaskOutline(itsTraj, itsCurrFOAmask, col, itsFOAthick.getVal(), 00980 itsCurrFOA.p, itsMetrics->getFOAradius()); 00981 } 00982 00983 // ###################################################################### 00984 void SimulationViewerNerdCam::linkFOAs() 00985 { 00986 if (itsCurrFOA.isValid() == false) return; 00987 00988 const PixRGB<byte> col = itsColorLink.getVal(); 00989 if (itsPrevFOA.isValid()) 00990 { 00991 int d = int(itsPrevFOA.p.distance(itsCurrFOA.p)); 00992 if (d > 0) drawArrow(itsTraj, itsPrevFOA.p, itsCurrFOA.p, 00993 col, itsFOAlinkThick.getVal()); 00994 } 00995 } 00996 00997 // ##################################################################### 00998 Image< PixRGB<byte> > SimulationViewerNerdCam:: 00999 drawMegaCombo(SimEventQueue& q) const 01000 { 01001 LINFO("Drawing Mega Combo"); 01002 01003 const PixRGB<byte> bg(128, 128, 255); 01004 const short XWW = itsTraj.getWidth() * 2; 01005 const short XWH = itsTraj.getHeight() * 2; 01006 Image< PixRGB<byte> > xwi(XWW/2, XWH/2, ZEROS); 01007 Image< PixRGB<byte> > xwin(XWW, XWH, ZEROS); 01008 01009 Rectangle r(Point2D<int>(0,0), Dims(XWW/2, XWH/2)); 01010 inplaceEmbed(xwi, itsTraj, r, bg, true); 01011 inplacePaste(xwin, xwi, Point2D<int>(0, 0)); 01012 01013 // get the normalized SM: 01014 const Image<float> agm = getMap(q); 01015 Image< PixRGB<byte> > xwi2(XWW/2, XWH/2, NO_INIT); 01016 01017 // get the non-normalized TRM (neutral is 1.0): 01018 Image<float> trm; 01019 if (SeC<SimEventTaskRelevanceMapOutput> e = 01020 q.check<SimEventTaskRelevanceMapOutput>(this, SEQ_ANY)) 01021 trm = e->trm(1.0F); 01022 else LFATAL("Cannot find a TRM!"); 01023 01024 // useful range is 0.0 .. 3.0; let's show values smaller 01025 // than 1 as red and those larger that 1 as green: 01026 Image<byte> rr, gg, bb; 01027 Image<float> trmfac(trm); 01028 inplaceClamp(trmfac, 0.0F, 1.0F); 01029 trmfac *= -1.0F; trmfac += 1.0F; 01030 rr = trmfac * 255.0F; // the redder, the lower the relevance 01031 trmfac = trm; 01032 inplaceClamp(trmfac, 1.0F, 3.0F); 01033 trmfac -= 1.0F; 01034 gg = trmfac * 127.5F; // the greener, the higher the relevance 01035 bb = agm; // in blue is the AGM 01036 01037 // place the agm into our result image: 01038 Image<PixRGB<byte> > cbtmp = rescale(makeRGB(rr, gg, bb), XWW/2, XWH/2); 01039 inplaceEmbed(xwi2, cbtmp, r, PixRGB<byte>(192, 192, 192), true); 01040 writeText(xwi2, Point2D<int>(0,0), " Attention Map "); 01041 inplacePaste(xwin, xwi2, Point2D<int>(XWW/2, 0)); 01042 01043 // now do the conspicuity maps: 01044 r = Rectangle::tlbrI(0, 0, XWH/4 - 1, XWW/4 - 1); 01045 xwi2.resize(XWW/4, XWH/4); 01046 01047 LFATAL("FIXME I should derive from SimulationViewerStd"); 01048 /* 01049 const nub::ref<VisualCortex> vc = itsBrain->getVC(); 01050 01051 if (vc->hasSubChan("color")) { 01052 Image<float> ftmp = vc->subChan("color")->getOutput(); 01053 ftmp = rescale(ftmp, XWW / 4, XWH / 4); 01054 inplaceNormalize(ftmp, 0.0f, 255.0f); 01055 Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Color "); 01056 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01057 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01058 inplacePaste(xwin, xwi2, Point2D<int>(0, XWH/2)); 01059 } 01060 01061 if (vc->hasSubChan("intensity")) { 01062 Image<float> ftmp = vc->subChan("intensity")->getOutput(); 01063 ftmp = rescale(ftmp, XWW/4, XWH/4); 01064 inplaceNormalize(ftmp, 0.0f, 255.0f); 01065 Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Intensity "); 01066 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01067 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01068 inplacePaste(xwin, xwi2, Point2D<int>(XWW/4, XWH/2)); 01069 } 01070 01071 if (vc->hasSubChan("orientation")) { 01072 Image<float> ftmp = vc->subChan("orientation")->getOutput(); 01073 ftmp = rescale(ftmp, XWW/4, XWH/4); 01074 inplaceNormalize(ftmp, 0.0f, 255.0f); 01075 Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Orientation "); 01076 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01077 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01078 inplacePaste(xwin, xwi2, Point2D<int>(XWW/2, XWH/2)); 01079 } 01080 01081 if (vc->hasSubChan("flicker")) { 01082 Image<float> ftmp = vc->subChan("flicker")->getOutput(); 01083 ftmp = rescale(ftmp, XWW/4, XWH/4); 01084 inplaceNormalize(ftmp, 0.0f, 255.0f); 01085 Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " Flicker "); 01086 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01087 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01088 inplacePaste(xwin, xwi2, Point2D<int>(XWW/4+XWW/2, XWH/2)); 01089 } 01090 01091 if (vc->hasSubChan("motion")) { 01092 nub::soft_ref<MotionChannel> mc; dynCastWeakToFrom(mc, vc->subChan("motion")); 01093 if (mc.isInvalid()) LFATAL("Channel named 'motion' not a MotionChannel"); 01094 if (mc->numChans() == 4) { 01095 Image<float> ftmp = mc->dirChan(2).getOutput(); 01096 ftmp = rescale(ftmp, XWW/4, XWH/4); 01097 inplaceNormalize(ftmp, 0.0f, 255.0f); 01098 Image<byte> btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionLeft "); 01099 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01100 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01101 inplacePaste(xwin, xwi2, Point2D<int>(0, XWH/4 + XWH/2)); 01102 01103 ftmp = mc->dirChan(1).getOutput(); 01104 ftmp = rescale(ftmp, XWW/4, XWH/4); 01105 inplaceNormalize(ftmp, 0.0f, 255.0f); 01106 btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionDown "); 01107 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01108 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01109 inplacePaste(xwin, xwi2, Point2D<int>(XWW/4, XWH/4 + XWH/2)); 01110 01111 ftmp = mc->dirChan(3).getOutput(); 01112 ftmp = rescale(ftmp, XWW/4, XWH/4); 01113 inplaceNormalize(ftmp, 0.0f, 255.0f); 01114 btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionUp "); 01115 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01116 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01117 inplacePaste(xwin, xwi2, Point2D<int>(XWW/2, XWH/4 + XWH/2)); 01118 01119 ftmp = mc->dirChan(0).getOutput(); 01120 ftmp = rescale(ftmp, XWW/4, XWH/4); 01121 inplaceNormalize(ftmp, 0.0f, 255.0f); 01122 btmp = ftmp; writeText(btmp, Point2D<int>(0,0), " MotionRight "); 01123 inplaceEmbed(xwi2, Image<PixRGB<byte> >(btmp), r, PixRGB<byte>(192), true); 01124 drawRect(xwi2, r, PixRGB<byte>(255), 1); 01125 inplacePaste(xwin, xwi2, Point2D<int>(XWW/2 + XWW/4, XWH/4 + XWH/2)); 01126 } 01127 } 01128 */ 01129 return xwin; 01130 } 01131 01132 // ###################################################################### 01133 void SimulationViewerNerdCam::drawMaskOutline(Image< PixRGB<byte> >& traj, 01134 const Image<byte> mask, 01135 const PixRGB<byte>& col, 01136 const int thick, 01137 const Point2D<int>& pos, 01138 const int radius) const 01139 { 01140 if (traj.initialized() == false) return; // can't draw... 01141 01142 // object-shaped drawing 01143 Image<byte> om(mask); 01144 inplaceLowThresh(om, byte(128)); // cut off fuzzy (interpolated) object boundaries 01145 om = contour2D(om); // compute binary contour image 01146 const int w = traj.getWidth(); 01147 const int h = traj.getHeight(); 01148 Point2D<int> ppp; 01149 for (ppp.j = 0; ppp.j < h; ppp.j ++) 01150 for (ppp.i = 0; ppp.i < w; ppp.i ++) 01151 if (om.getVal(ppp.i, ppp.j)) // got a contour point -> draw here 01152 drawDisk(traj, ppp, thick, col); // small disk for each point 01153 // OBSOLETE: drawCircle(traj, pos, radius, col, thick); 01154 } 01155 01156 // ###################################################################### 01157 /* So things look consistent in everyone's emacs... */ 01158 /* Local Variables: */ 01159 /* indent-tabs-mode: nil */ 01160 /* End: */