EnvSegmenterColorRegion.C

Go to the documentation of this file.
00001 /*!@file Neuro/EnvSegmenterColorRegion.C FOA segmenter */
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/Neuro/EnvSegmenterColorRegion.C $
00035 // $Id: EnvSegmenterColorRegion.C 9740 2008-05-10 03:20:14Z rjpeters $
00036 //
00037 
00038 #ifndef NEURO_ENVSEGMENTERCOLORREGION_C_DEFINED
00039 #define NEURO_ENVSEGMENTERCOLORREGION_C_DEFINED
00040 
00041 #include "Neuro/EnvSegmenterColorRegion.H"
00042 
00043 #include "Component/ModelOptionDef.H"
00044 #include "Image/ColorOps.H"
00045 #include "Image/Image.H"
00046 #include "Image/ImageSet.H"
00047 #include "Image/LowPass.H"
00048 #include "Image/MathOps.H"
00049 #include "Image/Normalize.H"
00050 #include "Image/Pixels.H"
00051 #include "Image/PyramidOps.H"
00052 #include "Neuro/NeuroOpts.H"
00053 #include "Util/MathFunctions.H"
00054 
00055 static const ModelOptionDef OPT_EseDynamicFoa =
00056   { MODOPT_FLAG, "EseDynamicFoa", &MOC_ITC, OPTEXP_CORE,
00057     "Whether to use a dynamically-sized FOA obtained from color-based "
00058     "segmentation",
00059     "ese-dynamic-foa", '\0', "", "true" };
00060 
00061 static const ModelOptionDef OPT_EseFoaSize =
00062   { MODOPT_ARG(int), "EseFoaSize", &MOC_ITC, OPTEXP_CORE,
00063     "Size, in pixels, of the FOA box for non-dynamically-sized FOAs",
00064     "ese-foa-size", '\0', "int", "180" };
00065 
00066 static const ModelOptionDef OPT_EseDynamicFoaMinSize =
00067   { MODOPT_ARG(int), "EseFoaMinSize", &MOC_ITC, OPTEXP_CORE,
00068     "Minimum size, in pixels, of the FOA box for dynamically-sized FOAs",
00069     "ese-foa-min-size", '\0', "int", "32" };
00070 
00071 static const ModelOptionDef OPT_EseDynamicFoaMaxSize =
00072   { MODOPT_ARG(int), "EseFoaMaxSize", &MOC_ITC, OPTEXP_CORE,
00073     "Maximum size, in pixels, of the FOA box for dynamically-sized FOAs",
00074     "ese-foa-max-size", '\0', "int", "360" };
00075 
00076 static const ModelOptionDef OPT_EseSegmentationThresh =
00077   { MODOPT_ARG(double), "EseSegmentationThresh", &MOC_ITC, OPTEXP_CORE,
00078     "Pixel-similarity threshold for object segmentation (0.0 .. 1.0)",
00079     "ese-segmentation-thresh", '\0', "double", "0.5" };
00080 
00081 static const ModelOptionDef OPT_EseSegmentationScale =
00082   { MODOPT_ARG(size_t), "EseSegmentationScale", &MOC_ITC, OPTEXP_CORE,
00083     "Pyramid scale at which to compute object segmentation",
00084     "ese-segmentation-scale", '\0', "uint", "4" };
00085 
00086 namespace
00087 {
00088   Rectangle segmentColor(const Image<PixRGB<byte> >& rgbin,
00089                          const Point2D<int>& foacenter,
00090                          const size_t segmentationScale,
00091                          const float segmentationThresh,
00092                          const int foaminsize,
00093                          const int foamaxsize,
00094                          Image<float>& distmap,
00095                          Image<byte>& mask)
00096   {
00097     /* color-based target segmentation:
00098 
00099        (1) scale rgb input down by (1 << segmentationScale), e.g. 16
00100        (2) convert to h2sv1 color space
00101        (3) spatially smooth the h1, h2, s, and v maps
00102        (4) find the color values at the foa center
00103        (5) compute a distance map reflecting both the distance in
00104            color space from the foa center as well as the distance in
00105            retinotopic space -- we want to find pixels that have a
00106            similar color to the target and that are also spatially
00107            close to the target
00108        (6) start a flood from the foa center in the distance map
00109            looking for connected pixels whose similarity (inverse
00110            distance) to the target is above some threshold
00111        (7) the foa is smallest rectangular bounding box that contains
00112            the flooded pixels, and optionally constrain the foa to
00113            given min/max dimensions
00114     */
00115 
00116     const ImageSet<PixRGB<byte> > pyr =
00117       buildPyrLocalAvg2x2(rgbin, segmentationScale+1);
00118 
00119     Image<PixH2SV1<float> > h2sv1(pyr[segmentationScale]);
00120     Image<float> h1 = lowPass9(getPixelComponentImage(h2sv1, 0));
00121     Image<float> h2 = lowPass9(getPixelComponentImage(h2sv1, 1));
00122     Image<float> s = lowPass9(getPixelComponentImage(h2sv1, 2));
00123     Image<float> v = lowPass9(getPixelComponentImage(h2sv1, 3));
00124 
00125     const PixH2SV1<float> target(h1.getVal(foacenter),
00126                                  h2.getVal(foacenter),
00127                                  s.getVal(foacenter),
00128                                  v.getVal(foacenter));
00129     distmap = Image<float>(h2sv1.getDims(), NO_INIT);
00130 
00131     Image<PixH2SV1<float> >::const_iterator ptr = h2sv1.begin();
00132     Image<float>::iterator bptr = distmap.beginw();
00133 
00134     Point2D<int> p;
00135     for (p.j = 0; p.j < distmap.getHeight(); ++p.j)
00136       for (p.i = 0; p.i < distmap.getWidth(); ++p.i)
00137         {
00138           const float dist = p.distance(foacenter) / 15.0;
00139           *bptr =
00140             0.2 * exp(-dist*dist)
00141             +
00142             0.8 * exp(-sqrt(0.3 * squareOf(ptr->p[0] - target.p[0])
00143                             +
00144                             0.3 * squareOf(ptr->p[1] - target.p[1])
00145                             +
00146                             0.3 * squareOf(ptr->p[2] - target.p[2])
00147                             +
00148                             0.1 * squareOf(ptr->p[3] - target.p[3])
00149                             ));
00150 
00151           ++bptr;
00152           ++ptr;
00153         }
00154 
00155     distmap = lowPass9(distmap);
00156 
00157     float mi, ma, avg; getMinMaxAvg(distmap, mi, ma, avg);
00158 
00159     const float thresh = avg + segmentationThresh * (ma - avg);
00160 
00161     mask = Image<byte>(distmap.getDims(), ZEROS);
00162 
00163     std::vector<Point2D<int> > pts;
00164     pts.push_back(foacenter);
00165     mask[foacenter] = 255;
00166 
00167 #if 0
00168     const Point2D<int> offsets[8] =
00169       {
00170         Point2D<int>(-1, -1), Point2D<int>(0, -1), Point2D<int>(1, -1),
00171         Point2D<int>(-1,  0),                 Point2D<int>(1,  0),
00172         Point2D<int>(-1,  1), Point2D<int>(0,  1), Point2D<int>(1,  1)
00173       };
00174 #endif
00175 
00176     const Point2D<int> offsets[4] =
00177       {
00178         Point2D<int>(0, -1),
00179         Point2D<int>(-1,  0), Point2D<int>(1,  0),
00180         Point2D<int>(0,  1),
00181       };
00182 
00183     int left = foacenter.i, top = foacenter.j, right = foacenter.i, bottom = foacenter.j;
00184 
00185     while (pts.size() > 0)
00186       {
00187         const Point2D<int> p = pts.back();
00188         pts.pop_back();
00189 
00190         if      (p.i < left) left = p.i;
00191         else if (p.i > right) right = p.i;
00192         if      (p.j < top) top = p.j;
00193         else if (p.j > bottom) bottom = p.j;
00194 
00195         for (size_t i = 0; i < sizeof(offsets) / sizeof(offsets[0]); ++i)
00196           if (distmap.coordsOk(p+offsets[i]) &&
00197               distmap[p+offsets[i]] >= thresh &&
00198               mask[p+offsets[i]] == 0)
00199             {
00200               pts.push_back(p+offsets[i]);
00201               mask[p+offsets[i]] = 255;
00202             }
00203       }
00204 
00205     ASSERT(left >= 0);
00206     ASSERT(right < mask.getWidth());
00207     ASSERT(top >= 0);
00208     ASSERT(bottom < mask.getHeight());
00209 
00210     const Rectangle rawfoa =
00211        Rectangle::tlbrO(top << segmentationScale,
00212                         left << segmentationScale,
00213                         (bottom + 1) << segmentationScale,
00214                         (right + 1) << segmentationScale);
00215 
00216     return constrainRect(rawfoa, rgbin.getBounds(),
00217                          foaminsize, foamaxsize);
00218   }
00219 }
00220 
00221 // ######################################################################
00222 EnvSegmenterColorRegion::EnvSegmenterColorRegion(OptionManager& mgr)
00223   :
00224   EnvSegmenter(mgr, "Embeddable Color-Region FOA Segmenter", "EnvSegmenterColorRegion"),
00225   itsDynamicFoa(&OPT_EseDynamicFoa, this, ALLOW_ONLINE_CHANGES),
00226   itsFoaSize(&OPT_EseFoaSize, this, ALLOW_ONLINE_CHANGES),
00227   itsFoaMinSize(&OPT_EseDynamicFoaMinSize, this, ALLOW_ONLINE_CHANGES),
00228   itsFoaMaxSize(&OPT_EseDynamicFoaMaxSize, this, ALLOW_ONLINE_CHANGES),
00229   itsSegmentationThresh(&OPT_EseSegmentationThresh, this, ALLOW_ONLINE_CHANGES),
00230   itsSegmentationScale(&OPT_EseSegmentationScale, this, ALLOW_ONLINE_CHANGES)
00231 {}
00232 
00233 // ######################################################################
00234 EnvSegmenterColorRegion::~EnvSegmenterColorRegion()
00235 {}
00236 
00237 // ######################################################################
00238 void EnvSegmenterColorRegion::paramChanged(ModelParamBase* const param,
00239                                      const bool valueChanged,
00240                                      ParamClient::ChangeStatus* status)
00241 {
00242   EnvSegmenter::paramChanged(param, valueChanged, status);
00243 
00244   if (param == &itsDynamicFoa)
00245     {
00246       const bool dyn = itsDynamicFoa.getVal();
00247 
00248       itsFoaSize.setInactive(dyn);
00249       itsFoaMinSize.setInactive(!dyn);
00250       itsFoaMaxSize.setInactive(!dyn);
00251       itsSegmentationThresh.setInactive(!dyn);
00252     }
00253   else if (param == &itsFoaSize)
00254     {
00255       if (itsFoaSize.getVal() < 16)
00256         *status = ParamClient::CHANGE_REJECTED;
00257     }
00258   else if (param == &itsFoaMinSize)
00259     {
00260       if (itsFoaMinSize.getVal() < 16)
00261         *status = ParamClient::CHANGE_REJECTED;
00262     }
00263   else if (param == &itsFoaMaxSize)
00264     {
00265       if (itsFoaMaxSize.getVal() < itsFoaMinSize.getVal())
00266         *status = ParamClient::CHANGE_REJECTED;
00267     }
00268   else if (param == &itsSegmentationScale)
00269     {
00270       if (itsSegmentationScale.getVal() > 8)
00271         *status = ParamClient::CHANGE_REJECTED;
00272     }
00273 }
00274 
00275 // ######################################################################
00276 Rectangle EnvSegmenterColorRegion::getFoa(const Image<PixRGB<byte> >& rgbin,
00277                                const Point2D<int>& center,
00278                                Image<byte>* foamask,
00279                                Image<PixRGB<byte> >* segmentdisp) const
00280 {
00281   *foamask = Image<byte>();
00282   *segmentdisp = Image<PixRGB<byte> >();
00283 
00284   if (itsDynamicFoa.getVal())
00285     {
00286       const int seg_zoom = (1 << itsSegmentationScale.getVal());
00287 
00288       const Point2D<int> seg_scaled_maxpos = center / seg_zoom;
00289 
00290       Image<float> distmap;
00291       const Rectangle foa =
00292         segmentColor(rgbin, seg_scaled_maxpos,
00293                      itsSegmentationScale.getVal(),
00294                      itsSegmentationThresh.getVal(),
00295                      itsFoaMinSize.getVal(),
00296                      itsFoaMaxSize.getVal(),
00297                      distmap, *foamask);
00298 
00299       *segmentdisp = normalizeFloat(distmap, FLOAT_NORM_0_255);
00300 
00301       return foa;
00302     }
00303   else
00304     {
00305       Point2D<int> foatopleft = center - itsFoaSize.getVal()/2;
00306       foatopleft.clampToDims(rgbin.getDims());
00307 
00308       const Rectangle foa =
00309         Rectangle(foatopleft, Dims(itsFoaSize.getVal(), itsFoaSize.getVal()))
00310         .getOverlap(rgbin.getBounds());
00311 
00312       return foa;
00313     }
00314 }
00315 
00316 // ######################################################################
00317 /* So things look consistent in everyone's emacs... */
00318 /* Local Variables: */
00319 /* mode: c++ */
00320 /* indent-tabs-mode: nil */
00321 /* End: */
00322 
00323 #endif // NEURO_ENVSEGMENTERCOLORREGION_C_DEFINED
Generated on Sun May 8 08:05:24 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3