00001 /*!@file Neuro/SimulationViewerStats.C View/save a bunch of stats */ 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: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/SimulationViewerStats.C $ 00035 // $Id: SimulationViewerStats.C 13065 2010-03-28 00:01:00Z itti $ 00036 // 00037 00038 #include "Neuro/SimulationViewerStats.H" 00039 #include "Channels/ChannelMaps.H" 00040 #include "Channels/ChannelOpts.H" 00041 #include "Image/colorDefs.H" 00042 #include "Image/CutPaste.H" 00043 #include "Image/ColorOps.H" 00044 #include "Image/DrawOps.H" 00045 #include "Image/fancynorm.H" 00046 #include "Image/FFTWWrapper.H" 00047 #include "Image/ImageSet.H" 00048 #include "Image/MathOps.H" 00049 #include "Image/ShapeOps.H" 00050 #include "Image/NamedImage.H" 00051 #include "Media/MediaSimEvents.H" 00052 #include "Neuro/Brain.H" 00053 #include "Neuro/NeuroOpts.H" 00054 #include "Neuro/NeuroSimEvents.H" 00055 #include "Neuro/VisualCortex.H" 00056 #include "Transport/FrameInfo.H" 00057 #include "Transport/FrameOstream.H" 00058 #include <fcntl.h> // for open() 00059 #include <cerrno> // for errno 00060 00061 00062 // ###################################################################### 00063 SimulationViewerStats::SimulationViewerStats(OptionManager& mgr, 00064 const std::string& descrName, 00065 const std::string& tagName) : 00066 SimulationViewer(mgr, descrName, tagName), 00067 SIMCALLBACK_INIT(SimEventSaveOutput), 00068 itsStatsFname(&OPT_SVstatsFname, this), 00069 itsSaveXcombo(&OPT_SVsaveXcombo, this), 00070 itsSaveYcombo(&OPT_SVsaveYcombo, this), 00071 itsComputeAGStats(&OPT_ComputeAGStats, this), 00072 itsAGTargetFrame(&OPT_AGTargetFrame, this), 00073 itsAGMaskFile(&OPT_AGMaskFile, this), 00074 itsAGStatsSaveFile(&OPT_AGStatsSaveFile, this), 00075 itsGetSingleChannelStats(&OPT_GetSingleChannelStats, this), 00076 itsGetSingleChannelStatsFile(&OPT_GetSingleChannelStatsFile, this), 00077 itsSaveStatsPerChannelFreq(&OPT_SaveStatsPerChannelFreq, this), 00078 itsStatsFile(NULL) 00079 { } 00080 00081 // ###################################################################### 00082 SimulationViewerStats::~SimulationViewerStats() 00083 { } 00084 00085 // ###################################################################### 00086 void SimulationViewerStats::start2() 00087 { 00088 // Used by saveCompat for frame counts 00089 itsFrameIdx = 0; 00090 00091 // Reset counters 00092 itsMaskCount = 0; itsLamCount = 0; itsOverlapCount = 0; 00093 } 00094 00095 // ###################################################################### 00096 void SimulationViewerStats::stop2() 00097 { 00098 // close our stats file if we have one: 00099 if (itsStatsFile) 00100 { 00101 itsStatsFile->flush(); 00102 itsStatsFile->close(); 00103 delete itsStatsFile; 00104 itsStatsFile = NULL; 00105 } 00106 } 00107 00108 // ##################################################################### 00109 void SimulationViewerStats::lockFile(const std::string fileName, 00110 int &fd, 00111 struct flock &fl) const 00112 { 00113 // lock file 00114 fd = open(fileName.c_str(), O_RDWR); 00115 if (fd < 0) 00116 { 00117 LINFO("lockFile: Open failure on file %s",fileName.c_str()); 00118 } 00119 else 00120 { 00121 fl.l_type = F_WRLCK; 00122 fl.l_whence = SEEK_SET; 00123 fl.l_start = 0; 00124 fl.l_len = 0; 00125 if (fcntl(fd, F_SETLK, &fl) == -1) 00126 { 00127 if (errno == EACCES || errno == EAGAIN) 00128 LINFO("'%s' Already locked by another process",fileName.c_str()); 00129 else if(errno == EBADF) 00130 LINFO("'%s' not a valid open file descriptor",fileName.c_str()); 00131 else if(errno == EINVAL) 00132 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()); 00133 else if(errno == EMFILE) 00134 LINFO("'%s' process has already reached its maximum number of file descriptors",fileName.c_str()); 00135 else 00136 LINFO("Cannot lock file '%s' Error code '%d' \(Is this an NFS mount?)",fileName.c_str(),errno); 00137 } 00138 } 00139 } 00140 00141 // ##################################################################### 00142 void SimulationViewerStats::unlockFile(const std::string fileName, 00143 const int fd, 00144 struct flock &fl) const 00145 { 00146 // unlockfile 00147 fl.l_type = F_UNLCK; 00148 fl.l_whence = SEEK_SET; 00149 fl.l_start = 0; 00150 fl.l_len = 0; 00151 if (fcntl(fd, F_SETLK, &fl) == -1) 00152 { 00153 LINFO("Cannot unlock file '%s'",fileName.c_str()); 00154 } 00155 close(fd); 00156 } 00157 00158 // ###################################################################### 00159 void SimulationViewerStats:: 00160 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e) 00161 { 00162 this->save1(e->sinfo()); 00163 } 00164 00165 // ###################################################################### 00166 void SimulationViewerStats::save1(const ModelComponentSaveInfo& sinfo) 00167 { 00168 // Use a LINFO here since we are already slowed down by writing 00169 // stats, we should at least have a short debug on this fact 00170 LINFO("SAVING STATS TO %s",itsStatsFname.getVal().c_str()); 00171 00172 // Lock the file. We put this here to support multi-process in the 00173 // future. However, this will not work on NFS mounts. 00174 struct flock fl; int fd; 00175 lockFile(itsStatsFname.getVal().c_str(),fd,fl); 00176 00177 // Since this is more or less debug info we open and flush every iteration. 00178 // rather than once each run. 00179 std::ofstream statsFile; 00180 statsFile.open(itsStatsFname.getVal().c_str(),std::ios_base::app); 00181 00182 // get the OFS to save to, assuming sinfo is of type 00183 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00184 nub::ref<FrameOstream> ofs = 00185 dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs; 00186 00187 // also get the SimEventQueue: 00188 SimEventQueue *q = dynamic_cast<const SimModuleSaveInfo&>(sinfo).q; 00189 00190 // initialize our stats dump file if desired: 00191 if(itsFrameIdx == 0) 00192 { 00193 rutz::shared_ptr<SimReqVCXmaps> vcxm(new SimReqVCXmaps(this)); 00194 q->request(vcxm); // VisualCortex is now filling-in the maps... 00195 00196 if (itsStatsFname.getVal().size()) 00197 { 00198 itsStatsFile = new std::ofstream(itsStatsFname.getVal().c_str()); 00199 if (itsStatsFile->is_open() == false) 00200 LFATAL("Failed to open '%s' for writing.", 00201 itsStatsFname.getVal().c_str()); 00202 00203 // dump the settings of the model: 00204 getRootObject()->printout(*itsStatsFile, "# "); 00205 00206 // list all our channels: 00207 //LFATAL("FIXME"); 00208 // also get the SimEventQueue: 00209 00210 rutz::shared_ptr<ChannelMaps> chm = vcxm->channelmaps(); 00211 uint numSubmaps = chm->numSubmaps(); 00212 00213 *itsStatsFile << "# CHANNELS: "; 00214 00215 for(uint i = 0; i < numSubmaps; i++) 00216 { 00217 NamedImage<float> smap = chm->getRawCSmap(i); 00218 *itsStatsFile << smap.name() << ", "; 00219 } 00220 *itsStatsFile << std::endl; 00221 } 00222 } 00223 00224 // We flush frequently since this output is debuggy in nature or it's being used 00225 // to collect information which needs assurance of accuracy for instance in 00226 // RSVP analysis. It is better to err on the side of caution. 00227 (*itsStatsFile).flush(); 00228 (*itsStatsFile).close(); 00229 00230 // get the basic input frame info 00231 if (SeC<SimEventInputFrame> e = q->check<SimEventInputFrame>(this)) 00232 { 00233 itsSizeX = e->frame().getWidth(); 00234 itsSizeY = e->frame().getHeight(); 00235 itsFrameNumber = (unsigned int)e->frameNum(); 00236 itsFrameIdx = itsFrameNumber; 00237 } 00238 else 00239 { 00240 itsFrameNumber = itsFrameIdx; 00241 itsFrameIdx++; 00242 } 00243 00244 // get the latest input frame: 00245 // Since we are only using it's basic statistics (Height / Width) , we don't care about it's 00246 // blackboard status. Use SEQ_ANY then. Otherwise, this will not fetch at any rate. 00247 Image< PixRGB<byte> > input; 00248 if (SeC<SimEventRetinaImage> e = q->check<SimEventRetinaImage>(this,SEQ_ANY)) 00249 input = e->frame().colorByte(); 00250 else 00251 LINFO("No input? Check the SimEventCue."); 00252 00253 // Get the current frame number or keep track on your own 00254 /* 00255 if (SeC<SimEventInputFrame> e = q->check<SimEventInputFrame>(this)) 00256 itsFrameIdx = e->frameNum(); 00257 else 00258 itsFrameIdx++; 00259 */ 00260 00261 // get the latest raw AGM: 00262 Image<float> agm; 00263 if (SeC<SimEventAttentionGuidanceMapOutput> e = 00264 q->check<SimEventAttentionGuidanceMapOutput>(this)) 00265 agm = e->agm(1.0F); 00266 else 00267 LINFO("No AGM? Check the SimEventCue."); 00268 00269 // if we are missing input or agm, return: 00270 // We also need to warn so that we know why the stats file may be empty 00271 bool quit = false; 00272 if (input.initialized() == false) 00273 { 00274 LINFO("WARNING!!! Input seems not to be initialized, so detailed stats cannot be saved."); 00275 quit = true; 00276 } 00277 if(agm.initialized() == false) 00278 { 00279 LINFO("WARNING!!! NO Attention Guidance MAP \"AGM\" so detailed stats cannot be saved."); 00280 quit = true; 00281 } 00282 00283 if(quit == true) return; 00284 00285 // update the trajectory: 00286 Image< PixRGB<byte> > res; 00287 const int w = input.getWidth(); 00288 00289 // save image results? if so let's prepare it 00290 if (itsSaveXcombo.getVal() || itsSaveYcombo.getVal()) 00291 { 00292 Image<float> nagm = getMap(*q); 00293 res = colGreyCombo(input, nagm, itsSaveXcombo.getVal(), 00294 itsDisplayInterp.getVal()); 00295 } 00296 00297 // if we are saving single channel stats save saliency stats using a compatable format 00298 // SEE: SingleChannel.C / saveStats(..) for more info on format 00299 if (itsGetSingleChannelStats.getVal()) 00300 saveCompat(agm); 00301 00302 // Save a bunch of stats? 00303 if (statsFile) 00304 { 00305 // start with the current simulation time: 00306 statsFile <<std::endl<<"= "<<q->now().msecs() 00307 <<" # time of frame in ms"<<std::endl; 00308 00309 // get min/max/avg and stdev and number of peaks in AGM: 00310 float mi, ma, av; getMinMaxAvg(agm, mi, ma, av); 00311 double sdev = stdev(agm); 00312 double peaksum; int npeaks = findPeaks(agm, 0.0f, 255.0f, peaksum); 00313 00314 // find the location of max in the AGM, at scale of original input: 00315 float maxval; Point2D<int> maxloc; 00316 findMax(agm, maxloc, maxval); 00317 float scale = float(w) / float(agm.getWidth()); 00318 maxloc.i = int(maxloc.i * scale + 0.4999F); 00319 maxloc.j = int(maxloc.j * scale + 0.4999F); 00320 if (res.initialized()) 00321 { 00322 drawPatch(res, maxloc, 4, COL_YELLOW); 00323 drawPatch(res, maxloc + Point2D<int>(w, 0), 4, COL_YELLOW); 00324 } 00325 00326 // find the location of min in the AGM, at scale of original input: 00327 float minval; Point2D<int> minloc; 00328 findMin(agm, minloc, minval); 00329 minloc.i = int(minloc.i * scale + 0.4999F); 00330 minloc.j = int(minloc.j * scale + 0.4999F); 00331 if (res.initialized()) 00332 { 00333 drawPatch(res, minloc, 4, COL_GREEN); 00334 drawPatch(res, minloc + Point2D<int>(w, 0), 4, COL_GREEN); 00335 } 00336 00337 // save some stats for that location: 00338 statsFile <<maxloc.i<<' '<<maxloc.j<<' '<<minloc.i<<' ' 00339 <<minloc.j<<' '<<ma<<' '<<mi<<' '<<av<<' '<<sdev 00340 <<' '<<npeaks<<' '<<peaksum 00341 <<" # Xmax Ymax Xmin Ymin max min avg std npeaks peaksum" 00342 <<std::endl; 00343 00344 // build a vector of points where we will save samples. First is 00345 // the max, second the min, then a bunch of random locations: 00346 std::vector<Point2D<int> > loc; 00347 loc.push_back(maxloc); 00348 loc.push_back(minloc); 00349 for (uint n = 0; n < 100; n ++) 00350 loc.push_back(Point2D<int>(randomUpToNotIncluding(input.getWidth()), 00351 randomUpToNotIncluding(input.getHeight()))); 00352 00353 // Get all the conspicuity maps: 00354 ImageSet<float> cmap; 00355 //LFATAL("FIXME"); 00356 rutz::shared_ptr<SimReqVCXmaps> vcxm(new SimReqVCXmaps(this)); 00357 q->request(vcxm); // VisualCortex is now filling-in the maps... 00358 rutz::shared_ptr<ChannelMaps> chm = vcxm->channelmaps(); 00359 uint numSubmaps = chm->numSubmaps(); 00360 for(uint i=0;i < numSubmaps; i++) 00361 { 00362 NamedImage<float> tempMap = chm->getRawCSmap(i); 00363 Image<float> m = tempMap; 00364 cmap.push_back(m); 00365 00366 // also store sample points at the min/max locations: 00367 Point2D<int> p; float v; 00368 findMax(m, p, v); loc.push_back(p); 00369 findMin(m, p, v); loc.push_back(p); 00370 } 00371 /* 00372 for (uint i = 0; i < itsBrain->getVC()->numChans(); i ++) 00373 { 00374 Image<float> m = itsBrain->getVC()->subChan(i)->getOutput(); 00375 cmap.push_back(m); 00376 00377 // also store sample points at the min/max locations: 00378 Point2D<int> p; float v; 00379 findMax(m, p, v); loc.push_back(p); 00380 findMin(m, p, v); loc.push_back(p); 00381 } 00382 */ 00383 00384 // Go over all sample points and save feature map and 00385 // conspicuity map values at those locations: 00386 for (uint i = 0; i < loc.size(); i ++) 00387 { 00388 Point2D<int> p = loc[i]; 00389 Point2D<int> pp(int(p.i / scale), int(p.j / scale)); 00390 00391 statsFile <<p.i<<' '<<p.j<<" "; 00392 00393 // do the conspicuity maps first. Since they are all at the 00394 // scale of the AGM, we use pp: 00395 for (uint j = 0; j < cmap.size(); j ++) 00396 { 00397 if((int(p.i / scale) < agm.getWidth()) && 00398 (int(p.j / scale) < agm.getHeight())) 00399 { 00400 (statsFile)<<cmap[j].getVal(pp)<<' '; 00401 (statsFile)<<" "; 00402 } 00403 else 00404 { 00405 (statsFile)<<"-1"<<' '; 00406 (statsFile)<<" "; 00407 } 00408 } 00409 00410 // now the feature maps, we use coordinates p: 00411 /* TOO BOGUS - disabled for now 00412 std::vector<double> f; 00413 itsBrain->getVC()->getFeatures(p, f); 00414 for (uint j = 0; j < f.size(); j ++) (*statsFile)<<f[j]<<' '; 00415 */ 00416 00417 statsFile <<"# features "<<i<<" at ("<<p.i 00418 <<", "<<p.j<<')'<<std::endl; 00419 } 00420 } 00421 00422 statsFile.flush(); 00423 statsFile.close(); 00424 unlockFile(itsStatsFname.getVal().c_str(),fd,fl); 00425 // save results? 00426 if (res.initialized()) 00427 ofs->writeRGB(res, "T", 00428 FrameInfo("SimulationViewerStats trajectory", SRC_POS)); 00429 00430 // Should we compute attention gate stats 00431 // If we have AG stats we will save the basic LAM stats anyways 00432 if(itsComputeAGStats.getVal()) 00433 computeAGStats(*q); 00434 else if (SeC<SimEventAttentionGateOutput> ag = 00435 q->check<SimEventAttentionGateOutput>(this)) 00436 computeLAMStats(ag->lam()); 00437 00438 //! Save the overlap image 00439 if(itsOverlap.initialized()) 00440 ofs->writeRGB(itsOverlap, "AG-STAT-MASK", 00441 FrameInfo("Stats mask overlap", SRC_POS)); 00442 00443 if(itsVisualSegments.initialized()) 00444 ofs->writeRGB(itsVisualSegments, "AG-STAT-SEGS", 00445 FrameInfo("Stats segments", SRC_POS)); 00446 00447 if(itsVisualCandidates.initialized()) 00448 ofs->writeGray(itsVisualCandidates, "AG-STAT-CAND", 00449 FrameInfo("Stats candidates", SRC_POS)); 00450 00451 } 00452 00453 // ###################################################################### 00454 void SimulationViewerStats::computeLAMStats(const Image<float> &img) 00455 { 00456 00457 saveCompat(img,".final-lam.txt",-1); 00458 00459 Image<float> lamr = rescale(img,itsSizeX,itsSizeY); 00460 00461 itsMaskCount = 0; itsLamCount = 0; itsOverlapCount = 0; 00462 itsTotalCount = 0; 00463 00464 // Threshold the attention mask at 12.5% 00465 for(Image<float>::iterator litr = lamr.beginw(); 00466 litr != lamr.endw(); litr++) 00467 { 00468 if(*litr > 32) itsLamCount++; 00469 itsTotalCount++; 00470 } 00471 saveAGMaskStats(lamr,"LAM"); 00472 00473 } 00474 00475 // ###################################################################### 00476 void SimulationViewerStats::computeAGStats(SimEventQueue& q) 00477 { 00478 // Do we have attention gate output 00479 if (SeC<SimEventAttentionGateOutput> ag = 00480 q.check<SimEventAttentionGateOutput>(this)) 00481 { 00482 Image<float> lam = ag->lam(); 00483 saveCompat(lam,".final-lam.txt",-1); 00484 // Do we have a frame? 00485 00486 //LINFO("Checking Frame"); 00487 // get the mask if we havn't already 00488 if(!itsMask.initialized()) 00489 { 00490 // Open the mask file 00491 const Image< PixRGB<byte> > cmask = 00492 Raster::ReadRGB(itsAGMaskFile.getVal()); 00493 00494 LINFO("Target Mask File Read %s",itsAGMaskFile.getVal().c_str()); 00495 00496 //Image<float> fmask = luminance(cmask); 00497 itsMask.resize(cmask.getWidth(),cmask.getHeight()); 00498 Image<bool>::iterator mitr = itsMask.beginw(); 00499 // Set mask usging a stepper to 1 or 0; 00500 for(Image<PixRGB<byte> >::const_iterator citr = cmask.begin(); 00501 citr != cmask.end(); citr++) 00502 { 00503 // Above 90% gray 00504 if(citr->p[0] < 230) *mitr++ = true; 00505 else *mitr++ = false; 00506 } 00507 00508 itsLamMask.resize(itsMask.getWidth(),itsMask.getHeight(),true); 00509 itsOverlap.resize(itsMask.getWidth(),itsMask.getHeight(),true); 00510 } 00511 00512 00513 // We are offset by one frame back in the AG 00514 // so we need to make sure we stay in sync 00515 if(itsMask.initialized()) 00516 { 00517 LINFO("FRAME %d",itsFrameNumber); 00518 // Are we at the target frame + 1? or 00519 // are we outputing all frame overlaps? 00520 if((itsFrameNumber == (unsigned int)(itsAGTargetFrame.getVal() + 1)) || 00521 ((itsAGTargetFrame.getVal() == 0) && (itsFrameIdx > 0))) 00522 { 00523 00524 LINFO("Checking Mask file to target Attention Gate Frame %d", 00525 (itsFrameNumber + 1)); 00526 // We need to compute basically how much of the mask and 00527 // the last attention gate overlap. 00528 00529 // If the mask and attention gate never overlap, then the 00530 // target should never be seen. HOWEVER, if there is some 00531 // overlap, then whether the target is detected or not 00532 // may be more ambiguous. 00533 00534 // resize lam to the mask size 00535 Image<float> lamr = rescale(lam,itsMask.getWidth(), 00536 itsMask.getHeight()); 00537 Image<bool>::iterator mitr = itsLamMask.beginw(); 00538 00539 // Threshold the attention mask at 25% 00540 for(Image<float>::iterator litr = lamr.beginw(); 00541 litr != lamr.endw(); 00542 litr++) 00543 { 00544 // threshold at 12.5% 00545 if(*litr > 32) *mitr++ = true; 00546 else *mitr++ = false; 00547 } 00548 00549 itsMaskCount = 0; itsLamCount = 0; itsOverlapCount = 0; 00550 itsTotalCount = 0; 00551 00552 Image<bool>::iterator aitr = itsMask.beginw(); 00553 Image<bool>::iterator litr = itsLamMask.beginw(); 00554 Image<PixRGB<byte> >::iterator oitr = itsOverlap.beginw(); 00555 00556 // count overlapped pixels as well as total pixels active in 00557 // each of the two maps 00558 while(litr != itsLamMask.endw()) 00559 { 00560 if(*aitr++) 00561 { 00562 itsMaskCount++; 00563 if(*litr++) 00564 { 00565 itsLamCount++; 00566 itsOverlapCount++; 00567 *oitr++ = PixRGB<byte>(0,0,0); // Union = Black 00568 } 00569 else *oitr++ = PixRGB<byte>(255,0,0); // Mask Only = Red 00570 } 00571 else if(*litr++) 00572 { 00573 itsLamCount++; 00574 *oitr++ = PixRGB<byte>(0,0,255); // Att Gate Only = Blue 00575 } 00576 else 00577 { 00578 *oitr++ = PixRGB<byte>(255,255,255); // None = White 00579 } 00580 itsTotalCount++; 00581 } 00582 00583 //char filename[128]; 00584 //sprintf(filename,"mask-AG%0'6d-union.png",(itsFrameIdx - 1)); 00585 //Raster::WriteRGB(itsOverlap,filename); 00586 00587 // Check constistancy of mask. Transparency in PNG can mess it up 00588 if(itsMaskCount == itsTotalCount) 00589 LFATAL("Constancy Check failed for mask - Too Large!"); 00590 else if(itsMaskCount == 0) 00591 LFATAL("Constancy Check failed for mask - Too Small!"); 00592 00593 saveAGMaskStats(lamr,"AG-MASK"); 00594 } 00595 } 00596 00597 // do we have segments from stage two? 00598 if (SeC<SimEventAttentionGateStageTwoSegments> agst = 00599 q.check<SimEventAttentionGateStageTwoSegments>(this)) 00600 { 00601 LINFO("Getting Segments Image"); 00602 const Image<int> segments = agst->obj().segments; 00603 Image<float> newSegments = static_cast<Image<float> >(segments); 00604 00605 float min,max,avg; 00606 00607 getMinMaxAvg(newSegments,min,max,avg); 00608 00609 LINFO("Segments min %f max %f",min,max); 00610 00611 Image<PixHSV<float> > classImage; 00612 00613 classImage.resize(segments.getWidth(),segments.getHeight()); 00614 00615 if((max-min) > 0.0f) 00616 { 00617 // Create a rainbow to show the classes using HSV color space 00618 // 330 since 360 is red 00619 newSegments = ((newSegments - min) / (max - min)) * 300.0f; 00620 00621 Image<PixHSV<float> >::iterator classImageItr = classImage.beginw(); 00622 00623 for(Image<float>::iterator segmentsItr = newSegments.beginw(); 00624 segmentsItr != newSegments.endw(); ++segmentsItr) 00625 { 00626 classImageItr->p[0] = *segmentsItr; 00627 //LINFO("%f",*segmentsItr); 00628 classImageItr->p[1] = 100.0f; 00629 classImageItr->p[2] = 255.0f; 00630 ++classImageItr; 00631 } 00632 00633 // convert back to RGB 00634 Image<PixRGB<float> > temp = 00635 static_cast<Image<PixRGB<float> > >(classImage); 00636 00637 itsVisualSegments = temp; 00638 } 00639 00640 const Image<bool> cand = agst->candidates(); 00641 Image<float> newCand = static_cast<Image<float> >(cand); 00642 00643 newCand = newCand * 255.0f; 00644 00645 itsVisualCandidates = newCand; 00646 00647 } 00648 } 00649 } 00650 00651 00652 // ###################################################################### 00653 void SimulationViewerStats::saveCompat(const Image<float>& img, 00654 const std::string suffix, 00655 const int frameOffset) 00656 { 00657 00658 00659 unsigned int frameIdx = (unsigned int)((int)itsFrameNumber + frameOffset); 00660 00661 std::string fileName; 00662 std::string txt = suffix; 00663 fileName = itsGetSingleChannelStatsFile.getVal() + txt; 00664 00665 ushort minx = 0, miny = 0, maxx = 0, maxy = 0; 00666 float min, max, avg, std; 00667 uint N; 00668 // get a whole bunch of stats about this output image 00669 getMinMaxAvgEtc(img, min, max, avg, std, minx, miny, maxx, maxy, N); 00670 00671 LINFO("SAVING COMPAT STATS TO %s",fileName.c_str()); 00672 00673 std::ofstream statsFile(fileName.c_str(), std::ios::app); 00674 00675 statsFile << "final" << "\t"; 00676 00677 statsFile << frameIdx << "\t"; 00678 00679 // differentiate between scale image stats and the combined max norm 00680 // for compatability with single channel stats 00681 00682 statsFile << "COMBINED\t-1\t"; 00683 //itsFrameIdx++; 00684 00685 statsFile << "final" << "\t" << "FINAL" << "\t"; 00686 statsFile << min << "\t" << max << "\t" << avg << "\t" << std << "\t" 00687 << minx << "\t" << miny << "\t" << maxx << "\t" << maxy << "\t" 00688 << N << "\n"; 00689 statsFile.close(); 00690 00691 if(itsSaveStatsPerChannelFreq.getVal()) 00692 { 00693 std::string txt = ".final.freq.txt"; 00694 fileName = itsGetSingleChannelStatsFile.getVal() + txt; 00695 00696 FFTWWrapper fft(img.getWidth(), img.getHeight()); 00697 double dimg[img.getHeight() * img.getWidth()]; 00698 Image<float>::const_iterator itr = img.begin(); 00699 double *ditr = &dimg[0]; 00700 while(itr != img.end()) *ditr++ = double(*itr++); 00701 fft.init(dimg); 00702 double mag[img.getHeight() * (img.getWidth()/2 + 1)]; 00703 fft.compute(mag); 00704 00705 std::ofstream freqFile(fileName.c_str(), std::ios::app); 00706 freqFile << "final" << "\t"; 00707 freqFile << frameIdx << "\t"; 00708 00709 freqFile << "COMBINED\t-1\t"; 00710 00711 freqFile << "SIZE\t" << img.getWidth() <<"\t"<< img.getHeight() << "\n"; 00712 00713 for(int i = 0; i < img.getHeight(); i++) 00714 { 00715 for(int j = 0; j < (img.getWidth()/2 + 1); j++) 00716 freqFile << mag[i * (img.getWidth()/2 + 1) + j] << "\t"; 00717 freqFile << "\n"; 00718 } 00719 freqFile.close(); 00720 } 00721 } 00722 00723 // ###################################################################### 00724 void SimulationViewerStats::saveAGMaskStats(const Image<float> &img, 00725 const std::string caller, 00726 const std::string suffix) 00727 { 00728 00729 ushort minx = 0, miny = 0, maxx = 0, maxy = 0; 00730 float min, max, avg, std; 00731 uint N; 00732 // get a whole bunch of stats about this output image 00733 getMinMaxAvgEtc(img, min, max, avg, std, minx, miny, maxx, maxy, N); 00734 00735 std::string fileName; 00736 std::string txt = suffix; 00737 fileName = itsGetSingleChannelStatsFile.getVal() + txt; 00738 00739 LINFO("SAVING AG STATS TO %s",fileName.c_str()); 00740 00741 std::ofstream statsFile(fileName.c_str(), std::ios::app); 00742 00743 statsFile << "AGstats" << "\t"; 00744 00745 statsFile << (itsFrameNumber - 1) << "\t"; 00746 00747 // differentiate between scale image stats and the combined max norm 00748 // for compatability with single channel stats 00749 00750 statsFile << "COMBINED\t" << caller << "\t"; 00751 //itsFrameIdx++; 00752 00753 statsFile << "final" << "\t" << "FINAL" << "\t"; 00754 statsFile << itsTotalCount << "\t" 00755 << itsMaskCount << "\t" 00756 << itsLamCount << "\t" 00757 << itsOverlapCount << "\t"; 00758 statsFile << min << "\t" << max << "\t" << avg << "\t" << std << "\t" 00759 << minx << "\t" << miny << "\t" << maxx << "\t" << maxy << "\t" 00760 << N << "\n"; 00761 00762 statsFile.close(); 00763 } 00764 00765 // ###################################################################### 00766 /* So things look consistent in everyone's emacs... */ 00767 /* Local Variables: */ 00768 /* mode: c++ */ 00769 /* indent-tabs-mode: nil */ 00770 /* End: */