00001 /*!@file Channels/SpectralResidualChannel.C "Spectral Residual" channel based on Hou&Zhang (CVPR 2007) */ 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/Channels/SpectralResidualChannel.C $ 00035 // $Id: SpectralResidualChannel.C 12820 2010-02-11 05:44:51Z itti $ 00036 // 00037 00038 #ifndef CHANNELS_SPECTRALRESIDUALCHANNEL_C_DEFINED 00039 #define CHANNELS_SPECTRALRESIDUALCHANNEL_C_DEFINED 00040 00041 #include "Channels/SpectralResidualChannel.H" 00042 00043 #include "Channels/ChannelOpts.H" 00044 #include "Channels/ChannelVisitor.H" 00045 #include "Component/ModelOptionDef.H" 00046 #include "Image/FilterOps.H" 00047 #include "Image/FourierEngine.H" 00048 #include "Image/Kernels.H" 00049 #include "Image/MathOps.H" 00050 #include "Image/ShapeOps.H" 00051 #include "Transport/FrameInfo.H" 00052 #include "Transport/FrameOstream.H" 00053 #include "rutz/trace.h" 00054 00055 // Used by: SpectralResidualChannel 00056 const ModelOptionDef OPT_SpectralResidualChannelSaveOutputMap = 00057 { MODOPT_FLAG, "SpectralResidualChannelSaveOutputMap", &MOC_CHANNEL, OPTEXP_SAVE, 00058 "Save output maps from the Spectral Residual channel (\"SRS\")", 00059 "save-srs-output", '\0', "", "false" }; 00060 00061 // Used by: SpectralResidualChannel 00062 const ModelOptionDef OPT_SpectralResidualChannelSaveExtraOutput = 00063 { MODOPT_FLAG, "SpectralResidualChannelSaveExtraOutput", &MOC_CHANNEL, OPTEXP_SAVE, 00064 "Save additional output maps from the Spectral Residual channel", 00065 "save-srs-extra-output", '\0', "", "false" }; 00066 00067 // Used by: SpectralResidualChannel 00068 const ModelOptionDef OPT_SpectralResidualChannelResizeSpec = 00069 { MODOPT_ARG(ResizeSpec), "SpectralResidualChannelResizeSpec", &MOC_CHANNEL, OPTEXP_CORE, 00070 "Specification for how the spectral residual channel should " 00071 "resize the input prior to the fft and subsequent operations. ", 00072 "srs-resize", '\0', "<None | WxH | *WFxHF | /WFxHF>", "64x64" }; 00073 00074 // Used by: SpectralResidualChannel 00075 const ModelOptionDef OPT_SpectralResidualChannelSpectralBlur = 00076 { MODOPT_ARG(uint), "SpectralResidualChannelSpectralBlur", &MOC_CHANNEL, OPTEXP_CORE, 00077 "Size (in pixels) of the blur filter applied to the FFT " 00078 "log-magnitude image to produce the spectral residual image", 00079 "srs-spectral-blur", '\0', "<uint>", "3" }; 00080 00081 // Used by: SpectralResidualChannel 00082 const ModelOptionDef OPT_SpectralResidualChannelOutputBlur = 00083 { MODOPT_ARG(float), "SpectralResidualChannelOutputBlur", &MOC_CHANNEL, OPTEXP_CORE, 00084 "Standard deviation of the Gaussian blur filter applied to the " 00085 "Spectral Residual channel output", 00086 "srs-output-blur", '\0', "<float>", "3.5" }; 00087 00088 // Used by: SpectralResidualChannel 00089 const ModelOptionDef OPT_SpectralResidualChannelOutputBlurFactor = 00090 { MODOPT_ARG(double), "SpectralResidualOutputChannelBlurFactor", &MOC_CHANNEL, OPTEXP_CORE, 00091 "If non-zero, then this option overrides any value set with " 00092 "--srs-output-blur, such that the output blur filter width&height " 00093 "is set to this factor times the width&height of the channel's " 00094 "resized input.", 00095 "srs-output-blur-factor", '\0', "<double>", "0.0" }; 00096 00097 // Used by: SpectralResidualChannel 00098 const ModelOptionDef OPT_SpectralResidualChannelDownSizeFilterWidth = 00099 { MODOPT_ARG(int), "SpectralResidualChannelDownSizeFilterWidth", &MOC_CHANNEL, OPTEXP_CORE, 00100 "Low-pass filter width used when downsizing input prior to " 00101 "processing in the Spectral Residual channel", 00102 "srs-lowpass-filter-width", '\0', "<int>", "8" }; 00103 00104 // Used by: SpectralResidualChannel 00105 const ModelOptionDef OPT_SpectralResidualChannelAttenuationWidth = 00106 { MODOPT_ARG(double), "SpectralResidualChannelAttenuationWidth", &MOC_CHANNEL, OPTEXP_CORE, 00107 "Width across which the borders of the Spectral Residual output " 00108 "should be attenuated, expressed as a proportion of the output " 00109 "image size.", 00110 "srs-attenuation-width", '\0', "<double>", "0.0" }; 00111 00112 // Used by: SpectralResidualChannel 00113 const ModelOptionDef OPT_SpectralResidualChannelOutputResize = 00114 { MODOPT_FLAG, "SpectralResidualChannelOutputResize", &MOC_CHANNEL, OPTEXP_CORE, 00115 "Whether or not to do any output resizing; if yes, then choose output " 00116 "dims according to --srs-output-resize-spec.", 00117 "srs-output-resize", '\0', "", "false" }; 00118 00119 // Used by: SpectralResidualChannel 00120 const ModelOptionDef OPT_SpectralResidualChannelOutputResizeSpec = 00121 { MODOPT_ARG(ResizeSpec), "SpectralResidualChannelOutputResizeSpec", &MOC_CHANNEL, OPTEXP_CORE, 00122 "Specification for how the spectral residual channel should " 00123 "resize its output, relative to the original input size.", 00124 "srs-output-resize-spec", '\0', "<None | WxH | *WFxHF | /WFxHF>", "None" }; 00125 00126 // Used by: SpectralResidualChannel 00127 const ModelOptionDef OPT_SpectralResidualChannelHiboostBypass = 00128 { MODOPT_FLAG, "SpectralResidualChannelHiboostBypass", &MOC_CHANNEL, OPTEXP_CORE, 00129 "Whether to bypass spectral-residual computations with a simple " 00130 "high-frequency boost instead.", 00131 "srs-hiboost-bypass", '\0', "", "false" }; 00132 00133 // Used by: SpectralResidualChannel 00134 const ModelOptionDef OPT_SpectralResidualChannelGradientBypass = 00135 { MODOPT_FLAG, "SpectralResidualChannelGradientBypass", &MOC_CHANNEL, OPTEXP_CORE, 00136 "Whether to bypass spectral-residual computations with a simple " 00137 "gradient magnitude computation instead.", 00138 "srs-gradient-bypass", '\0', "", "false" }; 00139 00140 // ###################################################################### 00141 static Image<complexd> joinLogampliPhase(const Image<float>& logampli, 00142 const Image<double>& phase) 00143 { 00144 GVX_TRACE("SpectralResidualChannel::joinLogampliPhase"); 00145 00146 ASSERT(logampli.getDims() == phase.getDims()); 00147 00148 Image<complexd> newFFT(phase.getDims(), NO_INIT); 00149 00150 const int size = newFFT.getSize(); 00151 00152 Image<complexd>::iterator const dptr = newFFT.beginw(); 00153 Image<float>::const_iterator const aptr = logampli.begin(); 00154 Image<double>::const_iterator const pptr = phase.begin(); 00155 00156 // normalization factor so that we get approximately the same 00157 // range of values regardless of the rescale size: 00158 const double div = 1.0 / sqrt(size); 00159 00160 for (int i = 0; i < size; ++i) 00161 dptr[i] = std::exp(complexd(aptr[i], pptr[i])) * div; 00162 00163 return newFFT; 00164 } 00165 00166 // ###################################################################### 00167 SpectralResidualChannel::Downsizer::Downsizer() 00168 : 00169 itsInput(), itsFilterWidth(-1), itsPyr() 00170 { 00171 if (0 != pthread_mutex_init(&itsMutex, NULL)) 00172 PLFATAL("pthread_mutex_init() failed"); 00173 } 00174 00175 // ###################################################################### 00176 SpectralResidualChannel::Downsizer::~Downsizer() 00177 { 00178 if (0 != pthread_mutex_destroy(&itsMutex)) 00179 PLERROR("pthread_mutex_destroy() failed"); 00180 } 00181 00182 // ###################################################################### 00183 Image<float> SpectralResidualChannel::Downsizer:: 00184 getDownsized(const Image<float>& x, int filtwidth, const Dims& newdims) 00185 { 00186 GVX_TRACE("SRS::Downsizer::getDownsized"); 00187 00188 GVX_MUTEX_LOCK(&itsMutex); 00189 00190 if (!itsInput.hasSameData(x) || filtwidth != itsFilterWidth) 00191 { 00192 itsInput = x; 00193 itsFilterWidth = filtwidth; 00194 itsPyr.resize(0); 00195 itsPyr.push_back(x); 00196 LINFO("initializing downsize cache"); 00197 } 00198 else 00199 { 00200 LINFO("reusing downsize cache"); 00201 } 00202 00203 while (itsPyr.back().getWidth() > newdims.w() * 2 00204 && itsPyr.back().getHeight() > newdims.h() * 2) 00205 { 00206 Image<float> nextlev = itsPyr.back(); 00207 if (itsFilterWidth == 1) 00208 { 00209 nextlev = decX(nextlev); 00210 nextlev = decY(nextlev); 00211 } 00212 else if (itsFilterWidth == 2) 00213 { 00214 nextlev = quickLocalAvg2x2(nextlev); 00215 } 00216 else 00217 { 00218 nextlev = decX(lowPassX(itsFilterWidth, nextlev)); 00219 nextlev = decY(lowPassY(itsFilterWidth, nextlev)); 00220 } 00221 itsPyr.push_back(nextlev); 00222 } 00223 00224 size_t pyrlev = 0; 00225 00226 while (itsPyr[pyrlev].getWidth() > newdims.w() * 2 00227 && itsPyr[pyrlev].getHeight() > newdims.h() * 2) 00228 { 00229 ASSERT(pyrlev + 1 < itsPyr.size()); 00230 ++pyrlev; 00231 } 00232 00233 ASSERT(pyrlev < itsPyr.size()); 00234 ASSERT(pyrlev == 0 || itsPyr[pyrlev].getWidth() >= newdims.w()); 00235 ASSERT(pyrlev == 0 || itsPyr[pyrlev].getHeight() >= newdims.h()); 00236 ASSERT(itsPyr[pyrlev].getWidth() <= newdims.w() * 2 00237 || itsPyr[pyrlev].getHeight() <= newdims.h() * 2); 00238 00239 return rescaleBilinear(itsPyr[pyrlev], newdims); 00240 } 00241 00242 // ###################################################################### 00243 SpectralResidualChannel::SpectralResidualChannel 00244 (OptionManager& mgr, 00245 const std::string& descrName, 00246 const std::string& tagName) 00247 : 00248 ChannelBase(mgr, descrName, tagName, UNKNOWN), 00249 itsSaveOutput(&OPT_SpectralResidualChannelSaveOutputMap, this), 00250 itsSaveExtraOutput(&OPT_SpectralResidualChannelSaveExtraOutput, this), 00251 itsResizeSpec(&OPT_SpectralResidualChannelResizeSpec, this), 00252 itsSpectralBlur(&OPT_SpectralResidualChannelSpectralBlur, this), 00253 itsOutputBlur(&OPT_SpectralResidualChannelOutputBlur, this), 00254 itsOutputBlurFactor(&OPT_SpectralResidualChannelOutputBlurFactor, this), 00255 itsDownSizeFilterWidth(&OPT_SpectralResidualChannelDownSizeFilterWidth, this), 00256 itsAttenuationWidth(&OPT_SpectralResidualChannelAttenuationWidth, this), 00257 itsDoResizeOutput(&OPT_SpectralResidualChannelOutputResize, this), 00258 itsOutputResizeSpec(&OPT_SpectralResidualChannelOutputResizeSpec, this), 00259 itsNormType(&OPT_MaxNormType, this), // see Channels/ChannelOpts.{H,C} 00260 itsOutputRangeMin(&OPT_ChannelOutputRangeMin, this), 00261 itsOutputRangeMax(&OPT_ChannelOutputRangeMax, this), 00262 itsHiboostBypass(&OPT_SpectralResidualChannelHiboostBypass, this), 00263 itsGradientBypass(&OPT_SpectralResidualChannelGradientBypass, this), 00264 itsDownsizer(new Downsizer), 00265 itsFFT(0), 00266 itsIFFT(0), 00267 itsInput(), 00268 itsOutput() 00269 { 00270 } 00271 00272 // ###################################################################### 00273 SpectralResidualChannel::~SpectralResidualChannel() 00274 { 00275 delete itsFFT; 00276 delete itsIFFT; 00277 } 00278 00279 // ###################################################################### 00280 void SpectralResidualChannel::accept(ChannelVisitor& v) 00281 { 00282 v.visitChannelBase(*this); 00283 } 00284 00285 // ###################################################################### 00286 bool SpectralResidualChannel::isHomogeneous() const 00287 { 00288 return true; 00289 } 00290 00291 // ###################################################################### 00292 void SpectralResidualChannel::readFrom(const ParamMap& pmap) 00293 { 00294 ChannelBase::readFrom(pmap); 00295 } 00296 00297 // ###################################################################### 00298 void SpectralResidualChannel::writeTo(ParamMap& pmap) const 00299 { 00300 ChannelBase::writeTo(pmap); 00301 } 00302 00303 // ###################################################################### 00304 bool SpectralResidualChannel::outputAvailable() const 00305 { 00306 return itsInput.initialized(); 00307 } 00308 00309 // ###################################################################### 00310 Dims SpectralResidualChannel::getMapDims() const 00311 { 00312 return 00313 itsDoResizeOutput.getVal() 00314 ? itsOutputResizeSpec.getVal().transformDims(this->getInputDims()) 00315 : itsResizeSpec.getVal().transformDims(this->getInputDims()); 00316 } 00317 00318 // ###################################################################### 00319 uint SpectralResidualChannel::numSubmaps() const 00320 { 00321 return 1; 00322 } 00323 00324 // ###################################################################### 00325 Image<float> SpectralResidualChannel::getSubmap(const uint index) const 00326 { 00327 if (index == 0) 00328 return const_cast<SpectralResidualChannel*>(this)->getOutput(); 00329 00330 LFATAL("submap index %u out of range; I have only %u submap(s)", 00331 index, this->numSubmaps()); 00332 00333 /* can't happen */ return Image<float>(); 00334 } 00335 00336 // ###################################################################### 00337 std::string SpectralResidualChannel::getSubmapName(const uint index) const 00338 { 00339 if (index == 0) return "SpectralResidual"; 00340 00341 LFATAL("submap index %u out of range; I have only %u submap(s)", 00342 index, this->numSubmaps()); 00343 00344 /* can't happen */ return std::string(); 00345 } 00346 00347 // ###################################################################### 00348 std::string SpectralResidualChannel::getSubmapNameShort(const uint index) const 00349 { 00350 if (index == 0) return "SpecRes"; 00351 00352 LFATAL("submap index %u out of range; I have only %u submap(s)", 00353 index, this->numSubmaps()); 00354 00355 /* can't happen */ return std::string(); 00356 } 00357 00358 // ###################################################################### 00359 void SpectralResidualChannel::getFeatures(const Point2D<int>& locn, 00360 std::vector<float>& mean) const 00361 { 00362 LFATAL("not implemented"); 00363 } 00364 00365 // ###################################################################### 00366 void SpectralResidualChannel::getFeaturesBatch(std::vector<Point2D<int>*> *locn, 00367 std::vector<std::vector<float> > *mean, 00368 int *count) const 00369 { 00370 LFATAL("not implemented"); 00371 } 00372 00373 // ###################################################################### 00374 Image<float> SpectralResidualChannel::getOutput() 00375 { 00376 GVX_TRACE("SRS::getOutput"); 00377 00378 if (!itsInput.initialized()) 00379 LFATAL("I have no input yet!"); 00380 00381 if (!itsOutput.initialized()) 00382 { 00383 const Dims newdims = 00384 itsResizeSpec.getVal().transformDims(itsInput.getDims()); 00385 00386 itsRescaledInput = 00387 itsDownsizer->getDownsized(itsInput, 00388 itsDownSizeFilterWidth.getVal(), 00389 newdims); 00390 00391 if (itsFFT == 0) 00392 itsFFT = new FourierEngine<double>(itsRescaledInput.getDims()); 00393 00394 if (itsIFFT == 0) 00395 itsIFFT = new FourierInvEngine<double>(itsRescaledInput.getDims()); 00396 00397 if (itsGradientBypass.getVal()) 00398 { 00399 if (itsHiboostBypass.getVal()) 00400 LFATAL("can't use both --%s and --%s", 00401 itsHiboostBypass.getOptionDef()->longoptname, 00402 itsGradientBypass.getOptionDef()->longoptname); 00403 00404 itsProtoSaliencyMap = gradientmag(itsRescaledInput); 00405 } 00406 else 00407 { 00408 const Image<complexd> myFFT = itsFFT->fft(itsRescaledInput); 00409 itsLogMagnitude = Image<float>(logmagnitude(myFFT)); 00410 itsPhase = phase(myFFT); 00411 00412 const int size = myFFT.getSize(); 00413 00414 if (itsHiboostBypass.getVal()) 00415 { 00416 if (itsGradientBypass.getVal()) 00417 LFATAL("can't use both --%s and --%s", 00418 itsHiboostBypass.getOptionDef()->longoptname, 00419 itsGradientBypass.getOptionDef()->longoptname); 00420 00421 // multiply each fourier magnitude by the spatial 00422 // frequency; or, add log(freq) to the log magnitude 00423 00424 itsSpectralResidual.resize(itsLogMagnitude.getDims()); 00425 00426 const int w = itsLogMagnitude.getWidth(); 00427 const int h = itsLogMagnitude.getHeight(); 00428 00429 Image<float>::const_iterator sptr = itsLogMagnitude.begin(); 00430 Image<float>::iterator dptr = itsSpectralResidual.beginw(); 00431 00432 const double logsize = log(size); 00433 00434 for (int y = 0; y < h; ++y) 00435 for (int x = 0; x < w; ++x) 00436 { 00437 const int yf = std::min(y, h-y); 00438 00439 const double fsq = x*x + yf*yf; 00440 00441 *dptr++ = (*sptr++) + 0.5 * log(fsq) - logsize; 00442 } 00443 } 00444 else if (itsSpectralBlur.getVal() < 1) 00445 { 00446 LFATAL("--%s must be >= 1", 00447 itsSpectralBlur.getOptionDef()->longoptname); 00448 } 00449 else if (itsSpectralBlur.getVal() == 1) 00450 { 00451 itsSpectralResidual.resize(itsLogMagnitude.getDims(), true); 00452 } 00453 else 00454 { 00455 Image<float> filt(itsSpectralBlur.getVal(), 1, ZEROS); 00456 filt.clear(1.0f / itsSpectralBlur.getVal()); 00457 00458 itsSpectralResidual = 00459 itsLogMagnitude - sepFilter(itsLogMagnitude, filt, filt, 00460 CONV_BOUNDARY_REPLICATE); 00461 } 00462 00463 const Image<complexd> newFFT = joinLogampliPhase(itsSpectralResidual, itsPhase); 00464 00465 itsProtoSaliencyMap = itsIFFT->ifft(newFFT); 00466 } 00467 00468 if (MYLOGVERB >= LOG_DEBUG) 00469 { 00470 float mi1, ma1; getMinMax(itsRescaledInput, mi1, ma1); 00471 float mi, ma; getMinMax(itsProtoSaliencyMap, mi, ma); 00472 LDEBUG("input range %f .. %f; proto range %f .. %f", 00473 mi1, ma1, mi, ma); 00474 } 00475 00476 itsProtoSaliencyMap = squared(itsProtoSaliencyMap); 00477 00478 if (itsAttenuationWidth.getVal() > 0.0) 00479 { 00480 const int w = int(0.5 00481 + itsAttenuationWidth.getVal() 00482 * itsProtoSaliencyMap.getDims().max()); 00483 00484 inplaceAttenuateBorders(itsProtoSaliencyMap, w); 00485 } 00486 00487 float fw = 00488 itsOutputBlurFactor.getVal() > 0.0 00489 ? itsOutputBlurFactor.getVal() * itsProtoSaliencyMap.getWidth() 00490 : itsOutputBlur.getVal(); 00491 00492 float fh = 00493 itsOutputBlurFactor.getVal() > 0.0 00494 ? itsOutputBlurFactor.getVal() * itsProtoSaliencyMap.getHeight() 00495 : itsOutputBlur.getVal(); 00496 00497 itsOutput = itsProtoSaliencyMap; 00498 00499 const Dims mapdims = this->getMapDims(); 00500 ASSERT(mapdims.isNonEmpty()); 00501 00502 // if we're going to be downscaling the image eventually, then 00503 // let's avoid convolving with huge gaussian filters in 00504 // sepFilter() below by first averaging+decimating the image 00505 // and, in parallel, shrinking the corresponding gaussian 00506 // filters, until we get close to the final desired dims 00507 while (itsOutput.getWidth() >= mapdims.w()*2 00508 && itsOutput.getHeight() >= mapdims.h()*2) 00509 { 00510 itsOutput = quickLocalAvg2x2(itsOutput); 00511 fw /= 2.0f; 00512 fh /= 2.0f; 00513 } 00514 00515 Image<float> wfilt = gaussian<float>(0.0f, fw, 0, 1.0f); 00516 wfilt = wfilt / float(sum(wfilt)); 00517 00518 Image<float> hfilt = gaussian<float>(0.0f, fh, 0, 1.0f); 00519 hfilt = hfilt / float(sum(hfilt)); 00520 00521 LDEBUG("wfilt is %dx%d, hfilt is %dx%d", 00522 wfilt.getWidth(), wfilt.getHeight(), 00523 hfilt.getWidth(), hfilt.getHeight()); 00524 00525 itsOutput = sepFilter(itsOutput, wfilt, hfilt, 00526 CONV_BOUNDARY_ZERO); 00527 00528 // now resize the output to the requested ouput dims, or no-op 00529 // if the dims already match: 00530 itsOutput = rescaleBilinear(itsOutput, mapdims); 00531 00532 itsOutput = maxNormalize(itsOutput, 00533 itsOutputRangeMin.getVal(), 00534 itsOutputRangeMax.getVal(), 00535 itsNormType.getVal()); 00536 LINFO("%s OK: in=%dx%d -> resize %s -> internal=%dx%d -> resize %s -> out=%dx%d; " 00537 "spectral blur %u; output blur %gx%g; lpwidth %d; atten width %g", 00538 this->descriptiveName().c_str(), 00539 itsInput.getWidth(), itsInput.getHeight(), 00540 convertToString(itsResizeSpec.getVal()).c_str(), 00541 newdims.w(), newdims.h(), 00542 itsDoResizeOutput.getVal() 00543 ? convertToString(itsOutputResizeSpec.getVal()).c_str() 00544 : "skip", 00545 mapdims.w(), mapdims.h(), 00546 itsSpectralBlur.getVal(), fw, fh, 00547 itsDownSizeFilterWidth.getVal(), 00548 itsAttenuationWidth.getVal()); 00549 } 00550 00551 return itsOutput; 00552 } 00553 00554 // ###################################################################### 00555 void SpectralResidualChannel::saveResults(const nub::ref<FrameOstream>& ofs) 00556 { 00557 const std::string tag = this->tagName(); 00558 00559 if (itsSaveOutput.getVal()) 00560 ofs->writeFloat(this->getOutput(), FLOAT_NORM_PRESERVE, 00561 tag+"-", 00562 FrameInfo("Spectral Residual output", 00563 SRC_POS)); 00564 00565 if (itsSaveExtraOutput.getVal()) 00566 { 00567 ofs->writeGray(Image<byte>(itsInput), tag+"-input", 00568 FrameInfo("Spectral Residual input", SRC_POS)); 00569 00570 ofs->writeFloat(itsRescaledInput, FLOAT_NORM_PRESERVE, 00571 tag+"-rescaled-input", 00572 FrameInfo("Spectral Residual rescaled input", SRC_POS)); 00573 00574 ofs->writeFloat(itsLogMagnitude, FLOAT_NORM_PRESERVE, 00575 tag+"-logmagnitude", 00576 FrameInfo("Spectral Residual fft log-magnitude", 00577 SRC_POS)); 00578 00579 ofs->writeFloat(itsPhase, FLOAT_NORM_PRESERVE, 00580 tag+"-phase", 00581 FrameInfo("Spectral Residual fft phase", 00582 SRC_POS)); 00583 00584 ofs->writeFloat(itsSpectralResidual, FLOAT_NORM_PRESERVE, 00585 tag+"-spectral-residual", 00586 FrameInfo("Spectral Residual fft spectral residual", 00587 SRC_POS)); 00588 00589 ofs->writeFloat(itsProtoSaliencyMap, FLOAT_NORM_PRESERVE, 00590 tag+"-proto-saliency", 00591 FrameInfo("Spectral Residual proto-saliency", 00592 SRC_POS)); 00593 } 00594 } 00595 00596 // ###################################################################### 00597 void SpectralResidualChannel::killCaches() 00598 { 00599 itsOutput = Image<float>(); 00600 00601 // kill any previous intermediary results: 00602 itsRescaledInput.freeMem(); 00603 itsLogMagnitude.freeMem(); 00604 itsPhase.freeMem(); 00605 itsSpectralResidual.freeMem(); 00606 itsProtoSaliencyMap.freeMem(); 00607 } 00608 00609 // ###################################################################### 00610 void SpectralResidualChannel::doInput(const InputFrame& inframe) 00611 { 00612 if (!inframe.grayFloat().initialized()) 00613 LFATAL("Oops! I need luminance input"); 00614 00615 itsInput = inframe.grayFloat(); 00616 } 00617 00618 // ###################################################################### 00619 /* So things look consistent in everyone's emacs... */ 00620 /* Local Variables: */ 00621 /* mode: c++ */ 00622 /* indent-tabs-mode: nil */ 00623 /* End: */ 00624 00625 #endif // CHANNELS_SPECTRALRESIDUALCHANNEL_C_DEFINED