SuperPixel.H

00001 /*!@file Gist/test-SuperPixel.C testing SuperPixel segmentation algorithm */
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu>
00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Gist/SuperPixel.H $
00034 // $Id: SuperPixel.H 14762 2011-05-03 01:13:16Z siagian $
00035 //
00036 //////////////////////////////////////////////////////////////////////////
00037 //
00038 // Implementation of the segmentation algorithm described in:
00039 //
00040 // Efficient Graph-Based Image Segmentation
00041 // Pedro F. Felzenszwalb and Daniel P. Huttenlocher
00042 // International Journal of Computer Vision, 59(2) September 2004.
00043 // Copyright (C) 2006 Pedro Felzenszwalb
00044 
00045 #ifndef SUPERPIXEL_SEGMENT_IMAGE
00046 #define SUPERPIXEL_SEGMENT_IMAGE
00047 
00048 #include <cstdlib>
00049 
00050 #include "Image/Image.H"
00051 #include "Image/Pixels.H"
00052 #include "Raster/Raster.H"
00053 #include "Image/MathOps.H"
00054 #include "Image/ColorOps.H"
00055 
00056 #include "Gist/SuperPixel_filter.H"
00057 #include "Gist/SuperPixel_segment_graph.H"
00058 
00059 #include "Util/Timer.H"
00060 
00061 // random color
00062 PixRGB<byte> random_rgb(){ 
00063   PixRGB<byte> c((byte)random(),
00064                  (byte)random(),
00065                  (byte)random());
00066   return c;
00067 }
00068 
00069 // dissimilarity measure between pixels
00070 static inline float 
00071 diff(Image<float> r, Image<float> g, Image<float> b,
00072      int x1, int y1, int x2, int y2) 
00073 {
00074   return sqrt(pow(r.getVal(x1, y1) - r.getVal(x2, y2), 2.0) +
00075               pow(g.getVal(x1, y1) - g.getVal(x2, y2), 2.0) +
00076               pow(b.getVal(x1, y1) - b.getVal(x2, y2), 2.0));
00077 }
00078 // dissimilarity measure between pixels
00079 static inline float 
00080 diff(std::vector<Image<float> > channels,
00081      int x1, int y1, int x2, int y2) 
00082 {
00083   float difference = 0.0;
00084   std::vector<Image<float> >::iterator 
00085     it = channels.begin(), 
00086     stop = channels.end();
00087   for (;it!=stop; ++it) 
00088     {
00089       Image<float> ch = *it;
00090       difference+= pow(ch.getVal(x1, y1) - ch.getVal(x2, y2), 2.0) ;
00091     }
00092   
00093   return sqrt(difference);
00094 }
00095 
00096 
00097 
00098 //! Segment an image using Super Pixel Segmentation.
00099 /*!
00100  * Returns an integer image where the value at each pixel denotes the
00101  * group it belongs to.  Additionally, if a groups vector is supplied,
00102  * it will be filled with vectors of points belonging to each group.
00103  *
00104  * \param im image to segment.
00105  * \param sigma to smooth the image.
00106  * \param c constant for treshold function.
00107  * \param min_size minimum component size (enforced by post-processing stage).
00108  * \param num_ccs number of connected components in the segmentation.
00109  * \param channels :instead use default RGB channels, it takes all channels as graph base 
00110  *
00111  */
00112 
00113 // ######################################################################
00114 Image<int> SuperPixelSegment
00115 (Image<PixRGB<byte> > im, 
00116  float sigma, float c, int min_size, int &num_ccs, 
00117  std::vector<std::vector<Point2D<int> > > *groups , 
00118  std::vector<Image<float> > channels )
00119 {
00120   //smooth out each channel
00121   std::vector<Image<float> > smooth_channels;
00122   std::vector<Image<float> >::iterator 
00123     it = channels.begin(), 
00124     stop = channels.end();
00125   for (;it!=stop; ++it) {
00126           Image<float> ch = *it;
00127           Image<float> smooth_temp = smooth(ch, sigma);
00128           smooth_channels.push_back(smooth_temp);
00129   }
00130  
00131   int width  = im.getWidth();
00132   int height = im.getHeight();
00133 
00134   // build graph
00135   edge *edges = new edge[width*height*4];
00136   int num = 0;
00137   for (int y = 0; y < height; y++) {
00138     for (int x = 0; x < width; x++) {
00139       if (x < width-1) {
00140         edges[num].a = y * width + x;
00141         edges[num].b = y * width + (x+1);
00142         edges[num].w = diff(smooth_channels, x, y, x+1, y);
00143         num++;
00144       }
00145 
00146       if (y < height-1) {
00147         edges[num].a = y * width + x;
00148         edges[num].b = (y+1) * width + x;
00149         edges[num].w = diff(smooth_channels, x, y, x, y+1);
00150         num++;
00151       }
00152 
00153       if ((x < width-1) && (y < height-1)) {
00154         edges[num].a = y * width + x;
00155         edges[num].b = (y+1) * width + (x+1);
00156         edges[num].w = diff(smooth_channels, x, y, x+1, y+1);
00157         num++;
00158       }
00159 
00160       if ((x < width-1) && (y > 0)) {
00161         edges[num].a = y * width + x;
00162         edges[num].b = (y-1) * width + (x+1);
00163         edges[num].w = diff(smooth_channels, x, y, x+1, y-1);
00164         num++;
00165       }
00166     }
00167   }
00168 
00169   // segment
00170   universe *u = segment_graph(width*height, num, edges, c);
00171 
00172   // post process small components
00173   for (int i = 0; i < num; i++) {
00174     int a = u->find(edges[i].a);
00175     int b = u->find(edges[i].b);
00176     if ((a != b) && ((u->size(a) < min_size) || (u->size(b) < min_size)))
00177       u->join(a, b);
00178   }
00179   delete [] edges;
00180   num_ccs = u->num_sets();
00181 
00182   Image<int> groupImage(width, height, NO_INIT);
00183 
00184   // If a group vector is provided, then let's resize it and fill it along
00185   // with the output image
00186   groups->resize(u->num_sets());
00187   
00188   // The group numbers created by the algorithm are more or less random. We
00189   // need to compress them so we can easily insert the group points into
00190   // vectors.
00191   std::map<int, int> groupLabels; 
00192   int labelCount = 0;
00193   
00194   for (int y = 0; y < height; y++) 
00195     for (int x = 0; x < width; x++) 
00196       {
00197         int groupUnorderedId = u->find(y * width + x);
00198         
00199         // If we haven't seen this group before, 
00200         // create a new ordered label for it
00201         if(groupLabels.find(groupUnorderedId) == groupLabels.end())
00202           groupLabels[groupUnorderedId] = labelCount++;
00203         
00204         int groupOrderedId = groupLabels[groupUnorderedId];
00205         
00206         if(groups != NULL)
00207           (*groups)[groupOrderedId].push_back(Point2D<int>(x,y));
00208         groupImage.setVal(x, y, groupOrderedId);
00209       }
00210   
00211   delete u;
00212   
00213   return groupImage;
00214 }
00215 
00216 // ######################################################################
00217 Image<int> SuperPixelSegment
00218 (Image<PixRGB<byte> > im, 
00219  float sigma, float c, int min_size, int &num_ccs, 
00220  std::vector<std::vector<Point2D<int> > > *groups)
00221 {
00222   Image<byte> r, g, b; getComponents(im, r, g, b);
00223 
00224   std::vector<Image<float> > channels;
00225   channels.push_back(r);        
00226   channels.push_back(g);        
00227   channels.push_back(b);        
00228 
00229   return SuperPixelSegment
00230     (im,sigma,c,min_size,num_ccs,groups,channels);
00231 }
00232 
00233 // ######################################################################
00234 namespace
00235 { std::vector<PixRGB<byte> > groupColors; }
00236 
00237 // ######################################################################
00238 Image<int> SuperPixelRegionSizeImage 
00239 (std::vector<std::vector<Point2D<int> > > const& groups, Image<int> groupImage)
00240 {
00241         Image<int> debugSizeImage(groupImage.getDims(), NO_INIT);
00242 
00243   for(size_t grpIdx=0; grpIdx < groups.size(); grpIdx++)
00244   {
00245     int regionSize =  (int) groups[grpIdx].size();
00246     for(size_t pntIdx=0; pntIdx<groups[grpIdx].size(); pntIdx++)
00247       debugSizeImage.setVal(groups[grpIdx][pntIdx], regionSize);
00248   }
00249   
00250   return debugSizeImage;
00251 }
00252 
00253 // ######################################################################
00254 Image<PixRGB<byte> > SuperPixelDebugImage(Image<int> groupImage)
00255 {
00256   // pick random colors for each component
00257   if(groupColors.size() == 0)
00258     {
00259       groupColors.resize(255);
00260       std::vector<PixRGB<byte> >::iterator 
00261         it = groupColors.begin(), 
00262         stop = groupColors.end();
00263       for (;it!=stop; ++it) *it = random_rgb();
00264     }
00265   
00266   Image<PixRGB<byte> > debugImage(groupImage.getDims(), NO_INIT);
00267   
00268   for(size_t i=0; i<groupImage.size(); ++i)
00269     debugImage.setVal
00270       (i,groupColors[groupImage.getVal(i)%groupColors.size()]);
00271   
00272   return debugImage;
00273 }
00274 
00275 // ######################################################################
00276 Image<PixRGB<byte> > SuperPixelDebugImage
00277 (std::vector<std::vector<Point2D<int> > > const& groups, 
00278  Image<PixRGB<byte> > originalImage)
00279 {
00280   Image<PixRGB<byte> > debugImage(originalImage.getDims(), NO_INIT);
00281   
00282   for(size_t grpIdx=0; grpIdx < groups.size(); grpIdx++)
00283   {
00284     PixRGB<long> avgColor(0,0,0);
00285     for(size_t pntIdx=0; pntIdx<groups[grpIdx].size(); pntIdx++)
00286       avgColor += originalImage.getVal(groups[grpIdx][pntIdx]);
00287     avgColor /= groups[grpIdx].size();
00288     for(size_t pntIdx=0; pntIdx<groups[grpIdx].size(); pntIdx++)
00289       debugImage.setVal(groups[grpIdx][pntIdx], avgColor);
00290   }
00291   
00292   return debugImage;
00293 }
00294 
00295 /*
00296  * Segment an image
00297  *
00298  * Returns a color image representing the segmentation.
00299  *
00300  * im: image to segment.
00301  * sigma: to smooth the image.
00302  * c: constant for treshold function.
00303  * min_size: minimum component size (enforced by post-processing stage).
00304  * num_ccs: number of connected components in the segmentation.
00305 
00306 
00307  :::::NOTE::::: This method is now deprecated. 
00308  Please use SuperPixelSegment, and SuperPixelDebugImage instead.
00309 
00310  */
00311 // ######################################################################
00312 Image<PixRGB<byte> > segment_image
00313 (Image<PixRGB<byte> > im, float sigma, float c, int min_size,
00314  int &num_ccs)
00315 {
00316         LINFO("This method is now deprecated. "
00317               "Please use SuperPixelSegment "
00318               "and SuperPixelDebugImage instead.");
00319         std::vector<std::vector<Point2D<int> > > groups;
00320         Image<int> groupImage = 
00321           SuperPixelSegment
00322           (im, sigma, c, min_size, num_ccs, &groups);
00323         return SuperPixelDebugImage(groups,im);
00324 }
00325 
00326 #endif
00327 
00328 // ######################################################################
00329 /* So things look consistent in everyone's emacs... */
00330 /* Local Variables: */
00331 /* indent-tabs-mode: nil */
00332 /* End: */
Generated on Sun May 8 08:40:39 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3