00001 /*!@file VFAT/segmentImage.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/segmentImage.C $ 00035 // $Id: segmentImage.C 14376 2011-01-11 02:44:34Z pez $ 00036 // 00037 00038 #include "VFAT/segmentImage.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 segmentImage::findCandidatesRGB() 00053 { 00054 PixRGB<float> pix; 00055 00056 for(unsigned int x = 0; x < masterVec.size(); x++) 00057 masterVec[x] = -1; 00058 00059 for(int x = frameX1; x < frameX2; x++) 00060 { 00061 for(int y = frameY1; y < frameY2; y++) 00062 { 00063 pix = workImage.getVal(x,y); 00064 candidatePixels.setVal(x,y,false); 00065 00066 // first check if the values are within threshold 00067 if ((pix.red() < redUT) && 00068 (pix.green() < greenUT) && 00069 (pix.blue() < blueUT) && 00070 (pix.red() > redLT) && 00071 (pix.green() > greenLT) && 00072 (pix.blue() > blueLT)) 00073 { 00074 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 segmentImage::findCandidatesHSV() 00086 { 00087 PixRGB<float> pix; 00088 00089 for(unsigned int x = 0; x < masterVec.size(); x++) 00090 masterVec[x] = -1; 00091 00092 for(int x = frameX1; x < frameX2; x++) 00093 { 00094 for(int y = frameY1; y < frameY2; y++) 00095 { 00096 float pixH,pixS,pixV; 00097 pix = workImage.getVal(x,y); 00098 PixHSV<float>(pix).getHSV(pixH,pixS,pixV); 00099 candidatePixels.setVal(x,y,false); 00100 00101 //LINFO("%f,%f,%f,%f,%f,%f",pixH, HUT, pixS, SUT, pixV, VUT); 00102 //LINFO("%f,%f,%f,%f,%f,%f",pixH, HLT, pixS, SLT, pixV, VLT); 00103 // first check if the values are within threshold 00104 if ((pixS < SUT) && 00105 (pixV < VUT) && 00106 (pixS > SLT) && 00107 (pixV > VLT)) 00108 { 00109 // changed to account for modulus properties in HSV for H 00110 if((pixH < HUT) && (pixH > HLT)) 00111 //if(((modu == false) && (pixH < HUT) && (pixH > HLT)) || 00112 // ((modu == true) && (!((pixH > HUT) && (pixH < Hmodu))))) 00113 { 00114 if(preCandidatePixels.getVal(x,y) == true) 00115 { 00116 //LINFO("SET CANDIDATE"); 00117 candidatePixels.setVal(x,y,true); 00118 } 00119 preCandidatePixels.setVal(x,y,true); 00120 } 00121 else 00122 { 00123 preCandidatePixels.setVal(x,y,false); 00124 } 00125 } 00126 } 00127 } 00128 } 00129 00130 /* find candidate pixels by just checking image pixels to see if they 00131 are within threshold of desired HSV values 00132 if so, set candidatePixels image pixel to true 00133 */ 00134 00135 void segmentImage::findCandidatesGREY() 00136 { 00137 float pix; 00138 00139 for(unsigned int x = 0; x < masterVec.size(); x++) 00140 masterVec[x] = -1; 00141 00142 for(int x = frameX1; x < frameX2; x++) 00143 { 00144 for(int y = frameY1; y < frameY2; y++) 00145 { 00146 pix = workImageGREY.getVal(x,y); 00147 candidatePixels.setVal(x,y,false); 00148 00149 // first check if the values are within threshold 00150 if ((pix < VUT) && (pix > VLT)) 00151 { 00152 candidatePixels.setVal(x,y,true); 00153 } 00154 } 00155 } 00156 } 00157 00158 /* if a pixel does not have an orthogonal neighbor then it is removed 00159 i.e. all pixels without 4 connectivity are removed as noise 00160 */ 00161 00162 void segmentImage::removeSingles() 00163 { 00164 for(int x = frameX1; x < frameX2; x++) 00165 { 00166 for(int y = frameY1; y < frameY2; y++) 00167 { 00168 if(candidatePixels.getVal(x,y)) 00169 { 00170 int kill = 0; 00171 int XLeft = x - 1; 00172 int XRight = x + 1; 00173 int YTop = y - 1; 00174 int YBottom = y + 1; 00175 if((XLeft >= 0) && (candidatePixels.getVal(XLeft,y))) 00176 kill++; 00177 if((XRight < candidatePixels.getWidth()) 00178 && (candidatePixels.getVal(XRight,y))) 00179 kill++; 00180 if((YTop >= 0) && (candidatePixels.getVal(x,YTop))) 00181 kill++; 00182 if((YBottom < candidatePixels.getHeight()) 00183 && (candidatePixels.getVal(x,YBottom))) 00184 kill++; 00185 if(kill < 2) 00186 candidatePixels.setVal(x,y,false); 00187 } 00188 } 00189 } 00190 } 00191 00192 /* scan pixels from top to bottom/left to right. Link all pixels in the 00193 same blob. Do this using recursive back tracking to make a blob linked 00194 as one object and not a collection of objects 00195 */ 00196 00197 void segmentImage::discreteLinking() 00198 { 00199 00200 bool trace = false; 00201 long pixID = 0; 00202 long lastNeighbor; 00203 masters = 0; 00204 mastersCount = 0; 00205 for(int x = frameX1; x < frameX2; x++) 00206 { 00207 trace = false; 00208 lastNeighbor = -2; 00209 for(int y = frameY1; y < frameY2; y++) 00210 { 00211 if(candidatePixels.getVal(x,y)) 00212 { 00213 if(!trace) 00214 { 00215 pixID++; 00216 trace = true; 00217 lastNeighbor = -2; 00218 } 00219 blobID.setVal(x,y,pixID); 00220 if((x-1) > frameX1) 00221 { 00222 if(candidatePixels.getVal(x-1,y)) 00223 { 00224 // relink blob pixels if needed 00225 long check = blobID.getVal((x-1),y); 00226 if(check != lastNeighbor) 00227 { 00228 backwardLink(pixID,check); 00229 lastNeighbor = check; 00230 } 00231 } 00232 else 00233 { 00234 lastNeighbor = -2; 00235 } 00236 } 00237 else 00238 { 00239 backwardLink(pixID,pixID); 00240 } 00241 } 00242 else 00243 { 00244 trace = false; 00245 blobID.setVal(x,y,0); 00246 lastNeighbor = -2; 00247 } 00248 } 00249 } 00250 //LINFO("Candidate Blobs scanned %d", pixID); 00251 //LINFO("Candidate pixels recognized %d",candi); 00252 num = pixID; 00253 } 00254 00255 /* relink pixels with new val. This allows pixels that have a new value 00256 to take on the old value of the blob. Slaves take on masters and 00257 masters can take on a slaves master. 00258 00259 */ 00260 00261 void segmentImage::backwardLink(long slave, long master) 00262 { 00263 long *masterVecMaster = &masterVec[master]; 00264 long *masterVecSlave = &masterVec[slave]; 00265 // my master has no master 00266 if(*masterVecMaster == -1) 00267 { 00268 // I have no master 00269 if(*masterVecSlave == -1) 00270 { 00271 //LINFO("my master has no master/I have no master"); 00272 *masterVecMaster = masters; 00273 *masterVecSlave = masters; 00274 masters++; 00275 mastersCount++; 00276 } 00277 // I already have a master 00278 else 00279 { 00280 //LINFO("my master has no master/I already have a master"); 00281 *masterVecMaster = *masterVecSlave; 00282 } 00283 } 00284 // my master has a master 00285 else 00286 { 00287 // I have no master 00288 if(*masterVecSlave == -1) 00289 { 00290 //LINFO("my master has a master/I have no master"); 00291 *masterVecSlave = *masterVecMaster; 00292 } 00293 // I already have a master 00294 else 00295 { 00296 //LINFO("my master has a master/I already have a master"); 00297 mastersCount--; 00298 for(int i = 0; i < slave; i++) 00299 { 00300 if(masterVec[i] == *masterVecMaster) 00301 { 00302 //LINFO("SET %d to %d",masterVec[i],masterVec[slave]); 00303 masterVec[i] = *masterVecSlave; 00304 } 00305 } 00306 } 00307 } 00308 } 00309 00310 /* combine individual elements into a fully combined blob */ 00311 00312 void segmentImage::combine() 00313 { 00314 totalBlobs = 0; 00315 for(int x = frameX1; x < frameX2; x++) 00316 { 00317 for(int y = frameY1; y < frameY2; y++) 00318 { 00319 if(candidatePixels.getVal(x,y)) 00320 { 00321 blobID.setVal(x,y,masterVec[blobID.getVal(x,y)]); 00322 } 00323 } 00324 } 00325 for(int x = 0; x < num; x++) 00326 { 00327 bool add = true; 00328 //LINFO("Master Vec %d is %d",x,masterVec[x]); 00329 for(int y = 0; y < totalBlobs; y++) 00330 { 00331 if(reOrderVec[y] == masterVec[x]) 00332 add = false; 00333 } 00334 00335 if((add) && (masterVec[x] != -1)) 00336 { 00337 //LINFO("DOING %d",masterVec[x]); 00338 reOrderVec[totalBlobs] = masterVec[x]; 00339 reverseOrderVec[masterVec[x]] = totalBlobs; 00340 reset[totalBlobs] = true; 00341 totalBlobs++; 00342 } 00343 } 00344 //totalBlobs--; 00345 } 00346 00347 void segmentImage::doSegment() 00348 { 00349 //LINFO("FINDING CANDIDATES"); 00350 if(doType == 1) 00351 { 00352 ASSERT(set1); ASSERT(set2); ASSERT(set3); ASSERT(set4); 00353 findCandidatesRGB(); 00354 } 00355 if(doType == 2) 00356 { 00357 ASSERT(set1); ASSERT(set2); ASSERT(set3); ASSERT(set4); 00358 findCandidatesHSV(); 00359 } 00360 if(doType == 3) 00361 { 00362 ASSERT(set3); ASSERT(set4); 00363 findCandidatesGREY(); 00364 } 00365 //LINFO("REMOVING SINGLES"); 00366 removeSingles(); 00367 //LINFO("LINKING PIXELS"); 00368 discreteLinking(); 00369 //LINFO("RELABELING"); 00370 combine(); 00371 //LINFO("DONE"); 00372 } 00373 00374 /*=============================================================*/ 00375 /* PUBLIC methods */ 00376 /*=============================================================*/ 00377 00378 segmentImage::segmentImage(int imageType) 00379 { 00380 doType = imageType; 00381 set1 = false; set2 = false; set3 = false; set4 = false; 00382 LINFO("CREATED"); 00383 } 00384 00385 segmentImage::segmentImage() 00386 { 00387 doType = HSV; 00388 set1 = false; set2 = false; set3 = false; set4 = false; 00389 LINFO("CREATED"); 00390 } 00391 00392 segmentImage::~segmentImage() 00393 {} 00394 00395 /* set color segmentation values for color and 00396 threshold 00397 */ 00398 00399 void segmentImage::setRed(int val, int thresh = 1, int skew = 0) 00400 { 00401 ASSERT(doType == 1); 00402 red = val; 00403 if(skew <= 0) 00404 { 00405 redLT = val - thresh + skew; 00406 redUT = val + thresh; 00407 } 00408 else 00409 { 00410 redLT = val - thresh; 00411 redUT = val + thresh + skew; 00412 } 00413 set1 = true; 00414 } 00415 00416 void segmentImage::setGreen(int val, int thresh = 1, int skew = 0) 00417 { 00418 ASSERT(doType == 1); 00419 green = val; 00420 if(skew <= 0) 00421 { 00422 greenLT = val - thresh + skew; 00423 greenUT = val + thresh; 00424 } 00425 else 00426 { 00427 greenLT = val - thresh; 00428 greenUT = val + thresh + skew; 00429 } 00430 set2 = true; 00431 } 00432 00433 void segmentImage::setBlue(int val, int thresh = 1, int skew = 0) 00434 { 00435 ASSERT(doType == 1); 00436 blue = val; 00437 if(skew <= 0) 00438 { 00439 blueLT = val - thresh + skew; 00440 blueUT = val + thresh; 00441 } 00442 else 00443 { 00444 blueLT = val - thresh; 00445 blueUT = val + thresh + skew; 00446 } 00447 set3 = true; 00448 } 00449 00450 void segmentImage::setHue(double val, double thresh = 1, double skew = 0) 00451 { 00452 ASSERT(doType == 2); 00453 H = val; 00454 if(skew <= 0) 00455 { 00456 HLT = val - thresh + skew; 00457 HUT = val + thresh; 00458 } 00459 else 00460 { 00461 HLT = val - thresh; 00462 HUT = val + thresh + skew; 00463 } 00464 set1 = true; 00465 } 00466 00467 void segmentImage::setSat(double val, double thresh = 1, double skew = 0) 00468 { 00469 ASSERT(doType == 2); 00470 S = val; 00471 if(skew <= 0) 00472 { 00473 SLT = val - thresh + skew; 00474 SUT = val + thresh; 00475 } 00476 else 00477 { 00478 SLT = val - thresh; 00479 SUT = val + thresh + skew; 00480 } 00481 set2 = true; 00482 } 00483 00484 void segmentImage::setVal(double val, double thresh = 1, double skew = 0) 00485 { 00486 ASSERT((doType == 2) || (doType == 3)); 00487 V = val; 00488 if(skew <= 0) 00489 { 00490 VLT = val - thresh + skew; 00491 VUT = val + thresh; 00492 } 00493 else 00494 { 00495 VLT = val - thresh; 00496 VUT = val + thresh + skew; 00497 } 00498 set3 = true; 00499 } 00500 00501 /* set size of window frame to inspect in image */ 00502 00503 void segmentImage::setFrame(int x1, int y1, int x2, int y2, 00504 int realX, int realY) 00505 { 00506 frameX1 = x1; 00507 frameX2 = x2; 00508 frameY1 = y1; 00509 frameY2 = y2; 00510 masterVec.resize(((x2-x1)*(y2-y1)),-1); 00511 reOrderVec.resize(((x2-x1)*(y2-y1))); 00512 reverseOrderVec.resize(((x2-x1)*(y2-y1))); 00513 centerX.resize(((x2-x1)*(y2-y1))); 00514 centerY.resize(((x2-x1)*(y2-y1))); 00515 Xsum.resize(((x2-x1)*(y2-y1))); 00516 Ysum.resize(((x2-x1)*(y2-y1))); 00517 mass.resize(((x2-x1)*(y2-y1))); 00518 xmin.resize(((x2-x1)*(y2-y1))); 00519 xmax.resize(((x2-x1)*(y2-y1))); 00520 ymin.resize(((x2-x1)*(y2-y1))); 00521 ymax.resize(((x2-x1)*(y2-y1))); 00522 reset.resize(((x2-x1)*(y2-y1))); 00523 LINFO("SETTING WIDTH %d, HEIGHT %d",realX,realY); 00524 blobID.resize(realX,realY,-1); 00525 candidatePixels.resize(realX,realY,false); 00526 preCandidatePixels.resize(realX,realY,false); 00527 set4 = true; 00528 } 00529 00530 void segmentImage::setHSVavg(long doAvg) 00531 { 00532 Havg.resize(doAvg,0); 00533 Savg.resize(doAvg,0); 00534 Vavg.resize(doAvg,0); 00535 Hstdd.resize(doAvg,0); 00536 Sstdd.resize(doAvg,0); 00537 Vstdd.resize(doAvg,0); 00538 HSVN.resize(doAvg,0); 00539 HSViter = doAvg; 00540 HSVcount = 0; 00541 } 00542 00543 /* do image segmentation by calling private memebers to 00544 operate on image. 00545 1. Low pass image 00546 2. Find candidate pixels 00547 3. Eleminate single isolated candidates 00548 4. Link pixels in each blob 00549 5. Clean up 00550 */ 00551 00552 void segmentImage::segment(Image<PixRGB<float> > &image) 00553 { 00554 struct timezone tz; 00555 struct timeval start, stop; 00556 tz.tz_minuteswest = 0; 00557 tz.tz_dsttime = 0; 00558 gettimeofday(&start, &tz); 00559 00560 workImage.resize(1,1); 00561 workImage = lowPass5(image); 00562 00563 doSegment(); 00564 00565 gettimeofday(&stop,&tz); 00566 //std::cout << micros << " Microseconds to segment\n"; 00567 00568 } 00569 00570 void segmentImage::segment(Image<float> &image) 00571 { 00572 struct timezone tz; 00573 struct timeval start, stop; 00574 tz.tz_minuteswest = 0; 00575 tz.tz_dsttime = 0; 00576 gettimeofday(&start, &tz); 00577 00578 workImageGREY.resize(1,1); 00579 workImageGREY = lowPass5(image); 00580 00581 doSegment(); 00582 00583 gettimeofday(&stop,&tz); 00584 //std::cout << micros << " Microseconds to segment\n"; 00585 00586 } 00587 00588 /* This method when called will take all remaning blobs from post 00589 processing and create a mother blob 00590 */ 00591 00592 Image<long> segmentImage::createMother(Image<long> &img) 00593 { 00594 Image<long> mother; 00595 mother.resize(img.getWidth(),img.getHeight(),ZEROS); 00596 for(int x = frameX1; x < frameX2; x++) 00597 { 00598 for(int y = frameY1; y < frameY2; y++) 00599 { 00600 if(img.getVal(x,y) != 0) 00601 mother.setVal(x,y,1); 00602 else 00603 mother.setVal(x,y,0); 00604 } 00605 } 00606 return mother; 00607 } 00608 00609 /* return blob map 00610 */ 00611 00612 Image<long> segmentImage::returnBlobs() 00613 { 00614 return blobID; 00615 } 00616 00617 Image<bool> segmentImage::returnCandidates() 00618 { 00619 return candidatePixels; 00620 } 00621 00622 Image<float> segmentImage::returnNormalizedCandidates() 00623 { 00624 Image<float> NC; 00625 NC.resize(candidatePixels.getWidth(),candidatePixels.getHeight()); 00626 for(int x = 0; x < candidatePixels.getWidth(); x++) 00627 { 00628 for(int y = 0; y < candidatePixels.getHeight(); y++) 00629 { 00630 if(candidatePixels.getVal(x,y)) 00631 NC.setVal(x,y,255.0F); 00632 else 00633 NC.setVal(x,y,0.0F); 00634 } 00635 } 00636 return NC; 00637 } 00638 00639 Image<PixRGB<float> > segmentImage::returnWorkImage() 00640 { 00641 ASSERT((doType == 1) || (doType == 2)); 00642 return workImage; 00643 } 00644 00645 Image<float> segmentImage::returnWorkImageGREY() 00646 { 00647 ASSERT(doType == 3); 00648 return workImageGREY; 00649 } 00650 00651 00652 int segmentImage::numberBlobs() 00653 { 00654 return totalBlobs; 00655 } 00656 00657 std::vector<long> segmentImage::getBlobMap() 00658 { 00659 return reOrderVec; 00660 } 00661 00662 void segmentImage::calcMassCenter() 00663 { 00664 for(int x = frameX1; x < frameX2; x++) 00665 { 00666 for(int y = frameY1; y < frameY2; y++) 00667 { 00668 if((candidatePixels.getVal(x,y)) && (blobID.getVal(x,y) != -1)) 00669 { 00670 //std::cerr << "foo " << reverseOrderVec[blobID.getVal(x,y)] << "\n"; 00671 long *indexBlob = &reverseOrderVec[blobID.getVal(x,y)]; 00672 if(reset[*indexBlob]) 00673 { 00674 reset[*indexBlob] = false; 00675 Xsum[*indexBlob] = x; 00676 Ysum[*indexBlob] = y; 00677 mass[*indexBlob] = 1; 00678 xmin[*indexBlob] = x; 00679 ymin[*indexBlob] = y; 00680 xmax[*indexBlob] = x; 00681 ymax[*indexBlob] = y; 00682 } 00683 else 00684 { 00685 Xsum[*indexBlob] += x; 00686 Ysum[*indexBlob] += y; 00687 mass[*indexBlob]++; 00688 if(x <= xmin[*indexBlob]) 00689 xmin[*indexBlob] = x; 00690 if(x >= xmax[*indexBlob]) 00691 xmax[*indexBlob] = x; 00692 if(y <= ymin[*indexBlob]) 00693 ymin[*indexBlob] = y; 00694 if(y >= ymax[*indexBlob]) 00695 ymax[*indexBlob] = y; 00696 } 00697 } 00698 } 00699 } 00700 00701 for(int x = 0; x < totalBlobs; x++) 00702 { 00703 //std::cerr << "MASS " << mass[x] << "\n"; 00704 if(mass[x] > 0) 00705 { 00706 centerX[x] = Xsum[x]/mass[x]; 00707 centerY[x] = Ysum[x]/mass[x]; 00708 } 00709 } 00710 } 00711 00712 float segmentImage::getCenterX(long blob) 00713 { 00714 return centerX[blob]; 00715 } 00716 00717 float segmentImage::getCenterY(long blob) 00718 { 00719 return centerY[blob]; 00720 } 00721 00722 long segmentImage::getMass(long blob) 00723 { 00724 return mass[blob]; 00725 } 00726 00727 int segmentImage::getXmin(long blob) 00728 { 00729 return xmin[blob]; 00730 } 00731 00732 //! get X max for a blob 00733 00734 int segmentImage::getXmax(long blob) 00735 { 00736 return xmax[blob]; 00737 } 00738 00739 //! get Y min for a blob 00740 00741 int segmentImage::getYmin(long blob) 00742 { 00743 return ymin[blob]; 00744 } 00745 00746 //! get Y max for a blob 00747 00748 int segmentImage::getYmax(long blob) 00749 { 00750 return ymax[blob]; 00751 } 00752 00753 //! get the working image size in X 00754 int segmentImage::getImageSizeX() 00755 { 00756 return candidatePixels.getWidth(); 00757 } 00758 //! get the working image size in Y 00759 int segmentImage::getImageSizeY() 00760 { 00761 return candidatePixels.getHeight(); 00762 } 00763 00764 void segmentImage::getHSVvalue(long blob, float *H, float *S, float *V, 00765 float *Hstd, float *Sstd, float *Vstd) 00766 { 00767 float totH = 0.0F, totS = 0.0F, totV = 0.0F; 00768 float ssH = 0.0F, ssS = 0.0F, ssV = 0.0F; 00769 PixRGB<float> pix; 00770 for(int x = frameX1; x < frameX2; x++) 00771 { 00772 for(int y = frameY1; y < frameY2; y++) 00773 { 00774 if((candidatePixels.getVal(x,y)) && (blobID.getVal(x,y) != -1)) 00775 { 00776 if(reverseOrderVec[blobID.getVal(x,y)] == blob) 00777 { 00778 float pixH,pixS,pixV; 00779 pix = workImage.getVal(x,y); 00780 PixHSV<float>(pix).getHSV(pixH,pixS,pixV); 00781 totH +=pixH; totS += pixS; totV += pixV; 00782 ssH += (pow(pixH,2))/mass[blob]; 00783 ssS += (pow(pixS,2))/mass[blob]; 00784 ssV += (pow(pixV,2))/mass[blob]; 00785 } 00786 } 00787 } 00788 } 00789 if(mass[blob] > 0) 00790 { 00791 *H = totH/mass[blob]; 00792 *S = totS/mass[blob]; 00793 *V = totV/mass[blob]; 00794 *Hstd = sqrt(ssH - pow(*H,2)); 00795 *Sstd = sqrt(ssS - pow(*S,2)); 00796 *Vstd = sqrt(ssV - pow(*V,2)); 00797 } 00798 } 00799 00800 void segmentImage::getHSVvalueMean(long blob, float *H, float *S, float *V, 00801 float *Hstd, float *Sstd, float *Vstd) 00802 { 00803 double massSum = 0; 00804 if(HSVcount == HSViter) 00805 HSVcount = 0; 00806 getHSVvalue(blob, &Havg[HSVcount], &Savg[HSVcount], &Vavg[HSVcount] 00807 ,&Hstdd[HSVcount], &Sstdd[HSVcount], &Vstdd[HSVcount]); 00808 HSVN[HSVcount] = mass[blob]; 00809 HSVcount++; 00810 for(int i = 0; i < HSViter; i++) 00811 { 00812 massSum += HSVN[i]; 00813 *H += Havg[i]*HSVN[i]; 00814 *S += Savg[i]*HSVN[i]; 00815 *V += Vavg[i]*HSVN[i]; 00816 *Hstd += Hstdd[i]*HSVN[i]; 00817 *Sstd += Sstdd[i]*HSVN[i]; 00818 *Vstd += Vstdd[i]*HSVN[i]; 00819 } 00820 if(massSum > 0) 00821 { 00822 *H = *H/massSum; 00823 *S = *S/massSum; 00824 *V = *V/massSum; 00825 *Hstd = *Hstd/massSum; 00826 *Sstd = *Sstd/massSum; 00827 *Vstd = *Vstd/massSum; 00828 } 00829 } 00830 00831 // ###################################################################### 00832 /* So things look consistent in everyone's emacs... */ 00833 /* Local Variables: */ 00834 /* indent-tabs-mode: nil */ 00835 /* End: */