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