00001 /*!@file VFAT/segmentImage2.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/segmentImage2.C $ 00035 // $Id: segmentImage2.C 14376 2011-01-11 02:44:34Z pez $ 00036 // 00037 00038 #include "VFAT/segmentImage2.H" 00039 00040 #include "Util/Assert.H" 00041 #include <iostream> 00042 #include <vector> 00043 #include <cstdio> 00044 #include <cstdlib> 00045 00046 00047 00048 /* find candidate pixels by just checking image pixels to see if they 00049 are within threshold of desired RGB values 00050 if so, set candidatePixels image pixel to true 00051 */ 00052 void segmentImage2::SIfindCandidatesRGB() 00053 { 00054 PixRGB<float> pix; 00055 00056 for(unsigned int x = 0; x < SI_masterVec.size(); x++) 00057 SI_masterVec[x] = -1; 00058 00059 for(int x = SI_frameX1; x < SI_frameX2; x++) 00060 { 00061 for(int y = SI_frameY1; y < SI_frameY2; y++) 00062 { 00063 pix = SI_workImage.getVal(x,y); 00064 SI_candidatePixels.setVal(x,y,false); 00065 00066 // first check if the values are within threshold 00067 if ((pix.red() < SI_redUT) && 00068 (pix.green() < SI_greenUT) && 00069 (pix.blue() < SI_blueUT) && 00070 (pix.red() > SI_redLT) && 00071 (pix.green() > SI_greenLT) && 00072 (pix.blue() > SI_blueLT)) 00073 { 00074 SI_candidatePixels.setVal(x,y,true); 00075 00076 } 00077 } 00078 } 00079 } 00080 00081 /* find candidate pixels by just checking image pixels to see if they 00082 are within threshold of desired HSV values 00083 if so, set candidatePixels image pixel to true 00084 */ 00085 void segmentImage2::SIfindCandidatesHSV() 00086 { 00087 PixRGB<float> pix; 00088 00089 for(unsigned int x = 0; x < SI_masterVec.size(); x++) 00090 SI_masterVec[x] = -1; 00091 00092 bool modu = false; 00093 double HmoduL = SI_HLT; 00094 double HmoduU = SI_HUT; 00095 // modulus on the hue value, if lower bound is less than 0 00096 if(SI_HLT < 0) 00097 { 00098 modu = true; 00099 HmoduL = 360.0F + SI_HLT; 00100 } 00101 //else if used here because wrapping both upper and lower bounds will 00102 //cause undesirable behavior (pixels out of range for hue even though 00103 //whole range should be in range) 00104 // modulus on upper bound, if greater than 360 00105 else if(SI_HUT > 360) 00106 { 00107 modu = true; 00108 HmoduU = SI_HUT - 360.0F; 00109 } 00110 00111 Image<PixRGB<float> >::iterator 00112 workImageIter = SI_workImage.beginw() + SI_frameX1 + 00113 (SI_frameY1*SI_workImage.getWidth()); 00114 Image<bool>::iterator 00115 candidatePixelsIter = SI_candidatePixels.beginw() + SI_frameX1 + 00116 (SI_frameY1*SI_workImage.getWidth()); 00117 Image<bool>::iterator 00118 preCandidatePixelsIter = SI_preCandidatePixels.beginw() + SI_frameX1 + 00119 (SI_frameY1*SI_workImage.getWidth()); 00120 00121 int jump = SI_frameX1 + (SI_workImage.getWidth()-SI_frameX2); 00122 00123 for(int y = SI_frameY1; y < SI_frameY2; y++) 00124 { 00125 for(int x = SI_frameX1; x < SI_frameX2; x++) 00126 { 00127 float pixH,pixS,pixV; 00128 pix = (*workImageIter); 00129 PixHSV<float>(pix).getHSV(pixH,pixS,pixV); 00130 *candidatePixelsIter = false; 00131 00132 //LINFO("%f,%f,%f,%f,%f,%f",pixH, SI_HUT, pixS, SI_SUT, pixV, SI_VUT); 00133 //LINFO("%f,%f,%f,%f,%f,%f",pixH, SI_HLT, pixS, SI_SLT, pixV, SI_VLT); 00134 // first check if the values are within threshold 00135 if ((pixS < SI_SUT) && 00136 (pixV < SI_VUT) && 00137 (pixS > SI_SLT) && 00138 (pixV > SI_VLT)) 00139 { 00140 //if((pixH < SI_HUT) && (pixH > SI_HLT)) 00141 // changed to account for modulus properties in HSV for H 00142 if(((modu == false) && (pixH < SI_HUT) && (pixH > SI_HLT)) || 00143 ((modu == true) && (!((pixH > HmoduU) && (pixH < HmoduL))))) 00144 { 00145 // LINFO("PASS: %f, %f, %f,%d,%d", pixH,pixS,pixV,x,y); 00146 if((*preCandidatePixelsIter) == true) 00147 { 00148 //LINFO("SET CANDIDATE: (%d,%d)",x,y); 00149 *candidatePixelsIter = true; 00150 } 00151 *preCandidatePixelsIter = true; 00152 } 00153 else 00154 { 00155 //LINFO("FAIL: %f, %f, %f,%d,%d", pixH,pixS,pixV,x,y); 00156 *preCandidatePixelsIter = false; 00157 } 00158 } 00159 ++workImageIter; ++candidatePixelsIter; ++preCandidatePixelsIter; 00160 } 00161 workImageIter = workImageIter + jump; 00162 candidatePixelsIter = candidatePixelsIter + jump; 00163 preCandidatePixelsIter = preCandidatePixelsIter + jump; 00164 } 00165 } 00166 00167 /* find candidate pixels by just checking image pixels to see if they 00168 are within threshold of desired HSV values 00169 if so, set candidatePixels image pixel to true 00170 */ 00171 00172 void segmentImage2::SIfindCandidatesGREY() 00173 { 00174 float pix; 00175 00176 for(unsigned int x = 0; x < SI_masterVec.size(); x++) 00177 SI_masterVec[x] = -1; 00178 00179 for(int x = SI_frameX1; x < SI_frameX2; x++) 00180 { 00181 for(int y = SI_frameY1; y < SI_frameY2; y++) 00182 { 00183 pix = SI_workImageGREY.getVal(x,y); 00184 SI_candidatePixels.setVal(x,y,false); 00185 00186 // first check if the values are within threshold 00187 if ((pix < SI_VUT) && (pix > SI_VLT)) 00188 { 00189 SI_candidatePixels.setVal(x,y,true); 00190 } 00191 } 00192 } 00193 } 00194 00195 /* if a pixel does not have an orthogonal neighbor then it is removed 00196 i.e. all pixels without 4 connectivity are removed as noise 00197 */ 00198 00199 void segmentImage2::SIremoveSingles() 00200 { 00201 for(int x = SI_frameX1; x < SI_frameX2; x++) 00202 { 00203 for(int y = SI_frameY1; y < SI_frameY2; y++) 00204 { 00205 if(SI_candidatePixels.getVal(x,y)) 00206 { 00207 int kill = 0; 00208 int XLeft = x - 1; 00209 int XRight = x + 1; 00210 int YTop = y - 1; 00211 int YBottom = y + 1; 00212 if((XLeft >= 0) && (SI_candidatePixels.getVal(XLeft,y))) 00213 kill++; 00214 if((XRight < SI_candidatePixels.getWidth()) 00215 && (SI_candidatePixels.getVal(XRight,y))) 00216 kill++; 00217 if((YTop >= 0) && (SI_candidatePixels.getVal(x,YTop))) 00218 kill++; 00219 if((YBottom < SI_candidatePixels.getHeight()) 00220 && (SI_candidatePixels.getVal(x,YBottom))) 00221 kill++; 00222 if(kill < 2) 00223 SI_candidatePixels.setVal(x,y,false); 00224 } 00225 } 00226 } 00227 } 00228 00229 /* scan pixels from top to bottom/left to right. Link all pixels in the 00230 same blob. Do this using recursive back tracking to make a blob linked 00231 as one object and not a collection of objects 00232 */ 00233 00234 void segmentImage2::SIdiscreteLinking() 00235 { 00236 00237 bool trace = false; 00238 long pixID = 0; 00239 long lastNeighbor; 00240 SI_masters = 0; 00241 SI_mastersCount = 0; 00242 for(int x = SI_frameX1; x < SI_frameX2; x++) 00243 { 00244 trace = false; 00245 lastNeighbor = -2; 00246 for(int y = SI_frameY1; y < SI_frameY2; y++) 00247 { 00248 if(SI_candidatePixels.getVal(x,y)) 00249 { 00250 if(!trace) 00251 { 00252 pixID++; 00253 trace = true; 00254 lastNeighbor = -2; 00255 } 00256 SI_blobID.setVal(x,y,pixID); 00257 if((x-1) > SI_frameX1) 00258 { 00259 if(SI_candidatePixels.getVal(x-1,y)) 00260 { 00261 // relink blob pixels if needed 00262 long check = SI_blobID.getVal((x-1),y); 00263 if(check != lastNeighbor) 00264 { 00265 SIbackwardLink(pixID,check); 00266 lastNeighbor = check; 00267 } 00268 } 00269 else 00270 { 00271 lastNeighbor = -2; 00272 } 00273 } 00274 else 00275 { 00276 SIbackwardLink(pixID,pixID); 00277 } 00278 } 00279 else 00280 { 00281 trace = false; 00282 SI_blobID.setVal(x,y,0); 00283 lastNeighbor = -2; 00284 } 00285 } 00286 } 00287 //LINFO("Candidate Blobs scanned %d", pixID); 00288 //LINFO("Candidate pixels recognized %d",candi); 00289 SI_num = pixID; 00290 } 00291 00292 /* relink pixels with new val. This allows pixels that have a new value 00293 to take on the old value of the blob. Slaves take on masters and 00294 masters can take on a slaves master. 00295 00296 */ 00297 00298 void segmentImage2::SIbackwardLink(long slave, long master) 00299 { 00300 long *masterVecMaster = &SI_masterVec[master]; 00301 long *masterVecSlave = &SI_masterVec[slave]; 00302 // my master has no master 00303 if(*masterVecMaster == -1) 00304 { 00305 // I have no master 00306 if(*masterVecSlave == -1) 00307 { 00308 //LINFO("my master has no master/I have no master"); 00309 *masterVecMaster = SI_masters; 00310 *masterVecSlave = SI_masters; 00311 SI_masters++; 00312 SI_mastersCount++; 00313 } 00314 // I already have a master 00315 else 00316 { 00317 //LINFO("my master has no master/I already have a master"); 00318 *masterVecMaster = *masterVecSlave; 00319 } 00320 } 00321 // my master has a master 00322 else 00323 { 00324 // I have no master 00325 if(*masterVecSlave == -1) 00326 { 00327 //LINFO("my master has a master/I have no master"); 00328 *masterVecSlave = *masterVecMaster; 00329 } 00330 // I already have a master 00331 else 00332 { 00333 //LINFO("my master has a master/I already have a master"); 00334 SI_mastersCount--; 00335 for(int i = 0; i < slave; i++) 00336 { 00337 if(SI_masterVec[i] == *masterVecMaster) 00338 { 00339 //LINFO("SET %d to %d",masterVec[i],masterVec[slave]); 00340 SI_masterVec[i] = *masterVecSlave; 00341 } 00342 } 00343 } 00344 } 00345 } 00346 00347 /* combine individual elements into a fully combined blob */ 00348 00349 void segmentImage2::SIcombine() 00350 { 00351 SI_totalBlobs = 0; 00352 for(int x = SI_frameX1; x < SI_frameX2; x++) 00353 { 00354 for(int y = SI_frameY1; y < SI_frameY2; y++) 00355 { 00356 if(SI_candidatePixels.getVal(x,y)) 00357 { 00358 SI_blobID.setVal(x,y,SI_masterVec[SI_blobID.getVal(x,y)]); 00359 } 00360 } 00361 } 00362 for(int x = 0; x < SI_num; x++) 00363 { 00364 bool add = true; 00365 //LINFO("Master Vec %d is %d",x,masterVec[x]); 00366 for(int y = 0; y < SI_totalBlobs; y++) 00367 { 00368 if(SI_reOrderVec[y] == SI_masterVec[x]) 00369 add = false; 00370 } 00371 00372 if((add) && (SI_masterVec[x] != -1)) 00373 { 00374 //LINFO("DOING %d",masterVec[x]); 00375 SI_reOrderVec[SI_totalBlobs] = SI_masterVec[x]; 00376 SI_reverseOrderVec[SI_masterVec[x]] = SI_totalBlobs; 00377 SI_reset[SI_totalBlobs] = true; 00378 SI_totalBlobs++; 00379 } 00380 } 00381 //totalBlobs--; 00382 } 00383 00384 void segmentImage2::SIdoSegment() 00385 { 00386 //LINFO("FINDING CANDIDATES"); 00387 if(SI_doType == 1) 00388 { 00389 ASSERT(SI_set1); ASSERT(SI_set2); ASSERT(SI_set3); ASSERT(SI_set4); 00390 SIfindCandidatesRGB(); 00391 } 00392 if(SI_doType == 2) 00393 { 00394 ASSERT(SI_set1); ASSERT(SI_set2); ASSERT(SI_set3); ASSERT(SI_set4); 00395 SIfindCandidatesHSV(); 00396 } 00397 if(SI_doType == 3) 00398 { 00399 ASSERT(SI_set3); ASSERT(SI_set4); 00400 SIfindCandidatesGREY(); 00401 } 00402 //LINFO("REMOVING SINGLES"); 00403 SIremoveSingles(); 00404 //LINFO("LINKING PIXELS"); 00405 SIdiscreteLinking(); 00406 //LINFO("RELABELING"); 00407 SIcombine(); 00408 //LINFO("DONE"); 00409 } 00410 00411 /*=============================================================*/ 00412 /* PUBLIC methods */ 00413 /*=============================================================*/ 00414 00415 segmentImage2::segmentImage2(int imageType) 00416 { 00417 SI_doType = imageType; 00418 SI_set1 = false; SI_set2 = false; SI_set3 = false; SI_set4 = false; 00419 LINFO("CREATED"); 00420 } 00421 00422 segmentImage2::segmentImage2() 00423 { 00424 SI_doType = HSV; 00425 SI_set1 = false; SI_set2 = false; SI_set3 = false; SI_set4 = false; 00426 LINFO("CREATED"); 00427 } 00428 00429 segmentImage2::~segmentImage2() 00430 {} 00431 00432 /* set color segmentation values for color and 00433 threshold 00434 */ 00435 00436 void segmentImage2::SIsetRed(int val, int thresh = 1, int skew = 0) 00437 { 00438 ASSERT(SI_doType == 1); 00439 SI_red = val; 00440 if(skew <= 0) 00441 { 00442 SI_redLT = val - thresh + skew; 00443 SI_redUT = val + thresh; 00444 } 00445 else 00446 { 00447 SI_redLT = val - thresh; 00448 SI_redUT = val + thresh + skew; 00449 } 00450 SI_set1 = true; 00451 } 00452 00453 void segmentImage2::SIsetGreen(int val, int thresh = 1, int skew = 0) 00454 { 00455 ASSERT(SI_doType == 1); 00456 SI_green = val; 00457 if(skew <= 0) 00458 { 00459 SI_greenLT = val - thresh + skew; 00460 SI_greenUT = val + thresh; 00461 } 00462 else 00463 { 00464 SI_greenLT = val - thresh; 00465 SI_greenUT = val + thresh + skew; 00466 } 00467 SI_set2 = true; 00468 } 00469 00470 void segmentImage2::SIsetBlue(int val, int thresh = 1, int skew = 0) 00471 { 00472 ASSERT(SI_doType == 1); 00473 SI_blue = val; 00474 if(skew <= 0) 00475 { 00476 SI_blueLT = val - thresh + skew; 00477 SI_blueUT = val + thresh; 00478 } 00479 else 00480 { 00481 SI_blueLT = val - thresh; 00482 SI_blueUT = val + thresh + skew; 00483 } 00484 SI_set3 = true; 00485 } 00486 00487 void segmentImage2::SIsetHue(double val, double thresh = 1, double skew = 0) 00488 { 00489 ASSERT(SI_doType == 2); 00490 SI_H = val; 00491 if(skew <= 0) 00492 { 00493 SI_HLT = val - thresh + skew; 00494 SI_HUT = val + thresh; 00495 } 00496 else 00497 { 00498 SI_HLT = val - thresh; 00499 SI_HUT = val + thresh + skew; 00500 } 00501 SI_set1 = true; 00502 } 00503 00504 void segmentImage2::SIsetSat(double val, double thresh = 1, double skew = 0) 00505 { 00506 ASSERT(SI_doType == 2); 00507 SI_S = val; 00508 if(skew <= 0) 00509 { 00510 SI_SLT = val - thresh + skew; 00511 SI_SUT = val + thresh; 00512 } 00513 else 00514 { 00515 SI_SLT = val - thresh; 00516 SI_SUT = val + thresh + skew; 00517 } 00518 SI_set2 = true; 00519 } 00520 00521 void segmentImage2::SIsetVal(double val, double thresh = 1, double skew = 0) 00522 { 00523 ASSERT((SI_doType == 2) || (SI_doType == 3)); 00524 SI_V = val; 00525 if(skew <= 0) 00526 { 00527 SI_VLT = val - thresh + skew; 00528 SI_VUT = val + thresh; 00529 } 00530 else 00531 { 00532 SI_VLT = val - thresh; 00533 SI_VUT = val + thresh + skew; 00534 } 00535 SI_set3 = true; 00536 } 00537 00538 /* set size of window frame to inspect in image */ 00539 00540 void segmentImage2::SIsetFrame(int x1, int y1, int x2, int y2, 00541 int realX, int realY) 00542 { 00543 SI_frameX1 = x1; 00544 SI_frameX2 = x2; 00545 SI_frameY1 = y1; 00546 SI_frameY2 = y2; 00547 SI_masterVec.resize(((x2-x1)*(y2-y1)),-1); 00548 SI_reOrderVec.resize(((x2-x1)*(y2-y1))); 00549 SI_reverseOrderVec.resize(((x2-x1)*(y2-y1))); 00550 SI_centerX.resize(((x2-x1)*(y2-y1))); 00551 SI_centerY.resize(((x2-x1)*(y2-y1))); 00552 SI_Xsum.resize(((x2-x1)*(y2-y1))); 00553 SI_Ysum.resize(((x2-x1)*(y2-y1))); 00554 SI_mass.resize(((x2-x1)*(y2-y1))); 00555 SI_xmin.resize(((x2-x1)*(y2-y1))); 00556 SI_xmax.resize(((x2-x1)*(y2-y1))); 00557 SI_ymin.resize(((x2-x1)*(y2-y1))); 00558 SI_ymax.resize(((x2-x1)*(y2-y1))); 00559 SI_reset.resize(((x2-x1)*(y2-y1))); 00560 LINFO("SETTING WIDTH %d, HEIGHT %d",realX,realY); 00561 SI_blobID.resize(realX,realY,-1); 00562 SI_candidatePixels.resize(realX,realY,false); 00563 SI_preCandidatePixels.resize(realX,realY,false); 00564 SI_set4 = true; 00565 } 00566 00567 void segmentImage2::SIsetHSVavg(long doAvg) 00568 { 00569 SI_Havg.resize(doAvg,0); 00570 SI_Savg.resize(doAvg,0); 00571 SI_Vavg.resize(doAvg,0); 00572 SI_Hstdd.resize(doAvg,0); 00573 SI_Sstdd.resize(doAvg,0); 00574 SI_Vstdd.resize(doAvg,0); 00575 SI_HSVN.resize(doAvg,0); 00576 SI_HSViter = doAvg; 00577 SI_HSVcount = 0; 00578 } 00579 00580 /* do image segmentation by calling private memebers to 00581 operate on image. 00582 1. Low pass image 00583 2. Find candidate pixels 00584 3. Eleminate single isolated candidates 00585 4. Link pixels in each blob 00586 5. Clean up 00587 */ 00588 00589 void segmentImage2::SIsegment(Image<PixRGB<float> > &image) 00590 { 00591 double micros; 00592 struct timezone tz; 00593 struct timeval start, stop; 00594 tz.tz_minuteswest = 0; 00595 tz.tz_dsttime = 0; 00596 gettimeofday(&start, &tz); 00597 00598 SI_workImage.resize(1,1); 00599 SI_workImage = lowPass5(image); 00600 00601 SIdoSegment(); 00602 00603 gettimeofday(&stop,&tz); 00604 micros = stop.tv_usec - start.tv_usec; 00605 LINFO("%.1f Microseconds to segment\n", micros); 00606 //std::cout << micros << " Microseconds to segment\n"; 00607 00608 } 00609 00610 void segmentImage2::SIsegment(Image<float> &image) 00611 { 00612 struct timezone tz; 00613 struct timeval start, stop; 00614 tz.tz_minuteswest = 0; 00615 tz.tz_dsttime = 0; 00616 gettimeofday(&start, &tz); 00617 00618 SI_workImageGREY.resize(1,1); 00619 SI_workImageGREY = lowPass5(image); 00620 00621 SIdoSegment(); 00622 00623 gettimeofday(&stop,&tz); 00624 //LINFO("%.1f Microseconds to segment\n", micros); 00625 00626 } 00627 00628 /* This method when called will take all remaning blobs from post 00629 processing and create a mother blob 00630 */ 00631 00632 Image<long> segmentImage2::SIcreateMother(Image<long> &img) 00633 { 00634 Image<long> mother; 00635 mother.resize(img.getWidth(),img.getHeight(),ZEROS); 00636 for(int x = SI_frameX1; x < SI_frameX2; x++) 00637 { 00638 for(int y = SI_frameY1; y < SI_frameY2; y++) 00639 { 00640 if(img.getVal(x,y) != 0) 00641 mother.setVal(x,y,1); 00642 else 00643 mother.setVal(x,y,0); 00644 } 00645 } 00646 return mother; 00647 } 00648 00649 /* return blob map 00650 */ 00651 00652 Image<long> segmentImage2::SIreturnBlobs() 00653 { 00654 return SI_blobID; 00655 } 00656 00657 Image<bool> segmentImage2::SIreturnCandidates() 00658 { 00659 return SI_candidatePixels; 00660 } 00661 00662 Image<float> segmentImage2::SIreturnNormalizedCandidates() 00663 { 00664 Image<float> NC; 00665 NC.resize(SI_candidatePixels.getWidth(),SI_candidatePixels.getHeight()); 00666 for(int x = 0; x < SI_candidatePixels.getWidth(); x++) 00667 { 00668 for(int y = 0; y < SI_candidatePixels.getHeight(); y++) 00669 { 00670 if(SI_candidatePixels.getVal(x,y)) 00671 NC.setVal(x,y,255.0F); 00672 else 00673 NC.setVal(x,y,0.0F); 00674 } 00675 } 00676 return NC; 00677 } 00678 00679 Image<PixRGB<float> > segmentImage2::SIreturnWorkImage() 00680 { 00681 ASSERT((SI_doType == 1) || (SI_doType == 2)); 00682 return SI_workImage; 00683 } 00684 00685 Image<float> segmentImage2::SIreturnWorkImageGREY() 00686 { 00687 ASSERT(SI_doType == 3); 00688 return SI_workImageGREY; 00689 } 00690 00691 00692 int segmentImage2::SInumberBlobs() 00693 { 00694 return SI_totalBlobs; 00695 } 00696 00697 std::vector<long> segmentImage2::SIgetBlobMap() 00698 { 00699 return SI_reOrderVec; 00700 } 00701 00702 void segmentImage2::SIcalcMassCenter() 00703 { 00704 for(int x = SI_frameX1; x < SI_frameX2; x++) 00705 { 00706 for(int y = SI_frameY1; y < SI_frameY2; y++) 00707 { 00708 if((SI_candidatePixels.getVal(x,y)) && (SI_blobID.getVal(x,y) != -1)) 00709 { 00710 //std::cerr << "foo " << reverseOrderVec[blobID.getVal(x,y)] << "\n"; 00711 long *indexBlob = &SI_reverseOrderVec[SI_blobID.getVal(x,y)]; 00712 if(SI_reset[*indexBlob]) 00713 { 00714 SI_reset[*indexBlob] = false; 00715 SI_Xsum[*indexBlob] = x; 00716 SI_Ysum[*indexBlob] = y; 00717 SI_mass[*indexBlob] = 1; 00718 SI_xmin[*indexBlob] = x; 00719 SI_ymin[*indexBlob] = y; 00720 SI_xmax[*indexBlob] = x; 00721 SI_ymax[*indexBlob] = y; 00722 } 00723 else 00724 { 00725 SI_Xsum[*indexBlob] += x; 00726 SI_Ysum[*indexBlob] += y; 00727 SI_mass[*indexBlob]++; 00728 if(x <= SI_xmin[*indexBlob]) 00729 SI_xmin[*indexBlob] = x; 00730 if(x >= SI_xmax[*indexBlob]) 00731 SI_xmax[*indexBlob] = x; 00732 if(y <= SI_ymin[*indexBlob]) 00733 SI_ymin[*indexBlob] = y; 00734 if(y >= SI_ymax[*indexBlob]) 00735 SI_ymax[*indexBlob] = y; 00736 } 00737 } 00738 } 00739 } 00740 00741 for(int x = 0; x < SI_totalBlobs; x++) 00742 { 00743 //std::cerr << "MASS " << mass[x] << "\n"; 00744 if(SI_mass[x] > 0) 00745 { 00746 SI_centerX[x] = SI_Xsum[x]/SI_mass[x]; 00747 SI_centerY[x] = SI_Ysum[x]/SI_mass[x]; 00748 } 00749 } 00750 } 00751 00752 float segmentImage2::SIgetCenterX(long blob) 00753 { 00754 return SI_centerX[blob]; 00755 } 00756 00757 float segmentImage2::SIgetCenterY(long blob) 00758 { 00759 return SI_centerY[blob]; 00760 } 00761 00762 long segmentImage2::SIgetMass(long blob) 00763 { 00764 return SI_mass[blob]; 00765 } 00766 00767 int segmentImage2::SIgetXmin(long blob) 00768 { 00769 return SI_xmin[blob]; 00770 } 00771 00772 //! get X max for a blob 00773 00774 int segmentImage2::SIgetXmax(long blob) 00775 { 00776 return SI_xmax[blob]; 00777 } 00778 00779 //! get Y min for a blob 00780 00781 int segmentImage2::SIgetYmin(long blob) 00782 { 00783 return SI_ymin[blob]; 00784 } 00785 00786 //! get Y max for a blob 00787 00788 int segmentImage2::SIgetYmax(long blob) 00789 { 00790 return SI_ymax[blob]; 00791 } 00792 00793 //! get the working image size in X 00794 int segmentImage2::SIgetImageSizeX() 00795 { 00796 return SI_candidatePixels.getWidth(); 00797 } 00798 //! get the working image size in Y 00799 int segmentImage2::SIgetImageSizeY() 00800 { 00801 return SI_candidatePixels.getHeight(); 00802 } 00803 00804 void segmentImage2::SIgetHSVvalue(long blob, float *H, float *S, float *V, 00805 float *Hstd, float *Sstd, float *Vstd) 00806 { 00807 float totH = 0.0F, totS = 0.0F, totV = 0.0F; 00808 float ssH = 0.0F, ssS = 0.0F, ssV = 0.0F; 00809 PixRGB<float> pix; 00810 for(int x = SI_frameX1; x < SI_frameX2; x++) 00811 { 00812 for(int y = SI_frameY1; y < SI_frameY2; y++) 00813 { 00814 if((SI_candidatePixels.getVal(x,y)) && (SI_blobID.getVal(x,y) != -1)) 00815 { 00816 if(SI_reverseOrderVec[SI_blobID.getVal(x,y)] == blob) 00817 { 00818 float pixH,pixS,pixV; 00819 pix = SI_workImage.getVal(x,y); 00820 PixHSV<float>(pix).getHSV(pixH,pixS,pixV); 00821 totH +=pixH; totS += pixS; totV += pixV; 00822 ssH += (pow(pixH,2))/SI_mass[blob]; 00823 ssS += (pow(pixS,2))/SI_mass[blob]; 00824 ssV += (pow(pixV,2))/SI_mass[blob]; 00825 } 00826 } 00827 } 00828 } 00829 if(SI_mass[blob] > 0) 00830 { 00831 *H = totH/SI_mass[blob]; 00832 *S = totS/SI_mass[blob]; 00833 *V = totV/SI_mass[blob]; 00834 *Hstd = sqrt(ssH - pow(*H,2)); 00835 *Sstd = sqrt(ssS - pow(*S,2)); 00836 *Vstd = sqrt(ssV - pow(*V,2)); 00837 } 00838 } 00839 00840 void segmentImage2::SIgetHSVvalueMean(long blob, float *H, float *S, float *V, 00841 float *Hstd, float *Sstd, float *Vstd) 00842 { 00843 double massSum = 0; 00844 if(SI_HSVcount == SI_HSViter) 00845 SI_HSVcount = 0; 00846 00847 SIgetHSVvalue(blob, &SI_Havg[SI_HSVcount], &SI_Savg[SI_HSVcount], 00848 &SI_Vavg[SI_HSVcount], &SI_Hstdd[SI_HSVcount], 00849 &SI_Sstdd[SI_HSVcount], &SI_Vstdd[SI_HSVcount]); 00850 00851 SI_HSVN[SI_HSVcount] = SI_mass[blob]; 00852 SI_HSVcount++; 00853 for(int i = 0; i < SI_HSViter; i++) 00854 { 00855 massSum += SI_HSVN[i]; 00856 *H += SI_Havg[i]*SI_HSVN[i]; 00857 *S += SI_Savg[i]*SI_HSVN[i]; 00858 *V += SI_Vavg[i]*SI_HSVN[i]; 00859 *Hstd += SI_Hstdd[i]*SI_HSVN[i]; 00860 *Sstd += SI_Sstdd[i]*SI_HSVN[i]; 00861 *Vstd += SI_Vstdd[i]*SI_HSVN[i]; 00862 } 00863 if(massSum > 0) 00864 { 00865 *H = *H/massSum; 00866 *S = *S/massSum; 00867 *V = *V/massSum; 00868 *Hstd = *Hstd/massSum; 00869 *Sstd = *Sstd/massSum; 00870 *Vstd = *Vstd/massSum; 00871 } 00872 } 00873 00874 // ###################################################################### 00875 /* So things look consistent in everyone's emacs... */ 00876 /* Local Variables: */ 00877 /* indent-tabs-mode: nil */ 00878 /* End: */