segmentImageMC.C

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