Retina.C

Go to the documentation of this file.
00001 /*!@file Neuro/Retina.C a human retina */
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: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/Retina.C $
00035 // $Id: Retina.C 14634 2011-03-24 00:33:16Z dberg $
00036 //
00037 
00038 #include "Neuro/Retina.H"
00039 
00040 #include "Component/OptionManager.H"
00041 #include "Component/ModelOptionDef.H"
00042 #include "Image/CutPaste.H"
00043 #include "Image/DrawOps.H"
00044 #include "Image/ColorOps.H"//for luminance()
00045 #include "Image/MatrixOps.H"
00046 #include "Image/Point2DT.H"
00047 #include "Image/PyramidOps.H" // for buildPyrGaussian(), foveate()
00048 #include "SpaceVariant/SpaceVariantOpts.H"
00049 #include "Media/MediaSimEvents.H"
00050 #include "Neuro/NeuroOpts.H"
00051 #include "Neuro/NeuroSimEvents.H"
00052 #include "Neuro/SpatialMetrics.H"
00053 #include "Channels/ChannelOpts.H"
00054 #include "Psycho/EyeData.H"
00055 #include "Raster/Raster.H"
00056 #include "Simulation/SimEventQueue.H"
00057 #include "Transport/FrameInfo.H"
00058 #include "Transport/FrameOstream.H"
00059 #include "Util/sformat.H"  // for sformat()
00060 
00061 #include <cstdlib>
00062 #include <iostream>
00063 #include <exception>
00064 #include <vector>
00065 
00066 // ######################################################################
00067 
00068 static const ModelOptionDef OPT_ClipMaskFname =
00069   { MODOPT_ARG_STRING, "ClipMaskFname", &MOC_BRAIN, OPTEXP_CORE,
00070     "Name of a grayscale image file to be loaded and used as a "
00071     "clipmask for Brain",
00072     "clip-mask", '\0', "<filename>", "" };
00073 
00074 static const ModelOptionDef OPT_RawInpRectBorder =
00075   { MODOPT_ARG(int), "RawInpRectBorder", &MOC_BRAIN, OPTEXP_CORE,
00076     "Border size to use for the Retina's raw input rectangle (used to "
00077     "select random samples in SimulationViewerCompress), in pixels.",
00078     "rawinput-rect-border", '\0', "<int>", "128" };
00079 
00080 static const ModelOptionDef OPT_EnablePyramidCaches =
00081   { MODOPT_FLAG, "EnablePyramidCaches", &MOC_BRAIN, OPTEXP_CORE,
00082     "Whether to allow caching of commonly-needed image pyramids based "
00083     "on the current input image, such as the intensity pyramid shared "
00084     "between the intensity channel and the motion channels, or the "
00085     "laplacian pyramid shared among the oriented gabor channels. There "
00086     "should be no reason to disable pyramid caching except for "
00087     "debugging or profiling.",
00088     "enable-pyramid-caches", '\0', "", "true" };
00089 
00090 // ######################################################################
00091 // ######################################################################
00092 // ########## Retina implementation
00093 // ######################################################################
00094 // ######################################################################
00095 Retina::Retina(OptionManager& mgr, const std::string& descrName, const std::string& tagName) :
00096   SimModule(mgr, descrName, tagName)
00097 { }
00098 
00099 Retina::~Retina()
00100 { }
00101 
00102 // ######################################################################
00103 // ######################################################################
00104 // ########## RetinaAdapter implementation
00105 // ######################################################################
00106 // ######################################################################
00107 RetinaAdapter::RetinaAdapter(OptionManager& mgr, const std::string& descrName, const std::string& tagName) :
00108   Retina(mgr, descrName, tagName),
00109   SIMCALLBACK_INIT(SimEventInputFrame),
00110   SIMCALLBACK_INIT(SimEventSaccadeStatusEye),
00111   SIMCALLBACK_INIT(SimEventSaveOutput),
00112   itsClipMaskFname(&OPT_ClipMaskFname, this),
00113   itsRawInpRectBorder(&OPT_RawInpRectBorder, this),
00114   itsInitialEyePosition(&OPT_SCeyeInitialPosition, this),
00115   itsEnablePyramidCaches(&OPT_EnablePyramidCaches, this),
00116   itsFoveaRadius(&OPT_FoveaRadius, this),
00117   itsSaveInput(&OPT_RetinaSaveInput, this), // see Neuro/NeuroOpts.{H,C}
00118   itsSaveOutput(&OPT_RetinaSaveOutput, this),
00119   itsFramingImageName(&OPT_InputFramingImageName, this),
00120   itsFramingImagePos(&OPT_InputFramingImagePos, this),
00121   itsFoveateInputDepth(&OPT_FoveateInputDepth, this), // idem
00122   itsShiftInput(&OPT_ShiftInputToEye, this), // see Neuro/NeuroOpts.{H,C}
00123   itsShiftInputBGcol(&OPT_ShiftInputToEyeBGcol, this), // idem
00124   itsInputFOV(&OPT_InputFOV, this),  // see Neuro/NeuroOpts.{H,C}
00125   itsSavePyr(&OPT_RetinaStdSavePyramid, this),
00126   itsBlankBlink(&OPT_BlankBlink, this),
00127   itsRetMaskFname(&OPT_RetinaMaskFname, this),
00128   itsFlipHoriz(&OPT_RetinaFlipHoriz, this),
00129   itsFlipVertic(&OPT_RetinaFlipVertic, this),
00130   itsClipMask(),
00131   itsEyePos(-1, -1),
00132   itsEyeBlinkStatus(false),
00133   itsRawInput(),
00134   itsOutput(),
00135   itsFramingImage(),
00136   itsRetinalShift(0, 0),
00137   itsRetMask()
00138 { }
00139 
00140 // ######################################################################
00141 RetinaAdapter::~RetinaAdapter()
00142 { }
00143 
00144 // ######################################################################
00145 void RetinaAdapter::onSimEventSaccadeStatusEye(SimEventQueue& q, rutz::shared_ptr<SimEventSaccadeStatusEye>& e)
00146 {
00147   // update our blink status and eye position:
00148   const TransientStatus bs = e->blinkStatus();
00149   if (transientStatusIsOn(bs)) itsEyeBlinkStatus = true;
00150   else if (transientStatusIsOff(bs)) itsEyeBlinkStatus = false;
00151   itsEyePos = e->position(); // in retinal coordinates
00152 
00153   if (itsEyePos.isValid()) LDEBUG("Using eye position (%d, %d).", itsEyePos.i, itsEyePos.j);
00154 
00155   // if we are shifting inputs according to eye position, then we here need to output a new retina every time the eye
00156   // moves; otherwise, we will do it only every time the input frame changes, in onSimEventInputFrame(). Of course if
00157   // there is no input image yet, we output nothing, also time 0 is handled by onSimEventInputFrame():
00158   if (itsShiftInput.getVal() && itsRawInput.initialized() && q.now() != SimTime::ZERO()) {
00159     // all right, let's process the frame!
00160     const Image<PixRGB<byte> > outimg = getOutput(itsRawInput, itsEyePos, itsEyeBlinkStatus);
00161 
00162     // post an event with our output:
00163     InputFrame ifr = InputFrame::fromRgb(&outimg, q.now(), &itsClipMask,
00164                                          InputFrame::emptyCache, !itsEnablePyramidCaches.getVal());
00165     postInputFrame(q, ifr);
00166   }
00167 }
00168 
00169 // ######################################################################
00170 void RetinaAdapter::onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e)
00171 {
00172   // here is the inputs image:
00173   const Image<PixRGB<byte> > inimg = e->frame().asRgb();
00174 
00175   // keep a copy of input in case we want to later save or use it:
00176   itsRawInput = inimg;
00177 
00178   // NOTE that when we are just starting a simulation, the saccade controller will not have had a chance to post an eye
00179   // position yet. In this case, we will get it from our command-line:
00180   if (q.now() == SimTime::ZERO()) {
00181     itsEyePos = itsInitialEyePosition.getVal();
00182     if (itsEyePos.i == -2 && itsEyePos.j == -2) {
00183       // we want to start at center:
00184       itsEyePos.i = inimg.getWidth() / 2; itsEyePos.j = inimg.getHeight() / 2;
00185 
00186       // convert to retinal coords:
00187       itsEyePos += getRawToRetinalOffset();
00188     }
00189     if (itsEyePos.isValid()) LDEBUG("Using eye position (%d, %d).", itsEyePos.i, itsEyePos.j);
00190   }
00191 
00192   // if we are shifting inputs accordint to eye position, then we need to output a new retina every time the eye moves,
00193   // so that's done in onSimEventSaccadeStatusEye; otherwise, here, we will do it only every time the input frame
00194   // changes (except at time 0):
00195   if (itsShiftInput.getVal() == false || q.now() == SimTime::ZERO()) {
00196     // all right, let's process the frame!
00197     const Image<PixRGB<byte> > outimg = getOutput(inimg, itsEyePos, itsEyeBlinkStatus);
00198 
00199     // post an event with our output:
00200     InputFrame ifr =
00201       InputFrame::fromRgb(&outimg, q.now(), &itsClipMask, InputFrame::emptyCache, !itsEnablePyramidCaches.getVal());
00202     postInputFrame(q, ifr);
00203   }
00204 }
00205 
00206 // ######################################################################
00207 void RetinaAdapter::postInputFrame(SimEventQueue& q, InputFrame& ifr) 
00208 {
00209   rutz::shared_ptr<SimEventRetinaImage>
00210     eri(new SimEventRetinaImage(this, ifr, getRawInputRectangle(itsRawInput.getDims(), ifr.getDims()),
00211                                 getRawToRetinalOffset()));
00212   q.post(eri);
00213 }
00214 
00215 // ######################################################################
00216 Rectangle RetinaAdapter::getRawInputRectangle(const Dims& indims, const Dims& outdims) const
00217 {
00218   const int border = itsRawInpRectBorder.getVal();
00219   Point2D<int> fpos = itsFramingImagePos.getVal();
00220   Rectangle r = Rectangle::tlbrI(itsRetinalShift.j + fpos.j + border,
00221                                  itsRetinalShift.i + fpos.i + border,
00222                                  itsRetinalShift.j + fpos.j + indims.h()-1 - border,
00223                                  itsRetinalShift.i + fpos.i + indims.w()-1 - border);
00224   return r.getOverlap(Rectangle(Point2D<int>(0,0), outdims));
00225 }
00226 
00227 // ######################################################################
00228 Point2D<int> RetinaAdapter::getRawToRetinalOffset() const
00229 { return itsFramingImagePos.getVal() + itsRetinalShift; }
00230 
00231 // ######################################################################
00232 void RetinaAdapter::start1()
00233 {
00234   if (!itsClipMaskFname.getVal().empty()) {
00235     itsClipMask = Raster::ReadGray(itsClipMaskFname.getVal());
00236     LINFO("Using clipmask from image file %s", itsClipMaskFname.getVal().c_str());
00237   }
00238 
00239   // if doing framing, read the framing image:
00240   if (itsFramingImageName.getVal().empty() == false) {
00241     itsFramingImage = Raster::ReadRGB(itsFramingImageName.getVal());
00242     LINFO("Using %dx%d framing image %s", itsFramingImage.getWidth(),
00243           itsFramingImage.getHeight(), itsFramingImageName.getVal().c_str());
00244   }
00245 
00246   // if doing input masking, read the mask image:
00247   if (itsRetMaskFname.getVal().empty() == false) {
00248     itsRetMask = Raster::ReadGray(itsRetMaskFname.getVal());
00249     LINFO("Using %dx%d retinal mask %s", itsRetMask.getWidth(),
00250           itsRetMask.getHeight(), itsRetMaskFname.getVal().c_str());
00251   }
00252 
00253   Retina::start1();
00254 }
00255 
00256 // ######################################################################
00257 void RetinaAdapter::
00258 onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00259 {
00260   this->save1(e->sinfo());
00261 }
00262 
00263 // ######################################################################
00264 void RetinaAdapter::save1(const ModelComponentSaveInfo& sinfo)
00265 {
00266   // get the OFS to save to, assuming sinfo is of type
00267   // SimModuleSaveInfo (will throw a fatal exception otherwise):
00268   nub::ref<FrameOstream> ofs = dynamic_cast<const SimModuleSaveInfo&>(sinfo).ofs;
00269 
00270   // save input?
00271   if (itsSaveInput.getVal() && itsRawInput.initialized())
00272     ofs->writeRGB(itsRawInput, "RETIN-", FrameInfo("retinal input", SRC_POS));
00273 
00274   // save output?
00275   if (itsSaveOutput.getVal() && itsOutput.initialized())
00276     ofs->writeRGB(itsOutput, "RETOUT-", FrameInfo("retinal output", SRC_POS));
00277 
00278   // save pyramid?
00279   if (itsSavePyr.getVal() && itsOutput.initialized())
00280     for (uint i = 0; i < itsMultiRetina.size(); i ++)
00281       ofs->writeRGB(itsMultiRetina[i], sformat("RET%d-", i),
00282                     FrameInfo(sformat("pyramid level %d in RetinaStd", i), SRC_POS));
00283 }
00284 
00285 // ######################################################################
00286 Image< PixRGB<byte> > RetinaAdapter::getOutput(const Image<PixRGB<byte> >& inp,
00287                                                const Point2D<int>& eye, const bool inBlink)
00288 {
00289   // start with our latest input:
00290   Image< PixRGB<byte> > ret = inp;
00291 
00292   // if we have a retinal mask image, apply it:
00293   if (itsRetMask.initialized())
00294     {
00295       if (ret.isSameSize(itsRetMask) == false)
00296         LFATAL("Retina (%dx%d) and retinal mask (%dx%d) dim mismatch",
00297                ret.getWidth(), ret.getHeight(), itsRetMask.getWidth(), itsRetMask.getHeight());
00298 
00299       // we rely on automatic promotions (ret * itsRetMask is Image< PixRGB<int> >) and demotion (assigment to result):
00300       ret = (ret * itsRetMask) / 255;
00301     }
00302 
00303   // any flipping?
00304   if (itsFlipHoriz.getVal()) ret = flipHoriz(ret);
00305   if (itsFlipVertic.getVal()) ret = flipVertic(ret);
00306 
00307   // embed our latest raw input within a larger framing image if any:
00308   if (itsFramingImage.initialized())
00309     {
00310       ret = itsFramingImage;
00311       inplacePaste(ret, inp, itsFramingImagePos.getVal());
00312     }
00313 
00314   // do we want to shift the input so that it is centered at the current eye position?
00315   if (itsShiftInput.getVal())
00316     {
00317       // do we have a valid eye position yet?
00318       if (eye.isValid())
00319         {
00320           LINFO("Shifting input to eye position (%d, %d)", eye.i, eye.j);
00321 
00322           itsRetinalShift.i += ret.getWidth() / 2 - eye.i;
00323           itsRetinalShift.j += ret.getHeight() / 2 - eye.j;
00324 
00325           ret = shiftClean(ret, itsRetinalShift.i, itsRetinalShift.j, itsShiftInputBGcol.getVal());
00326         }
00327 
00328       // in addition, do we want to crop the shifted input to a central field of view?
00329       Dims fovd(itsInputFOV.getVal());
00330       if (fovd.isEmpty() == false)
00331         {
00332           Point2D<int> fovoff( (ret.getWidth() - fovd.w()) / 2, (ret.getHeight() - fovd.h()) / 2);
00333           if (eye.i != -1 || eye.j != -1) itsRetinalShift -= fovoff;
00334           ret = crop(ret, fovoff, fovd);
00335         }
00336     }
00337 
00338   // if doing foveation, create color pyramid for itsMultiRetina, and foveate the input image, storing the result into
00339   // itsRetina; otherwise, itsMultiRetina remains unitialized and itsRetina is a straight copy of the input frame:
00340   const uint fid = itsFoveateInputDepth.getVal();
00341   if (fid > 0)
00342     {
00343       LINFO("Initializing multiretina (depth %d)", fid);
00344       itsMultiRetina = buildPyrGaussian(ret, 0, fid, 9);
00345 
00346       // create a mask with a disk at current overt fixation:
00347       Image<byte> mask(ret.getDims(), ZEROS);
00348 
00349       // do we have a valid eye position yet?
00350       if (eye.isValid())
00351         {
00352           drawDisk(mask, eye, itsFoveaRadius.getVal(), byte(255));
00353           LINFO("Foveating input at (%d, %d)", eye.i, eye.j);
00354         }
00355       else
00356         LINFO("Foveating input with uniform medium blur");
00357 
00358       // use the mask to foveate; if we don't have a SaccadeController but have nevertheless requested
00359       // itsFoveateInputDepth > 0, the behavior of foveate() is to apply a uniform medium blur to the entire image. If
00360       // we do have a SaccadeController, this will only happen as long as no overt fixation has been made yet:
00361       ret = foveate(mask, itsMultiRetina);
00362     }
00363 
00364   // if we are in a blink, assume that inputs are blanked out:
00365   if (inBlink && itsBlankBlink.getVal()) {
00366       LINFO("#### Visual input blanked out while in blink ####");
00367       ret.clear(PixRGB<byte>(0));
00368     }
00369 
00370   // derived classes may want to transform the retinal image at this point:
00371   ret = transform(ret);
00372 
00373   // keep a copy of output in case we want to later save or use it:
00374   itsOutput = ret;
00375 
00376   // ready to return:
00377   return ret;
00378 }
00379 
00380 // ######################################################################
00381 // ######################################################################
00382 // ########## RetinaConfigurator implementation
00383 // ######################################################################
00384 // ######################################################################
00385 RetinaConfigurator::RetinaConfigurator(OptionManager& mgr, const std::string& descrName, const std::string& tagName) :
00386   ModelComponent(mgr, descrName, tagName),
00387   itsType(&OPT_RetinaType, this),
00388   itsRET(new RetinaStub(mgr))
00389 {
00390   addSubComponent(itsRET);
00391 }
00392 
00393 // ######################################################################
00394 RetinaConfigurator::~RetinaConfigurator()
00395 {  }
00396 
00397 // ######################################################################
00398 nub::ref<Retina> RetinaConfigurator::getRET() const
00399 { return itsRET; }
00400 
00401 // ######################################################################
00402 void RetinaConfigurator::paramChanged(ModelParamBase* const param,
00403                                       const bool valueChanged,
00404                                       ParamClient::ChangeStatus* status)
00405 {
00406   ModelComponent::paramChanged(param, valueChanged, status);
00407 
00408   // was that a change of our baby's name?
00409   if (param == &itsType) {
00410     // let's unregister our existing Retina:
00411     removeSubComponent(*itsRET);
00412 
00413     // instantiate a Retina of the appropriate type (when the old
00414     // Retina is destroyed, it will un-export its command-line
00415     // options):
00416     if (itsType.getVal().compare("Stub") == 0)          // stub
00417       itsRET.reset(new RetinaStub(getManager()));
00418     else if (itsType.getVal().compare("Std") == 0)      // standard
00419       itsRET.reset(new RetinaStd(getManager()));
00420     else if (itsType.getVal().compare("CT") == 0)      // Cortical or collicular - Transform 
00421       itsRET.reset(new RetinaCT(getManager()));
00422     else
00423       LFATAL("Unknown Retina type %s", itsType.getVal().c_str());
00424 
00425     // add our baby as a subcomponent of us so that it will become
00426     // linked to the manager through us (hopefully we are registered
00427     // with the manager), which in turn will allow it to export its
00428     // command-line options and get configured:
00429     addSubComponent(itsRET);
00430 
00431     // tell the controller to export its options:
00432     itsRET->exportOptions(MC_RECURSE);
00433 
00434     // some info message:
00435     LINFO("Selected RET of type %s", itsType.getVal().c_str());
00436   }
00437 }
00438 
00439 // ######################################################################
00440 // ######################################################################
00441 // ########## RetinaStub implementation
00442 // ######################################################################
00443 // ######################################################################
00444 RetinaStub::RetinaStub(OptionManager& mgr, const std::string& descrName, const std::string& tagName) :
00445   Retina(mgr, descrName, tagName),
00446   SIMCALLBACK_INIT(SimEventInputFrame)
00447 { }
00448 
00449 // ######################################################################
00450 RetinaStub::~RetinaStub()
00451 { }
00452 
00453 // ######################################################################
00454 void RetinaStub::onSimEventInputFrame(SimEventQueue& q, rutz::shared_ptr<SimEventInputFrame>& e)
00455 {
00456   GenericFrame fr = e->frame();
00457   InputFrame ifr;
00458 
00459   switch(fr.nativeType()) {
00460   case GenericFrame::RGBD:
00461     {
00462       const Image<PixRGB<byte> > inimg = fr.asRgb();
00463       const Image<uint16> dimg = fr.asGrayU16();
00464       ifr = InputFrame::fromRgbDepth(&inimg, &dimg, q.now());
00465     }
00466     break;
00467   default:
00468     {
00469       const Image<PixRGB<byte> > inimg = fr.asRgb();
00470       ifr = InputFrame::fromRgb(&inimg, q.now());
00471     }
00472     break;
00473   }
00474 
00475   // post an event with our output:
00476   Rectangle rect(Point2D<int>(0,0), ifr.getDims());
00477   rutz::shared_ptr<SimEventRetinaImage> eri(new SimEventRetinaImage(this, ifr, rect, Point2D<int>(0,0)));
00478   q.post(eri);
00479 }
00480 
00481 // ######################################################################
00482 // ######################################################################
00483 // ########## RetinaStd implementation
00484 // ######################################################################
00485 // ######################################################################
00486 RetinaStd::RetinaStd(OptionManager& mgr, const std::string& descrName,
00487                      const std::string& tagName) :
00488   RetinaAdapter(mgr, descrName, tagName)
00489 { }
00490 
00491 // ######################################################################
00492 RetinaStd::~RetinaStd()
00493 { }
00494 
00495 // ######################################################################
00496 Image<PixRGB<byte> > RetinaStd::transform(const Image<PixRGB<byte> >& image)
00497 { return image; }
00498 
00499 // ######################################################################
00500 // ######################################################################
00501 // ########## RetinaCT implementation
00502 // ######################################################################
00503 // ######################################################################
00504 RetinaCT::RetinaCT(OptionManager& mgr, const std::string& descrName, const std::string& tagName) :
00505   RetinaAdapter(mgr, descrName, tagName), 
00506   itsSurrFac(&OPT_SpaceVariantDogSize, this),
00507   itsLevels(&OPT_SpaceVariantChanScales, this),
00508   itsTransform(new SpaceVariantModule(mgr)),
00509   itsRgbCache(new PyramidCache<PixRGB<float> >), itsFloatCache(new PyramidCache<float>)
00510 {
00511   this->addSubComponent(itsTransform);
00512 }
00513 
00514 // ######################################################################
00515 RetinaCT::~RetinaCT()
00516 { }
00517 
00518 // ######################################################################
00519 void RetinaCT::start1()
00520 { 
00521   getRootObject()->setModelParamVal("UseSpaceVariantBoundary", true, MC_RECURSE | MC_IGNORE_MISSING);
00522   RetinaAdapter::start1();
00523 }
00524 
00525 // ######################################################################
00526 Rectangle RetinaCT::getRawInputRectangle(const Dims& indims, const Dims& outdims) const
00527 {
00528   Rectangle r(Point2D<int>(0,0), indims);
00529   return r;
00530 }
00531 
00532 // ######################################################################
00533 void RetinaCT::postInputFrame(SimEventQueue& q, InputFrame& ifr) 
00534 {
00535   ifr.setPyrCacheRgb(itsRgbCache);
00536   ifr.setPyrCache(itsFloatCache);
00537 
00538   rutz::shared_ptr<SimEventRetinaImage>
00539     eri(new SimEventRetinaImage(this, ifr, getRawInputRectangle(itsRawInput.getDims(), ifr.getDims()), 
00540                                 getRawToRetinalOffset(),itsTransform->getTransform(),itsTransform->getMapTransform()));
00541   q.post(eri);
00542 }
00543 
00544 // ######################################################################
00545 Image<PixRGB<byte> > RetinaCT::transform(const Image<PixRGB<byte> >& inp)
00546 {
00547   //transform image and cache
00548   ImageSet<PixRGB<float> > rgbcache;
00549   rutz::mutex_lock_class lock;
00550   if (itsRgbCache->gaussian5.beginSet(inp, &lock))
00551     {
00552       const float maxrf = itsTransform->getMaxRf(itsLevels.getVal().getMaxVariance(), itsSurrFac.getVal());
00553       rgbcache = itsTransform->getScaleSpace(inp, maxrf);
00554       itsRgbCache->gaussian5.endSet(inp, rgbcache, &lock);
00555     }
00556 
00557   Image<float> inpl = luminance(inp);
00558   if (itsFloatCache->gaussian5.beginSet(inpl, &lock))
00559     {
00560       ImageSet<float> floatcache(rgbcache.size());
00561       for (uint ii = 0; ii < floatcache.size(); ++ii)
00562         floatcache[ii] = luminance(rgbcache[ii]);
00563       
00564       itsFloatCache->gaussian5.endSet(inpl, floatcache, &lock);
00565     }
00566   
00567   Image<PixRGB<byte> > output = itsTransform->transform(inp, &rgbcache);
00568   return output;
00569 }
00570 
00571 // ######################################################################
00572 /* So things look consistent in everyone's emacs... */
00573 /* Local Variables: */
00574 /* indent-tabs-mode: nil */
00575 /* End: */
Generated on Sun May 8 08:05:25 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3