segmentImageMC2.C

Go to the documentation of this file.
00001 /*!@file VFAT/segmentImageMC2.C Basic image segmenter blob finder using color */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: T. Nathan Mundhenk <mundhenk@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/VFAT/segmentImageMC2.C $
00035 // $Id: segmentImageMC2.C 10794 2009-02-08 06:21:09Z itti $
00036 //
00037 
00038 // ############################################################
00039 // ############################################################
00040 // ##### --- VFAT ---
00041 // ##### Vision Feature Analysis Tool:
00042 // ##### T. Nathan Mundhenk nathan@mundhenk.com
00043 // ##### Laurent Itt itti@pollux.usc.edu
00044 // #####
00045 // ############################################################
00046 // ############################################################
00047 
00048 #ifndef SEGMENTIMAGEMC2_C_DEFINED
00049 #define SEGMENTIMAGEMC2_C_DEFINED
00050 
00051 #include "Util/Assert.H"
00052 #include "VFAT/segmentImageMC2.H"
00053 #include <iostream>
00054 #include <vector>
00055 #include <cstdio>
00056 #include <cstdlib>
00057 
00058 /*********************************************************************/
00059 /*********************************************************************/
00060 /*        PUBLIC methods                                             */
00061 /*********************************************************************/
00062 /*********************************************************************/
00063 
00064 /*********************************************************************/
00065 
00066 template SI_TEMPLATE_CLASS
00067 segmentImageMC2<SI_TEMPLATE>::segmentImageMC2()
00068 {
00069   SI_set1 = false; SI_set2 = false; SI_set3 = false; SI_set4 = false;
00070   LINFO("CREATED");
00071   SI_lowThresh.resize(SI_channels,0);
00072   SI_highThresh.resize(SI_channels,0);
00073   SI_maxIDVal = 0;
00074   SI_killVal  = 2;
00075   Image<FLOAT> timage;
00076   SI_infeatureMaps.resize(SI_channels,timage);
00077   SI_useCandidateBandPass = true;
00078   SI_removeSingles        = true;
00079   SI_set4                 = true;
00080 }
00081 
00082 /*********************************************************************/
00083 
00084 template SI_TEMPLATE_CLASS
00085 segmentImageMC2<SI_TEMPLATE>::~segmentImageMC2()
00086 {}
00087 
00088 /* set color segmentation values for color and
00089    threshold
00090 */
00091 
00092 /*********************************************************************/
00093 
00094 template SI_TEMPLATE_CLASS inline
00095 void segmentImageMC2<SI_TEMPLATE>::SIsetVal(const typename
00096                                            std::vector<FLOAT> &val,
00097                                            const typename
00098                                            std::vector<FLOAT> &thresh)
00099 {
00100   typename std::vector<FLOAT>::iterator ilowThresh    = SI_lowThresh.begin();
00101   typename std::vector<FLOAT>::iterator ihighThresh   = SI_highThresh.begin();
00102   typename std::vector<FLOAT>::const_iterator ival    = val.begin();
00103   typename std::vector<FLOAT>::const_iterator ithresh = thresh.begin();
00104 
00105   for(INT i = 0; i < val.size(); i++, ++ilowThresh, ++ihighThresh,
00106         ++ival, ++ithresh)
00107   {
00108     *ilowThresh  = *ival - *ithresh;
00109     *ihighThresh = *ival + *ithresh;
00110   }
00111   SI_set1 = true;
00112 }
00113 
00114 /*********************************************************************/
00115 
00116 template SI_TEMPLATE_CLASS inline
00117 void segmentImageMC2<SI_TEMPLATE>::SIsetValThresh(const typename
00118                                                  std::vector<FLOAT> &high,
00119                                                  const typename
00120                                                  std::vector<FLOAT> &low)
00121 {
00122   SI_lowThresh  = low;
00123   SI_highThresh = high;
00124 
00125   typename std::vector<FLOAT>::iterator ilow  = SI_lowThresh.begin();
00126   typename std::vector<FLOAT>::iterator ihigh = SI_highThresh.begin();
00127 
00128   // Check to make sure low is less than high for each feature
00129   while(ilow != SI_lowThresh.end())
00130   {
00131     if(*ilow >= *ihigh)
00132     {
00133       LFATAL("Low threshold must be less than high theshold. Got L %f H %f",*ilow,*ihigh);
00134     }
00135     ++ilow; ++ihigh;
00136   }
00137 
00138   SI_set1 = true;
00139 }
00140 /*********************************************************************/
00141 
00142 template SI_TEMPLATE_CLASS inline
00143 void segmentImageMC2<SI_TEMPLATE>::SIresetCandidates(const bool whichWay)
00144 {
00145   Image<bool>::iterator
00146     candidatePixelsIter    = SI_candidatePixels.beginw();
00147 
00148   Image<bool>::iterator
00149     preCandidatePixelsIter = SI_preCandidatePixels.beginw();
00150 
00151   // set initial candidates for each pixel
00152 
00153   while(candidatePixelsIter != SI_candidatePixels.endw())
00154   {
00155     *candidatePixelsIter    = false;
00156     *preCandidatePixelsIter = whichWay;
00157     ++candidatePixelsIter; ++preCandidatePixelsIter;
00158   }
00159 }
00160 
00161 /*********************************************************************/
00162 /* set size of window frame to inspect in image */
00163 
00164 template SI_TEMPLATE_CLASS inline
00165 void segmentImageMC2<SI_TEMPLATE>::SIsetFrame(int *x, int *y)
00166 {
00167   SI_masterVec.resize(*x*(*y),-1);
00168   SI_reOrderVec.resize(*x*(*y));
00169   SI_reverseOrderVec.resize(*x*(*y));
00170   SI_centerX.resize(*x*(*y));
00171   SI_centerY.resize(*x*(*y));
00172   SI_Xsum.resize(*x*(*y));
00173   SI_Ysum.resize(*x*(*y));
00174   SI_mass.resize(*x*(*y));
00175   SI_xmin.resize(*x*(*y));
00176   SI_xmax.resize(*x*(*y));
00177   SI_ymin.resize(*x*(*y));
00178   SI_ymax.resize(*x*(*y));
00179   SI_reset.resize(*x*(*y));
00180   LINFO("SETTING WIDTH %d, HEIGHT %d",*x,*y);
00181   SI_blobID.resize(*x,*y,-1);
00182   SI_candidatePixels.resize(*x,*y,false);
00183   SI_preCandidatePixels.resize(*x,*y,false);
00184   SI_set2 = true;
00185 }
00186 
00187 /*********************************************************************/
00188 
00189 template SI_TEMPLATE_CLASS inline
00190 void segmentImageMC2<SI_TEMPLATE>::SIsetAvg(const INT doAvg)
00191 {
00192   typename std::vector<FLOAT> temp(SI_channels,0);
00193 
00194   SI_avg.resize(doAvg,temp);
00195   SI_std.resize(doAvg,temp);
00196   SI_N.resize(doAvg,0);
00197   SI_tempAvg.resize(doAvg,0);
00198   SI_tempStd.resize(doAvg,0);
00199   SI_iter = doAvg;
00200   SI_count = 0;
00201   SI_set3 = true;
00202 }
00203 
00204 /*********************************************************************/
00205 
00206 template SI_TEMPLATE_CLASS inline
00207 void segmentImageMC2<SI_TEMPLATE>::SIresetAvg()
00208 {
00209   typename std::vector<FLOAT> temp(SI_channels,0);
00210 
00211   for(typename std::vector<std::vector<FLOAT> >::iterator
00212         iavg = SI_avg.begin(); iavg != SI_avg.end(); ++iavg)
00213     *iavg = temp;
00214   for(typename std::vector<std::vector<FLOAT> >::iterator
00215         istd = SI_std.begin(); istd != SI_std.end(); ++istd)
00216     *istd = temp;
00217 
00218   typename std::vector<FLOAT>::iterator itempAvg = SI_tempAvg.begin();
00219   typename std::vector<FLOAT>::iterator itempStd = SI_tempStd.begin();
00220   typename std::vector<INT>::iterator   iN       = SI_N.begin();
00221 
00222   for(unsigned int i = 0; i < SI_N.size(); i++,
00223         ++itempAvg, ++itempStd, ++iN)
00224   {
00225     *itempAvg = 0.0F; *itempStd = 0.0F; *iN = 0;
00226   }
00227   SI_count = 0;
00228 
00229 }
00230 
00231 /*********************************************************************/
00232 /*********************************************************************/
00233 /* do image segmentation by calling private memebers to
00234    operate on image.
00235    1. Low pass image
00236    2. Find candidate pixels
00237    3. Eleminate single isolated candidates
00238    4. Link pixels in each blob
00239    5. Clean up
00240 */
00241 /*********************************************************************/
00242 /*********************************************************************/
00243 template SI_TEMPLATE_CLASS
00244 void segmentImageMC2<SI_TEMPLATE>::SIsegment(
00245                                Image<PixRGB<byte> > *image,
00246                                typename std::vector<Image<FLOAT> > *featureMap,
00247                                const bool lowPass)
00248 {
00249   SI_workImage      = image;
00250   SIsegment(featureMap,lowPass);
00251 }
00252 
00253 /*********************************************************************/
00254 template SI_TEMPLATE_CLASS
00255 void segmentImageMC2<SI_TEMPLATE>::SIsegment(
00256                                typename std::vector<Image<FLOAT> > *featureMap,
00257                                const bool lowPass)
00258 {
00259   struct timezone tz;
00260   struct timeval start, stop;
00261   tz.tz_minuteswest = 0;
00262   tz.tz_dsttime     = 0;
00263   gettimeofday(&start, &tz);
00264 
00265   // Low pass image if desired
00266   if(lowPass)
00267   {
00268     typename std::vector<Image<FLOAT> >::iterator
00269       iimage = featureMap->begin();
00270     typename std::vector<Image<FLOAT> >::iterator
00271       ifmap = SI_infeatureMaps.begin();
00272 
00273     while(iimage != featureMap->end())
00274     {
00275       *ifmap = lowPass5(*iimage);
00276       ++ifmap; ++iimage;
00277     }
00278     SI_featureMaps = &SI_infeatureMaps;
00279   }
00280   else
00281     SI_featureMaps = featureMap;
00282 
00283 
00284   // run doSegment which will call several consecutive methods
00285   SIdoSegment();
00286 
00287   gettimeofday(&stop,&tz);
00288 }
00289 
00290 /*********************************************************************/
00291 template SI_TEMPLATE_CLASS
00292 void segmentImageMC2<SI_TEMPLATE>::SItoggleCandidateBandPass(const bool toggle)
00293 {
00294   SI_useCandidateBandPass = toggle;
00295 }
00296 
00297 /*********************************************************************/
00298 template SI_TEMPLATE_CLASS
00299 void segmentImageMC2<SI_TEMPLATE>::SItoggleRemoveSingles(const bool toggle)
00300 {
00301   SI_removeSingles = toggle;
00302 }
00303 
00304 /*********************************************************************/
00305 template SI_TEMPLATE_CLASS
00306 void segmentImageMC2<SI_TEMPLATE>::SIsetKillValue(const unsigned int kv)
00307 {
00308   SI_killVal = kv;
00309 }
00310 
00311 /*********************************************************************/
00312 /* This method when called will take all remaning blobs from post
00313    processing and create a mother blob
00314 */
00315 template SI_TEMPLATE_CLASS
00316 Image<INT> segmentImageMC2<SI_TEMPLATE>::SIcreateMother(const Image<INT> &img) const
00317 {
00318   Image<INT> mother;
00319   mother.resize(img.getWidth(),img.getHeight(),ZEROS);
00320   for(int x = SI_frameX1; x < SI_frameX2; x++)
00321   {
00322     for(int y = SI_frameY1; y < SI_frameY2; y++)
00323     {
00324       if(img.getVal(x,y) != 0)
00325         mother.setVal(x,y,1);
00326       else
00327         mother.setVal(x,y,0);
00328     }
00329   }
00330   return mother;
00331 }
00332 
00333 /*********************************************************************/
00334 /* return blob map
00335  */
00336 template SI_TEMPLATE_CLASS
00337 Image<int> segmentImageMC2<SI_TEMPLATE>::SIreturnBlobs() const
00338 {
00339   return SI_blobID;
00340 }
00341 
00342 /*********************************************************************/
00343 
00344 template SI_TEMPLATE_CLASS
00345 Image<bool> segmentImageMC2<SI_TEMPLATE>::SIreturnCandidates() const
00346 {
00347   return SI_candidatePixels;
00348 }
00349 
00350 /*********************************************************************/
00351 
00352 template SI_TEMPLATE_CLASS
00353 Image<FLOAT> segmentImageMC2<SI_TEMPLATE>::SIreturnNormalizedCandidates() const
00354 {
00355   Image<FLOAT> NC;
00356   NC.resize(SI_candidatePixels.getWidth(),SI_candidatePixels.getHeight());
00357   for(int x = 0; x < SI_candidatePixels.getWidth(); x++)
00358   {
00359     for(int y = 0; y < SI_candidatePixels.getHeight(); y++)
00360     {
00361       if(SI_candidatePixels.getVal(x,y))
00362         NC.setVal(x,y,255);
00363       else
00364         NC.setVal(x,y,0);
00365     }
00366   }
00367   return NC;
00368 }
00369 
00370 /*********************************************************************/
00371 
00372 template SI_TEMPLATE_CLASS
00373 Image<PixRGB<FLOAT> > segmentImageMC2<SI_TEMPLATE>::SIreturnWorkImage() const
00374 {
00375   ASSERT((SI_doType == 1) || (SI_doType == 2));
00376   return *SI_workImage;
00377 }
00378 
00379 /*********************************************************************/
00380 
00381 template SI_TEMPLATE_CLASS
00382 INT segmentImageMC2<SI_TEMPLATE>::SInumberBlobs() const
00383 {
00384   return SI_totalBlobs;
00385 }
00386 
00387 /*********************************************************************/
00388 
00389 template SI_TEMPLATE_CLASS
00390 std::vector<INT> segmentImageMC2<SI_TEMPLATE>::SIgetBlobMap() const
00391 {
00392   return SI_reOrderVec;
00393 }
00394 
00395 /*********************************************************************/
00396 
00397 template SI_TEMPLATE_CLASS
00398 void segmentImageMC2<SI_TEMPLATE>::SIcalcMassCenter()
00399 {
00400 
00401   Image<int>::iterator iblobID           = SI_blobID.beginw();
00402   Image<bool>::iterator icandidatePixels = SI_candidatePixels.beginw();
00403 
00404   const ushort width  = (ushort)SI_candidatePixels.getWidth();
00405   const ushort height = (ushort)SI_candidatePixels.getHeight();
00406 
00407   for(ushort y = 0 ; y < height; y++)
00408   {
00409     for(ushort x = 0 ; x < width; x++)
00410     {
00411       if((*icandidatePixels) && (*iblobID != -1))
00412       {
00413         //std::cerr << "foo " << reverseOrderVec[blobID.getVal(x,y)] << "\n";
00414         INT *indexBlob = &SI_reverseOrderVec[*iblobID];
00415         if(SI_reset[*indexBlob])
00416         {
00417           SI_reset[*indexBlob] = false;
00418           SI_Xsum[*indexBlob]  = x;
00419           SI_Ysum[*indexBlob]  = y;
00420           SI_mass[*indexBlob]  = 1;
00421           SI_xmin[*indexBlob]  = x;
00422           SI_ymin[*indexBlob]  = y;
00423           SI_xmax[*indexBlob]  = x;
00424           SI_ymax[*indexBlob]  = y;
00425         }
00426         else
00427         {
00428           SI_Xsum[*indexBlob] += x;
00429           SI_Ysum[*indexBlob] += y;
00430           SI_mass[*indexBlob]++;
00431 
00432           if(x <= SI_xmin[*indexBlob])
00433             SI_xmin[*indexBlob] = x;
00434           if(x >= SI_xmax[*indexBlob])
00435             SI_xmax[*indexBlob] = x;
00436           if(y <= SI_ymin[*indexBlob])
00437             SI_ymin[*indexBlob] = y;
00438           if(y >= SI_ymax[*indexBlob])
00439             SI_ymax[*indexBlob] = y;
00440         }
00441       }
00442       ++iblobID; ++icandidatePixels;
00443     }
00444   }
00445 
00446   for(INT b = 0; b < SI_totalBlobs; b++)
00447   {
00448     //std::cerr << "MASS " << mass[x] << "\n";
00449     if(SI_mass[b] > 0)
00450     {
00451       SI_centerX[b] = SI_Xsum[b]/SI_mass[b];
00452       SI_centerY[b] = SI_Ysum[b]/SI_mass[b];
00453     }
00454   }
00455 }
00456 
00457 /*********************************************************************/
00458 
00459 template SI_TEMPLATE_CLASS
00460 FLOAT segmentImageMC2<SI_TEMPLATE>::SIgetCenterX(const INT blob) const
00461 {
00462   return SI_centerX[blob];
00463 }
00464 
00465 /*********************************************************************/
00466 
00467 template SI_TEMPLATE_CLASS
00468 FLOAT segmentImageMC2<SI_TEMPLATE>::SIgetCenterY(const INT blob) const
00469 {
00470   return SI_centerY[blob];
00471 }
00472 
00473 /*********************************************************************/
00474 
00475 template SI_TEMPLATE_CLASS
00476 INT segmentImageMC2<SI_TEMPLATE>::SIgetMass(const INT blob) const
00477 {
00478   return SI_mass[blob];
00479 }
00480 
00481 /*********************************************************************/
00482 
00483 template SI_TEMPLATE_CLASS
00484 int segmentImageMC2<SI_TEMPLATE>::SIgetXmin(const INT blob) const
00485 {
00486   return SI_xmin[blob];
00487 }
00488 
00489 /*********************************************************************/
00490 //! get X max for a blob
00491 template SI_TEMPLATE_CLASS
00492 int segmentImageMC2<SI_TEMPLATE>::SIgetXmax(const INT blob) const
00493 {
00494   return SI_xmax[blob];
00495 }
00496 
00497 /*********************************************************************/
00498 //! get Y min for a blob
00499 template SI_TEMPLATE_CLASS
00500 int segmentImageMC2<SI_TEMPLATE>::SIgetYmin(const INT blob) const
00501 {
00502   return SI_ymin[blob];
00503 }
00504 
00505 /*********************************************************************/
00506 //! get Y max for a blob
00507 template SI_TEMPLATE_CLASS
00508 int segmentImageMC2<SI_TEMPLATE>::SIgetYmax(const INT blob) const
00509 {
00510   return SI_ymax[blob];
00511 }
00512 
00513 /*********************************************************************/
00514 //! get the working image size in X
00515 template SI_TEMPLATE_CLASS
00516 int segmentImageMC2<SI_TEMPLATE>::SIgetImageSizeX() const
00517 {
00518   return SI_candidatePixels.getWidth();
00519 }
00520 
00521 /*********************************************************************/
00522 //! get the working image size in Y
00523 template SI_TEMPLATE_CLASS
00524 int segmentImageMC2<SI_TEMPLATE>::SIgetImageSizeY() const
00525 {
00526   return SI_candidatePixels.getHeight();
00527 }
00528 
00529 /*********************************************************************/
00530 template SI_TEMPLATE_CLASS inline
00531 void segmentImageMC2<SI_TEMPLATE>::SIgetValue(INT *blob,
00532                                       typename std::vector<FLOAT> *mean,
00533                                       typename std::vector<FLOAT> *std,
00534                                       INT *in)
00535 {
00536   typename std::vector<FLOAT>::iterator imean = mean->begin();
00537   typename std::vector<FLOAT>::iterator istd  = std->begin();
00538   typename std::vector<Image<FLOAT> >::iterator
00539     ifeatureMaps = SI_featureMaps->begin();
00540 
00541   bool dothis = true;
00542   *in = 0;
00543   for(INT i = 0; i < SI_featureMaps->size(); i++, ++imean, ++istd,
00544         ++ifeatureMaps)
00545   {
00546     Image<bool>::iterator icandidatePixels      = SI_candidatePixels.beginw();
00547     Image<int>::iterator iblobID               = SI_blobID.beginw();
00548     typename Image<FLOAT>::iterator iifeatureMaps = ifeatureMaps->beginw();
00549 
00550     FLOAT tot = 0;
00551     FLOAT ss = 0;
00552 
00553     while(icandidatePixels != SI_candidatePixels.endw())
00554     {
00555       if((*icandidatePixels) && (*iblobID != -1))
00556       {
00557         if(SI_reverseOrderVec[*iblobID] == *blob)
00558         {
00559           tot += *iifeatureMaps;
00560           ss += (pow(*iifeatureMaps,2))/SI_mass[*blob];
00561         }
00562       }
00563       ++icandidatePixels; ++iblobID; ++iifeatureMaps;
00564     }
00565     if(SI_mass[*blob] > 0)
00566     {
00567       *imean = tot/SI_mass[*blob];
00568       *istd = sqrt(fabs(ss - pow(*imean,2)));
00569       if(dothis == true)
00570         *in = SI_mass[*blob] + *in;
00571     }
00572     dothis = false;
00573   }
00574 }
00575 
00576 /*********************************************************************/
00577 
00578 template SI_TEMPLATE_CLASS
00579 void segmentImageMC2<SI_TEMPLATE>::SIgetValueMean(INT *blobListSize,
00580                                           typename std::vector<INT> *blobList,
00581                                           typename std::vector<FLOAT> *mean,
00582                                           typename std::vector<FLOAT> *stdd,
00583                                           FLOAT *mass)
00584 {
00585   // average feature channels over N iterations for all motherblobs
00586   // modulus on dataset size
00587   if(SI_count == SI_iter)
00588     SI_count = 0;
00589 
00590   INT SI_tempN;
00591 
00592   typename std::vector<INT>::iterator iN                   = SI_N.begin();
00593   typename std::vector<std::vector<FLOAT> >::iterator iavg = SI_avg.begin();
00594   typename std::vector<std::vector<FLOAT> >::iterator istd = SI_std.begin();
00595 
00596   typename std::vector<FLOAT> *pavg = &SI_avg[SI_count];
00597   typename std::vector<FLOAT> *pstd = &SI_std[SI_count];
00598   INT *pcount = &SI_N[SI_count];
00599   *pcount = 0;
00600 
00601   // get mean values etc. for all blobs in this iteration
00602   for(INT i = 0; i < *blobListSize; i++)
00603   {
00604     SIgetValue(&blobList->at(i), &SI_tempAvg, &SI_tempStd, &SI_tempN);
00605     *pcount = SI_tempN + (*pcount);
00606     for(INT f = 0; f < SI_featureMaps->size(); f++)
00607     {
00608       pavg->at(f) += SI_tempAvg[f]*SI_tempN;
00609       pstd->at(f) += SI_tempStd[f]*SI_tempN;
00610     }
00611   }
00612 
00613   for(INT f = 0; f < SI_featureMaps->size(); f++)
00614   {
00615     pavg->at(f) = pavg->at(f)/(*pcount);
00616     pstd->at(f) = pstd->at(f)/(*pcount);
00617   }
00618   *mass = *pcount;
00619   SI_count++;
00620 
00621   INT massSum = 0;
00622 
00623   // combine the results over the last N iterations for everything
00624   for(INT c = 0; c < SI_iter; c++, ++iavg, ++istd, ++iN)
00625   {
00626     massSum += *iN;
00627     typename std::vector<FLOAT>::iterator iiavg = iavg->begin();
00628     typename std::vector<FLOAT>::iterator iistd = istd->begin();
00629     typename std::vector<FLOAT>::iterator imean = mean->begin();
00630     typename std::vector<FLOAT>::iterator istdd = stdd->begin();
00631 
00632     for(INT i = 0; i < SI_featureMaps->size(); i++, ++iiavg, ++iistd,
00633           ++imean, ++istdd)
00634     {
00635       if(*iN != 0)
00636       {
00637         *imean += *iiavg*(*iN);
00638         *istdd += *iistd*(*iN);
00639       }
00640     }
00641   }
00642 
00643   // find the total mean and std over all blobs and iterations
00644   typename std::vector<FLOAT>::iterator imean = mean->begin();
00645   typename std::vector<FLOAT>::iterator istdd = stdd->begin();
00646   for(INT i = 0; i < SI_featureMaps->size(); i++, ++imean, ++istdd)
00647   {
00648     *imean = *imean/massSum;
00649     *istdd = *istdd/massSum;
00650   }
00651 }
00652 
00653 /*********************************************************************/
00654 /*********************************************************************/
00655 /*        PRIVATE methods                                            */
00656 /*********************************************************************/
00657 /*********************************************************************/
00658 
00659 /*********************************************************************/
00660 
00661 /*! find candidate pixels by just checking image pixels to see if they
00662    are within threshold of desired feature values
00663    if so, set candidatePixels image pixel to true
00664 */
00665 template SI_TEMPLATE_CLASS inline
00666 void segmentImageMC2<SI_TEMPLATE>::SIfindCandidates()
00667 {
00668   // FIX
00669   std::vector<int>::iterator imasterVec = SI_masterVec.begin();
00670 
00671   while(imasterVec != SI_masterVec.end())
00672     *imasterVec++ = -1;
00673 
00674   Image<bool>::iterator
00675     candidatePixelsIter    = SI_candidatePixels.beginw();
00676 
00677   Image<bool>::iterator
00678     preCandidatePixelsIter = SI_preCandidatePixels.beginw();
00679 
00680   // set initial candidates for each pixel
00681 
00682   while(candidatePixelsIter != SI_candidatePixels.endw())
00683   {
00684     if((*preCandidatePixelsIter) == true)
00685     {
00686       *candidatePixelsIter = true;
00687     }
00688     else
00689     {
00690       *candidatePixelsIter = false;
00691     }
00692     *preCandidatePixelsIter = true;
00693     ++candidatePixelsIter; ++preCandidatePixelsIter;
00694   }
00695 
00696   typename std::vector<Image<FLOAT> >::iterator ifeatureMaps;
00697   typename std::vector<FLOAT>::iterator ilowThresh  = SI_lowThresh.begin();
00698   typename std::vector<FLOAT>::iterator ihighThresh = SI_highThresh.begin();
00699   // Run over each feature channel
00700 
00701   for(ifeatureMaps = SI_featureMaps->begin();
00702       ifeatureMaps !=  SI_featureMaps->end(); ++ifeatureMaps,
00703         ++ilowThresh, ++ihighThresh)
00704   {
00705     typename Image<FLOAT>::iterator iifeatureMaps = ifeatureMaps->beginw();
00706     preCandidatePixelsIter = SI_preCandidatePixels.beginw();
00707     candidatePixelsIter    = SI_candidatePixels.beginw();
00708 
00709     // Run over each pixel
00710 
00711     while(iifeatureMaps != ifeatureMaps->endw())
00712     {
00713       if((*iifeatureMaps > *ihighThresh) || (*iifeatureMaps < *ilowThresh))
00714       {
00715         *preCandidatePixelsIter = false;
00716         *candidatePixelsIter    = false;
00717       }
00718       //else
00719         //LINFO("VAL %f",*iifeatureMaps);
00720       ++preCandidatePixelsIter; ++candidatePixelsIter; ++iifeatureMaps;
00721     }
00722   }
00723 }
00724 
00725 /*********************************************************************/
00726 
00727 /*! find candidate pixels by just checking image pixels to see if they
00728    are within threshold of desired feature values
00729    if so, set candidatePixels image pixel to true
00730 */
00731 template SI_TEMPLATE_CLASS inline
00732 void segmentImageMC2<SI_TEMPLATE>::SIfindCandidatesNoBandPass()
00733 {
00734   // FIX
00735   std::vector<int>::iterator imasterVec = SI_masterVec.begin();
00736 
00737   while(imasterVec != SI_masterVec.end())
00738     *imasterVec++ = -1;
00739 
00740   Image<bool>::iterator
00741     candidatePixelsIter    = SI_candidatePixels.beginw();
00742 
00743   // set initial candidates for each pixel
00744 
00745   while(candidatePixelsIter != SI_candidatePixels.endw())
00746   {
00747     *candidatePixelsIter = true;
00748     ++candidatePixelsIter;
00749   }
00750 
00751 
00752   typename std::vector<Image<FLOAT> >::iterator ifeatureMaps;
00753   typename std::vector<FLOAT>::iterator ilowThresh  = SI_lowThresh.begin();
00754   typename std::vector<FLOAT>::iterator ihighThresh = SI_highThresh.begin();
00755   // Run over each feature channel
00756 
00757   for(ifeatureMaps = SI_featureMaps->begin();
00758       ifeatureMaps !=  SI_featureMaps->end(); ++ifeatureMaps,
00759         ++ilowThresh, ++ihighThresh)
00760   {
00761     typename Image<FLOAT>::iterator iifeatureMaps = ifeatureMaps->beginw();
00762     candidatePixelsIter = SI_candidatePixels.beginw();
00763 
00764     // Run over each pixel
00765 
00766     while(iifeatureMaps != ifeatureMaps->endw())
00767     {
00768       //LINFO("Feature %f, high %f, low %f",*iifeatureMaps,*ihighThresh,*ilowThresh);
00769       if((*iifeatureMaps > *ihighThresh) || (*iifeatureMaps < *ilowThresh))
00770         *candidatePixelsIter = false;
00771 
00772       ++candidatePixelsIter; ++iifeatureMaps;
00773     }
00774   }
00775 }
00776 
00777 /*********************************************************************/
00778 /*! if a pixel does not have an orthogonal neighbor then it is removed
00779    i.e. all pixels without 4 connectivity are removed as noise
00780 */
00781 template SI_TEMPLATE_CLASS inline
00782 void segmentImageMC2<SI_TEMPLATE>::SIremoveSingles()
00783 {
00784   Image<bool>::iterator icandidatePixels = SI_candidatePixels.beginw();
00785 
00786   const int width  = SI_candidatePixels.getWidth();
00787   const int height = SI_candidatePixels.getHeight();
00788   for(int y = 0; y < height; y++)
00789   {
00790     for(int x = 0; x < width; x++)
00791     {
00792       if(*icandidatePixels)
00793       {
00794         unsigned int kill = 0;
00795         const int XLeft   = x - 1;
00796         const int XRight  = x + 1;
00797         const int YTop    = y - 1;
00798         const int YBottom = y + 1;
00799         if((XLeft >= 0) && (SI_candidatePixels.getVal(XLeft,y)))
00800           kill++;
00801         if((XRight < width)
00802            && (SI_candidatePixels.getVal(XRight,y)))
00803           kill++;
00804         if((YTop >= 0) && (SI_candidatePixels.getVal(x,YTop)))
00805           kill++;
00806         if((YBottom < height)
00807            && (SI_candidatePixels.getVal(x,YBottom)))
00808           kill++;
00809         if(kill < SI_killVal)
00810           *icandidatePixels = false;
00811       }
00812       ++icandidatePixels;
00813     }
00814   }
00815 }
00816 
00817 /*********************************************************************/
00818 /*! if a pixel does not have an orthogonal neighbor then it is removed
00819    i.e. all pixels without 4 connectivity are removed as noise
00820 */
00821 template SI_TEMPLATE_CLASS inline
00822 void segmentImageMC2<SI_TEMPLATE>::SIremoveSinglesItr()
00823 {
00824   Image<bool>::iterator icandidatePixels = SI_candidatePixels.beginw();
00825 
00826   const unsigned int width  = SI_candidatePixels.getWidth();
00827   const unsigned int height = SI_candidatePixels.getHeight();
00828 
00829   // hypothetically, this could cause a segmentation fault, but
00830   // we don't access this until the memory is aligned so we are OK
00831   Image<bool>::iterator icandidatePixelsTop    =
00832     SI_candidatePixels.beginw() - width;
00833   Image<bool>::iterator icandidatePixelsBottom =
00834     SI_candidatePixels.beginw() + width;
00835   Image<bool>::iterator icandidatePixelsLeft   =
00836     SI_candidatePixels.beginw() - 1;
00837   Image<bool>::iterator icandidatePixelsRight  =
00838     SI_candidatePixels.beginw() + 1;
00839 
00840   for(unsigned int y = 0; y < height; y++)
00841   {
00842     for(unsigned int x = 0; x < width; x++)
00843     {
00844       if(*icandidatePixels)
00845       {
00846         unsigned int kill = 0;
00847         if(x != 0)
00848           if(*icandidatePixelsLeft)
00849             kill++;
00850         if(x < width - 1)
00851           if(*icandidatePixelsRight)
00852             kill++;
00853         if(y != 0)
00854           if(*icandidatePixelsTop)
00855             kill++;
00856         if(y < height - 1)
00857           if(*icandidatePixelsBottom)
00858             kill++;
00859         if(kill < SI_killVal)
00860           *icandidatePixels = false;
00861       }
00862 
00863       ++icandidatePixels;
00864       ++icandidatePixelsBottom; ++icandidatePixelsRight;
00865       ++icandidatePixelsTop;    ++icandidatePixelsLeft;
00866     }
00867   }
00868 }
00869 
00870 /*********************************************************************/
00871 /*! scan pixels from top to bottom/left to right. Link all pixels in the
00872     same blob. Do this using recursive back tracking to make a blob linked
00873     as one object and not a collection of objects
00874 */
00875 template SI_TEMPLATE_CLASS inline
00876 void segmentImageMC2<SI_TEMPLATE>::SIdiscreteLinking()
00877 {
00878   const ushort width    = (ushort)SI_candidatePixels.getWidth();
00879   const ushort height   = (ushort)SI_candidatePixels.getHeight();
00880   bool trace            = false;
00881   INT pixID             = 0;
00882   SI_maxIDVal           = 1;
00883   SI_masters            = 1;
00884   SI_mastersCount       = 0;
00885   int lastNeighbor;
00886 
00887   for(ushort x = 0; x < width; x++)
00888   {
00889     trace        = false;
00890     lastNeighbor = -2;
00891     for(ushort y = 0; y < height; y++)
00892     {
00893       if(SI_candidatePixels.getVal(x,y))
00894       {
00895         if(!trace)
00896         {
00897           pixID++;
00898           trace        = true;
00899           lastNeighbor = -2;
00900         }
00901         SI_blobID.setVal(x,y,pixID);
00902         if(x > 0) // 1 or 0?
00903         {
00904           if(SI_candidatePixels.getVal(x-1,y))
00905           {
00906             // relink blob pixels if needed
00907             const INT check =  SI_blobID.getVal((x-1),y);
00908             if((signed)check != lastNeighbor)
00909             {
00910               SIbackwardLink(pixID,check);
00911               lastNeighbor = check;
00912             }
00913             else
00914             {
00915               SIbasicLink(pixID);
00916             }
00917           }
00918           else
00919           {
00920             lastNeighbor = -2;
00921             SIbasicLink(pixID);
00922           }
00923         }
00924         else
00925         {
00926           SIbasicLink(pixID);
00927         }
00928       }
00929       else
00930       {
00931         trace        = false;
00932         SI_blobID.setVal(x,y,0);
00933         lastNeighbor = -2;
00934       }
00935     }
00936   }
00937   LINFO("Candidate pixels recognized %d",pixID);
00938   SI_num = pixID;
00939 }
00940 
00941 /*********************************************************************/
00942 /*! scan pixels from top to bottom/left to right. Link all pixels in the
00943     same blob. Do this using recursive back tracking to make a blob linked
00944     as one object and not a collection of objects
00945 */
00946 template SI_TEMPLATE_CLASS inline
00947 void segmentImageMC2<SI_TEMPLATE>::SIdiscreteLinkingOrtho()
00948 {
00949   const int width       = SI_candidatePixels.getWidth();
00950   const int height      = SI_candidatePixels.getHeight();
00951   bool trace            = false;
00952   INT pixID             = 0;
00953   SI_maxIDVal           = 1;
00954   SI_masters            = 1;
00955   SI_mastersCount       = 0;
00956   int lastNeighbor;
00957 
00958   Image<bool>::iterator candidatePixelsItr = SI_candidatePixels.beginw();
00959   Image<int>::iterator  blobIDItr          = SI_blobID.beginw();
00960 
00961   for(int y = 0; y < height; y++)
00962   {
00963     trace        = false;
00964     lastNeighbor = -2;
00965     for(int x = 0; x < width; x++)
00966     {
00967       // This is: if(SI_candidatePixels.getVal(x,y))
00968       if(*candidatePixelsItr++)
00969       {
00970         // Start a new pixel row group
00971         if(!trace)
00972         {
00973           pixID++;
00974           trace        = true;
00975           lastNeighbor = -2;
00976         }
00977         // This is: SI_blobID.setVal(x,y,pixID);
00978         *blobIDItr++ = pixID;
00979         if(y > 0) // 1 or 0?
00980         {
00981           //This is: if(SI_candidatePixels.getVal(x,y-1))
00982           if(*(candidatePixelsItr - (1 + width)))
00983           {
00984             // relink blob pixels if needed
00985             //This is: const INT check =  SI_blobID.getVal(x,y-1);
00986             const INT check = *(blobIDItr - (1 + width));
00987             if((signed)check != lastNeighbor)
00988             {
00989               SIbackwardLink(pixID,check);
00990               lastNeighbor = check;
00991             }
00992             else
00993             {
00994               SIbasicLink(pixID);
00995             }
00996           }
00997           else
00998           {
00999             lastNeighbor = -2;
01000             SIbasicLink(pixID);
01001           }
01002         }
01003         else
01004         {
01005           SIbasicLink(pixID);
01006         }
01007       }
01008       else
01009       {
01010         trace        = false;
01011         //This is: SI_blobID.setVal(x,y,0);
01012         *blobIDItr++ = 0;
01013         lastNeighbor = -2;
01014       }
01015     }
01016   }
01017   //LINFO("Candidate pixels recognized %d",pixID);
01018   SI_num = pixID;
01019 }
01020 
01021 /*********************************************************************/
01022 /*! relink pixels with new val. This allows pixels that have a new value
01023    to take on the old value of the blob. Slaves take on masters and
01024    masters can take on a slaves master.
01025 
01026 */
01027 template SI_TEMPLATE_CLASS inline
01028 void segmentImageMC2<SI_TEMPLATE>::SIbackwardLink(const INT slave,
01029                                                   const INT master)
01030 {
01031   if(master > SI_maxIDVal)
01032     SI_maxIDVal = master;
01033   if(slave > SI_maxIDVal)
01034     SI_maxIDVal = slave;
01035 
01036   // my master has no master
01037   if(SI_masterVec[master] == -1)
01038   {
01039     // I have no master
01040     if(SI_masterVec[slave] == -1)
01041     {
01042       //LINFO("my master has no master/I have no master");
01043       SI_masterVec[master] = SI_masters;
01044       SI_masterVec[slave]  = SI_masters;
01045       SI_masters++;
01046       SI_mastersCount++;
01047     }
01048     // I already have a master
01049     else
01050     {
01051       //LINFO("my master has no master/I already have a master");
01052       SI_masterVec[master] = SI_masterVec[slave];
01053     }
01054   }
01055   // my master has a master
01056   else
01057   {
01058     // I have no master
01059     if(SI_masterVec[slave] == -1)
01060     {
01061       //LINFO("my master has a master/I have no master");
01062       SI_masterVec[slave] = SI_masterVec[master];
01063     }
01064     // I already have a master
01065     else
01066     {
01067       //LINFO("my master has a master/I already have a master");
01068 
01069       std::vector<int>::iterator masterVecItr = SI_masterVec.begin();
01070       for(INT i = 0; i <= SI_maxIDVal; i++, ++masterVecItr)
01071       {
01072         if(*masterVecItr == SI_masterVec[slave])
01073         {
01074           //LINFO("SET %d to %d",masterVec[i],masterVec[slave]);
01075           *masterVecItr = SI_masterVec[master];
01076         }
01077       }
01078       SI_masterVec[slave] = SI_masterVec[master];
01079       SI_mastersCount--;
01080     }
01081   }
01082 }
01083 
01084 /*********************************************************************/
01085 template SI_TEMPLATE_CLASS inline
01086 void segmentImageMC2<SI_TEMPLATE>::SIbasicLink(const INT node)
01087 {
01088   if(node > SI_maxIDVal)
01089     SI_maxIDVal = node;
01090 
01091   // my master has no master
01092   if(SI_masterVec[node] == -1)
01093   {
01094     //LINFO("my master has no master/I have no master");
01095     SI_masterVec[node] = SI_masters;
01096     SI_masters++;
01097     SI_mastersCount++;
01098   }
01099 }
01100 
01101 /*********************************************************************/
01102 /*! combine individual elements into a fully combined blob */
01103 template SI_TEMPLATE_CLASS inline
01104 void segmentImageMC2<SI_TEMPLATE>::SIcombine()
01105 {
01106   SI_totalBlobs = 0;
01107 
01108   Image<bool>::iterator candidatePixelsItr = SI_candidatePixels.beginw();
01109   Image<int>::iterator  blobIDItr          = SI_blobID.beginw();
01110 
01111   while(candidatePixelsItr != SI_candidatePixels.endw())
01112   {
01113     if(*candidatePixelsItr++)
01114       *blobIDItr = SI_masterVec[*blobIDItr];
01115     blobIDItr++;
01116   }
01117 
01118   /*
01119   for(int x = 0; x < SI_blobID.getWidth(); x++)
01120   {
01121     for(int y = 0; y < SI_blobID.getHeight(); y++)
01122     {
01123       if(SI_candidatePixels.getVal(x,y))
01124         SI_blobID.setVal(x,y,SI_masterVec[SI_blobID.getVal(x,y)]);
01125     }
01126   }
01127   */
01128 
01129   std::vector<int>::iterator masterVecItr           = SI_masterVec.begin();
01130   typename std::vector<INT>::iterator reOrderVecItr = SI_reOrderVec.begin();
01131   std::vector<bool>::iterator resetItr              = SI_reset.begin();
01132 
01133   for(INT x = 0; x < SI_num; x++, ++masterVecItr)
01134   {
01135     bool add = true;
01136     //LINFO("Master Vec %d is %d",x,masterVec[x]);
01137     for(INT y = 0; y < SI_totalBlobs; y++)
01138     {
01139       if((int)SI_reOrderVec[y] == *masterVecItr)
01140         add = false;
01141     }
01142 
01143     if((add) && (*masterVecItr != -1))
01144     {
01145       //LINFO("DOING %d",masterVec[x]);
01146       *reOrderVecItr = *masterVecItr;
01147       SI_reverseOrderVec[*masterVecItr] = SI_totalBlobs;
01148       *resetItr = true;
01149       SI_totalBlobs++; ++reOrderVecItr; ++resetItr;
01150     }
01151   }
01152 }
01153 
01154 /*********************************************************************/
01155 
01156 template SI_TEMPLATE_CLASS inline
01157 void segmentImageMC2<SI_TEMPLATE>::SIdoSegment()
01158 {
01159   ASSERT(SI_set1); ASSERT(SI_set2); ASSERT(SI_set3); ASSERT(SI_set4);
01160   //LINFO("FINDING CANDIDATES");
01161   if(SI_useCandidateBandPass == true)
01162     SIfindCandidates();
01163   else
01164     SIfindCandidatesNoBandPass();
01165   //
01166   if(SI_removeSingles == true)
01167   {
01168     //LINFO("REMOVING SINGLES");
01169     SIremoveSinglesItr();
01170   }
01171   //LINFO("LINKING PIXELS");
01172   //SIdiscreteLinking();
01173   SIdiscreteLinkingOrtho();
01174   //LINFO("RELABELING");
01175   SIcombine();
01176   //LINFO("DONE");
01177 }
01178 
01179 #undef SI_TEMPLATE_CLASS
01180 #undef SI_TEMPLATE
01181 
01182 template class segmentImageMC2<float, unsigned int, 1>;
01183 template class segmentImageMC2<float, unsigned int, 2>;
01184 template class segmentImageMC2<float, unsigned int, 3>;
01185 template class segmentImageMC2<float, unsigned int, 4>;
01186 
01187 // ######################################################################
01188 /* So things look consistent in everyone's emacs... */
01189 /* Local Variables: */
01190 /* indent-tabs-mode: nil */
01191 /* End: */
01192 
01193 #endif
Generated on Sun May 8 08:07:04 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3