SalientRegionSegmenter.C

Go to the documentation of this file.
00001 /*!@file Gist/SalientRegionSegmenter.C segment out object depicted by the
00002 salient point. Here we use both region growing and boundary detection
00003  */
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Gist/SalientRegionSegmenter.C $
00036 // $Id: $
00037 //
00038 //////////////////////////////////////////////////////////////////////////
00039 
00040 #include "Gist/SalientRegionSegmenter.H"
00041 
00042 #include "Image/CutPaste.H"     // for inplacePaste()
00043 #include "Image/DrawOps.H"
00044 #include "Image/ColorOps.H"
00045 #include "Image/ShapeOps.H"
00046 #include "Image/Kernels.H"
00047 #include  <cstdio>
00048 
00049 #define MINIMUM_CONTOUR_LENGTH     5
00050 
00051 #define LEN_WEIGHT               .20 // contour boundary length weight
00052 #define SIM_WEIGHT               .20 // similarity with closer side weight 
00053 #define STR_WEIGHT               .20 // strength of boundary weight
00054 #define RAT_WEIGHT               .20 // ratio of in:out weight
00055 #define DIS_WEIGHT               .20 // distance between sal pt and segment
00056 
00057 #define NEIGHBORHOOD_RADIUS       12
00058 //#define NEIGHBORHOOD_RADIUS        8
00059 #define MAX_FAR_TO_NEAR_RATIO    5.0
00060 #define MAX_DISTANCE             .25 // quarter of the diagonal
00061 
00062 #define NUM_CHANNELS               3 // current number of channels   
00063 #define NUM_L_BINS                25 // # bins for L component of CIELab
00064 #define NUM_A_BINS                25 // # bins for a component of CIELab
00065 #define NUM_B_BINS                25 // # bins for b component of CIELab
00066 #define NUM_HISTOGRAM_DIMS        75 // current total number of bins
00067 
00068 #define UNVISITED_REGION           0 // unvisited mean, just looked at
00069                                      // for the first time 
00070 #define CENTER_REGION              1
00071 #define CENTER_CORE_REGION         2
00072 #define SURROUND_REGION            3
00073 #define UNASSIGNED_REGION          4
00074 #define OTHER_OBJECT_REGION        5 
00075 
00076 #define CLOSER_SIDE                1
00077 #define FAR_SIDE                   2
00078 
00079 // ######################################################################
00080 // ######################################################################
00081 
00082 // ######################################################################
00083 SalientRegionSegmenter::SalientRegionSegmenter()
00084 :
00085 itsContourBoundaryDetector(new ContourBoundaryDetector())
00086 {
00087   itsWin.reset();
00088 
00089   // These color features are inspired by Martin, PAMI 2004 pb paper
00090   float bg_smooth_sigma    = 0.1;       // bg histogram smoothing sigma
00091   float cg_smooth_sigma    = 0.05;      // cg histogram smoothing sigma
00092 
00093   itsLKernel = 
00094     gaussian<float>(1.0F, NUM_L_BINS*bg_smooth_sigma, 
00095                     int(3.0F*NUM_L_BINS*bg_smooth_sigma + 0.5F));
00096   itsAKernel = 
00097     gaussian<float>(1.0F, NUM_A_BINS*cg_smooth_sigma, 
00098                     int(3.0F*NUM_A_BINS*cg_smooth_sigma + 0.5F));
00099   itsBKernel = 
00100     gaussian<float>(1.0F, NUM_B_BINS*cg_smooth_sigma, 
00101                     int(3.0F*NUM_B_BINS*cg_smooth_sigma + 0.5F));
00102 
00103   float suml = sum(itsLKernel); itsLKernel = itsLKernel/suml;
00104   float suma = sum(itsAKernel); itsAKernel = itsAKernel/suma;
00105   float sumb = sum(itsBKernel); itsBKernel = itsBKernel/sumb;
00106 
00107   // LINFO("check kernels");
00108 
00109   // for(int i = 0; i < itsLKernel.getWidth(); i++)
00110   //   {
00111   //     for(int j = 0; j < itsLKernel.getHeight(); j++)
00112   //       printf("%10.3f ", itsLKernel.getVal(i,j));
00113   //     printf("\n");
00114   //   }
00115   // Raster::waitForKey();
00116 
00117   // for(int i = 0; i < aKernel.getWidth(); i++)
00118   //   {
00119   //     for(int j = 0; j < aKernel.getHeight(); j++)
00120   //       printf("%10.3f ", aKernel.getVal(i,j));
00121   //     printf("\n");
00122   //   }
00123   // Raster::waitForKey();
00124 
00125   // for(int i = 0; i < bKernel.getWidth(); i++)
00126   //   {
00127   //     for(int j = 0; j < bKernel.getHeight(); j++)
00128   //       printf("%10.3f ", bKernel.getVal(i,j));
00129   //     printf("\n");
00130   //   }
00131   // Raster::waitForKey();
00132 }
00133 
00134 // ######################################################################
00135 SalientRegionSegmenter::~SalientRegionSegmenter()
00136 { }
00137 
00138 // ######################################################################
00139 void SalientRegionSegmenter::setImage(Image<PixRGB<byte> > image)
00140 { 
00141   // reset everything
00142   itsSalientPoints.clear();
00143 
00144   itsImage = image;
00145 
00146   // this is the feature histogram in Martin's pb PAMI 2004
00147   setImageFeatureHistogramValues();
00148 
00149   uint w = itsImage.getWidth();
00150   uint h = itsImage.getHeight();
00151 
00152   if(itsWin.is_invalid())
00153     itsWin.reset(new XWinManaged(Dims(4*w,2*h), 0, 0, 
00154                                  "SalReg Segmenter"));
00155   else itsWin->setDims(Dims(4*w,2*h));
00156 
00157   // calculate the contour boundary and region map
00158   computeBoundaryAndRegionInformation();
00159 
00160   // keep track of what histograms has been computed
00161   uint hstep = BOUNDARY_STEP_SIZE/2;
00162   uint wG = (w-hstep)/BOUNDARY_STEP_SIZE;
00163   uint hG = (h-hstep)/BOUNDARY_STEP_SIZE;
00164   itsComputedHistograms = 
00165     Image<rutz::shared_ptr<Histogram> >(wG, hG, ZEROS);
00166 }
00167 
00168 // ######################################################################
00169 void SalientRegionSegmenter::setImageFeatureHistogramValues()
00170 {
00171   // convert to CIElab color space
00172   Image<float> lImg; 
00173   Image<float> aImg;
00174   Image<float> bImg;
00175   getNormalizedLAB(itsImage, lImg, aImg, bImg);
00176   
00177   // convert to bin numbers
00178   itsImageHistogramEntries.clear();
00179   itsImageHistogramEntries.push_back(quantize_values(lImg, NUM_L_BINS));
00180   itsImageHistogramEntries.push_back(quantize_values(aImg, NUM_A_BINS));
00181   itsImageHistogramEntries.push_back(quantize_values(bImg, NUM_B_BINS));
00182 
00183   // uint w = itsImage.getWidth();
00184   // uint h = itsImage.getHeight();
00185   // for(uint i = 0; i < w; i++)
00186   //   for(uint j = 0; j < h; j++)
00187   //     {
00188   //       if(lImg.getVal(i,j) > 1.0) LINFO("limg: %3d %3d", i,j);
00189   //       if(aImg.getVal(i,j) > 1.0) LINFO("aimg: %3d %3d", i,j);
00190   //       if(bImg.getVal(i,j) > 1.0) LINFO("bimg: %3d %3d", i,j);
00191   //     }
00192 }
00193 
00194 // ######################################################################
00195 Image<int> SalientRegionSegmenter::quantize_values
00196 (Image<float> image, int num_bins, bool normalize)
00197 {
00198   // FIXXX: May want to move to MathOps later
00199   // if(normalize)
00200   //   inplaceNormalize(image, 0.0F, 1.0F);
00201 
00202   uint w = itsImage.getWidth();
00203   uint h = itsImage.getHeight();
00204   Image<int> result(w,h,NO_INIT);
00205 
00206   Image<float>::iterator iptr = image.beginw();  
00207 
00208   Image<int>::iterator aptr = result.beginw(), stop = result.endw();  
00209   float nbins = num_bins;
00210   while(aptr != stop)
00211     {
00212       float in = *iptr++;
00213 
00214       // bins will be 0 to num_bins-1
00215       int bin = int(in*nbins);
00216       if(bin == num_bins) bin = num_bins - 1;
00217       *aptr++ = bin;
00218 
00219       //LINFO("val: %f --> bin: %d", in, bin);
00220     }
00221 
00222   return result;
00223 }
00224 
00225 // ######################################################################
00226 void SalientRegionSegmenter::computeBoundaryAndRegionInformation()
00227 {
00228   computeBoundaryInformation(); 
00229   computeRegionInformation(); 
00230 
00231   displayBoundaryAndRegionInformation();
00232 }
00233 
00234 // ######################################################################
00235 void SalientRegionSegmenter::computeBoundaryInformation()
00236 {
00237   // compute contour boundary map
00238   Timer timer(1000000); timer.reset();
00239   itsContourBoundaryDetector->computeContourBoundary(itsImage);
00240   LINFO("time: %f ms", timer.get()/1000.0);
00241 
00242   itsContourBoundaries = 
00243     itsContourBoundaryDetector->getContourBoundaries();
00244 
00245   float maxVal = 0.0; 
00246   for(uint i = 0; i < itsContourBoundaries.size(); i++)
00247     {
00248       rutz::shared_ptr<Contour> contour = 
00249         itsContourBoundaries[i];
00250       
00251       // go through each contour
00252       uint cLen = contour->edgels.size();
00253       for(uint j = 0; j < cLen; j++)
00254         {
00255           float val = contour->edgels[j]->val;
00256           if(maxVal < val) maxVal = val;
00257         }
00258     }
00259 
00260   itsMaximumEdgelStrength = maxVal;
00261 }
00262 
00263 // ######################################################################
00264 void SalientRegionSegmenter::computeRegionInformation()
00265 {
00266   // default parameters for the graph-based segmentation
00267   // NOTE: in original Felzenswalb-Huttenlocher paper: 
00268   // k = 500 --> here k = 25 create over-segmented object
00269   float sigma = .5; uint k = 25; uint min_size = 20; int num_ccs;
00270 
00271   itsInitialRegionImage = 
00272     SuperPixelSegment
00273     (itsImage, sigma, k, min_size, num_ccs, &itsInitialRegions);
00274 
00275   itsInitialRegionColorImage = 
00276     SuperPixelDebugImage(itsInitialRegions, itsImage);
00277  
00278   itsRegionAdjecencyList = getRegionAdjecencyList(); 
00279   //  displayRegionAdjecencyList();
00280 }
00281 
00282 // ######################################################################
00283 std::vector<std::vector<uint> > 
00284 SalientRegionSegmenter::getRegionAdjecencyList()
00285 {
00286   uint nRegions = itsInitialRegions.size();
00287   std::vector<std::vector<uint> >  adjList(nRegions);
00288   for(uint i = 0; i < nRegions; i++)
00289     adjList[i] = std::vector<uint>();
00290 
00291   // find regions:
00292   // FIXXX: there may be a better way
00293 
00294   // check out all the 
00295   for(uint i = 0; i < nRegions; i++)
00296     {
00297       for(uint j = 0; j < itsInitialRegions[i].size(); j++)
00298         {          
00299           Point2D<int> pt = itsInitialRegions[i][j];          
00300           uint label = i;
00301 
00302           for(int di = -1; di <= 1; di++)
00303             {
00304               for(int dj = -1; dj <= -1; dj++)
00305                 {
00306                   Point2D<int> dpt(di,dj);
00307                   Point2D<int> pt2 = pt + dpt;
00308                   if(!(di == 0 && dj == 0) &&  
00309                      itsInitialRegionImage.coordsOk(pt2))
00310                     {
00311                       //if the neighbor is different
00312                       uint label2 = itsInitialRegionImage.getVal(pt2);
00313 
00314                       // check if the label is already 
00315                       // in the adjecency list
00316                       if(label != label2)
00317                         {
00318                           bool in = false;
00319                           for(uint l = 0; l < adjList[i].size(); l++)
00320                             {
00321                               if(adjList[i][l] == label2) 
00322                                 { in = true; l = adjList[i].size(); }
00323                             }
00324                           if(!in) adjList[i].push_back(label2);
00325                         }
00326                     }
00327                 }
00328             }
00329         }
00330     }  
00331   return adjList;
00332 }
00333 
00334 // ######################################################################
00335 void SalientRegionSegmenter::displayRegionAdjecencyList()
00336 {
00337   // display stuff
00338   Image<PixRGB<byte> > ima = itsImage;
00339 
00340   Image<float> fIma(luminance(ima));
00341   Image<float> tempFIma = fIma;
00342   inplaceNormalize(tempFIma, 0.0f,255.0f);  
00343   Image<byte>  bIma(tempFIma); 
00344 
00345   // get non-max suppressed boundary map image
00346   float mVal = 32;
00347   float bVal = 255 - mVal;
00348 
00349   Image<byte> dImaR, dImaG, dImaB;
00350   getComponents(ima, dImaR, dImaG, dImaB);
00351   inplaceNormalize(dImaR, byte(0), byte(mVal));
00352   inplaceNormalize(dImaG, byte(0), byte(mVal));
00353   inplaceNormalize(dImaB, byte(0), byte(mVal));
00354   Image<PixRGB<byte> > dIma  = makeRGB(dImaR,dImaG,dImaB);
00355 
00356   uint w = ima.getWidth();
00357   uint h = ima.getHeight();
00358   Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS);
00359 
00360   inplacePaste (dispIma, ima, Point2D<int>(0,0));
00361 
00362   uint nRegions = itsInitialRegions.size();
00363   for(uint i = 0; i < nRegions; i++)
00364     {     
00365       LINFO("region: %d (%d pix): has %d neighbors", 
00366             i, int(itsInitialRegions[i].size()), 
00367             int(itsRegionAdjecencyList[i].size()));
00368       Image<float> regionMap(w,h, ZEROS);
00369       
00370       for(uint j = 0; j < itsInitialRegions[i].size(); j++)
00371         {
00372           Point2D<int> pt = itsInitialRegions[i][j]; 
00373           regionMap.setVal(pt, 1.0);
00374 
00375           //LINFO("  pt[%3d]: %3d %3d ", j, pt.i, pt.j);
00376         }
00377 
00378       for(uint j = 0; j < itsRegionAdjecencyList[i].size(); j++)
00379         {
00380           uint label = itsRegionAdjecencyList[i][j];
00381           LINFO("  [%3d] label: %d has: %d pixels", 
00382                 j, label,  int(itsInitialRegions[label].size()));
00383           float randVal = rand()/(RAND_MAX+1.0);
00384           for(uint k = 0; k < itsInitialRegions[label].size(); k++)
00385             {
00386               Point2D<int> ptNeighbor = itsInitialRegions[label][k]; 
00387               regionMap.setVal(ptNeighbor, randVal);
00388               //LINFO("  pt[%3d]: %3d %3d ", j, ptNeighbor.i, ptNeighbor.j);
00389             }
00390         }
00391       
00392       inplaceNormalize(regionMap, 0.0f,bVal);
00393       Image<byte> dBmapc(regionMap);
00394       Image<PixRGB<byte> > dBmap = toRGB(dBmapc);
00395   
00396       inplacePaste
00397         (dispIma, Image<PixRGB<byte> >(dIma+dBmap), Point2D<int>(w,0));
00398 
00399       itsWin->drawImage(dispIma, 0,0);
00400 
00401       Raster::waitForKey();
00402     }
00403 }
00404 
00405 
00406 // ######################################################################
00407 void SalientRegionSegmenter::displayBoundaryAndRegionInformation()
00408 {
00409   // display stuff
00410   Image<PixRGB<byte> > ima = itsImage;
00411   uint w = ima.getWidth();
00412   uint h = ima.getHeight();
00413 
00414   Image<float> fIma(luminance(ima));
00415   Image<float> tempFIma = fIma;
00416   inplaceNormalize(tempFIma, 0.0f,255.0f);  
00417   Image<byte>  bIma(tempFIma); 
00418 
00419   // get non-max suppressed boundary map image
00420   float mVal = 32;
00421   float bVal = 255 - mVal;
00422   Image<byte> dImaR, dImaG, dImaB;
00423   getComponents(ima, dImaR, dImaG, dImaB);
00424   inplaceNormalize(dImaR, byte(0), byte(mVal));
00425   inplaceNormalize(dImaG, byte(0), byte(mVal));
00426   inplaceNormalize(dImaB, byte(0), byte(mVal));
00427   Image<PixRGB<byte> > dIma  = makeRGB(dImaR,dImaG,dImaB);
00428 
00429   Image<float> tboundaryMap = 
00430     itsContourBoundaryDetector->getVarianceRidgeBoundaryMap();
00431   Image<float> boundaryMap = 
00432     clampedDiff(tboundaryMap, Image<float>(w,h,ZEROS));
00433   inplaceNormalize(boundaryMap, 0.0f,bVal);
00434   Image<byte> dBmapc(boundaryMap);
00435   Image<PixRGB<byte> > tdBmap = toRGB(dBmapc);
00436   Image<PixRGB<byte> > dBmap(dIma+tdBmap);
00437   //inplacePaste(dispIma, Image<PixRGB<byte> >(dIma+dBmap), Point2D<int>(w,0));
00438 
00439   // the non-max suppressed boundary map image
00440   Image<float> dBmapNMStemp = 
00441     itsContourBoundaryDetector->getNmsBoundaryMap();
00442   inplaceNormalize(dBmapNMStemp, 0.0F, 255.0F);
00443   Image<PixRGB<byte> > dBmapNMS = 
00444     toRGB(Image<byte>(dBmapNMStemp));
00445 
00446   // the contour boundary edgel map image
00447   Image<float> dCBEmapTemp = 
00448     itsContourBoundaryDetector->getEdgelBoundaryMap();
00449   inplaceNormalize(dCBEmapTemp, 0.0F, bVal);
00450   Image<PixRGB<byte> > tdCBEmap = 
00451     toRGB(Image<byte>(dCBEmapTemp));
00452   Image<PixRGB<byte> > dCBEmap(dIma+tdCBEmap);
00453 
00454   // get the contour boundary map
00455   Image<PixRGB<byte> > dCBmapTemp =
00456     itsContourBoundaryDetector->getContourBoundaryMap();
00457   Image<PixRGB<byte> > dCBmap(dIma+dCBmapTemp);
00458 
00459   // add the receptive field
00460   // 300, 140
00461   //uint cl = 156; uint ct = 68; uint cr = 8;
00462   //uint sl = cl - 4; uint st = ct - 4; uint sr = 16;
00463 
00464   uint cl = 90; uint ct = 14; uint cr = 8;
00465   uint sl = cl - 4; uint st = ct - 4; uint sr = 16;
00466 
00467   // to the image
00468   drawRect(ima,
00469            Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 
00470            PixRGB<byte>(255,0,0));
00471   drawRect(ima,
00472            Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 
00473            PixRGB<byte>(255,255,0));
00474   //Raster::WriteRGB(ima, std::string("starfish_image.png"));
00475 
00476   // to the VRD
00477   drawRect(dBmap,
00478            Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 
00479            PixRGB<byte>(255,0,0));
00480   drawRect(dBmap,
00481            Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 
00482            PixRGB<byte>(255,255,0));
00483   //Raster::WriteRGB(dBmap, std::string("starfish_vrd_image.png"));
00484 
00485   // to the NMS VRD
00486   drawRect(dBmapNMS, 
00487            Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 
00488            PixRGB<byte>(255,0,0));
00489   drawRect(dBmapNMS, 
00490            Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 
00491            PixRGB<byte>(255,255,0));
00492   //Raster::WriteRGB(dBmapNMS, std::string("starfish_nms_vrd_image.png"));
00493 
00494   // to the edgel map
00495   drawRect(dCBEmap,
00496            Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 
00497            PixRGB<byte>(255,0,0));
00498   drawRect(dCBEmap,
00499            Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 
00500            PixRGB<byte>(255,255,0));
00501   //Raster::WriteRGB(dCBEmap, std::string("starfish_cbe_image.png"));
00502   
00503   // to the contour map
00504   drawRect(dCBmap, 
00505            Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 
00506            PixRGB<byte>(255,0,0));
00507   drawRect(dCBmap, 
00508            Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 
00509            PixRGB<byte>(255,255,0));
00510   //Raster::WriteRGB(dCBmap, std::string("starfish_cb_image.png"));
00511 
00512   // setup the display map
00513   Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS);
00514   inplacePaste(dispIma, ima,      Point2D<int>(  0, 0));
00515   inplacePaste(dispIma, dBmap,    Point2D<int>(  w, 0));
00516   inplacePaste(dispIma, dBmapNMS, Point2D<int>(  0, h));
00517   inplacePaste(dispIma, dCBEmap,  Point2D<int>(  w, h));
00518   inplacePaste(dispIma, dCBmap,   Point2D<int>(2*w, 0));
00519   inplacePaste(dispIma, itsInitialRegionColorImage, Point2D<int>(2*w, h));
00520   //Raster::WriteRGB(itsInitialRegionColorImage, 
00521   //                 std::string("starfish_FelzHutt_500.png"));
00522 
00523   itsWin->drawImage(dispIma, 0,0);
00524   Raster::waitForKey();
00525 }
00526 
00527 // ######################################################################
00528 Image<float> SalientRegionSegmenter::getSalientRegion(Point2D<int> pt)
00529 { 
00530   // FIXXX: we may want to move the salient points 
00531   //        away from the contours
00532   //        This may be a problem with the orientation channel  
00533   //        May be scale dependent
00534   // from salient point get most appropriate salient region 
00535   // FIXXX: for orientation saliency the border is salient, 
00536   //        we move the point perpendicular to the area 
00537   //        (pick it randomly or the one with
00538   //        higher average salient energy) We might hit object 
00539   //        or background (it's ok, either way we are going to 
00540   //        reduce the number of unassign region
00541   pt = Point2D<int>(155,37); 
00542   LINFO("\n\n\n\n\n hard coding salient location: %d %d "
00543         "TAKE IT OUT LATER!\n\n\n", pt.i, pt.j);
00544 
00545   // Round it to the closest 8x8 grid location
00546   uint hstep = BOUNDARY_STEP_SIZE/2;
00547   uint i = ((pt.i+hstep)/BOUNDARY_STEP_SIZE) * BOUNDARY_STEP_SIZE; 
00548   uint j = ((pt.j+hstep)/BOUNDARY_STEP_SIZE) * BOUNDARY_STEP_SIZE; 
00549   itsSalientPoints.push_back(Point2D<int>(i,j));
00550 
00551   LINFO("adjusted point: %d %d", i,j);
00552 
00553   // calculate the region first
00554   computeSalientRegion();
00555 
00556   return itsSalientRegionImage;
00557 }
00558 
00559 // ######################################################################
00560 void SalientRegionSegmenter::computeSalientRegion()
00561 { 
00562   // we have original resolution
00563   // and an 8x8 grid overlay resolution
00564   // --> this can be refined later or make MULTISCALE
00565   uint w = itsImage.getWidth();
00566   uint h = itsImage.getHeight();
00567 
00568   uint hstep = BOUNDARY_STEP_SIZE/2;
00569   uint wG = (w-hstep)/BOUNDARY_STEP_SIZE;
00570   uint hG = (h-hstep)/BOUNDARY_STEP_SIZE;
00571 
00572   Point2D<int> currentSalPoint = 
00573     itsSalientPoints[itsSalientPoints.size()-1];
00574   LINFO("START at salient point %d %d", 
00575         currentSalPoint.i, currentSalPoint.j);
00576 
00577   Point2D<int> currentSalPointGrid
00578     (currentSalPoint.i/BOUNDARY_STEP_SIZE, 
00579      currentSalPoint.j/BOUNDARY_STEP_SIZE);
00580  
00581   // assignment map on the grid overlay resolution
00582   Image<int> assignmentMap(wG, hG, ZEROS);
00583 
00584   // the image borders are out of bounds
00585   for(uint i = 0; i < wG; i++) 
00586     {
00587       assignmentMap.setVal(i,0, OTHER_OBJECT_REGION);
00588       assignmentMap.setVal(i,1, OTHER_OBJECT_REGION);
00589     }
00590   for(uint j = 0; j < hG; j++) 
00591     {
00592       assignmentMap.setVal(0,j, OTHER_OBJECT_REGION);
00593       assignmentMap.setVal(1,j, OTHER_OBJECT_REGION);      
00594     }
00595   
00596   for(uint i = 0; i < wG; i++) 
00597     {
00598       if(hG > 0)
00599         assignmentMap.setVal(i,hG-1, OTHER_OBJECT_REGION);
00600       if(hG > 1)
00601         assignmentMap.setVal(i,hG-2, OTHER_OBJECT_REGION);
00602     }
00603   for(uint j = 0; j < hG; j++) 
00604     {
00605       if(wG > 0)
00606         assignmentMap.setVal(0,j, OTHER_OBJECT_REGION);
00607       if(wG > 1)
00608         assignmentMap.setVal(1,j, OTHER_OBJECT_REGION);      
00609     }
00610 
00611   // list of grid nodes that are not yet assigned 
00612   // to either object, background, or unassigned list
00613   std::vector<Point2D<int> > currentObjectLocations;
00614   std::vector<Point2D<int> > currentObjectCoreLocations;
00615   std::vector<Point2D<int> > currentBackgroundLocations;
00616   std::vector<Point2D<int> > currentUnassignedLocations;
00617 
00618   // assignment map on the grid overlay resolution
00619   Image<int> regionAssignmentMap(w, h, ZEROS);
00620 
00621   // list of initial oversegmented regions that are  
00622   // assigned to either object or background
00623   std::vector<int> currentObjectRegionList;
00624   //std::vector<int> currentObjectCoreRegionList;
00625   std::vector<int> currentBackgroundRegionList;
00626   //std::vector<int> currentUnassignedRegionList;
00627 
00628   // add the start region to the core list
00629   currentObjectCoreLocations.push_back(currentSalPointGrid);  
00630   //assignmentMap.setVal(currentSalPointGrid, CENTER_CORE_REGION);
00631 
00632   // create boundary fragments (also call segments): 
00633   //   divide contour to segments of 5 edgels: about 30 - 40 pix long
00634   //   --> only consider contours of 5 edgels or more.
00635   // sort on longest contour, most similar chi-sq, closest, most salient, 
00636   std::list<Segment> sortedSegments = fillSegmentQueue(currentSalPoint);
00637 
00638   // current starting point to grow from
00639   Point2D<int> currPoint     = currentSalPoint;
00640   Point2D<int> currPointGrid = currentSalPointGrid;
00641 
00642   LINFO("START PT: %3d %3d --> %3d %3d", 
00643         currPoint.i, currPoint.j, currPointGrid.i, currPointGrid.j);
00644 
00645   std::vector<std::pair<Segment,Point2D<int> > > segmentPtCombo;
00646 
00647   // add the starting salient point 
00648   // to unassigned list just to start things up
00649   currentUnassignedLocations.push_back(currPointGrid); 
00650   assignmentMap.setVal(currPointGrid, UNASSIGNED_REGION);
00651 
00652   // while there are unassigned locations
00653   // around the growing center group
00654   while(currentUnassignedLocations.size() != 0)
00655     {      
00656       // if no segments qualified -- we break out 
00657       filterSegments(sortedSegments);
00658       if(sortedSegments.size() == 0) break;
00659 
00660       // pick best segment (on metric above)
00661       Segment segment = sortedSegments.front();
00662       sortedSegments.pop_front();
00663 
00664       // make sure we do not repeat the same combo twice
00665       segmentPtCombo.push_back
00666         (std::pair<Segment,Point2D<int> >(segment, currPoint));
00667 
00668       // compute histogram of distribution of points within 12pix
00669       Histogram hist1 = getHistogramDistribution(currPoint);      
00670       
00671       // compute distribution of both side of the boundary 
00672       // closer is pts2, farther is pts3
00673       std::vector<Point2D<int> > pts2;
00674       std::vector<Point2D<int> > pts3;
00675       getSegmentPointDistributions(segment, currPoint, pts2, pts3);
00676       Histogram hist2 = getHistogramDistribution(pts2);
00677       Histogram hist3 = getHistogramDistribution(pts3);
00678       
00679       // compute the Chi-sq difference: this is the threshold for growing
00680       float threshDiff = hist1.getChiSqDiff(hist2);
00681       LINFO("THRESH Diff: %f", threshDiff);
00682 
00683       LINFO("{%3d} %10.3f, %10.3f, %10.3f, %10.3f, %10.3f) = %10.3f", 
00684             segment.orgIndex,
00685             segment.lenVal, segment.simVal, segment.strVal, 
00686             segment.ratVal, segment.disVal, segment.pVal  );
00687 
00688       // grow CENTER in the direction of the boundary 
00689       // to connect the two 
00690       int index = segment.segStartIndex + MINIMUM_CONTOUR_LENGTH/2; 
00691       rutz::shared_ptr<Contour> contour = 
00692         itsContourBoundaries[segment.contourIndex];  
00693       rutz::shared_ptr<Edgel> edgel = contour->edgels[index];
00694       //Point2D<int> segCenterPoint = edgel->pt; 
00695       Point2D<int> segCenterPointGrid
00696         ((edgel->pt.i+hstep)/BOUNDARY_STEP_SIZE,
00697          (edgel->pt.j+hstep)/BOUNDARY_STEP_SIZE );
00698 
00699       std::vector<Point2D<int> > points = 
00700         getLine(currPointGrid, segCenterPointGrid);
00701 
00702       LINFO("segment points");
00703       for(uint i = segment.segStartIndex; i <= segment.segEndIndex; i++) 
00704         {
00705           rutz::shared_ptr<Edgel> tedgel = contour->edgels[i];
00706           Point2D<int> tptGrid
00707             ((tedgel->pt.i+hstep)/BOUNDARY_STEP_SIZE,
00708              (tedgel->pt.j+hstep)/BOUNDARY_STEP_SIZE );
00709            
00710           LINFO("[<<%3d>>] %d %d --> %d %d", 
00711                 i, tptGrid.i, tptGrid.j,
00712                 tedgel->pt.i,tedgel->pt.j);
00713         }
00714 
00715       LINFO("LINE: %3d %3d to %3d %3d", 
00716             currPointGrid.i, currPointGrid.j, 
00717             segCenterPointGrid.i, segCenterPointGrid.j);
00718       for(uint i = 0; i < points.size(); i++)
00719         {
00720           LINFO("[%3d]: %3d %3d", i, points[i].i, points[i].j);          
00721         }
00722 
00723       // go through each starting grow location
00724       Image<bool> isComparedWith(wG, hG, ZEROS);
00725       for(uint i = 0; i < points.size(); i++)
00726         {          
00727           Point2D<int> startPt = points[i];          
00728           LINFO("current starting point: %3d %3d", startPt.i, startPt.j);
00729 
00730           std::vector<Point2D<int> >::iterator culItr = 
00731             currentUnassignedLocations.begin();
00732 
00733           if(assignmentMap.getVal(startPt) == UNVISITED_REGION) 
00734             {
00735               // // find the current starting growing point
00736               // uint pos = 0;
00737               // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
00738               //   if(startPt == currentUnassignedLocations[i]) 
00739               //     { pos = i; i = currentUnassignedLocations.size(); }
00740               // culItr = currentUnassignedLocations.begin();
00741               // currentUnassignedLocations.erase(culItr+pos); 
00742               
00743               // and move it to the front of the unassigned list
00744               // even if that point is not there previously
00745               culItr = currentUnassignedLocations.begin();
00746               currentUnassignedLocations.insert(culItr, startPt);
00747               
00748               assignmentMap.setVal(startPt, UNASSIGNED_REGION);
00749             }
00750           else LINFO("skip adding starting point -- already visited");
00751           Raster::waitForKey();
00752 
00753           // start from the front of the queue 
00754           uint currIndex = 0;
00755 
00756           // while there is still neighbor that we have not visited
00757           // as a result of the current salreg-salcontour combo
00758           while(currIndex < currentUnassignedLocations.size())
00759             {
00760               // get location
00761               Point2D<int> ptGrid = currentUnassignedLocations[currIndex];
00762               Point2D<int> pt(ptGrid.i*BOUNDARY_STEP_SIZE, 
00763                               ptGrid.j*BOUNDARY_STEP_SIZE);
00764 
00765               LINFO("curr pt to check: %3d %3d --> %3d %3d", 
00766                     ptGrid.i, ptGrid.j, pt.i, pt.j);
00767              
00768               // if not yet checked
00769               if(!isComparedWith.getVal(ptGrid)) 
00770                 {
00771                   LINFO("was NOT compared with yet");
00772 
00773                   // check if the distribution in the location 
00774                   // goes past the threshold
00775                   Histogram thist = getHistogramDistribution(pt);
00776                   float diff = hist1.getChiSqDiff(thist);
00777                   LINFO("difference:(%3d %3d) & (%3d %3d): %f", 
00778                         currPoint.i, currPoint.j, pt.i, pt.j, diff);
00779                   
00780                   // if it is below threshold:
00781                   if(diff < threshDiff)
00782                     {
00783                       LINFO("pass %d", currIndex);
00784 
00785                       // assign current location to object list
00786                       currentObjectLocations.push_back(ptGrid);
00787                       assignmentMap.setVal(ptGrid, CENTER_REGION);
00788                       
00789                       // add its neighbors to unassigned locations list
00790                       uint bSize = currentUnassignedLocations.size();
00791                       addUnvisitedNeighbors
00792                         (currentUnassignedLocations, ptGrid, 
00793                          assignmentMap);
00794                       uint aSize = currentUnassignedLocations.size();
00795                       uint addN = aSize - bSize;
00796 
00797                       // take out the location from unassigned list
00798                       culItr = currentUnassignedLocations.begin();
00799                       currentUnassignedLocations.erase(culItr+currIndex+addN);
00800 
00801                       // LINFO("after deletion");
00802                       // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
00803                       //   {
00804                       //     LINFO("[%3d]: %3d %3d", i, 
00805                       //           currentUnassignedLocations[i].i,
00806                       //           currentUnassignedLocations[i].j);          
00807                       //   }
00808                       // Raster::waitForKey();
00809 
00810                       currIndex = 0;
00811 
00812                       // display current situation
00813                       displayGrowMap(assignmentMap, currPoint,
00814                                      currentObjectLocations,
00815                                      currentObjectCoreLocations,
00816                                      currentBackgroundLocations,
00817                                      currentUnassignedLocations,
00818                                      isComparedWith, segment);
00819                     }
00820                   else
00821                     {
00822                       LINFO("didn't pass: %d", currIndex);
00823 
00824                       // otherwise just advance the index
00825                       currIndex++;
00826                     }
00827 
00828                   // make note that this location is already compared
00829                   isComparedWith.setVal(ptGrid, true);
00830                 }
00831               // otherwise just advance the index
00832               else 
00833                 {
00834                   LINFO("already checked: %d", currIndex);
00835 
00836                   currIndex++;
00837                 }              
00838            }
00839         }
00840 
00841       LINFO("Done with segment {%3d}", segment.orgIndex);
00842       Raster::waitForKey();
00843 
00844       // assign regions next to the segment
00845       assignRegionsAroundSegment
00846         (segment, pts2, pts3, 
00847          assignmentMap,
00848          currentObjectLocations,
00849          currentBackgroundLocations,
00850          currentUnassignedLocations,
00851          regionAssignmentMap,
00852          currentObjectRegionList, 
00853          currentBackgroundRegionList);
00854 
00855       
00856       // GROW SURROUND also check if any of the unassigned neighbors 
00857       // can be added to the BG list
00858       // --> if closer to the other side of contour 
00859 
00860       // ==> note that Chi-sq thresholding need 3 regions
00861       //    ---> grow surround wrt/covering center 
00862       //         (this is Song Chun Zhu's negative cures)
00863       //         ---> that is, grow center and grow surround
00864 
00865       
00866       // display current situation
00867       LINFO("after the boundary assignment");
00868       displayGrowMap(assignmentMap, currPoint,
00869                      currentObjectLocations,
00870                      currentObjectCoreLocations,
00871                      currentBackgroundLocations,
00872                      currentUnassignedLocations,
00873                      isComparedWith, segment);
00874 
00875       // get the next region
00876       // FIXXX ADD THIS STEP LATER              
00877 
00878 
00879 
00880 
00881       // stop if all surroundings of the center list are assigned
00882       // bool allAssigned = false;
00883       // for(uint i = 0; i < ...; i++)
00884       //   {
00885       //     // check its neighbor if neither are
00886       //     // center nor surround assigned 
00887       //     allAssigned = true;
00888       //   }
00889       //
00890       // if(allAssigned) 
00891       //   {      
00892       //      ==> there is no need to go through all the boundaries 
00893       //      because it's already sorted
00894       //   }
00895       // else
00896       //   {
00897       //      add the neighbor that passes the threshold
00898       //      of the original seed to the core    
00899       //
00900       //      recalculate closest most similar boundary from regions
00901       //      somehow promote the ones that go through unassigned region
00902       //   }
00903 
00904       // currPoint     =
00905       // currPointGrid =
00906 
00907       // dead zone (no boundary and very non-similar colors) 
00908       // will be visited once core grows to it
00909     }
00910 
00911   Raster::waitForKey();
00912 }
00913 
00914 // ######################################################################
00915 std::list<Segment> SalientRegionSegmenter::fillSegmentQueue
00916 (Point2D<int> pt)
00917 {
00918   std::list<Segment> sortedSegments;
00919 
00920   // for each contour
00921   int index = 0;
00922   for(uint i = 0; i < itsContourBoundaries.size(); i++)
00923     {
00924       rutz::shared_ptr<Contour> contour = 
00925         itsContourBoundaries[i];
00926       
00927       uint cLen = contour->edgels.size();
00928 
00929       //LINFO("Contour[%3d]: %3d", i, cLen);
00930 
00931       // do we take out the short contours???
00932       if(cLen < MINIMUM_CONTOUR_LENGTH) continue;
00933 
00934       // go through each contour
00935       float step = float(MINIMUM_CONTOUR_LENGTH)/2.0F;
00936       uint numSegments = uint(floor(float(cLen)/step));
00937       if((cLen%MINIMUM_CONTOUR_LENGTH) == 0) numSegments--;
00938       LINFO("Contour[%3d]: %3d: numSegments: %d", 
00939             i, cLen, numSegments);
00940 
00941       for(uint j = 0; j < numSegments; j++)
00942         {
00943           uint start = uint(j*step);
00944           uint end   = start + MINIMUM_CONTOUR_LENGTH - 1;
00945 
00946           if(end >= cLen)
00947             {
00948               end   = cLen - 1;
00949               start = end + 1 - MINIMUM_CONTOUR_LENGTH;
00950             }
00951          
00952           Segment segment(index, i, start, end);
00953           
00954           LINFO("[i: %3d c: %3d s: %3d e: %3d]", index, i, start, end);
00955           
00956           setPriority(segment, pt);
00957           sortedSegments.push_back(segment);
00958 
00959           index++;
00960         }
00961     }
00962 
00963   Raster::waitForKey();
00964 
00965   // sort the segments
00966   LINFO("Before Sorting");
00967   std::list<Segment>::iterator 
00968     itr  = sortedSegments.begin(),
00969     stop = sortedSegments.end();
00970   // while (itr != stop)
00971   //   {
00972   //     LINFO("%6.3f*%10.3f + %6.3f*%10.3f + %6.3f*%10.3f + "
00973   //           "%6.3f*%10.3f + %6.3f*%10.3f = %10.3f", 
00974   //           LEN_WEIGHT, (*itr).lenVal,
00975   //           SIM_WEIGHT, (*itr).simVal,
00976   //           STR_WEIGHT, (*itr).strVal,
00977   //           RAT_WEIGHT, (*itr).ratVal,
00978   //           DIS_WEIGHT, (*itr).disVal, (*itr).pVal);
00979   //     itr++;
00980   //   }
00981   // Raster::waitForKey();
00982 
00983   sortedSegments.sort();
00984 
00985   LINFO("After  Sorting");
00986   
00987   itr  = sortedSegments.begin();
00988   stop = sortedSegments.end();
00989   while (itr != stop)
00990     {
00991       LINFO("[%3d] %6.3f*%10.3f + %6.3f*%10.3f + %6.3f*%10.3f + "
00992             "%6.3f*%10.3f + %6.3f*%10.3f = %10.3f", (*itr).orgIndex,
00993             LEN_WEIGHT, (*itr).lenVal,
00994             SIM_WEIGHT, (*itr).simVal,
00995             STR_WEIGHT, (*itr).strVal,
00996             RAT_WEIGHT, (*itr).ratVal,
00997             DIS_WEIGHT, (*itr).disVal, (*itr).pVal);
00998       itr++;
00999     }
01000   Raster::waitForKey();
01001 
01002   return sortedSegments;
01003 }
01004 
01005 // ######################################################################
01006 // FIXXX: what happen in the second reprioritization
01007 void SalientRegionSegmenter::setPriority
01008 (Segment &segment, Point2D<int> pt)
01009 {
01010   uint w = itsImage.getWidth();
01011   uint h = itsImage.getHeight();
01012   float diag = pow(w*w + h*h, 0.5);
01013 
01014   // selection priority is:
01015   // LEN_WEIGHT * length of the contour boundary +
01016   // SIM_WEIGHT * similarity with the closer side +
01017   // STR_WEIGHT * strength of boundary +
01018   // RAT_WEIGHT * ratio of in:out +
01019   // DIS_WEIGHT * proximity to the point
01020 
01021   // each factor has a max of 1.0
01022 
01023   rutz::shared_ptr<Contour> contour = 
01024     itsContourBoundaries[segment.contourIndex];  
01025   uint cLen = contour->edgels.size();
01026 
01027   // length of the contour boundary 
01028   float tempCLen = float(cLen);
01029   float maxLen = float(MINIMUM_CONTOUR_LENGTH * 3); 
01030   if(tempCLen > maxLen) tempCLen = maxLen;
01031   float lenVal = tempCLen/maxLen;
01032   segment.lenVal = lenVal; 
01033 
01034   LINFO("1. clen: %d --> lenVal: %f", cLen, lenVal);
01035 
01036   // similarity with the closer side 
01037   Histogram hist1 = getHistogramDistribution(pt);
01038   std::vector<Point2D<int> > pts2;
01039   std::vector<Point2D<int> > pts3;
01040   getSegmentPointDistributions(segment, pt, pts2, pts3);
01041 
01042   Histogram hist2 = getHistogramDistribution(pts2);
01043   Histogram hist3 = getHistogramDistribution(pts3);
01044   float diff12 = hist1.getChiSqDiff(hist2);
01045 
01046   float tempDiff =  diff12;
01047   if(tempDiff > 1.0) tempDiff = 1.0; 
01048   float simVal = 1.0F - tempDiff;
01049   segment.simVal = simVal;
01050 
01051   LINFO("2. diff12: %f --> simVal: %f", diff12, simVal);
01052 
01053   // strength of boundary
01054   float val = 0.0; 
01055   uint start = segment.segStartIndex;
01056   uint end   = segment.segEndIndex;
01057   for(uint i = start; i <= end; i++)
01058     {
01059       val += contour->edgels[i]->val;
01060     }
01061   val /= float(end - start + 1);
01062   float maxStr = .5 * itsMaximumEdgelStrength; 
01063   float strVal = val/maxStr; if(strVal > 1.0F) strVal = 1.0;
01064   segment.strVal = strVal;
01065 
01066   LINFO("3. strength of boundary: %f / %f = strVal: %f", 
01067         val, itsMaximumEdgelStrength, strVal);
01068     
01069   // ratio of near:far side
01070   float diff13  =  hist1.getChiSqDiff(hist3);
01071   float ratio  =  MAX_FAR_TO_NEAR_RATIO; 
01072   if(diff12 > 0.0) ratio = diff13/diff12;
01073   float nratio = MAX_FAR_TO_NEAR_RATIO;
01074   if(ratio < MAX_FAR_TO_NEAR_RATIO) nratio = ratio; 
01075   float ratVal = nratio/MAX_FAR_TO_NEAR_RATIO;
01076   segment.ratVal = ratVal;
01077 
01078   LINFO("4. ratio in&out: %f/%f = %f --> ratVal: %f", 
01079         diff13, diff12, ratio, ratVal);
01080 
01081   // distance between segment and salient point
01082   // while NOT going through a surround area
01083   int index   = segment.segStartIndex + MINIMUM_CONTOUR_LENGTH/2; 
01084   float dist  = pt.distance(contour->edgels[index]->pt);
01085   float mdist = MAX_DISTANCE * diag;
01086   float disVal  = 1.0; 
01087   if(dist > mdist) disVal = 1.0F - (dist - mdist)/(diag - mdist);
01088   segment.disVal = disVal;
01089 
01090   LINFO("5. distance: dist: %f/mdist: %f --> disVal: %f", 
01091         dist, mdist, disVal);
01092 
01093   segment.pVal =  
01094     LEN_WEIGHT * lenVal +
01095     SIM_WEIGHT * simVal +
01096     STR_WEIGHT * strVal +
01097     RAT_WEIGHT * ratVal +
01098     DIS_WEIGHT * disVal;
01099 
01100   LINFO("Total: %f", segment.pVal);
01101   //displayDistributionSetup(segment, pt, pts2, pts3);
01102 }
01103 
01104 // ######################################################################
01105 Histogram SalientRegionSegmenter::getHistogramDistribution
01106 (Point2D<int> pt)
01107 {
01108   // FIXXXX NEED TO CHECK IF ONE IS AVAILABLE (already computed)  
01109 
01110   Histogram lHist(NUM_L_BINS);
01111   Histogram aHist(NUM_A_BINS);
01112   Histogram bHist(NUM_L_BINS);
01113 
01114   int rad = NEIGHBORHOOD_RADIUS;
01115   int numPoints = 0;
01116   for(int i = -rad; i <= rad; i++) 
01117     for(int j = -rad; j <= rad; j++) 
01118       {
01119         bool isWithinCircle = ((i*i+j*j) <= (rad*rad));
01120 
01121         Point2D<int> pt2 = pt + Point2D<int>(i,j);
01122         if(itsImage.coordsOk(pt2) && isWithinCircle)
01123           {
01124             // L component
01125             int l_val = itsImageHistogramEntries[0].getVal(pt2);
01126             lHist.addValue(l_val, 1.0F);
01127 
01128             // a component
01129             int a_val = itsImageHistogramEntries[1].getVal(pt2);
01130             aHist.addValue(a_val, 1.0F);
01131 
01132             // b component
01133             int b_val = itsImageHistogramEntries[2].getVal(pt2);
01134             bHist.addValue(b_val, 1.0F);
01135 
01136             numPoints++;
01137           }
01138       }
01139   //LINFO("num points: %d", numPoints);
01140 
01141   // maybe later want to add the weight for each channel
01142   //(Point2D<int> pt, std::vector<float> &dist, float weight)
01143 
01144   // smooth the histogram individually
01145   lHist.smooth(itsLKernel);
01146   aHist.smooth(itsAKernel);
01147   bHist.smooth(itsBKernel);
01148 
01149   // combine the histograms
01150   std::vector<Histogram> histograms;
01151   histograms.push_back(lHist);
01152   histograms.push_back(aHist);
01153   histograms.push_back(bHist);
01154   Histogram histogram(histograms);
01155   
01156   // normalize with the number of points
01157   histogram.divide(numPoints);
01158 
01159   return histogram;
01160 }
01161 
01162 // ######################################################################
01163 Histogram SalientRegionSegmenter::getHistogramDistribution
01164 (std::vector<Point2D<int> > pts)
01165 {
01166   Histogram lHist(NUM_L_BINS);
01167   Histogram aHist(NUM_A_BINS);
01168   Histogram bHist(NUM_L_BINS);
01169 
01170   int numPoints = 0;
01171   for(uint i = 0; i < pts.size(); i++) 
01172       {
01173         Point2D<int> pt = pts[i];
01174         if(itsImage.coordsOk(pt))
01175           {
01176             // L component
01177             int l_val = itsImageHistogramEntries[0].getVal(pt);
01178             lHist.addValue(l_val, 1.0F);
01179 
01180             // a component
01181             int a_val = itsImageHistogramEntries[1].getVal(pt);
01182             aHist.addValue(a_val, 1.0F);
01183 
01184             // b component
01185             int b_val = itsImageHistogramEntries[2].getVal(pt);
01186             bHist.addValue(b_val, 1.0F);
01187 
01188             numPoints++;
01189           }
01190       }
01191 
01192   LINFO("num points: %d", numPoints);
01193   
01194   // maybe later want to add the weight for each channel
01195   //(Point2D<int> pt, std::vector<float> &dist, float weight)
01196 
01197   // smooth the histogram individually
01198   lHist.smooth(itsLKernel);
01199   aHist.smooth(itsAKernel);
01200   bHist.smooth(itsBKernel);
01201 
01202   // combine the histograms
01203   std::vector<Histogram> histograms;
01204   histograms.push_back(lHist);
01205   histograms.push_back(aHist);
01206   histograms.push_back(bHist);
01207   Histogram histogram(histograms);
01208   
01209   // normalize with the number of points
01210   histogram.divide(numPoints);
01211 
01212   return histogram;
01213 }
01214 
01215 // ######################################################################
01216 void SalientRegionSegmenter::getSegmentPointDistributions
01217 (Segment segment, Point2D<int> pt, 
01218  std::vector<Point2D<int> > &pts1, std::vector<Point2D<int> > &pts2)
01219 {
01220   // get the contour divider end points 
01221   uint start = segment.segStartIndex;
01222   uint end   = segment.segEndIndex;
01223 
01224   rutz::shared_ptr<Contour> contour = 
01225     itsContourBoundaries[segment.contourIndex];  
01226 
01227   rutz::shared_ptr<Edgel> edgels = contour->edgels[start];
01228   rutz::shared_ptr<Edgel> edgele = contour->edgels[end  ];
01229            
01230   uint  ainds  = edgels->angleIndex; 
01231   float bainds = 
01232     fmod((ainds+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS);
01233   uint  ainde  = edgele->angleIndex; 
01234   float bainde = 
01235     fmod((ainde+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS);
01236 
01237   int step  = BOUNDARY_STEP_SIZE;
01238   int hstep = step/2;
01239   float dxs = cos(bainds * M_PI/4.0) * hstep; 
01240   float dys = sin(bainds * M_PI/4.0) * hstep;
01241 
01242   float dxe = cos(bainde * M_PI/4.0) * hstep; 
01243   float dye = sin(bainde * M_PI/4.0) * hstep;
01244 
01245   Point2D<float> p1 = edgels->pt + Point2D<float>(-dxs-.5, -dys-.5);
01246   Point2D<float> p2 = edgele->pt + Point2D<float>( dxe+.5,  dye+.5); 
01247   
01248   // estimate the contour average angle
01249   float ang  = atan2(p2.j-p1.j, p2.i-p1.i);
01250 
01251   // the corrected angle would be to move it to PI/2
01252   // FIXXX: this could be incorrect 
01253   //        if we branch the contour to both left and right
01254   float cAng = M_PI/2.0F - ang;
01255   if(ang < 0.0F && ang > M_PI) 
01256     { LFATAL("out of Bounds Angle -- Fix it"); }
01257 
01258   if(cAng == 0.0F)
01259     {
01260       LINFO("Deal with ZERO corrected angle");
01261       Raster::waitForKey();
01262     }
01263 
01264   float cCAng = cos(cAng);
01265   float sCAng = sin(cAng);
01266 
01267   // get the midpoint of the angle line estimator
01268   Point2D<float> mid((p1.i+p2.i)/2.0, (p1.j+p2.j)/2.0);  
01269 
01270   // LINFO("c[%3d]:(%3d:a: %f)-(%3d:a: %3f) ", 
01271   //       segment.contourIndex, start, bainds, end, bainde);
01272   // LINFO("hstep: %d [%f %f] [%f %f]", 
01273   //       hstep, dxs, dys, dxe, dye);
01274   
01275   // LINFO("p1:(%f %f) p2:(%f %f) ", 
01276   //       p1.i, p1.j, p2.i, p2.j);
01277   // LINFO("ang: %f --> cAng: %f (c: %f s: %f) mid[%f %f] ", 
01278   //       ang, cAng, cCAng, sCAng, mid.i, mid.j);
01279 
01280 
01281   // rotate about that point to vertical
01282   float tbR = 0.0; float bbR = 0.0; 
01283   float lbR = 0.0; float rbR = 0.0;
01284   std::vector<Point2D<float> > sPt;
01285   std::vector<Point2D<float> > ePt;
01286   std::vector<Point2D<float> > srPt;
01287   std::vector<Point2D<float> > erPt;
01288   std::vector<Point2D<float> > mrPt;
01289   for(uint k = start; k <= end; k++)
01290     {
01291       Point2D<int> pt = contour->edgels[k]->pt;
01292       float i = pt.i - mid.i;
01293       float j = pt.j - mid.j; 
01294       float iR =  i*cCAng - j*sCAng;
01295       float jR =  i*sCAng + j*cCAng;
01296 
01297       uint aind   = contour->edgels[k]->angleIndex; 
01298       float baind = 
01299         fmod((aind+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS);
01300       float dx = cos(baind * M_PI/4.0) * hstep; 
01301       float dy = sin(baind * M_PI/4.0) * hstep;
01302 
01303       Point2D<float> ps = pt + Point2D<float>(-dx-.5, -dy-.5);
01304       Point2D<float> pe = pt + Point2D<float>( dx+.5,  dy+.5); 
01305       
01306       float si = ps.i - mid.i;
01307       float sj = ps.j - mid.j; 
01308       float siR =  si*cCAng - sj*sCAng;
01309       float sjR =  si*sCAng + sj*cCAng;
01310       
01311       float ei = pe.i - mid.i;
01312       float ej = pe.j - mid.j; 
01313       float eiR =  ei*cCAng - ej*sCAng;
01314       float ejR =  ei*sCAng + ej*cCAng;
01315 
01316       sPt.push_back(ps);
01317       ePt.push_back(pe);
01318       srPt.push_back(Point2D<float>(siR,sjR));
01319       erPt.push_back(Point2D<float>(eiR,ejR));
01320       mrPt.push_back(Point2D<float>( iR, jR));
01321 
01322       // initialize everything on the first iteration
01323       if(k == start)
01324         {
01325           tbR = sjR;
01326           bbR = sjR;
01327           lbR = siR;
01328           rbR = siR;
01329         }
01330 
01331       if(tbR > sjR) tbR = sjR;
01332       if(tbR > ejR) tbR = ejR;
01333 
01334       if(bbR < sjR) bbR = sjR;
01335       if(bbR < ejR) bbR = ejR;
01336 
01337       if(lbR > siR) lbR = siR;
01338       if(lbR > eiR) lbR = eiR;
01339 
01340       if(rbR < siR) rbR = siR;
01341       if(rbR < eiR) rbR = eiR;
01342 
01343       // LINFO("[[%d]]", k);
01344       // LINFO("M[%3d %3d] --> offset[%f %f] --> [%f %f]", 
01345       //       pt.i, pt.j, i ,j, iR, jR);
01346 
01347       // LINFO("S[%f %f] --> offset[%f %f] --> [%f %f]", 
01348       //       ps.i, ps.j, si ,sj, siR, sjR);
01349       // LINFO("E[%f %f] --> offset[%f %f] --> [%f %f] \n", 
01350       //       pe.i, pe.j, ei ,ej, eiR, ejR);
01351     }
01352 
01353   //LINFO("[t: %f b: %f l: %f r: %f] ", tbR, bbR, lbR, rbR);
01354 
01355   // count the pixels in the left and right within the bounding box  
01356   float areaL = 0; float areaR = 0;
01357   float w = rbR - lbR;
01358   float h = bbR - tbR;
01359   if(w > 0.0F && h > 0.0F)
01360     {
01361       for(uint k = start; k <= end; k++)
01362         {
01363           int i = k-start;
01364           // we will use a trapezoid area 
01365           // to approximate number of pixels
01366           
01367           float tl = rbR - srPt[i].i;
01368           float bl = rbR - erPt[i].i;
01369           
01370           float h = erPt[i].j - srPt[i].j;
01371           
01372           float trapArea = (tl+bl)*h/2.0F;
01373           float boxArea  = w*h;
01374           areaL += (boxArea-trapArea);
01375           areaR += trapArea;
01376           
01377           // LINFO("tl = %f = %f - %f||| bl = %f = %f - %f ",
01378           //       tl, rbR, srPt[i].i, bl, rbR, erPt[i].i);
01379           // LINFO("h = %f = %f - %f | w = %f = %f - %f",
01380           //       h, erPt[i].j, srPt[i].j, w, rbR, lbR);
01381 
01382           // LINFO("[%d] b: %f b-t: %f, t: %f", 
01383           //       k, boxArea, boxArea-trapArea, trapArea);
01384         }
01385     }
01386   // LINFO("areaL: %f, areaR: %f ==> h: %f", areaL, areaR, h);
01387 
01388   // extend the box so that the number of pixels on both sides 
01389   // are close to the area circle with radius = NEIGHBORHOOD_RADIUS
01390   uint nrad = NEIGHBORHOOD_RADIUS;
01391   float minArea = nrad * nrad * M_PI; 
01392   float extL = 0.0; float extR = 0.0;
01393 
01394   //LINFO("lbR: %f areaL: %f", lbR, areaL);
01395   //LINFO("rbR: %f areaR: %f", rbR, areaR);
01396   if(areaL < minArea)
01397     {
01398       extL = lbR - (minArea - areaL)/h;
01399     }
01400 
01401   if(areaR < minArea)
01402     {
01403       extR = rbR + (minArea - areaR)/h;
01404     }
01405 
01406   //LINFO("add L:%f ->  %f add R: %f -> %f", 
01407   //      (minArea - areaL), (minArea - areaL)/h,
01408   //      (minArea - areaR), (minArea - areaR)/h );
01409 
01410   //LINFO("Sanity Check: min Area: %f, Area: ((%f) - (%f))*%f = %f", 
01411   //      minArea, extR, extL, h, (extR - extL)*h);
01412 
01413   // figure out which side the pt is
01414   // FIXXX: may want to be more careful here
01415   int pti = pt.i - mid.i;
01416   int ptj = pt.j - mid.j; 
01417   float ptiR =  pti*cCAng - ptj*sCAng;
01418   //float ptjR =  pti*sCAng + ptj*cCAng;
01419   float isLeft = true; if(ptiR > 0.0) isLeft = false;
01420   //LINFO("isLeft: %d", int(isLeft));
01421 
01422   // create a box
01423   uint finalW = extR-extL;
01424   uint finalH = h;
01425   uint maxDim = finalW;
01426   if(finalH > finalW) maxDim = finalH;
01427   Image<byte> temp1(maxDim*2, maxDim*2, ZEROS);
01428   Image<byte> temp2(maxDim*2, maxDim*2, ZEROS);
01429 
01430   // LINFO("finalW: %d finalH: %d ==> maxDim: %d", finalW, finalH, maxDim);
01431   //uint ttt1 = 0; uint ttt2 = 0;
01432   for(uint k = start; k <= end; k++)
01433     {
01434       uint ind = k - start;
01435 
01436       float t  = srPt[ind].j; float b  =  erPt[ind].j;      
01437       float h  = b - t;
01438 
01439       float tH = srPt[ind].i; float bH =  erPt[ind].i;
01440       float w  = bH - tH;
01441 
01442       //LINFO("ind: %d h: %f = %f - %f w: %f = %f - %f", 
01443       //      ind, h, b, t, w, bH, tH);
01444 
01445       // FIXXX: there may be a vertical gap between indexes
01446 
01447       // get the pixels on the left and right side
01448       // LINFO("VERT range: %d to %d", int(t), int(b));
01449       //uint tt1 = 0; uint tt2 = 0;
01450       for(int j = int(t); j <= int(b + .5F); j++)
01451         {
01452           // compute the dividing edge location
01453           float div = (w/h*(j - b)) + tH;
01454           if(w < 0.0F) div = (w/h*(j - t)) + tH;
01455 
01456           float leftE  = extL+maxDim;
01457           float rightE = extR+maxDim;
01458 
01459           // LINFO("horizontal divider: %f, range: %f to %f", 
01460           //      div+maxDim, leftE, rightE);
01461 
01462           //uint t1 = 0; uint t2 = 0;
01463           uint jShift = j + maxDim;
01464           for(int i = int(leftE); i <= int(rightE+.5F); i++) 
01465             {              
01466               if(i < (div+maxDim)) 
01467                 {
01468                   if(isLeft) temp1.setVal(i,jShift, 128); //t1++; }
01469                   else       temp2.setVal(i,jShift, 128); //t2++; }
01470                 }
01471               else
01472                 {
01473                   if(isLeft) temp2.setVal(i,jShift, 128); //t2++; }
01474                   else       temp1.setVal(i,jShift, 128); //t1++; }
01475                 }
01476 
01477               //LINFO("i:%d %d: div: %f --> %d == %3d %3d", 
01478               //      i, jShift, div+maxDim, int(i<(div+maxDim)), t1, t2);
01479             }
01480           //LINFO("[%3d %3d] t1: %d t2: %d", k, j, t1, t2);
01481           //tt1 += t1;
01482           //tt2 += t2;
01483         }
01484       //LINFO("[%3d] t1: %d t2: %d", k, tt1, tt2);
01485       //ttt1 += tt1;
01486       //ttt2 += tt2;
01487     }
01488   //LINFO("ttt1: %d ttt2: %d", ttt1, ttt2);
01489 
01490   //LINFO("sum1: %f sum2: %f", 
01491   //      float(sum(temp1))/128.0F, float(sum(temp2))/128.0F);
01492 
01493   // re-rotate the bounding box
01494   Image<byte> temp1R = rotate(temp1, maxDim, maxDim, -cAng);
01495   Image<byte> temp2R = rotate(temp2, maxDim, maxDim, -cAng);
01496 
01497   //LINFO("md[%d] mid: %f %f", maxDim, mid.i, mid.j);
01498 
01499   // figure out which side is next to the point
01500   int tw = temp1.getWidth();
01501   int th = temp1.getHeight();
01502   for(int i = 0; i < tw; i++)
01503     for(int j = 0; j < th; j++)
01504       {
01505         if(temp1R.getVal(i,j) > 64)
01506           { 
01507             Point2D<int> pt(i+int(mid.i)-maxDim,
01508                             j+int(mid.j)-maxDim );
01509             pts1.push_back(pt); 
01510             //LINFO("1 %d %d --> %d %d", i,j,pt.i, pt.j);
01511             //Raster::waitForKey();
01512           }
01513 
01514         if(temp2R.getVal(i,j) > 64) 
01515           {
01516             Point2D<int> pt(i+int(mid.i)-maxDim,
01517                             j+int(mid.j)-maxDim );
01518             pts2.push_back(pt); 
01519             //LINFO("2 %d %d --> %d %d", i,j,pt.i, pt.j);
01520             //Raster::waitForKey();
01521           }
01522       }
01523 
01524   //LINFO("Final Size: %d %d", int(pts1.size()), int(pts2.size()));
01525 }
01526 
01527 // ######################################################################
01528 void SalientRegionSegmenter::filterSegments(std::list<Segment> &segments)
01529 {
01530   // FIXXX ==> what happens if  best segment is not good enough???
01531   //  --> need a threshold if the best one is worth pursuing.
01532   //  --> if not then stop
01533   //      --> the object is segmented perfectly by Graph-based segmented
01534 }
01535 
01536 // ######################################################################
01537 void SalientRegionSegmenter::addUnvisitedNeighbors
01538 (std::vector<Point2D<int> > &currentUnassignedLocations, 
01539  Point2D<int> currPointGrid, Image<int> &assignmentMap)
01540 {
01541   //--> make sure no duplicates 
01542   //    the grid area is unassigned to the list,
01543   //    as well as surround or previous object
01544   //--> this will keep growing maximally 
01545   //    on the current salreg-salcontour combo              
01546 
01547   // LINFO("BEFORE unassigned");
01548   // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01549   //   {
01550   //     LINFO("[%3d]: %3d %3d", i, 
01551   //           currentUnassignedLocations[i].i,
01552   //           currentUnassignedLocations[i].j);          
01553   //   }
01554   // Raster::waitForKey();
01555 
01556 
01557   // add to the front of the list
01558 
01559   for(int j = 1; j >= -1; j--)
01560     for(int i = 1; i >= -1; i--)
01561       if(!(i == 0 && j== 0))
01562         {
01563           Point2D<int> pt(currPointGrid.i+i, currPointGrid.j+j);
01564           
01565           // if the location is not yet visited
01566           if(assignmentMap.coordsOk(pt) && 
01567              assignmentMap.getVal(pt) == UNVISITED_REGION) 
01568             {
01569               LINFO("pt(%3d %3d): %d", pt.i,pt.j, 
01570                     assignmentMap.getVal(pt));
01571 
01572               std::vector<Point2D<int> >::iterator itr = 
01573                 currentUnassignedLocations.begin();
01574               currentUnassignedLocations.insert(itr, pt);
01575 
01576               assignmentMap.setVal(pt, UNASSIGNED_REGION);
01577             }
01578         }
01579 
01580   // LINFO("AFTER  unassigned");
01581   // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01582   //   {
01583   //     LINFO("[%3d]: %3d %3d", i, 
01584   //           currentUnassignedLocations[i].i,
01585   //           currentUnassignedLocations[i].j);          
01586   //   }
01587   // Raster::waitForKey();
01588 
01589 }
01590 
01591 // ######################################################################
01592 std::vector<Point2D<int> > SalientRegionSegmenter::getLine
01593 (Point2D<int> p1, Point2D<int> p2)
01594 {
01595   std::vector<Point2D<int> > points;
01596 
01597   // ray tracing algorithm
01598   // from Graphics Gems / Paul Heckbert
01599   int dx = p2.i - p1.i, ax = abs(dx) << 1, sx = signOf(dx);
01600   int dy = p2.j - p1.j, ay = abs(dy) << 1, sy = signOf(dy);
01601   int x = p1.i, y = p1.j;
01602 
01603   const int w = itsImage.getWidth();
01604   const int h = itsImage.getHeight();
01605 
01606   if (ax > ay)
01607     {
01608       int d = ay - (ax >> 1);
01609       for (;;)
01610         {
01611           // assignment
01612           if (x >= 0 && x < w && y >= 0 && y < h)
01613             points.push_back(Point2D<int>(x,y));
01614 
01615           if (x == p2.i) return points;
01616           if (d >= 0) { y += sy; d -= ax; }
01617           x += sx; d += ay;
01618         }
01619     }
01620   else
01621     {
01622       int d = ax - (ay >> 1);
01623       for (;;)
01624         {
01625           // assignment
01626           if (x >= 0 && x < w && y >= 0 && y < h)
01627             points.push_back(Point2D<int>(x,y));
01628 
01629           if (y == p2.j) return points;
01630           if (d >= 0) { x += sx; d -= ay; }
01631           y += sy; d += ax;
01632         }
01633     }
01634   
01635   return points;
01636 }
01637 
01638 // ######################################################################
01639 void SalientRegionSegmenter::assignRegionsAroundSegment
01640 (Segment segment, 
01641  std::vector<Point2D<int> > pts2, 
01642  std::vector<Point2D<int> > pts3, 
01643  Image<int>                 &assignmentMap,
01644  std::vector<Point2D<int> > &currentObjectLocations,
01645  std::vector<Point2D<int> > &currentBackgroundLocations,
01646  std::vector<Point2D<int> > &currentUnassignedLocations,
01647  Image<int>       &regionAssignmentMap,
01648  std::vector<int> &currentObjectRegionList, 
01649  std::vector<int> &currentBackgroundRegionList)
01650 {
01651   uint w = itsImage.getWidth();
01652   uint h = itsImage.getHeight();
01653 
01654   uint hstep = BOUNDARY_STEP_SIZE/2;
01655   //uint wG = (w-hstep)/BOUNDARY_STEP_SIZE;
01656   //uint hG = (h-hstep)/BOUNDARY_STEP_SIZE;
01657 
01658   Image<int> image(w,h, ZEROS);
01659   for(uint i = 0; i < pts2.size(); i++) 
01660     {
01661       if(image.coordsOk(pts2[i]))
01662         image.setVal(pts2[i], CLOSER_SIDE);
01663     }
01664   for(uint i = 0; i < pts3.size(); i++) 
01665     {
01666       if(image.coordsOk(pts3[i]))
01667         image.setVal(pts3[i], FAR_SIDE);
01668     }
01669   std::vector<std::vector<Point2D<int> > > 
01670     neighbor(NUM_RIDGE_DIRECTIONS);
01671 
01672   for(uint k = 0; k < NUM_RIDGE_DIRECTIONS; k++)
01673     {      
01674       neighbor[k] = std::vector<Point2D<int> >();
01675 
01676       if(k == 0)
01677         {
01678           neighbor[k].push_back(Point2D<int>( 1,  0));
01679           neighbor[k].push_back(Point2D<int>(-1,  0));
01680         }
01681       else if(k == 1)
01682         {
01683           neighbor[k].push_back(Point2D<int>(-1, -1));
01684           neighbor[k].push_back(Point2D<int>( 0, -1));
01685           neighbor[k].push_back(Point2D<int>(-1,  0));
01686           neighbor[k].push_back(Point2D<int>( 1,  0));
01687           neighbor[k].push_back(Point2D<int>( 0,  1));
01688           neighbor[k].push_back(Point2D<int>( 1,  1));
01689         }
01690       else if(k == 2)
01691         {
01692           neighbor[k].push_back(Point2D<int>( 0,  1));
01693           neighbor[k].push_back(Point2D<int>( 0, -1));
01694         }
01695       else if(k == 3)
01696         {
01697           neighbor[k].push_back(Point2D<int>( 0, -1));
01698           neighbor[k].push_back(Point2D<int>( 1, -1));
01699           neighbor[k].push_back(Point2D<int>(-1,  0));
01700           neighbor[k].push_back(Point2D<int>( 1,  0));
01701           neighbor[k].push_back(Point2D<int>(-1,  1));
01702           neighbor[k].push_back(Point2D<int>( 0,  1));
01703         }
01704     }
01705   
01706   // go through all the edgels' grid location first
01707   for(uint e = segment.segStartIndex; e <= segment.segEndIndex; e++) 
01708     {
01709       rutz::shared_ptr<Contour> contour = 
01710         itsContourBoundaries[segment.contourIndex];  
01711       rutz::shared_ptr<Edgel> edgel = contour->edgels[e];           
01712       Point2D<int> pt = edgel->pt;
01713       Point2D<int> ptGrid
01714         ((pt.i+hstep)/BOUNDARY_STEP_SIZE,
01715          (pt.j+hstep)/BOUNDARY_STEP_SIZE );      
01716       LINFO("[[[%3d]]] %d %d --> %d %d", e, pt.i, pt.j, ptGrid.i, ptGrid.j);
01717       
01718       uint label = assignmentMap.getVal(ptGrid);
01719 
01720       // do nothing on center, surround, other objects 
01721       if(label == CENTER_REGION)       LINFO(" C_REGION : do nothing");
01722       if(label == SURROUND_REGION)     LINFO(" S_REGION : do nothing");
01723       if(label == OTHER_OBJECT_REGION) LINFO("OO_REGION : do nothing");
01724       
01725       if(label == UNVISITED_REGION)
01726         {
01727           // add to background
01728           currentBackgroundLocations.push_back(ptGrid);
01729           assignmentMap.setVal(ptGrid, SURROUND_REGION);         
01730 
01731           LINFO("UNVISITED adding %3d %3d to the background", 
01732                 ptGrid.i, ptGrid.j);
01733         }
01734 
01735       if(label == UNASSIGNED_REGION)
01736         {
01737 
01738           // LINFO("before changing on edgel UNASSIGNED_REGION");
01739           // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01740           //   {
01741           //     LINFO("[%3d]: %3d %3d", i, 
01742           //           currentUnassignedLocations[i].i,
01743           //           currentUnassignedLocations[i].j);          
01744           //   }
01745 
01746           // LINFO("Background");
01747           // for(uint i = 0; i < currentBackgroundLocations.size(); i++)
01748           //   {
01749           //     LINFO("[%3d]: %3d %3d", i, 
01750           //           currentBackgroundLocations[i].i,
01751           //           currentBackgroundLocations[i].j);          
01752           //   }
01753 
01754           // Raster::waitForKey();
01755           
01756 
01757           // find it is in the unassigned list
01758           uint pos = 0;
01759           for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01760             if(ptGrid == currentUnassignedLocations[i]) 
01761               { pos = i; i = currentUnassignedLocations.size(); }
01762 
01763           // delete it
01764           std::vector<Point2D<int> >::iterator itr = 
01765             currentUnassignedLocations.begin();
01766           currentUnassignedLocations.erase(itr+pos); 
01767           
01768           // add to background list
01769           currentBackgroundLocations.push_back(ptGrid);
01770           assignmentMap.setVal(ptGrid, SURROUND_REGION);    
01771 
01772           // LINFO("after changing on edgel");
01773           // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01774           //   {
01775           //     LINFO("[%3d]: %3d %3d", i, 
01776           //           currentUnassignedLocations[i].i,
01777           //           currentUnassignedLocations[i].j);          
01778           //   }
01779 
01780 
01781           // LINFO("Background");
01782           // for(uint i = 0; i < currentBackgroundLocations.size(); i++)
01783           //   {
01784           //     LINFO("[%3d]: %3d %3d", i, 
01785           //           currentBackgroundLocations[i].i,
01786           //           currentBackgroundLocations[i].j);          
01787           //   }
01788 
01789           // Raster::waitForKey();
01790           
01791       
01792         }
01793     }
01794 
01795   // LINFO("before checking edgel neighbors");
01796   // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01797   //   {
01798   //     LINFO("[%3d]: %3d %3d", i, 
01799   //           currentUnassignedLocations[i].i,
01800   //           currentUnassignedLocations[i].j);          
01801   //   }
01802   
01803   
01804   // LINFO("Background");
01805   // for(uint i = 0; i < currentBackgroundLocations.size(); i++)
01806   //   {
01807   //     LINFO("[%3d]: %3d %3d", i, 
01808   //           currentBackgroundLocations[i].i,
01809   //           currentBackgroundLocations[i].j);          
01810   //   }
01811   
01812   // Raster::waitForKey();
01813  
01814   // then go through its neighbors
01815   for(uint e = segment.segStartIndex; e <= segment.segEndIndex; e++) 
01816     {
01817       rutz::shared_ptr<Contour> contour = 
01818         itsContourBoundaries[segment.contourIndex];  
01819       rutz::shared_ptr<Edgel> edgel = contour->edgels[e];           
01820       Point2D<int> pt = edgel->pt;
01821       Point2D<int> ptGrid
01822         ((pt.i+hstep)/BOUNDARY_STEP_SIZE,
01823          (pt.j+hstep)/BOUNDARY_STEP_SIZE );
01824       
01825       uint dir = edgel->angleIndex; 
01826 
01827       LINFO("[<<%3d>>] %d %d --> %d %d (%d)", 
01828             e,  pt.i, pt.j, ptGrid.i, ptGrid.j, dir);
01829 
01830       // classify current segment grid location as       
01831       for(uint i = 0; i < neighbor[dir].size(); i++)
01832         {
01833           Point2D<int> ptGrid2 = ptGrid + neighbor[dir][i];
01834           Point2D<int> pt2(ptGrid2.i*BOUNDARY_STEP_SIZE,
01835                            ptGrid2.j*BOUNDARY_STEP_SIZE );
01836 
01837           LINFO("    N[%3d]: %d %d --> %d %d", 
01838                 i, ptGrid2.i, ptGrid2.j, pt2.i, pt2.j);
01839 
01840           if(!assignmentMap.coordsOk(ptGrid2))
01841             {
01842               LINFO("out of bounds"); continue;
01843             }
01844 
01845           uint label2 = assignmentMap.getVal(ptGrid2);
01846           LINFO("LABEL2: %d", label2);
01847 
01848           // do nothing on center, surround, other objects 
01849           if(label2 == CENTER_REGION)       LINFO(" C_REGION : do nothing");
01850           if(label2 == SURROUND_REGION)     LINFO(" S_REGION : do nothing");
01851           if(label2 == OTHER_OBJECT_REGION) LINFO("OO_REGION : do nothing");
01852           
01853           if(label2 == UNVISITED_REGION)
01854             {
01855               // assign depending on which side of boundary
01856               int side = image.getVal(pt2);
01857 
01858               // LINFO("UNVISITED Before Background");
01859               // for(uint i = 0; i < currentBackgroundLocations.size(); i++)
01860               //   {
01861               //     LINFO("[%3d]: %3d %3d", i, 
01862               //           currentBackgroundLocations[i].i,
01863               //           currentBackgroundLocations[i].j);          
01864               //   }
01865               // for(uint i = 0; i < currentObjectLocations.size(); i++)
01866               //   {
01867               //     LINFO("[%3d]: %3d %3d", i, 
01868               //           currentObjectLocations[i].i,
01869               //           currentObjectLocations[i].j);          
01870               //   }
01871 
01872 
01873               if(side == CLOSER_SIDE)
01874                 {
01875                   // add to background
01876                   currentObjectLocations.push_back(ptGrid2);
01877                   assignmentMap.setVal(ptGrid2, CENTER_REGION);
01878 
01879                   LINFO("  adding %3d %3d to the center", 
01880                         ptGrid2.i, ptGrid2.j);
01881                 }
01882               else if(side == FAR_SIDE)
01883                 {
01884                   // add to background
01885                   currentBackgroundLocations.push_back(ptGrid2);
01886                   assignmentMap.setVal(ptGrid2, SURROUND_REGION);
01887 
01888                   LINFO("  adding %3d %3d to the background", 
01889                         ptGrid2.i, ptGrid2.j);
01890                 }
01891 
01892               // LINFO("UNVISITED after  Background");
01893               // for(uint i = 0; i < currentBackgroundLocations.size(); i++)
01894               //   {
01895               //     LINFO("[%3d]: %3d %3d", i, 
01896               //           currentBackgroundLocations[i].i,
01897               //           currentBackgroundLocations[i].j);          
01898               //   }
01899               // for(uint i = 0; i < currentObjectLocations.size(); i++)
01900               //   {
01901               //     LINFO("[%3d]: %3d %3d", i, 
01902               //           currentObjectLocations[i].i,
01903               //           currentObjectLocations[i].j);          
01904               //   }
01905 
01906             }
01907           
01908           if(label2 == UNASSIGNED_REGION)
01909             {
01910               // check if point is one either side of boundary          
01911               int side = image.getVal(pt2);
01912               LINFO("UN Side: %d", side);
01913 
01914               // LINFO("UNASSIGNED neighbors before");
01915               // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01916               //   {
01917               //     LINFO("[%3d]: %3d %3d", i, 
01918               //           currentUnassignedLocations[i].i,
01919               //           currentUnassignedLocations[i].j);          
01920               //   }
01921 
01922               if(side == CLOSER_SIDE || side == FAR_SIDE)
01923                 {                
01924                   // find the location in the unassigned list
01925                   uint pos = 0;
01926                   for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01927                     if(ptGrid2 == currentUnassignedLocations[i]) 
01928                       { pos = i; i = currentUnassignedLocations.size(); }
01929                   
01930                   // delete it
01931                   std::vector<Point2D<int> >::iterator itr = 
01932                     currentUnassignedLocations.begin();
01933                   currentUnassignedLocations.erase(itr+pos); 
01934                 }
01935               else LINFO("not on the close or far side");
01936 
01937               // LINFO("UNASSIGNED neighbors after ");
01938               // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
01939               //   {
01940               //     LINFO("[%3d]: %3d %3d", i, 
01941               //           currentUnassignedLocations[i].i,
01942               //           currentUnassignedLocations[i].j);          
01943               //   }
01944 
01945               // LINFO("UNASSIGNED before Background");
01946               // for(uint i = 0; i < currentBackgroundLocations.size(); i++)
01947               //   {
01948               //     LINFO("[%3d]: %3d %3d", i, 
01949               //           currentBackgroundLocations[i].i,
01950               //           currentBackgroundLocations[i].j);          
01951               //   }
01952               // for(uint i = 0; i < currentObjectLocations.size(); i++)
01953               //   {
01954               //     LINFO("[%3d]: %3d %3d", i, 
01955               //           currentObjectLocations[i].i,
01956               //           currentObjectLocations[i].j);          
01957               //   }
01958 
01959 
01960               if(side == CLOSER_SIDE)
01961                 {
01962                   // add to background
01963                   currentObjectLocations.push_back(ptGrid2);
01964                   assignmentMap.setVal(ptGrid2, CENTER_REGION);
01965 
01966                   LINFO("  adding %3d %3d to the center", 
01967                         ptGrid2.i, ptGrid2.j);
01968                 }
01969               else if(side == FAR_SIDE)
01970                 {
01971                   // add to background
01972                   currentBackgroundLocations.push_back(ptGrid2);
01973                   assignmentMap.setVal(ptGrid2, SURROUND_REGION);
01974 
01975                   LINFO("  adding %3d %3d to the background", 
01976                         ptGrid2.i, ptGrid2.j);
01977                 }
01978 
01979 
01980               // LINFO("UNASSIGNED after  Background");
01981               // for(uint i = 0; i < currentBackgroundLocations.size(); i++)
01982               //   {
01983               //     LINFO("[%3d]: %3d %3d", i, 
01984               //           currentBackgroundLocations[i].i,
01985               //           currentBackgroundLocations[i].j);          
01986               //   }
01987               // for(uint i = 0; i < currentObjectLocations.size(); i++)
01988               //   {
01989               //     LINFO("[%3d]: %3d %3d", i, 
01990               //           currentObjectLocations[i].i,
01991               //           currentObjectLocations[i].j);          
01992               //   }
01993 
01994             }
01995         }
01996     }
01997 
01998   // get the oversegmented regions
01999   
02000   // assign regions next to the segment      
02001   
02002 
02003 
02004   // // region index from the underlying Felz-Hutt region
02005   // int regIndex = itsInitialRegionImage.getVal(currentSalPoint); 
02006 
02007   // FIXXX: LATER include superpixel underneath the region
02008   // calculate the overlap on the region: 
02009   // anything over 50% of total bounding box is good
02010    // --> ok because the region is similar appearance-wise 
02011 
02012 
02013   // =============================================
02014       
02015   //currentObjectRegList.push_back(regIndex);
02016   //for(uint i = 0; i < itsRegionAdjecencyList[regIndex].size(); i++)
02017   //  currentUnassignedRegionsRegList.push_back
02018   //    (itsRegionAdjecencyList[regIndex][i]);
02019 
02020 
02021 
02022 
02023       // // find the current starting growing point
02024       // uint pos = 0;
02025       // for(uint i = 0; i < currentUnassignedLocations.size(); i++)
02026       //   if(startPt == currentUnassignedLocations[i]) 
02027       //     { pos = i; i = currentUnassignedLocations.size(); }
02028       // culItr = currentUnassignedLocations.begin();
02029       // currentUnassignedLocations.erase(culItr+pos); 
02030       
02031       // and move it to the front of the unassigned list
02032       // even if that point is not there previously
02033 
02034               // culItr = currentUnassignedLocations.begin();
02035               // currentUnassignedLocations.insert(culItr, startPt);
02036  
02037 
02038               //         // assign current location to object list
02039               //         currentObjectLocations.push_back(ptGrid);
02040               //         assignmentMap.setVal(ptGrid, CENTER_REGION);
02041                       
02042               //         // add its neighbors to unassigned locations list
02043               //         uint bSize = currentUnassignedLocations.size();
02044               //         addUnvisitedNeighbors
02045               //           (currentUnassignedLocations, ptGrid, 
02046               //            assignmentMap);
02047               //         uint aSize = currentUnassignedLocations.size();
02048               //         uint addN = aSize - bSize;
02049 
02050               //         // take out the location from unassigned list
02051               //         culItr = currentUnassignedLocations.begin();
02052               //         currentUnassignedLocations.erase(culItr+currIndex+addN);
02053 
02054 
02055 
02056 
02057 }
02058 
02059 // ######################################################################
02060 void SalientRegionSegmenter::displayDistributionSetup
02061 (Segment segment, Point2D<int> pt, 
02062  std::vector<Point2D<int> > pts2, 
02063  std::vector<Point2D<int> > pts3)
02064 {
02065   // display stuff
02066   Image<PixRGB<byte> > ima = itsImage;
02067   uint w = ima.getWidth();
02068   uint h = ima.getHeight();
02069 
02070   Image<float> fIma(luminance(ima));
02071   Image<float> tempFIma = fIma;
02072   inplaceNormalize(tempFIma, 0.0f,255.0f);  
02073   Image<byte>  bIma(tempFIma); 
02074 
02075   // get the image
02076   float mVal = 32;
02077   float bVal = 255 - mVal;
02078   Image<byte> dImaR, dImaG, dImaB;
02079   getComponents(ima, dImaR, dImaG, dImaB);
02080   inplaceNormalize(dImaR, byte(0), byte(mVal));
02081   inplaceNormalize(dImaG, byte(0), byte(mVal));
02082   inplaceNormalize(dImaB, byte(0), byte(mVal));
02083   Image<PixRGB<byte> > dIma  = makeRGB(dImaR,dImaG,dImaB);
02084 
02085   Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS);
02086 
02087   inplacePaste (dispIma, ima, Point2D<int>(0,0));
02088 
02089   Image<float> stateMapR(w,h, ZEROS);
02090   Image<float> stateMapG(w,h, ZEROS);
02091   Image<float> stateMapB(w,h, ZEROS);
02092 
02093   // draw core 
02094   std::vector<Point2D<int> > cores;
02095   std::vector<Point2D<int> > center;
02096   std::vector<Point2D<int> > surround;
02097   std::vector<Point2D<int> > unassigned;
02098 
02099  cores.push_back(Point2D<int>(152, 40));
02100 
02101  // // unassigned.push_back(Point2D<int>(144, 32));
02102  // // unassigned.push_back(Point2D<int>(152, 32));
02103  // // unassigned.push_back(Point2D<int>(160, 32));
02104 
02105  // // unassigned.push_back(Point2D<int>(144, 40));
02106  // // unassigned.push_back(Point2D<int>(160, 40));
02107 
02108  // // unassigned.push_back(Point2D<int>(144, 48));
02109  // // unassigned.push_back(Point2D<int>(152, 48));
02110  // // unassigned.push_back(Point2D<int>(160, 48));
02111 
02112  // cores.push_back(Point2D<int>(144, 32));
02113  // cores.push_back(Point2D<int>(152, 32));
02114  // cores.push_back(Point2D<int>(160, 32));
02115 
02116  // cores.push_back(Point2D<int>(144, 40));
02117  // cores.push_back(Point2D<int>(160, 40));
02118 
02119  // cores.push_back(Point2D<int>(144, 48));
02120  // cores.push_back(Point2D<int>(152, 48));
02121  // cores.push_back(Point2D<int>(160, 48));
02122 
02123  // center.push_back(Point2D<int>(136, 24));
02124  // center.push_back(Point2D<int>(144, 24));
02125  // center.push_back(Point2D<int>(152, 24));
02126  // center.push_back(Point2D<int>(136, 32));
02127  // center.push_back(Point2D<int>(136, 40));
02128 
02129  // center.push_back(Point2D<int>(128, 16));
02130  // center.push_back(Point2D<int>(136, 16));
02131  // center.push_back(Point2D<int>(128, 24));
02132  // center.push_back(Point2D<int>(128, 32));
02133 
02134  // center.push_back(Point2D<int>(120,  8));
02135  // center.push_back(Point2D<int>(120, 16));
02136  // center.push_back(Point2D<int>(120, 24));
02137 
02138  // center.push_back(Point2D<int>( 96,  8));
02139  // center.push_back(Point2D<int>(104,  8));
02140  // center.push_back(Point2D<int>(112,  8));
02141  // center.push_back(Point2D<int>(104, 16));
02142  // center.push_back(Point2D<int>(112, 16));
02143 
02144  // unassigned.push_back(Point2D<int>( 88,  8));
02145  // surround  .push_back(Point2D<int>( 88, 16));
02146  // unassigned.push_back(Point2D<int>( 96, 16));
02147  // surround  .push_back(Point2D<int>( 96, 24));
02148  // unassigned.push_back(Point2D<int>(104, 24));
02149 
02150  // unassigned.push_back(Point2D<int>(112, 24));
02151  // surround  .push_back(Point2D<int>(112, 32));
02152  // unassigned.push_back(Point2D<int>(120, 32));
02153  // surround  .push_back(Point2D<int>(120, 40));
02154  // unassigned.push_back(Point2D<int>(128, 40));
02155 
02156  // surround  .push_back(Point2D<int>(128, 48));
02157  // unassigned.push_back(Point2D<int>(136, 48));
02158  // surround  .push_back(Point2D<int>(136, 56));
02159  // unassigned.push_back(Point2D<int>(144, 56));
02160  // unassigned.push_back(Point2D<int>(152, 56));
02161  // unassigned.push_back(Point2D<int>(160, 56));
02162  // unassigned.push_back(Point2D<int>(168, 56));
02163 
02164  // unassigned.push_back(Point2D<int>(128,  8));
02165  // unassigned.push_back(Point2D<int>(136,  8));
02166 
02167  // unassigned.push_back(Point2D<int>(144, 16));
02168  // unassigned.push_back(Point2D<int>(152, 16));
02169  // unassigned.push_back(Point2D<int>(160, 16));
02170 
02171  // unassigned.push_back(Point2D<int>(160, 24));
02172  // unassigned.push_back(Point2D<int>(168, 24));
02173 
02174  // unassigned.push_back(Point2D<int>(168, 32));
02175  // unassigned.push_back(Point2D<int>(168, 40));
02176  // unassigned.push_back(Point2D<int>(168, 48));
02177 
02178   for(uint i = 0; i < cores.size(); i++)
02179     {
02180       Rectangle r = Rectangle::tlbrO
02181         (cores[i].j-4, cores[i].i-4, 
02182          cores[i].j+4, cores[i].i+4);
02183       drawFilledRect(stateMapB, r, 0.5F);
02184     }
02185 
02186   for(uint i = 0; i < center.size(); i++)
02187     {
02188       Rectangle r = Rectangle::tlbrO
02189         (center[i].j-4, center[i].i-4, 
02190          center[i].j+4, center[i].i+4);
02191       drawFilledRect(stateMapR, r, 0.5F);
02192     }
02193 
02194   for(uint i = 0; i < surround.size(); i++)
02195     {
02196       Rectangle r = Rectangle::tlbrO
02197         (surround[i].j-4, surround[i].i-4, 
02198          surround[i].j+4, surround[i].i+4);
02199       drawFilledRect(stateMapG, r, 0.5F);
02200     }
02201 
02202   for(uint i = 0; i < unassigned.size(); i++)
02203     {
02204       Rectangle r = Rectangle::tlbrO
02205         (unassigned[i].j-4, unassigned[i].i-4, 
02206          unassigned[i].j+4, unassigned[i].i+4);
02207       drawFilledRect(stateMapR, r, 0.5F);
02208       drawFilledRect(stateMapG, r, 0.5F);
02209     }
02210 
02211 
02212   // draw grid
02213   int grad = 8;
02214   for(uint i = grad; i < w; i++)
02215     for(uint j = grad; j < h; j++)
02216       {
02217         if(i%grad == 0 && j%grad == 0)
02218           {
02219             drawCross(stateMapR, Point2D<int>(i,j), 0.5F, 1);
02220             drawCross(stateMapG, Point2D<int>(i,j), 0.5F, 1);
02221             drawCross(stateMapB, Point2D<int>(i,j), 0.5F, 1);
02222           }
02223       }
02224 
02225   // draw closer population
02226   //LINFO("pts2 size: %d", int(pts2.size()));
02227   for(uint i = 0; i < pts2.size(); i++)
02228     {
02229       //LINFO("pts2[%3d]: %3d %3d", i, pts2[i].i, pts2[i].j);
02230       if(stateMapR.coordsOk(pts2[i]))
02231         {
02232           stateMapR.setVal(pts2[i], 0.25F);
02233           //stateMapG.setVal(pts2[i], 0.25F);
02234           //stateMapB.setVal(pts2[i], 0.25F);
02235         }
02236     }
02237 
02238   // draw farther population
02239   //LINFO("pts3 size: %d", int(pts3.size()));
02240   for(uint i = 0; i < pts3.size(); i++)
02241     {
02242       //LINFO("pts3[%3d]: %3d %3d", i, pts3[i].i, pts3[i].j);
02243       if(stateMapR.coordsOk(pts3[i]))
02244         {
02245           //stateMapR.setVal(pts3[i], 0.25F);
02246           stateMapG.setVal(pts3[i], 0.25F);
02247           //stateMapB.setVal(pts3[i], 0.25F);
02248         }
02249     } 
02250   
02251   // draw the point 
02252   int rad = NEIGHBORHOOD_RADIUS;
02253   for(int i = -rad; i <= rad; i++) 
02254     for(int j = -rad; j <= rad; j++) 
02255       {  
02256         bool isWithinCircle = ((i*i+j*j) <= (rad*rad));
02257 
02258         Point2D<int> pt2 = pt + Point2D<int>(i,j);
02259         if(itsImage.coordsOk(pt2) && isWithinCircle)
02260           {
02261             stateMapR.setVal(pt2, 0.5F);
02262             //stateMapG.setVal(pt2, 0.25F);
02263             //stateMapB.setVal(pt2, 0.25F);
02264           }
02265       }
02266 
02267   drawDisk(stateMapR, pt, 2,  1.0F);
02268   drawDisk(stateMapG, pt, 2,  1.0F);
02269   drawDisk(stateMapB, pt, 2,  1.0F);
02270 
02271   // drawLine(stateMapR, pt, Point2D<int>(90,14),  0.5F);
02272   // drawLine(stateMapG, pt, Point2D<int>(90,14),  0.5F);
02273   // drawLine(stateMapB, pt, Point2D<int>(90,14),  0.5F);
02274   
02275   // draw the contour 
02276   rutz::shared_ptr<Contour> contour = 
02277     itsContourBoundaries[segment.contourIndex];  
02278 
02279   int hstep = BOUNDARY_STEP_SIZE/2;
02280   uint start = segment.segStartIndex;
02281   uint end   = segment.segEndIndex;
02282   //for(uint i = start; i <= end; i++)
02283   //  {
02284   for(uint i = 0; i < contour->edgels.size(); i++)
02285     {
02286       rutz::shared_ptr<Edgel> edgel = contour->edgels[i];
02287           
02288       uint aind = edgel->angleIndex; 
02289       float baind = 
02290         fmod((aind+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS);
02291       
02292       float dx = cos(baind * M_PI/4.0) * hstep; 
02293       float dy = sin(baind * M_PI/4.0) * hstep;
02294       
02295       Point2D<int> pt = edgel->pt;
02296       Point2D<int> p1 = pt + Point2D<int>( dx+.5,  dy+.5); 
02297       Point2D<int> p2 = pt + Point2D<int>(-dx-.5, -dy-.5);
02298       
02299       if(i >= start && i <= end) 
02300         {
02301           drawLine(stateMapR, p1, p2, 1.0F);
02302           drawLine(stateMapG, p1, p2, 1.0F);
02303           drawLine(stateMapB, p1, p2, 1.0F);
02304         }
02305       else
02306         {
02307           drawLine(stateMapR, p1, p2, 0.5F);
02308           drawLine(stateMapG, p1, p2, 0.5F);
02309           drawLine(stateMapB, p1, p2, 0.5F);
02310         }
02311       //drawDisk(stateMap, pt, 2,  1.0F);
02312     }
02313 
02314   inplaceNormalize(stateMapR, 0.0f,bVal);
02315   inplaceNormalize(stateMapG, 0.0f,bVal);
02316   inplaceNormalize(stateMapB, 0.0f,bVal);
02317   Image<byte> dSMapR(stateMapR);
02318   Image<byte> dSMapG(stateMapG);
02319   Image<byte> dSMapB(stateMapB);
02320   Image<PixRGB<byte> > dSmap = makeRGB(dSMapR, dSMapG, dSMapB);
02321   inplacePaste
02322     (dispIma, Image<PixRGB<byte> >(dIma+dSmap), Point2D<int>(w,0));
02323 
02324   // Raster::WriteRGB(crop(Image<PixRGB<byte> >(dIma+dSmap), 
02325   //                       Point2D<int>(50,0), Dims(150,100)),
02326   //                  std::string("starfish_algorithm_4.pnm"));
02327 
02328   itsWin->drawImage(dispIma, 0,0);
02329   Raster::waitForKey();
02330 }
02331 
02332 // ######################################################################
02333 void SalientRegionSegmenter::displayGrowMap
02334   (Image<int> assignmentMap, Point2D<int> currPoint,
02335    std::vector<Point2D<int> > currentObjectLocations,
02336    std::vector<Point2D<int> > currentObjectCoreLocations,
02337    std::vector<Point2D<int> > currentBackgroundLocations,
02338    std::vector<Point2D<int> > currentUnassignedLocations,
02339    Image<bool> isComparedWith, Segment segment)
02340 {
02341   // display stuff
02342   Image<PixRGB<byte> > ima = itsImage;
02343   uint w = ima.getWidth();
02344   uint h = ima.getHeight();
02345 
02346   Image<float> fIma(luminance(ima));
02347   Image<float> tempFIma = fIma;
02348   inplaceNormalize(tempFIma, 0.0f,255.0f);  
02349   Image<byte>  bIma(tempFIma); 
02350 
02351   // get the image
02352   float mVal = 32;
02353   float bVal = 255 - mVal;
02354   Image<byte> dImaR, dImaG, dImaB;
02355   getComponents(ima, dImaR, dImaG, dImaB);
02356   inplaceNormalize(dImaR, byte(0), byte(mVal));
02357   inplaceNormalize(dImaG, byte(0), byte(mVal));
02358   inplaceNormalize(dImaB, byte(0), byte(mVal));
02359   Image<PixRGB<byte> > dIma  = makeRGB(dImaR,dImaG,dImaB);
02360 
02361   Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS);
02362 
02363   inplacePaste (dispIma, ima, Point2D<int>(0,0));
02364 
02365   Image<float> stateMapR(w,h, ZEROS);
02366   Image<float> stateMapG(w,h, ZEROS);
02367   Image<float> stateMapB(w,h, ZEROS);
02368 
02369   std::vector<Point2D<int> >::iterator oitr = 
02370     currentObjectLocations.begin();
02371   std::vector<Point2D<int> >::iterator citr = 
02372     currentObjectCoreLocations.begin();
02373   std::vector<Point2D<int> >::iterator sitr = 
02374     currentBackgroundLocations.begin();
02375   std::vector<Point2D<int> >::iterator uitr = 
02376     currentUnassignedLocations.begin();
02377   
02378   for(uint i = 0; i < currentObjectLocations.size(); i++)
02379     {
02380       Point2D<int> pt((*oitr).i*BOUNDARY_STEP_SIZE,
02381                       (*oitr).j*BOUNDARY_STEP_SIZE );
02382       Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4);
02383       drawFilledRect(stateMapR, r, 0.5F);
02384       oitr++;
02385     }
02386 
02387   for(uint i = 0; i < currentObjectCoreLocations.size(); i++)
02388     {
02389       Point2D<int> pt((*citr).i*BOUNDARY_STEP_SIZE,
02390                       (*citr).j*BOUNDARY_STEP_SIZE );
02391       Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4);
02392       drawFilledRect(stateMapB, r, 0.5F);
02393       citr++;
02394     }
02395 
02396   for(uint i = 0; i < currentBackgroundLocations.size(); i++)
02397     {
02398       Point2D<int> pt((*sitr).i*BOUNDARY_STEP_SIZE,
02399                       (*sitr).j*BOUNDARY_STEP_SIZE );
02400       Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4);
02401       drawFilledRect(stateMapG, r, 0.5F);
02402       sitr++;
02403     }
02404 
02405   for(uint i = 0; i < currentUnassignedLocations.size(); i++)
02406     {
02407       Point2D<int> pt((*uitr).i*BOUNDARY_STEP_SIZE,
02408                       (*uitr).j*BOUNDARY_STEP_SIZE );
02409       Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4);
02410       drawFilledRect(stateMapR, r, 0.5F);
02411       drawFilledRect(stateMapG, r, 0.5F);
02412       uitr++;
02413     }
02414 
02415   // draw grid
02416   int grad = 8;
02417   for(uint i = grad; i < w; i++)
02418     for(uint j = grad; j < h; j++)
02419       {
02420         if(i%grad == 0 && j%grad == 0)
02421           {
02422             drawCross(stateMapR, Point2D<int>(i,j), 0.5F, 1);
02423             drawCross(stateMapG, Point2D<int>(i,j), 0.5F, 1);
02424             drawCross(stateMapB, Point2D<int>(i,j), 0.5F, 1);
02425           }
02426       }
02427   
02428   // draw the contour 
02429   rutz::shared_ptr<Contour> contour = 
02430     itsContourBoundaries[segment.contourIndex];  
02431 
02432   int hstep = BOUNDARY_STEP_SIZE/2;
02433   uint start = segment.segStartIndex;
02434   uint end   = segment.segEndIndex;
02435   //for(uint i = start; i <= end; i++)
02436   //  {
02437   for(uint i = 0; i < contour->edgels.size(); i++)
02438     {
02439       rutz::shared_ptr<Edgel> edgel = contour->edgels[i];
02440           
02441       uint aind = edgel->angleIndex; 
02442       float baind = 
02443         fmod((aind+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS);
02444       
02445       float dx = cos(baind * M_PI/4.0) * hstep; 
02446       float dy = sin(baind * M_PI/4.0) * hstep;
02447       
02448       Point2D<int> pt = edgel->pt;
02449       Point2D<int> p1 = pt + Point2D<int>( dx+.5,  dy+.5); 
02450       Point2D<int> p2 = pt + Point2D<int>(-dx-.5, -dy-.5);
02451       
02452       if(i >= start && i <= end) 
02453         {
02454           drawLine(stateMapR, p1, p2, 1.0F);
02455           drawLine(stateMapG, p1, p2, 1.0F);
02456           drawLine(stateMapB, p1, p2, 1.0F);
02457         }
02458       else
02459         {
02460           drawLine(stateMapR, p1, p2, 0.5F);
02461           drawLine(stateMapG, p1, p2, 0.5F);
02462           drawLine(stateMapB, p1, p2, 0.5F);
02463         }
02464       //drawDisk(stateMap, pt, 2,  1.0F);
02465     }
02466 
02467   inplaceNormalize(stateMapR, 0.0f,bVal);
02468   inplaceNormalize(stateMapG, 0.0f,bVal);
02469   inplaceNormalize(stateMapB, 0.0f,bVal);
02470   Image<byte> dSMapR(stateMapR);
02471   Image<byte> dSMapG(stateMapG);
02472   Image<byte> dSMapB(stateMapB);
02473   Image<PixRGB<byte> > dSmap = makeRGB(dSMapR, dSMapG, dSMapB);
02474   inplacePaste
02475     (dispIma, Image<PixRGB<byte> >(dIma+dSmap), Point2D<int>(w,0));
02476 
02477   // Raster::WriteRGB(crop(Image<PixRGB<byte> >(dIma+dSmap), 
02478   //                       Point2D<int>(50,0), Dims(150,100)),
02479   //                  std::string("starfish_algorithm_4.pnm"));
02480 
02481   itsWin->drawImage(dispIma, 0,0);
02482   Raster::waitForKey();
02483 }
02484 
02485 // ######################################################################
02486 /* So things look consistent in everyone's emacs... */
02487 /* Local Variables: */
02488 /* indent-tabs-mode: nil */
02489 /* End: */
Generated on Sun May 8 08:04:48 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3