00001 /*!@file Gist/SalientRegionSegmenter.C segment out object depicted by the 00002 salient point. Here we use both region growing and boundary detection 00003 */ 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Gist/SalientRegionSegmenter.C $ 00036 // $Id: $ 00037 // 00038 ////////////////////////////////////////////////////////////////////////// 00039 00040 #include "Gist/SalientRegionSegmenter.H" 00041 00042 #include "Image/CutPaste.H" // for inplacePaste() 00043 #include "Image/DrawOps.H" 00044 #include "Image/ColorOps.H" 00045 #include "Image/ShapeOps.H" 00046 #include "Image/Kernels.H" 00047 #include <cstdio> 00048 00049 #define MINIMUM_CONTOUR_LENGTH 5 00050 00051 #define LEN_WEIGHT .20 // contour boundary length weight 00052 #define SIM_WEIGHT .20 // similarity with closer side weight 00053 #define STR_WEIGHT .20 // strength of boundary weight 00054 #define RAT_WEIGHT .20 // ratio of in:out weight 00055 #define DIS_WEIGHT .20 // distance between sal pt and segment 00056 00057 #define NEIGHBORHOOD_RADIUS 12 00058 //#define NEIGHBORHOOD_RADIUS 8 00059 #define MAX_FAR_TO_NEAR_RATIO 5.0 00060 #define MAX_DISTANCE .25 // quarter of the diagonal 00061 00062 #define NUM_CHANNELS 3 // current number of channels 00063 #define NUM_L_BINS 25 // # bins for L component of CIELab 00064 #define NUM_A_BINS 25 // # bins for a component of CIELab 00065 #define NUM_B_BINS 25 // # bins for b component of CIELab 00066 #define NUM_HISTOGRAM_DIMS 75 // current total number of bins 00067 00068 #define UNVISITED_REGION 0 // unvisited mean, just looked at 00069 // for the first time 00070 #define CENTER_REGION 1 00071 #define CENTER_CORE_REGION 2 00072 #define SURROUND_REGION 3 00073 #define UNASSIGNED_REGION 4 00074 #define OTHER_OBJECT_REGION 5 00075 00076 #define CLOSER_SIDE 1 00077 #define FAR_SIDE 2 00078 00079 // ###################################################################### 00080 // ###################################################################### 00081 00082 // ###################################################################### 00083 SalientRegionSegmenter::SalientRegionSegmenter() 00084 : 00085 itsContourBoundaryDetector(new ContourBoundaryDetector()) 00086 { 00087 itsWin.reset(); 00088 00089 // These color features are inspired by Martin, PAMI 2004 pb paper 00090 float bg_smooth_sigma = 0.1; // bg histogram smoothing sigma 00091 float cg_smooth_sigma = 0.05; // cg histogram smoothing sigma 00092 00093 itsLKernel = 00094 gaussian<float>(1.0F, NUM_L_BINS*bg_smooth_sigma, 00095 int(3.0F*NUM_L_BINS*bg_smooth_sigma + 0.5F)); 00096 itsAKernel = 00097 gaussian<float>(1.0F, NUM_A_BINS*cg_smooth_sigma, 00098 int(3.0F*NUM_A_BINS*cg_smooth_sigma + 0.5F)); 00099 itsBKernel = 00100 gaussian<float>(1.0F, NUM_B_BINS*cg_smooth_sigma, 00101 int(3.0F*NUM_B_BINS*cg_smooth_sigma + 0.5F)); 00102 00103 float suml = sum(itsLKernel); itsLKernel = itsLKernel/suml; 00104 float suma = sum(itsAKernel); itsAKernel = itsAKernel/suma; 00105 float sumb = sum(itsBKernel); itsBKernel = itsBKernel/sumb; 00106 00107 // LINFO("check kernels"); 00108 00109 // for(int i = 0; i < itsLKernel.getWidth(); i++) 00110 // { 00111 // for(int j = 0; j < itsLKernel.getHeight(); j++) 00112 // printf("%10.3f ", itsLKernel.getVal(i,j)); 00113 // printf("\n"); 00114 // } 00115 // Raster::waitForKey(); 00116 00117 // for(int i = 0; i < aKernel.getWidth(); i++) 00118 // { 00119 // for(int j = 0; j < aKernel.getHeight(); j++) 00120 // printf("%10.3f ", aKernel.getVal(i,j)); 00121 // printf("\n"); 00122 // } 00123 // Raster::waitForKey(); 00124 00125 // for(int i = 0; i < bKernel.getWidth(); i++) 00126 // { 00127 // for(int j = 0; j < bKernel.getHeight(); j++) 00128 // printf("%10.3f ", bKernel.getVal(i,j)); 00129 // printf("\n"); 00130 // } 00131 // Raster::waitForKey(); 00132 } 00133 00134 // ###################################################################### 00135 SalientRegionSegmenter::~SalientRegionSegmenter() 00136 { } 00137 00138 // ###################################################################### 00139 void SalientRegionSegmenter::setImage(Image<PixRGB<byte> > image) 00140 { 00141 // reset everything 00142 itsSalientPoints.clear(); 00143 00144 itsImage = image; 00145 00146 // this is the feature histogram in Martin's pb PAMI 2004 00147 setImageFeatureHistogramValues(); 00148 00149 uint w = itsImage.getWidth(); 00150 uint h = itsImage.getHeight(); 00151 00152 if(itsWin.is_invalid()) 00153 itsWin.reset(new XWinManaged(Dims(4*w,2*h), 0, 0, 00154 "SalReg Segmenter")); 00155 else itsWin->setDims(Dims(4*w,2*h)); 00156 00157 // calculate the contour boundary and region map 00158 computeBoundaryAndRegionInformation(); 00159 00160 // keep track of what histograms has been computed 00161 uint hstep = BOUNDARY_STEP_SIZE/2; 00162 uint wG = (w-hstep)/BOUNDARY_STEP_SIZE; 00163 uint hG = (h-hstep)/BOUNDARY_STEP_SIZE; 00164 itsComputedHistograms = 00165 Image<rutz::shared_ptr<Histogram> >(wG, hG, ZEROS); 00166 } 00167 00168 // ###################################################################### 00169 void SalientRegionSegmenter::setImageFeatureHistogramValues() 00170 { 00171 // convert to CIElab color space 00172 Image<float> lImg; 00173 Image<float> aImg; 00174 Image<float> bImg; 00175 getNormalizedLAB(itsImage, lImg, aImg, bImg); 00176 00177 // convert to bin numbers 00178 itsImageHistogramEntries.clear(); 00179 itsImageHistogramEntries.push_back(quantize_values(lImg, NUM_L_BINS)); 00180 itsImageHistogramEntries.push_back(quantize_values(aImg, NUM_A_BINS)); 00181 itsImageHistogramEntries.push_back(quantize_values(bImg, NUM_B_BINS)); 00182 00183 // uint w = itsImage.getWidth(); 00184 // uint h = itsImage.getHeight(); 00185 // for(uint i = 0; i < w; i++) 00186 // for(uint j = 0; j < h; j++) 00187 // { 00188 // if(lImg.getVal(i,j) > 1.0) LINFO("limg: %3d %3d", i,j); 00189 // if(aImg.getVal(i,j) > 1.0) LINFO("aimg: %3d %3d", i,j); 00190 // if(bImg.getVal(i,j) > 1.0) LINFO("bimg: %3d %3d", i,j); 00191 // } 00192 } 00193 00194 // ###################################################################### 00195 Image<int> SalientRegionSegmenter::quantize_values 00196 (Image<float> image, int num_bins, bool normalize) 00197 { 00198 // FIXXX: May want to move to MathOps later 00199 // if(normalize) 00200 // inplaceNormalize(image, 0.0F, 1.0F); 00201 00202 uint w = itsImage.getWidth(); 00203 uint h = itsImage.getHeight(); 00204 Image<int> result(w,h,NO_INIT); 00205 00206 Image<float>::iterator iptr = image.beginw(); 00207 00208 Image<int>::iterator aptr = result.beginw(), stop = result.endw(); 00209 float nbins = num_bins; 00210 while(aptr != stop) 00211 { 00212 float in = *iptr++; 00213 00214 // bins will be 0 to num_bins-1 00215 int bin = int(in*nbins); 00216 if(bin == num_bins) bin = num_bins - 1; 00217 *aptr++ = bin; 00218 00219 //LINFO("val: %f --> bin: %d", in, bin); 00220 } 00221 00222 return result; 00223 } 00224 00225 // ###################################################################### 00226 void SalientRegionSegmenter::computeBoundaryAndRegionInformation() 00227 { 00228 computeBoundaryInformation(); 00229 computeRegionInformation(); 00230 00231 displayBoundaryAndRegionInformation(); 00232 } 00233 00234 // ###################################################################### 00235 void SalientRegionSegmenter::computeBoundaryInformation() 00236 { 00237 // compute contour boundary map 00238 Timer timer(1000000); timer.reset(); 00239 itsContourBoundaryDetector->computeContourBoundary(itsImage); 00240 LINFO("time: %f ms", timer.get()/1000.0); 00241 00242 itsContourBoundaries = 00243 itsContourBoundaryDetector->getContourBoundaries(); 00244 00245 float maxVal = 0.0; 00246 for(uint i = 0; i < itsContourBoundaries.size(); i++) 00247 { 00248 rutz::shared_ptr<Contour> contour = 00249 itsContourBoundaries[i]; 00250 00251 // go through each contour 00252 uint cLen = contour->edgels.size(); 00253 for(uint j = 0; j < cLen; j++) 00254 { 00255 float val = contour->edgels[j]->val; 00256 if(maxVal < val) maxVal = val; 00257 } 00258 } 00259 00260 itsMaximumEdgelStrength = maxVal; 00261 } 00262 00263 // ###################################################################### 00264 void SalientRegionSegmenter::computeRegionInformation() 00265 { 00266 // default parameters for the graph-based segmentation 00267 // NOTE: in original Felzenswalb-Huttenlocher paper: 00268 // k = 500 --> here k = 25 create over-segmented object 00269 float sigma = .5; uint k = 25; uint min_size = 20; int num_ccs; 00270 00271 itsInitialRegionImage = 00272 SuperPixelSegment 00273 (itsImage, sigma, k, min_size, num_ccs, &itsInitialRegions); 00274 00275 itsInitialRegionColorImage = 00276 SuperPixelDebugImage(itsInitialRegions, itsImage); 00277 00278 itsRegionAdjecencyList = getRegionAdjecencyList(); 00279 // displayRegionAdjecencyList(); 00280 } 00281 00282 // ###################################################################### 00283 std::vector<std::vector<uint> > 00284 SalientRegionSegmenter::getRegionAdjecencyList() 00285 { 00286 uint nRegions = itsInitialRegions.size(); 00287 std::vector<std::vector<uint> > adjList(nRegions); 00288 for(uint i = 0; i < nRegions; i++) 00289 adjList[i] = std::vector<uint>(); 00290 00291 // find regions: 00292 // FIXXX: there may be a better way 00293 00294 // check out all the 00295 for(uint i = 0; i < nRegions; i++) 00296 { 00297 for(uint j = 0; j < itsInitialRegions[i].size(); j++) 00298 { 00299 Point2D<int> pt = itsInitialRegions[i][j]; 00300 uint label = i; 00301 00302 for(int di = -1; di <= 1; di++) 00303 { 00304 for(int dj = -1; dj <= -1; dj++) 00305 { 00306 Point2D<int> dpt(di,dj); 00307 Point2D<int> pt2 = pt + dpt; 00308 if(!(di == 0 && dj == 0) && 00309 itsInitialRegionImage.coordsOk(pt2)) 00310 { 00311 //if the neighbor is different 00312 uint label2 = itsInitialRegionImage.getVal(pt2); 00313 00314 // check if the label is already 00315 // in the adjecency list 00316 if(label != label2) 00317 { 00318 bool in = false; 00319 for(uint l = 0; l < adjList[i].size(); l++) 00320 { 00321 if(adjList[i][l] == label2) 00322 { in = true; l = adjList[i].size(); } 00323 } 00324 if(!in) adjList[i].push_back(label2); 00325 } 00326 } 00327 } 00328 } 00329 } 00330 } 00331 return adjList; 00332 } 00333 00334 // ###################################################################### 00335 void SalientRegionSegmenter::displayRegionAdjecencyList() 00336 { 00337 // display stuff 00338 Image<PixRGB<byte> > ima = itsImage; 00339 00340 Image<float> fIma(luminance(ima)); 00341 Image<float> tempFIma = fIma; 00342 inplaceNormalize(tempFIma, 0.0f,255.0f); 00343 Image<byte> bIma(tempFIma); 00344 00345 // get non-max suppressed boundary map image 00346 float mVal = 32; 00347 float bVal = 255 - mVal; 00348 00349 Image<byte> dImaR, dImaG, dImaB; 00350 getComponents(ima, dImaR, dImaG, dImaB); 00351 inplaceNormalize(dImaR, byte(0), byte(mVal)); 00352 inplaceNormalize(dImaG, byte(0), byte(mVal)); 00353 inplaceNormalize(dImaB, byte(0), byte(mVal)); 00354 Image<PixRGB<byte> > dIma = makeRGB(dImaR,dImaG,dImaB); 00355 00356 uint w = ima.getWidth(); 00357 uint h = ima.getHeight(); 00358 Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS); 00359 00360 inplacePaste (dispIma, ima, Point2D<int>(0,0)); 00361 00362 uint nRegions = itsInitialRegions.size(); 00363 for(uint i = 0; i < nRegions; i++) 00364 { 00365 LINFO("region: %d (%d pix): has %d neighbors", 00366 i, int(itsInitialRegions[i].size()), 00367 int(itsRegionAdjecencyList[i].size())); 00368 Image<float> regionMap(w,h, ZEROS); 00369 00370 for(uint j = 0; j < itsInitialRegions[i].size(); j++) 00371 { 00372 Point2D<int> pt = itsInitialRegions[i][j]; 00373 regionMap.setVal(pt, 1.0); 00374 00375 //LINFO(" pt[%3d]: %3d %3d ", j, pt.i, pt.j); 00376 } 00377 00378 for(uint j = 0; j < itsRegionAdjecencyList[i].size(); j++) 00379 { 00380 uint label = itsRegionAdjecencyList[i][j]; 00381 LINFO(" [%3d] label: %d has: %d pixels", 00382 j, label, int(itsInitialRegions[label].size())); 00383 float randVal = rand()/(RAND_MAX+1.0); 00384 for(uint k = 0; k < itsInitialRegions[label].size(); k++) 00385 { 00386 Point2D<int> ptNeighbor = itsInitialRegions[label][k]; 00387 regionMap.setVal(ptNeighbor, randVal); 00388 //LINFO(" pt[%3d]: %3d %3d ", j, ptNeighbor.i, ptNeighbor.j); 00389 } 00390 } 00391 00392 inplaceNormalize(regionMap, 0.0f,bVal); 00393 Image<byte> dBmapc(regionMap); 00394 Image<PixRGB<byte> > dBmap = toRGB(dBmapc); 00395 00396 inplacePaste 00397 (dispIma, Image<PixRGB<byte> >(dIma+dBmap), Point2D<int>(w,0)); 00398 00399 itsWin->drawImage(dispIma, 0,0); 00400 00401 Raster::waitForKey(); 00402 } 00403 } 00404 00405 00406 // ###################################################################### 00407 void SalientRegionSegmenter::displayBoundaryAndRegionInformation() 00408 { 00409 // display stuff 00410 Image<PixRGB<byte> > ima = itsImage; 00411 uint w = ima.getWidth(); 00412 uint h = ima.getHeight(); 00413 00414 Image<float> fIma(luminance(ima)); 00415 Image<float> tempFIma = fIma; 00416 inplaceNormalize(tempFIma, 0.0f,255.0f); 00417 Image<byte> bIma(tempFIma); 00418 00419 // get non-max suppressed boundary map image 00420 float mVal = 32; 00421 float bVal = 255 - mVal; 00422 Image<byte> dImaR, dImaG, dImaB; 00423 getComponents(ima, dImaR, dImaG, dImaB); 00424 inplaceNormalize(dImaR, byte(0), byte(mVal)); 00425 inplaceNormalize(dImaG, byte(0), byte(mVal)); 00426 inplaceNormalize(dImaB, byte(0), byte(mVal)); 00427 Image<PixRGB<byte> > dIma = makeRGB(dImaR,dImaG,dImaB); 00428 00429 Image<float> tboundaryMap = 00430 itsContourBoundaryDetector->getVarianceRidgeBoundaryMap(); 00431 Image<float> boundaryMap = 00432 clampedDiff(tboundaryMap, Image<float>(w,h,ZEROS)); 00433 inplaceNormalize(boundaryMap, 0.0f,bVal); 00434 Image<byte> dBmapc(boundaryMap); 00435 Image<PixRGB<byte> > tdBmap = toRGB(dBmapc); 00436 Image<PixRGB<byte> > dBmap(dIma+tdBmap); 00437 //inplacePaste(dispIma, Image<PixRGB<byte> >(dIma+dBmap), Point2D<int>(w,0)); 00438 00439 // the non-max suppressed boundary map image 00440 Image<float> dBmapNMStemp = 00441 itsContourBoundaryDetector->getNmsBoundaryMap(); 00442 inplaceNormalize(dBmapNMStemp, 0.0F, 255.0F); 00443 Image<PixRGB<byte> > dBmapNMS = 00444 toRGB(Image<byte>(dBmapNMStemp)); 00445 00446 // the contour boundary edgel map image 00447 Image<float> dCBEmapTemp = 00448 itsContourBoundaryDetector->getEdgelBoundaryMap(); 00449 inplaceNormalize(dCBEmapTemp, 0.0F, bVal); 00450 Image<PixRGB<byte> > tdCBEmap = 00451 toRGB(Image<byte>(dCBEmapTemp)); 00452 Image<PixRGB<byte> > dCBEmap(dIma+tdCBEmap); 00453 00454 // get the contour boundary map 00455 Image<PixRGB<byte> > dCBmapTemp = 00456 itsContourBoundaryDetector->getContourBoundaryMap(); 00457 Image<PixRGB<byte> > dCBmap(dIma+dCBmapTemp); 00458 00459 // add the receptive field 00460 // 300, 140 00461 //uint cl = 156; uint ct = 68; uint cr = 8; 00462 //uint sl = cl - 4; uint st = ct - 4; uint sr = 16; 00463 00464 uint cl = 90; uint ct = 14; uint cr = 8; 00465 uint sl = cl - 4; uint st = ct - 4; uint sr = 16; 00466 00467 // to the image 00468 drawRect(ima, 00469 Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 00470 PixRGB<byte>(255,0,0)); 00471 drawRect(ima, 00472 Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 00473 PixRGB<byte>(255,255,0)); 00474 //Raster::WriteRGB(ima, std::string("starfish_image.png")); 00475 00476 // to the VRD 00477 drawRect(dBmap, 00478 Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 00479 PixRGB<byte>(255,0,0)); 00480 drawRect(dBmap, 00481 Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 00482 PixRGB<byte>(255,255,0)); 00483 //Raster::WriteRGB(dBmap, std::string("starfish_vrd_image.png")); 00484 00485 // to the NMS VRD 00486 drawRect(dBmapNMS, 00487 Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 00488 PixRGB<byte>(255,0,0)); 00489 drawRect(dBmapNMS, 00490 Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 00491 PixRGB<byte>(255,255,0)); 00492 //Raster::WriteRGB(dBmapNMS, std::string("starfish_nms_vrd_image.png")); 00493 00494 // to the edgel map 00495 drawRect(dCBEmap, 00496 Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 00497 PixRGB<byte>(255,0,0)); 00498 drawRect(dCBEmap, 00499 Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 00500 PixRGB<byte>(255,255,0)); 00501 //Raster::WriteRGB(dCBEmap, std::string("starfish_cbe_image.png")); 00502 00503 // to the contour map 00504 drawRect(dCBmap, 00505 Rectangle(Point2D<int>(cl, ct), Dims(cr, cr)), 00506 PixRGB<byte>(255,0,0)); 00507 drawRect(dCBmap, 00508 Rectangle(Point2D<int>(sl, st), Dims(sr, sr)), 00509 PixRGB<byte>(255,255,0)); 00510 //Raster::WriteRGB(dCBmap, std::string("starfish_cb_image.png")); 00511 00512 // setup the display map 00513 Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS); 00514 inplacePaste(dispIma, ima, Point2D<int>( 0, 0)); 00515 inplacePaste(dispIma, dBmap, Point2D<int>( w, 0)); 00516 inplacePaste(dispIma, dBmapNMS, Point2D<int>( 0, h)); 00517 inplacePaste(dispIma, dCBEmap, Point2D<int>( w, h)); 00518 inplacePaste(dispIma, dCBmap, Point2D<int>(2*w, 0)); 00519 inplacePaste(dispIma, itsInitialRegionColorImage, Point2D<int>(2*w, h)); 00520 //Raster::WriteRGB(itsInitialRegionColorImage, 00521 // std::string("starfish_FelzHutt_500.png")); 00522 00523 itsWin->drawImage(dispIma, 0,0); 00524 Raster::waitForKey(); 00525 } 00526 00527 // ###################################################################### 00528 Image<float> SalientRegionSegmenter::getSalientRegion(Point2D<int> pt) 00529 { 00530 // FIXXX: we may want to move the salient points 00531 // away from the contours 00532 // This may be a problem with the orientation channel 00533 // May be scale dependent 00534 // from salient point get most appropriate salient region 00535 // FIXXX: for orientation saliency the border is salient, 00536 // we move the point perpendicular to the area 00537 // (pick it randomly or the one with 00538 // higher average salient energy) We might hit object 00539 // or background (it's ok, either way we are going to 00540 // reduce the number of unassign region 00541 pt = Point2D<int>(155,37); 00542 LINFO("\n\n\n\n\n hard coding salient location: %d %d " 00543 "TAKE IT OUT LATER!\n\n\n", pt.i, pt.j); 00544 00545 // Round it to the closest 8x8 grid location 00546 uint hstep = BOUNDARY_STEP_SIZE/2; 00547 uint i = ((pt.i+hstep)/BOUNDARY_STEP_SIZE) * BOUNDARY_STEP_SIZE; 00548 uint j = ((pt.j+hstep)/BOUNDARY_STEP_SIZE) * BOUNDARY_STEP_SIZE; 00549 itsSalientPoints.push_back(Point2D<int>(i,j)); 00550 00551 LINFO("adjusted point: %d %d", i,j); 00552 00553 // calculate the region first 00554 computeSalientRegion(); 00555 00556 return itsSalientRegionImage; 00557 } 00558 00559 // ###################################################################### 00560 void SalientRegionSegmenter::computeSalientRegion() 00561 { 00562 // we have original resolution 00563 // and an 8x8 grid overlay resolution 00564 // --> this can be refined later or make MULTISCALE 00565 uint w = itsImage.getWidth(); 00566 uint h = itsImage.getHeight(); 00567 00568 uint hstep = BOUNDARY_STEP_SIZE/2; 00569 uint wG = (w-hstep)/BOUNDARY_STEP_SIZE; 00570 uint hG = (h-hstep)/BOUNDARY_STEP_SIZE; 00571 00572 Point2D<int> currentSalPoint = 00573 itsSalientPoints[itsSalientPoints.size()-1]; 00574 LINFO("START at salient point %d %d", 00575 currentSalPoint.i, currentSalPoint.j); 00576 00577 Point2D<int> currentSalPointGrid 00578 (currentSalPoint.i/BOUNDARY_STEP_SIZE, 00579 currentSalPoint.j/BOUNDARY_STEP_SIZE); 00580 00581 // assignment map on the grid overlay resolution 00582 Image<int> assignmentMap(wG, hG, ZEROS); 00583 00584 // the image borders are out of bounds 00585 for(uint i = 0; i < wG; i++) 00586 { 00587 assignmentMap.setVal(i,0, OTHER_OBJECT_REGION); 00588 assignmentMap.setVal(i,1, OTHER_OBJECT_REGION); 00589 } 00590 for(uint j = 0; j < hG; j++) 00591 { 00592 assignmentMap.setVal(0,j, OTHER_OBJECT_REGION); 00593 assignmentMap.setVal(1,j, OTHER_OBJECT_REGION); 00594 } 00595 00596 for(uint i = 0; i < wG; i++) 00597 { 00598 if(hG > 0) 00599 assignmentMap.setVal(i,hG-1, OTHER_OBJECT_REGION); 00600 if(hG > 1) 00601 assignmentMap.setVal(i,hG-2, OTHER_OBJECT_REGION); 00602 } 00603 for(uint j = 0; j < hG; j++) 00604 { 00605 if(wG > 0) 00606 assignmentMap.setVal(0,j, OTHER_OBJECT_REGION); 00607 if(wG > 1) 00608 assignmentMap.setVal(1,j, OTHER_OBJECT_REGION); 00609 } 00610 00611 // list of grid nodes that are not yet assigned 00612 // to either object, background, or unassigned list 00613 std::vector<Point2D<int> > currentObjectLocations; 00614 std::vector<Point2D<int> > currentObjectCoreLocations; 00615 std::vector<Point2D<int> > currentBackgroundLocations; 00616 std::vector<Point2D<int> > currentUnassignedLocations; 00617 00618 // assignment map on the grid overlay resolution 00619 Image<int> regionAssignmentMap(w, h, ZEROS); 00620 00621 // list of initial oversegmented regions that are 00622 // assigned to either object or background 00623 std::vector<int> currentObjectRegionList; 00624 //std::vector<int> currentObjectCoreRegionList; 00625 std::vector<int> currentBackgroundRegionList; 00626 //std::vector<int> currentUnassignedRegionList; 00627 00628 // add the start region to the core list 00629 currentObjectCoreLocations.push_back(currentSalPointGrid); 00630 //assignmentMap.setVal(currentSalPointGrid, CENTER_CORE_REGION); 00631 00632 // create boundary fragments (also call segments): 00633 // divide contour to segments of 5 edgels: about 30 - 40 pix long 00634 // --> only consider contours of 5 edgels or more. 00635 // sort on longest contour, most similar chi-sq, closest, most salient, 00636 std::list<Segment> sortedSegments = fillSegmentQueue(currentSalPoint); 00637 00638 // current starting point to grow from 00639 Point2D<int> currPoint = currentSalPoint; 00640 Point2D<int> currPointGrid = currentSalPointGrid; 00641 00642 LINFO("START PT: %3d %3d --> %3d %3d", 00643 currPoint.i, currPoint.j, currPointGrid.i, currPointGrid.j); 00644 00645 std::vector<std::pair<Segment,Point2D<int> > > segmentPtCombo; 00646 00647 // add the starting salient point 00648 // to unassigned list just to start things up 00649 currentUnassignedLocations.push_back(currPointGrid); 00650 assignmentMap.setVal(currPointGrid, UNASSIGNED_REGION); 00651 00652 // while there are unassigned locations 00653 // around the growing center group 00654 while(currentUnassignedLocations.size() != 0) 00655 { 00656 // if no segments qualified -- we break out 00657 filterSegments(sortedSegments); 00658 if(sortedSegments.size() == 0) break; 00659 00660 // pick best segment (on metric above) 00661 Segment segment = sortedSegments.front(); 00662 sortedSegments.pop_front(); 00663 00664 // make sure we do not repeat the same combo twice 00665 segmentPtCombo.push_back 00666 (std::pair<Segment,Point2D<int> >(segment, currPoint)); 00667 00668 // compute histogram of distribution of points within 12pix 00669 Histogram hist1 = getHistogramDistribution(currPoint); 00670 00671 // compute distribution of both side of the boundary 00672 // closer is pts2, farther is pts3 00673 std::vector<Point2D<int> > pts2; 00674 std::vector<Point2D<int> > pts3; 00675 getSegmentPointDistributions(segment, currPoint, pts2, pts3); 00676 Histogram hist2 = getHistogramDistribution(pts2); 00677 Histogram hist3 = getHistogramDistribution(pts3); 00678 00679 // compute the Chi-sq difference: this is the threshold for growing 00680 float threshDiff = hist1.getChiSqDiff(hist2); 00681 LINFO("THRESH Diff: %f", threshDiff); 00682 00683 LINFO("{%3d} %10.3f, %10.3f, %10.3f, %10.3f, %10.3f) = %10.3f", 00684 segment.orgIndex, 00685 segment.lenVal, segment.simVal, segment.strVal, 00686 segment.ratVal, segment.disVal, segment.pVal ); 00687 00688 // grow CENTER in the direction of the boundary 00689 // to connect the two 00690 int index = segment.segStartIndex + MINIMUM_CONTOUR_LENGTH/2; 00691 rutz::shared_ptr<Contour> contour = 00692 itsContourBoundaries[segment.contourIndex]; 00693 rutz::shared_ptr<Edgel> edgel = contour->edgels[index]; 00694 //Point2D<int> segCenterPoint = edgel->pt; 00695 Point2D<int> segCenterPointGrid 00696 ((edgel->pt.i+hstep)/BOUNDARY_STEP_SIZE, 00697 (edgel->pt.j+hstep)/BOUNDARY_STEP_SIZE ); 00698 00699 std::vector<Point2D<int> > points = 00700 getLine(currPointGrid, segCenterPointGrid); 00701 00702 LINFO("segment points"); 00703 for(uint i = segment.segStartIndex; i <= segment.segEndIndex; i++) 00704 { 00705 rutz::shared_ptr<Edgel> tedgel = contour->edgels[i]; 00706 Point2D<int> tptGrid 00707 ((tedgel->pt.i+hstep)/BOUNDARY_STEP_SIZE, 00708 (tedgel->pt.j+hstep)/BOUNDARY_STEP_SIZE ); 00709 00710 LINFO("[<<%3d>>] %d %d --> %d %d", 00711 i, tptGrid.i, tptGrid.j, 00712 tedgel->pt.i,tedgel->pt.j); 00713 } 00714 00715 LINFO("LINE: %3d %3d to %3d %3d", 00716 currPointGrid.i, currPointGrid.j, 00717 segCenterPointGrid.i, segCenterPointGrid.j); 00718 for(uint i = 0; i < points.size(); i++) 00719 { 00720 LINFO("[%3d]: %3d %3d", i, points[i].i, points[i].j); 00721 } 00722 00723 // go through each starting grow location 00724 Image<bool> isComparedWith(wG, hG, ZEROS); 00725 for(uint i = 0; i < points.size(); i++) 00726 { 00727 Point2D<int> startPt = points[i]; 00728 LINFO("current starting point: %3d %3d", startPt.i, startPt.j); 00729 00730 std::vector<Point2D<int> >::iterator culItr = 00731 currentUnassignedLocations.begin(); 00732 00733 if(assignmentMap.getVal(startPt) == UNVISITED_REGION) 00734 { 00735 // // find the current starting growing point 00736 // uint pos = 0; 00737 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 00738 // if(startPt == currentUnassignedLocations[i]) 00739 // { pos = i; i = currentUnassignedLocations.size(); } 00740 // culItr = currentUnassignedLocations.begin(); 00741 // currentUnassignedLocations.erase(culItr+pos); 00742 00743 // and move it to the front of the unassigned list 00744 // even if that point is not there previously 00745 culItr = currentUnassignedLocations.begin(); 00746 currentUnassignedLocations.insert(culItr, startPt); 00747 00748 assignmentMap.setVal(startPt, UNASSIGNED_REGION); 00749 } 00750 else LINFO("skip adding starting point -- already visited"); 00751 Raster::waitForKey(); 00752 00753 // start from the front of the queue 00754 uint currIndex = 0; 00755 00756 // while there is still neighbor that we have not visited 00757 // as a result of the current salreg-salcontour combo 00758 while(currIndex < currentUnassignedLocations.size()) 00759 { 00760 // get location 00761 Point2D<int> ptGrid = currentUnassignedLocations[currIndex]; 00762 Point2D<int> pt(ptGrid.i*BOUNDARY_STEP_SIZE, 00763 ptGrid.j*BOUNDARY_STEP_SIZE); 00764 00765 LINFO("curr pt to check: %3d %3d --> %3d %3d", 00766 ptGrid.i, ptGrid.j, pt.i, pt.j); 00767 00768 // if not yet checked 00769 if(!isComparedWith.getVal(ptGrid)) 00770 { 00771 LINFO("was NOT compared with yet"); 00772 00773 // check if the distribution in the location 00774 // goes past the threshold 00775 Histogram thist = getHistogramDistribution(pt); 00776 float diff = hist1.getChiSqDiff(thist); 00777 LINFO("difference:(%3d %3d) & (%3d %3d): %f", 00778 currPoint.i, currPoint.j, pt.i, pt.j, diff); 00779 00780 // if it is below threshold: 00781 if(diff < threshDiff) 00782 { 00783 LINFO("pass %d", currIndex); 00784 00785 // assign current location to object list 00786 currentObjectLocations.push_back(ptGrid); 00787 assignmentMap.setVal(ptGrid, CENTER_REGION); 00788 00789 // add its neighbors to unassigned locations list 00790 uint bSize = currentUnassignedLocations.size(); 00791 addUnvisitedNeighbors 00792 (currentUnassignedLocations, ptGrid, 00793 assignmentMap); 00794 uint aSize = currentUnassignedLocations.size(); 00795 uint addN = aSize - bSize; 00796 00797 // take out the location from unassigned list 00798 culItr = currentUnassignedLocations.begin(); 00799 currentUnassignedLocations.erase(culItr+currIndex+addN); 00800 00801 // LINFO("after deletion"); 00802 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 00803 // { 00804 // LINFO("[%3d]: %3d %3d", i, 00805 // currentUnassignedLocations[i].i, 00806 // currentUnassignedLocations[i].j); 00807 // } 00808 // Raster::waitForKey(); 00809 00810 currIndex = 0; 00811 00812 // display current situation 00813 displayGrowMap(assignmentMap, currPoint, 00814 currentObjectLocations, 00815 currentObjectCoreLocations, 00816 currentBackgroundLocations, 00817 currentUnassignedLocations, 00818 isComparedWith, segment); 00819 } 00820 else 00821 { 00822 LINFO("didn't pass: %d", currIndex); 00823 00824 // otherwise just advance the index 00825 currIndex++; 00826 } 00827 00828 // make note that this location is already compared 00829 isComparedWith.setVal(ptGrid, true); 00830 } 00831 // otherwise just advance the index 00832 else 00833 { 00834 LINFO("already checked: %d", currIndex); 00835 00836 currIndex++; 00837 } 00838 } 00839 } 00840 00841 LINFO("Done with segment {%3d}", segment.orgIndex); 00842 Raster::waitForKey(); 00843 00844 // assign regions next to the segment 00845 assignRegionsAroundSegment 00846 (segment, pts2, pts3, 00847 assignmentMap, 00848 currentObjectLocations, 00849 currentBackgroundLocations, 00850 currentUnassignedLocations, 00851 regionAssignmentMap, 00852 currentObjectRegionList, 00853 currentBackgroundRegionList); 00854 00855 00856 // GROW SURROUND also check if any of the unassigned neighbors 00857 // can be added to the BG list 00858 // --> if closer to the other side of contour 00859 00860 // ==> note that Chi-sq thresholding need 3 regions 00861 // ---> grow surround wrt/covering center 00862 // (this is Song Chun Zhu's negative cures) 00863 // ---> that is, grow center and grow surround 00864 00865 00866 // display current situation 00867 LINFO("after the boundary assignment"); 00868 displayGrowMap(assignmentMap, currPoint, 00869 currentObjectLocations, 00870 currentObjectCoreLocations, 00871 currentBackgroundLocations, 00872 currentUnassignedLocations, 00873 isComparedWith, segment); 00874 00875 // get the next region 00876 // FIXXX ADD THIS STEP LATER 00877 00878 00879 00880 00881 // stop if all surroundings of the center list are assigned 00882 // bool allAssigned = false; 00883 // for(uint i = 0; i < ...; i++) 00884 // { 00885 // // check its neighbor if neither are 00886 // // center nor surround assigned 00887 // allAssigned = true; 00888 // } 00889 // 00890 // if(allAssigned) 00891 // { 00892 // ==> there is no need to go through all the boundaries 00893 // because it's already sorted 00894 // } 00895 // else 00896 // { 00897 // add the neighbor that passes the threshold 00898 // of the original seed to the core 00899 // 00900 // recalculate closest most similar boundary from regions 00901 // somehow promote the ones that go through unassigned region 00902 // } 00903 00904 // currPoint = 00905 // currPointGrid = 00906 00907 // dead zone (no boundary and very non-similar colors) 00908 // will be visited once core grows to it 00909 } 00910 00911 Raster::waitForKey(); 00912 } 00913 00914 // ###################################################################### 00915 std::list<Segment> SalientRegionSegmenter::fillSegmentQueue 00916 (Point2D<int> pt) 00917 { 00918 std::list<Segment> sortedSegments; 00919 00920 // for each contour 00921 int index = 0; 00922 for(uint i = 0; i < itsContourBoundaries.size(); i++) 00923 { 00924 rutz::shared_ptr<Contour> contour = 00925 itsContourBoundaries[i]; 00926 00927 uint cLen = contour->edgels.size(); 00928 00929 //LINFO("Contour[%3d]: %3d", i, cLen); 00930 00931 // do we take out the short contours??? 00932 if(cLen < MINIMUM_CONTOUR_LENGTH) continue; 00933 00934 // go through each contour 00935 float step = float(MINIMUM_CONTOUR_LENGTH)/2.0F; 00936 uint numSegments = uint(floor(float(cLen)/step)); 00937 if((cLen%MINIMUM_CONTOUR_LENGTH) == 0) numSegments--; 00938 LINFO("Contour[%3d]: %3d: numSegments: %d", 00939 i, cLen, numSegments); 00940 00941 for(uint j = 0; j < numSegments; j++) 00942 { 00943 uint start = uint(j*step); 00944 uint end = start + MINIMUM_CONTOUR_LENGTH - 1; 00945 00946 if(end >= cLen) 00947 { 00948 end = cLen - 1; 00949 start = end + 1 - MINIMUM_CONTOUR_LENGTH; 00950 } 00951 00952 Segment segment(index, i, start, end); 00953 00954 LINFO("[i: %3d c: %3d s: %3d e: %3d]", index, i, start, end); 00955 00956 setPriority(segment, pt); 00957 sortedSegments.push_back(segment); 00958 00959 index++; 00960 } 00961 } 00962 00963 Raster::waitForKey(); 00964 00965 // sort the segments 00966 LINFO("Before Sorting"); 00967 std::list<Segment>::iterator 00968 itr = sortedSegments.begin(), 00969 stop = sortedSegments.end(); 00970 // while (itr != stop) 00971 // { 00972 // LINFO("%6.3f*%10.3f + %6.3f*%10.3f + %6.3f*%10.3f + " 00973 // "%6.3f*%10.3f + %6.3f*%10.3f = %10.3f", 00974 // LEN_WEIGHT, (*itr).lenVal, 00975 // SIM_WEIGHT, (*itr).simVal, 00976 // STR_WEIGHT, (*itr).strVal, 00977 // RAT_WEIGHT, (*itr).ratVal, 00978 // DIS_WEIGHT, (*itr).disVal, (*itr).pVal); 00979 // itr++; 00980 // } 00981 // Raster::waitForKey(); 00982 00983 sortedSegments.sort(); 00984 00985 LINFO("After Sorting"); 00986 00987 itr = sortedSegments.begin(); 00988 stop = sortedSegments.end(); 00989 while (itr != stop) 00990 { 00991 LINFO("[%3d] %6.3f*%10.3f + %6.3f*%10.3f + %6.3f*%10.3f + " 00992 "%6.3f*%10.3f + %6.3f*%10.3f = %10.3f", (*itr).orgIndex, 00993 LEN_WEIGHT, (*itr).lenVal, 00994 SIM_WEIGHT, (*itr).simVal, 00995 STR_WEIGHT, (*itr).strVal, 00996 RAT_WEIGHT, (*itr).ratVal, 00997 DIS_WEIGHT, (*itr).disVal, (*itr).pVal); 00998 itr++; 00999 } 01000 Raster::waitForKey(); 01001 01002 return sortedSegments; 01003 } 01004 01005 // ###################################################################### 01006 // FIXXX: what happen in the second reprioritization 01007 void SalientRegionSegmenter::setPriority 01008 (Segment &segment, Point2D<int> pt) 01009 { 01010 uint w = itsImage.getWidth(); 01011 uint h = itsImage.getHeight(); 01012 float diag = pow(w*w + h*h, 0.5); 01013 01014 // selection priority is: 01015 // LEN_WEIGHT * length of the contour boundary + 01016 // SIM_WEIGHT * similarity with the closer side + 01017 // STR_WEIGHT * strength of boundary + 01018 // RAT_WEIGHT * ratio of in:out + 01019 // DIS_WEIGHT * proximity to the point 01020 01021 // each factor has a max of 1.0 01022 01023 rutz::shared_ptr<Contour> contour = 01024 itsContourBoundaries[segment.contourIndex]; 01025 uint cLen = contour->edgels.size(); 01026 01027 // length of the contour boundary 01028 float tempCLen = float(cLen); 01029 float maxLen = float(MINIMUM_CONTOUR_LENGTH * 3); 01030 if(tempCLen > maxLen) tempCLen = maxLen; 01031 float lenVal = tempCLen/maxLen; 01032 segment.lenVal = lenVal; 01033 01034 LINFO("1. clen: %d --> lenVal: %f", cLen, lenVal); 01035 01036 // similarity with the closer side 01037 Histogram hist1 = getHistogramDistribution(pt); 01038 std::vector<Point2D<int> > pts2; 01039 std::vector<Point2D<int> > pts3; 01040 getSegmentPointDistributions(segment, pt, pts2, pts3); 01041 01042 Histogram hist2 = getHistogramDistribution(pts2); 01043 Histogram hist3 = getHistogramDistribution(pts3); 01044 float diff12 = hist1.getChiSqDiff(hist2); 01045 01046 float tempDiff = diff12; 01047 if(tempDiff > 1.0) tempDiff = 1.0; 01048 float simVal = 1.0F - tempDiff; 01049 segment.simVal = simVal; 01050 01051 LINFO("2. diff12: %f --> simVal: %f", diff12, simVal); 01052 01053 // strength of boundary 01054 float val = 0.0; 01055 uint start = segment.segStartIndex; 01056 uint end = segment.segEndIndex; 01057 for(uint i = start; i <= end; i++) 01058 { 01059 val += contour->edgels[i]->val; 01060 } 01061 val /= float(end - start + 1); 01062 float maxStr = .5 * itsMaximumEdgelStrength; 01063 float strVal = val/maxStr; if(strVal > 1.0F) strVal = 1.0; 01064 segment.strVal = strVal; 01065 01066 LINFO("3. strength of boundary: %f / %f = strVal: %f", 01067 val, itsMaximumEdgelStrength, strVal); 01068 01069 // ratio of near:far side 01070 float diff13 = hist1.getChiSqDiff(hist3); 01071 float ratio = MAX_FAR_TO_NEAR_RATIO; 01072 if(diff12 > 0.0) ratio = diff13/diff12; 01073 float nratio = MAX_FAR_TO_NEAR_RATIO; 01074 if(ratio < MAX_FAR_TO_NEAR_RATIO) nratio = ratio; 01075 float ratVal = nratio/MAX_FAR_TO_NEAR_RATIO; 01076 segment.ratVal = ratVal; 01077 01078 LINFO("4. ratio in&out: %f/%f = %f --> ratVal: %f", 01079 diff13, diff12, ratio, ratVal); 01080 01081 // distance between segment and salient point 01082 // while NOT going through a surround area 01083 int index = segment.segStartIndex + MINIMUM_CONTOUR_LENGTH/2; 01084 float dist = pt.distance(contour->edgels[index]->pt); 01085 float mdist = MAX_DISTANCE * diag; 01086 float disVal = 1.0; 01087 if(dist > mdist) disVal = 1.0F - (dist - mdist)/(diag - mdist); 01088 segment.disVal = disVal; 01089 01090 LINFO("5. distance: dist: %f/mdist: %f --> disVal: %f", 01091 dist, mdist, disVal); 01092 01093 segment.pVal = 01094 LEN_WEIGHT * lenVal + 01095 SIM_WEIGHT * simVal + 01096 STR_WEIGHT * strVal + 01097 RAT_WEIGHT * ratVal + 01098 DIS_WEIGHT * disVal; 01099 01100 LINFO("Total: %f", segment.pVal); 01101 //displayDistributionSetup(segment, pt, pts2, pts3); 01102 } 01103 01104 // ###################################################################### 01105 Histogram SalientRegionSegmenter::getHistogramDistribution 01106 (Point2D<int> pt) 01107 { 01108 // FIXXXX NEED TO CHECK IF ONE IS AVAILABLE (already computed) 01109 01110 Histogram lHist(NUM_L_BINS); 01111 Histogram aHist(NUM_A_BINS); 01112 Histogram bHist(NUM_L_BINS); 01113 01114 int rad = NEIGHBORHOOD_RADIUS; 01115 int numPoints = 0; 01116 for(int i = -rad; i <= rad; i++) 01117 for(int j = -rad; j <= rad; j++) 01118 { 01119 bool isWithinCircle = ((i*i+j*j) <= (rad*rad)); 01120 01121 Point2D<int> pt2 = pt + Point2D<int>(i,j); 01122 if(itsImage.coordsOk(pt2) && isWithinCircle) 01123 { 01124 // L component 01125 int l_val = itsImageHistogramEntries[0].getVal(pt2); 01126 lHist.addValue(l_val, 1.0F); 01127 01128 // a component 01129 int a_val = itsImageHistogramEntries[1].getVal(pt2); 01130 aHist.addValue(a_val, 1.0F); 01131 01132 // b component 01133 int b_val = itsImageHistogramEntries[2].getVal(pt2); 01134 bHist.addValue(b_val, 1.0F); 01135 01136 numPoints++; 01137 } 01138 } 01139 //LINFO("num points: %d", numPoints); 01140 01141 // maybe later want to add the weight for each channel 01142 //(Point2D<int> pt, std::vector<float> &dist, float weight) 01143 01144 // smooth the histogram individually 01145 lHist.smooth(itsLKernel); 01146 aHist.smooth(itsAKernel); 01147 bHist.smooth(itsBKernel); 01148 01149 // combine the histograms 01150 std::vector<Histogram> histograms; 01151 histograms.push_back(lHist); 01152 histograms.push_back(aHist); 01153 histograms.push_back(bHist); 01154 Histogram histogram(histograms); 01155 01156 // normalize with the number of points 01157 histogram.divide(numPoints); 01158 01159 return histogram; 01160 } 01161 01162 // ###################################################################### 01163 Histogram SalientRegionSegmenter::getHistogramDistribution 01164 (std::vector<Point2D<int> > pts) 01165 { 01166 Histogram lHist(NUM_L_BINS); 01167 Histogram aHist(NUM_A_BINS); 01168 Histogram bHist(NUM_L_BINS); 01169 01170 int numPoints = 0; 01171 for(uint i = 0; i < pts.size(); i++) 01172 { 01173 Point2D<int> pt = pts[i]; 01174 if(itsImage.coordsOk(pt)) 01175 { 01176 // L component 01177 int l_val = itsImageHistogramEntries[0].getVal(pt); 01178 lHist.addValue(l_val, 1.0F); 01179 01180 // a component 01181 int a_val = itsImageHistogramEntries[1].getVal(pt); 01182 aHist.addValue(a_val, 1.0F); 01183 01184 // b component 01185 int b_val = itsImageHistogramEntries[2].getVal(pt); 01186 bHist.addValue(b_val, 1.0F); 01187 01188 numPoints++; 01189 } 01190 } 01191 01192 LINFO("num points: %d", numPoints); 01193 01194 // maybe later want to add the weight for each channel 01195 //(Point2D<int> pt, std::vector<float> &dist, float weight) 01196 01197 // smooth the histogram individually 01198 lHist.smooth(itsLKernel); 01199 aHist.smooth(itsAKernel); 01200 bHist.smooth(itsBKernel); 01201 01202 // combine the histograms 01203 std::vector<Histogram> histograms; 01204 histograms.push_back(lHist); 01205 histograms.push_back(aHist); 01206 histograms.push_back(bHist); 01207 Histogram histogram(histograms); 01208 01209 // normalize with the number of points 01210 histogram.divide(numPoints); 01211 01212 return histogram; 01213 } 01214 01215 // ###################################################################### 01216 void SalientRegionSegmenter::getSegmentPointDistributions 01217 (Segment segment, Point2D<int> pt, 01218 std::vector<Point2D<int> > &pts1, std::vector<Point2D<int> > &pts2) 01219 { 01220 // get the contour divider end points 01221 uint start = segment.segStartIndex; 01222 uint end = segment.segEndIndex; 01223 01224 rutz::shared_ptr<Contour> contour = 01225 itsContourBoundaries[segment.contourIndex]; 01226 01227 rutz::shared_ptr<Edgel> edgels = contour->edgels[start]; 01228 rutz::shared_ptr<Edgel> edgele = contour->edgels[end ]; 01229 01230 uint ainds = edgels->angleIndex; 01231 float bainds = 01232 fmod((ainds+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS); 01233 uint ainde = edgele->angleIndex; 01234 float bainde = 01235 fmod((ainde+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS); 01236 01237 int step = BOUNDARY_STEP_SIZE; 01238 int hstep = step/2; 01239 float dxs = cos(bainds * M_PI/4.0) * hstep; 01240 float dys = sin(bainds * M_PI/4.0) * hstep; 01241 01242 float dxe = cos(bainde * M_PI/4.0) * hstep; 01243 float dye = sin(bainde * M_PI/4.0) * hstep; 01244 01245 Point2D<float> p1 = edgels->pt + Point2D<float>(-dxs-.5, -dys-.5); 01246 Point2D<float> p2 = edgele->pt + Point2D<float>( dxe+.5, dye+.5); 01247 01248 // estimate the contour average angle 01249 float ang = atan2(p2.j-p1.j, p2.i-p1.i); 01250 01251 // the corrected angle would be to move it to PI/2 01252 // FIXXX: this could be incorrect 01253 // if we branch the contour to both left and right 01254 float cAng = M_PI/2.0F - ang; 01255 if(ang < 0.0F && ang > M_PI) 01256 { LFATAL("out of Bounds Angle -- Fix it"); } 01257 01258 if(cAng == 0.0F) 01259 { 01260 LINFO("Deal with ZERO corrected angle"); 01261 Raster::waitForKey(); 01262 } 01263 01264 float cCAng = cos(cAng); 01265 float sCAng = sin(cAng); 01266 01267 // get the midpoint of the angle line estimator 01268 Point2D<float> mid((p1.i+p2.i)/2.0, (p1.j+p2.j)/2.0); 01269 01270 // LINFO("c[%3d]:(%3d:a: %f)-(%3d:a: %3f) ", 01271 // segment.contourIndex, start, bainds, end, bainde); 01272 // LINFO("hstep: %d [%f %f] [%f %f]", 01273 // hstep, dxs, dys, dxe, dye); 01274 01275 // LINFO("p1:(%f %f) p2:(%f %f) ", 01276 // p1.i, p1.j, p2.i, p2.j); 01277 // LINFO("ang: %f --> cAng: %f (c: %f s: %f) mid[%f %f] ", 01278 // ang, cAng, cCAng, sCAng, mid.i, mid.j); 01279 01280 01281 // rotate about that point to vertical 01282 float tbR = 0.0; float bbR = 0.0; 01283 float lbR = 0.0; float rbR = 0.0; 01284 std::vector<Point2D<float> > sPt; 01285 std::vector<Point2D<float> > ePt; 01286 std::vector<Point2D<float> > srPt; 01287 std::vector<Point2D<float> > erPt; 01288 std::vector<Point2D<float> > mrPt; 01289 for(uint k = start; k <= end; k++) 01290 { 01291 Point2D<int> pt = contour->edgels[k]->pt; 01292 float i = pt.i - mid.i; 01293 float j = pt.j - mid.j; 01294 float iR = i*cCAng - j*sCAng; 01295 float jR = i*sCAng + j*cCAng; 01296 01297 uint aind = contour->edgels[k]->angleIndex; 01298 float baind = 01299 fmod((aind+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS); 01300 float dx = cos(baind * M_PI/4.0) * hstep; 01301 float dy = sin(baind * M_PI/4.0) * hstep; 01302 01303 Point2D<float> ps = pt + Point2D<float>(-dx-.5, -dy-.5); 01304 Point2D<float> pe = pt + Point2D<float>( dx+.5, dy+.5); 01305 01306 float si = ps.i - mid.i; 01307 float sj = ps.j - mid.j; 01308 float siR = si*cCAng - sj*sCAng; 01309 float sjR = si*sCAng + sj*cCAng; 01310 01311 float ei = pe.i - mid.i; 01312 float ej = pe.j - mid.j; 01313 float eiR = ei*cCAng - ej*sCAng; 01314 float ejR = ei*sCAng + ej*cCAng; 01315 01316 sPt.push_back(ps); 01317 ePt.push_back(pe); 01318 srPt.push_back(Point2D<float>(siR,sjR)); 01319 erPt.push_back(Point2D<float>(eiR,ejR)); 01320 mrPt.push_back(Point2D<float>( iR, jR)); 01321 01322 // initialize everything on the first iteration 01323 if(k == start) 01324 { 01325 tbR = sjR; 01326 bbR = sjR; 01327 lbR = siR; 01328 rbR = siR; 01329 } 01330 01331 if(tbR > sjR) tbR = sjR; 01332 if(tbR > ejR) tbR = ejR; 01333 01334 if(bbR < sjR) bbR = sjR; 01335 if(bbR < ejR) bbR = ejR; 01336 01337 if(lbR > siR) lbR = siR; 01338 if(lbR > eiR) lbR = eiR; 01339 01340 if(rbR < siR) rbR = siR; 01341 if(rbR < eiR) rbR = eiR; 01342 01343 // LINFO("[[%d]]", k); 01344 // LINFO("M[%3d %3d] --> offset[%f %f] --> [%f %f]", 01345 // pt.i, pt.j, i ,j, iR, jR); 01346 01347 // LINFO("S[%f %f] --> offset[%f %f] --> [%f %f]", 01348 // ps.i, ps.j, si ,sj, siR, sjR); 01349 // LINFO("E[%f %f] --> offset[%f %f] --> [%f %f] \n", 01350 // pe.i, pe.j, ei ,ej, eiR, ejR); 01351 } 01352 01353 //LINFO("[t: %f b: %f l: %f r: %f] ", tbR, bbR, lbR, rbR); 01354 01355 // count the pixels in the left and right within the bounding box 01356 float areaL = 0; float areaR = 0; 01357 float w = rbR - lbR; 01358 float h = bbR - tbR; 01359 if(w > 0.0F && h > 0.0F) 01360 { 01361 for(uint k = start; k <= end; k++) 01362 { 01363 int i = k-start; 01364 // we will use a trapezoid area 01365 // to approximate number of pixels 01366 01367 float tl = rbR - srPt[i].i; 01368 float bl = rbR - erPt[i].i; 01369 01370 float h = erPt[i].j - srPt[i].j; 01371 01372 float trapArea = (tl+bl)*h/2.0F; 01373 float boxArea = w*h; 01374 areaL += (boxArea-trapArea); 01375 areaR += trapArea; 01376 01377 // LINFO("tl = %f = %f - %f||| bl = %f = %f - %f ", 01378 // tl, rbR, srPt[i].i, bl, rbR, erPt[i].i); 01379 // LINFO("h = %f = %f - %f | w = %f = %f - %f", 01380 // h, erPt[i].j, srPt[i].j, w, rbR, lbR); 01381 01382 // LINFO("[%d] b: %f b-t: %f, t: %f", 01383 // k, boxArea, boxArea-trapArea, trapArea); 01384 } 01385 } 01386 // LINFO("areaL: %f, areaR: %f ==> h: %f", areaL, areaR, h); 01387 01388 // extend the box so that the number of pixels on both sides 01389 // are close to the area circle with radius = NEIGHBORHOOD_RADIUS 01390 uint nrad = NEIGHBORHOOD_RADIUS; 01391 float minArea = nrad * nrad * M_PI; 01392 float extL = 0.0; float extR = 0.0; 01393 01394 //LINFO("lbR: %f areaL: %f", lbR, areaL); 01395 //LINFO("rbR: %f areaR: %f", rbR, areaR); 01396 if(areaL < minArea) 01397 { 01398 extL = lbR - (minArea - areaL)/h; 01399 } 01400 01401 if(areaR < minArea) 01402 { 01403 extR = rbR + (minArea - areaR)/h; 01404 } 01405 01406 //LINFO("add L:%f -> %f add R: %f -> %f", 01407 // (minArea - areaL), (minArea - areaL)/h, 01408 // (minArea - areaR), (minArea - areaR)/h ); 01409 01410 //LINFO("Sanity Check: min Area: %f, Area: ((%f) - (%f))*%f = %f", 01411 // minArea, extR, extL, h, (extR - extL)*h); 01412 01413 // figure out which side the pt is 01414 // FIXXX: may want to be more careful here 01415 int pti = pt.i - mid.i; 01416 int ptj = pt.j - mid.j; 01417 float ptiR = pti*cCAng - ptj*sCAng; 01418 //float ptjR = pti*sCAng + ptj*cCAng; 01419 float isLeft = true; if(ptiR > 0.0) isLeft = false; 01420 //LINFO("isLeft: %d", int(isLeft)); 01421 01422 // create a box 01423 uint finalW = extR-extL; 01424 uint finalH = h; 01425 uint maxDim = finalW; 01426 if(finalH > finalW) maxDim = finalH; 01427 Image<byte> temp1(maxDim*2, maxDim*2, ZEROS); 01428 Image<byte> temp2(maxDim*2, maxDim*2, ZEROS); 01429 01430 // LINFO("finalW: %d finalH: %d ==> maxDim: %d", finalW, finalH, maxDim); 01431 //uint ttt1 = 0; uint ttt2 = 0; 01432 for(uint k = start; k <= end; k++) 01433 { 01434 uint ind = k - start; 01435 01436 float t = srPt[ind].j; float b = erPt[ind].j; 01437 float h = b - t; 01438 01439 float tH = srPt[ind].i; float bH = erPt[ind].i; 01440 float w = bH - tH; 01441 01442 //LINFO("ind: %d h: %f = %f - %f w: %f = %f - %f", 01443 // ind, h, b, t, w, bH, tH); 01444 01445 // FIXXX: there may be a vertical gap between indexes 01446 01447 // get the pixels on the left and right side 01448 // LINFO("VERT range: %d to %d", int(t), int(b)); 01449 //uint tt1 = 0; uint tt2 = 0; 01450 for(int j = int(t); j <= int(b + .5F); j++) 01451 { 01452 // compute the dividing edge location 01453 float div = (w/h*(j - b)) + tH; 01454 if(w < 0.0F) div = (w/h*(j - t)) + tH; 01455 01456 float leftE = extL+maxDim; 01457 float rightE = extR+maxDim; 01458 01459 // LINFO("horizontal divider: %f, range: %f to %f", 01460 // div+maxDim, leftE, rightE); 01461 01462 //uint t1 = 0; uint t2 = 0; 01463 uint jShift = j + maxDim; 01464 for(int i = int(leftE); i <= int(rightE+.5F); i++) 01465 { 01466 if(i < (div+maxDim)) 01467 { 01468 if(isLeft) temp1.setVal(i,jShift, 128); //t1++; } 01469 else temp2.setVal(i,jShift, 128); //t2++; } 01470 } 01471 else 01472 { 01473 if(isLeft) temp2.setVal(i,jShift, 128); //t2++; } 01474 else temp1.setVal(i,jShift, 128); //t1++; } 01475 } 01476 01477 //LINFO("i:%d %d: div: %f --> %d == %3d %3d", 01478 // i, jShift, div+maxDim, int(i<(div+maxDim)), t1, t2); 01479 } 01480 //LINFO("[%3d %3d] t1: %d t2: %d", k, j, t1, t2); 01481 //tt1 += t1; 01482 //tt2 += t2; 01483 } 01484 //LINFO("[%3d] t1: %d t2: %d", k, tt1, tt2); 01485 //ttt1 += tt1; 01486 //ttt2 += tt2; 01487 } 01488 //LINFO("ttt1: %d ttt2: %d", ttt1, ttt2); 01489 01490 //LINFO("sum1: %f sum2: %f", 01491 // float(sum(temp1))/128.0F, float(sum(temp2))/128.0F); 01492 01493 // re-rotate the bounding box 01494 Image<byte> temp1R = rotate(temp1, maxDim, maxDim, -cAng); 01495 Image<byte> temp2R = rotate(temp2, maxDim, maxDim, -cAng); 01496 01497 //LINFO("md[%d] mid: %f %f", maxDim, mid.i, mid.j); 01498 01499 // figure out which side is next to the point 01500 int tw = temp1.getWidth(); 01501 int th = temp1.getHeight(); 01502 for(int i = 0; i < tw; i++) 01503 for(int j = 0; j < th; j++) 01504 { 01505 if(temp1R.getVal(i,j) > 64) 01506 { 01507 Point2D<int> pt(i+int(mid.i)-maxDim, 01508 j+int(mid.j)-maxDim ); 01509 pts1.push_back(pt); 01510 //LINFO("1 %d %d --> %d %d", i,j,pt.i, pt.j); 01511 //Raster::waitForKey(); 01512 } 01513 01514 if(temp2R.getVal(i,j) > 64) 01515 { 01516 Point2D<int> pt(i+int(mid.i)-maxDim, 01517 j+int(mid.j)-maxDim ); 01518 pts2.push_back(pt); 01519 //LINFO("2 %d %d --> %d %d", i,j,pt.i, pt.j); 01520 //Raster::waitForKey(); 01521 } 01522 } 01523 01524 //LINFO("Final Size: %d %d", int(pts1.size()), int(pts2.size())); 01525 } 01526 01527 // ###################################################################### 01528 void SalientRegionSegmenter::filterSegments(std::list<Segment> &segments) 01529 { 01530 // FIXXX ==> what happens if best segment is not good enough??? 01531 // --> need a threshold if the best one is worth pursuing. 01532 // --> if not then stop 01533 // --> the object is segmented perfectly by Graph-based segmented 01534 } 01535 01536 // ###################################################################### 01537 void SalientRegionSegmenter::addUnvisitedNeighbors 01538 (std::vector<Point2D<int> > ¤tUnassignedLocations, 01539 Point2D<int> currPointGrid, Image<int> &assignmentMap) 01540 { 01541 //--> make sure no duplicates 01542 // the grid area is unassigned to the list, 01543 // as well as surround or previous object 01544 //--> this will keep growing maximally 01545 // on the current salreg-salcontour combo 01546 01547 // LINFO("BEFORE unassigned"); 01548 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01549 // { 01550 // LINFO("[%3d]: %3d %3d", i, 01551 // currentUnassignedLocations[i].i, 01552 // currentUnassignedLocations[i].j); 01553 // } 01554 // Raster::waitForKey(); 01555 01556 01557 // add to the front of the list 01558 01559 for(int j = 1; j >= -1; j--) 01560 for(int i = 1; i >= -1; i--) 01561 if(!(i == 0 && j== 0)) 01562 { 01563 Point2D<int> pt(currPointGrid.i+i, currPointGrid.j+j); 01564 01565 // if the location is not yet visited 01566 if(assignmentMap.coordsOk(pt) && 01567 assignmentMap.getVal(pt) == UNVISITED_REGION) 01568 { 01569 LINFO("pt(%3d %3d): %d", pt.i,pt.j, 01570 assignmentMap.getVal(pt)); 01571 01572 std::vector<Point2D<int> >::iterator itr = 01573 currentUnassignedLocations.begin(); 01574 currentUnassignedLocations.insert(itr, pt); 01575 01576 assignmentMap.setVal(pt, UNASSIGNED_REGION); 01577 } 01578 } 01579 01580 // LINFO("AFTER unassigned"); 01581 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01582 // { 01583 // LINFO("[%3d]: %3d %3d", i, 01584 // currentUnassignedLocations[i].i, 01585 // currentUnassignedLocations[i].j); 01586 // } 01587 // Raster::waitForKey(); 01588 01589 } 01590 01591 // ###################################################################### 01592 std::vector<Point2D<int> > SalientRegionSegmenter::getLine 01593 (Point2D<int> p1, Point2D<int> p2) 01594 { 01595 std::vector<Point2D<int> > points; 01596 01597 // ray tracing algorithm 01598 // from Graphics Gems / Paul Heckbert 01599 int dx = p2.i - p1.i, ax = abs(dx) << 1, sx = signOf(dx); 01600 int dy = p2.j - p1.j, ay = abs(dy) << 1, sy = signOf(dy); 01601 int x = p1.i, y = p1.j; 01602 01603 const int w = itsImage.getWidth(); 01604 const int h = itsImage.getHeight(); 01605 01606 if (ax > ay) 01607 { 01608 int d = ay - (ax >> 1); 01609 for (;;) 01610 { 01611 // assignment 01612 if (x >= 0 && x < w && y >= 0 && y < h) 01613 points.push_back(Point2D<int>(x,y)); 01614 01615 if (x == p2.i) return points; 01616 if (d >= 0) { y += sy; d -= ax; } 01617 x += sx; d += ay; 01618 } 01619 } 01620 else 01621 { 01622 int d = ax - (ay >> 1); 01623 for (;;) 01624 { 01625 // assignment 01626 if (x >= 0 && x < w && y >= 0 && y < h) 01627 points.push_back(Point2D<int>(x,y)); 01628 01629 if (y == p2.j) return points; 01630 if (d >= 0) { x += sx; d -= ay; } 01631 y += sy; d += ax; 01632 } 01633 } 01634 01635 return points; 01636 } 01637 01638 // ###################################################################### 01639 void SalientRegionSegmenter::assignRegionsAroundSegment 01640 (Segment segment, 01641 std::vector<Point2D<int> > pts2, 01642 std::vector<Point2D<int> > pts3, 01643 Image<int> &assignmentMap, 01644 std::vector<Point2D<int> > ¤tObjectLocations, 01645 std::vector<Point2D<int> > ¤tBackgroundLocations, 01646 std::vector<Point2D<int> > ¤tUnassignedLocations, 01647 Image<int> ®ionAssignmentMap, 01648 std::vector<int> ¤tObjectRegionList, 01649 std::vector<int> ¤tBackgroundRegionList) 01650 { 01651 uint w = itsImage.getWidth(); 01652 uint h = itsImage.getHeight(); 01653 01654 uint hstep = BOUNDARY_STEP_SIZE/2; 01655 //uint wG = (w-hstep)/BOUNDARY_STEP_SIZE; 01656 //uint hG = (h-hstep)/BOUNDARY_STEP_SIZE; 01657 01658 Image<int> image(w,h, ZEROS); 01659 for(uint i = 0; i < pts2.size(); i++) 01660 { 01661 if(image.coordsOk(pts2[i])) 01662 image.setVal(pts2[i], CLOSER_SIDE); 01663 } 01664 for(uint i = 0; i < pts3.size(); i++) 01665 { 01666 if(image.coordsOk(pts3[i])) 01667 image.setVal(pts3[i], FAR_SIDE); 01668 } 01669 std::vector<std::vector<Point2D<int> > > 01670 neighbor(NUM_RIDGE_DIRECTIONS); 01671 01672 for(uint k = 0; k < NUM_RIDGE_DIRECTIONS; k++) 01673 { 01674 neighbor[k] = std::vector<Point2D<int> >(); 01675 01676 if(k == 0) 01677 { 01678 neighbor[k].push_back(Point2D<int>( 1, 0)); 01679 neighbor[k].push_back(Point2D<int>(-1, 0)); 01680 } 01681 else if(k == 1) 01682 { 01683 neighbor[k].push_back(Point2D<int>(-1, -1)); 01684 neighbor[k].push_back(Point2D<int>( 0, -1)); 01685 neighbor[k].push_back(Point2D<int>(-1, 0)); 01686 neighbor[k].push_back(Point2D<int>( 1, 0)); 01687 neighbor[k].push_back(Point2D<int>( 0, 1)); 01688 neighbor[k].push_back(Point2D<int>( 1, 1)); 01689 } 01690 else if(k == 2) 01691 { 01692 neighbor[k].push_back(Point2D<int>( 0, 1)); 01693 neighbor[k].push_back(Point2D<int>( 0, -1)); 01694 } 01695 else if(k == 3) 01696 { 01697 neighbor[k].push_back(Point2D<int>( 0, -1)); 01698 neighbor[k].push_back(Point2D<int>( 1, -1)); 01699 neighbor[k].push_back(Point2D<int>(-1, 0)); 01700 neighbor[k].push_back(Point2D<int>( 1, 0)); 01701 neighbor[k].push_back(Point2D<int>(-1, 1)); 01702 neighbor[k].push_back(Point2D<int>( 0, 1)); 01703 } 01704 } 01705 01706 // go through all the edgels' grid location first 01707 for(uint e = segment.segStartIndex; e <= segment.segEndIndex; e++) 01708 { 01709 rutz::shared_ptr<Contour> contour = 01710 itsContourBoundaries[segment.contourIndex]; 01711 rutz::shared_ptr<Edgel> edgel = contour->edgels[e]; 01712 Point2D<int> pt = edgel->pt; 01713 Point2D<int> ptGrid 01714 ((pt.i+hstep)/BOUNDARY_STEP_SIZE, 01715 (pt.j+hstep)/BOUNDARY_STEP_SIZE ); 01716 LINFO("[[[%3d]]] %d %d --> %d %d", e, pt.i, pt.j, ptGrid.i, ptGrid.j); 01717 01718 uint label = assignmentMap.getVal(ptGrid); 01719 01720 // do nothing on center, surround, other objects 01721 if(label == CENTER_REGION) LINFO(" C_REGION : do nothing"); 01722 if(label == SURROUND_REGION) LINFO(" S_REGION : do nothing"); 01723 if(label == OTHER_OBJECT_REGION) LINFO("OO_REGION : do nothing"); 01724 01725 if(label == UNVISITED_REGION) 01726 { 01727 // add to background 01728 currentBackgroundLocations.push_back(ptGrid); 01729 assignmentMap.setVal(ptGrid, SURROUND_REGION); 01730 01731 LINFO("UNVISITED adding %3d %3d to the background", 01732 ptGrid.i, ptGrid.j); 01733 } 01734 01735 if(label == UNASSIGNED_REGION) 01736 { 01737 01738 // LINFO("before changing on edgel UNASSIGNED_REGION"); 01739 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01740 // { 01741 // LINFO("[%3d]: %3d %3d", i, 01742 // currentUnassignedLocations[i].i, 01743 // currentUnassignedLocations[i].j); 01744 // } 01745 01746 // LINFO("Background"); 01747 // for(uint i = 0; i < currentBackgroundLocations.size(); i++) 01748 // { 01749 // LINFO("[%3d]: %3d %3d", i, 01750 // currentBackgroundLocations[i].i, 01751 // currentBackgroundLocations[i].j); 01752 // } 01753 01754 // Raster::waitForKey(); 01755 01756 01757 // find it is in the unassigned list 01758 uint pos = 0; 01759 for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01760 if(ptGrid == currentUnassignedLocations[i]) 01761 { pos = i; i = currentUnassignedLocations.size(); } 01762 01763 // delete it 01764 std::vector<Point2D<int> >::iterator itr = 01765 currentUnassignedLocations.begin(); 01766 currentUnassignedLocations.erase(itr+pos); 01767 01768 // add to background list 01769 currentBackgroundLocations.push_back(ptGrid); 01770 assignmentMap.setVal(ptGrid, SURROUND_REGION); 01771 01772 // LINFO("after changing on edgel"); 01773 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01774 // { 01775 // LINFO("[%3d]: %3d %3d", i, 01776 // currentUnassignedLocations[i].i, 01777 // currentUnassignedLocations[i].j); 01778 // } 01779 01780 01781 // LINFO("Background"); 01782 // for(uint i = 0; i < currentBackgroundLocations.size(); i++) 01783 // { 01784 // LINFO("[%3d]: %3d %3d", i, 01785 // currentBackgroundLocations[i].i, 01786 // currentBackgroundLocations[i].j); 01787 // } 01788 01789 // Raster::waitForKey(); 01790 01791 01792 } 01793 } 01794 01795 // LINFO("before checking edgel neighbors"); 01796 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01797 // { 01798 // LINFO("[%3d]: %3d %3d", i, 01799 // currentUnassignedLocations[i].i, 01800 // currentUnassignedLocations[i].j); 01801 // } 01802 01803 01804 // LINFO("Background"); 01805 // for(uint i = 0; i < currentBackgroundLocations.size(); i++) 01806 // { 01807 // LINFO("[%3d]: %3d %3d", i, 01808 // currentBackgroundLocations[i].i, 01809 // currentBackgroundLocations[i].j); 01810 // } 01811 01812 // Raster::waitForKey(); 01813 01814 // then go through its neighbors 01815 for(uint e = segment.segStartIndex; e <= segment.segEndIndex; e++) 01816 { 01817 rutz::shared_ptr<Contour> contour = 01818 itsContourBoundaries[segment.contourIndex]; 01819 rutz::shared_ptr<Edgel> edgel = contour->edgels[e]; 01820 Point2D<int> pt = edgel->pt; 01821 Point2D<int> ptGrid 01822 ((pt.i+hstep)/BOUNDARY_STEP_SIZE, 01823 (pt.j+hstep)/BOUNDARY_STEP_SIZE ); 01824 01825 uint dir = edgel->angleIndex; 01826 01827 LINFO("[<<%3d>>] %d %d --> %d %d (%d)", 01828 e, pt.i, pt.j, ptGrid.i, ptGrid.j, dir); 01829 01830 // classify current segment grid location as 01831 for(uint i = 0; i < neighbor[dir].size(); i++) 01832 { 01833 Point2D<int> ptGrid2 = ptGrid + neighbor[dir][i]; 01834 Point2D<int> pt2(ptGrid2.i*BOUNDARY_STEP_SIZE, 01835 ptGrid2.j*BOUNDARY_STEP_SIZE ); 01836 01837 LINFO(" N[%3d]: %d %d --> %d %d", 01838 i, ptGrid2.i, ptGrid2.j, pt2.i, pt2.j); 01839 01840 if(!assignmentMap.coordsOk(ptGrid2)) 01841 { 01842 LINFO("out of bounds"); continue; 01843 } 01844 01845 uint label2 = assignmentMap.getVal(ptGrid2); 01846 LINFO("LABEL2: %d", label2); 01847 01848 // do nothing on center, surround, other objects 01849 if(label2 == CENTER_REGION) LINFO(" C_REGION : do nothing"); 01850 if(label2 == SURROUND_REGION) LINFO(" S_REGION : do nothing"); 01851 if(label2 == OTHER_OBJECT_REGION) LINFO("OO_REGION : do nothing"); 01852 01853 if(label2 == UNVISITED_REGION) 01854 { 01855 // assign depending on which side of boundary 01856 int side = image.getVal(pt2); 01857 01858 // LINFO("UNVISITED Before Background"); 01859 // for(uint i = 0; i < currentBackgroundLocations.size(); i++) 01860 // { 01861 // LINFO("[%3d]: %3d %3d", i, 01862 // currentBackgroundLocations[i].i, 01863 // currentBackgroundLocations[i].j); 01864 // } 01865 // for(uint i = 0; i < currentObjectLocations.size(); i++) 01866 // { 01867 // LINFO("[%3d]: %3d %3d", i, 01868 // currentObjectLocations[i].i, 01869 // currentObjectLocations[i].j); 01870 // } 01871 01872 01873 if(side == CLOSER_SIDE) 01874 { 01875 // add to background 01876 currentObjectLocations.push_back(ptGrid2); 01877 assignmentMap.setVal(ptGrid2, CENTER_REGION); 01878 01879 LINFO(" adding %3d %3d to the center", 01880 ptGrid2.i, ptGrid2.j); 01881 } 01882 else if(side == FAR_SIDE) 01883 { 01884 // add to background 01885 currentBackgroundLocations.push_back(ptGrid2); 01886 assignmentMap.setVal(ptGrid2, SURROUND_REGION); 01887 01888 LINFO(" adding %3d %3d to the background", 01889 ptGrid2.i, ptGrid2.j); 01890 } 01891 01892 // LINFO("UNVISITED after Background"); 01893 // for(uint i = 0; i < currentBackgroundLocations.size(); i++) 01894 // { 01895 // LINFO("[%3d]: %3d %3d", i, 01896 // currentBackgroundLocations[i].i, 01897 // currentBackgroundLocations[i].j); 01898 // } 01899 // for(uint i = 0; i < currentObjectLocations.size(); i++) 01900 // { 01901 // LINFO("[%3d]: %3d %3d", i, 01902 // currentObjectLocations[i].i, 01903 // currentObjectLocations[i].j); 01904 // } 01905 01906 } 01907 01908 if(label2 == UNASSIGNED_REGION) 01909 { 01910 // check if point is one either side of boundary 01911 int side = image.getVal(pt2); 01912 LINFO("UN Side: %d", side); 01913 01914 // LINFO("UNASSIGNED neighbors before"); 01915 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01916 // { 01917 // LINFO("[%3d]: %3d %3d", i, 01918 // currentUnassignedLocations[i].i, 01919 // currentUnassignedLocations[i].j); 01920 // } 01921 01922 if(side == CLOSER_SIDE || side == FAR_SIDE) 01923 { 01924 // find the location in the unassigned list 01925 uint pos = 0; 01926 for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01927 if(ptGrid2 == currentUnassignedLocations[i]) 01928 { pos = i; i = currentUnassignedLocations.size(); } 01929 01930 // delete it 01931 std::vector<Point2D<int> >::iterator itr = 01932 currentUnassignedLocations.begin(); 01933 currentUnassignedLocations.erase(itr+pos); 01934 } 01935 else LINFO("not on the close or far side"); 01936 01937 // LINFO("UNASSIGNED neighbors after "); 01938 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 01939 // { 01940 // LINFO("[%3d]: %3d %3d", i, 01941 // currentUnassignedLocations[i].i, 01942 // currentUnassignedLocations[i].j); 01943 // } 01944 01945 // LINFO("UNASSIGNED before Background"); 01946 // for(uint i = 0; i < currentBackgroundLocations.size(); i++) 01947 // { 01948 // LINFO("[%3d]: %3d %3d", i, 01949 // currentBackgroundLocations[i].i, 01950 // currentBackgroundLocations[i].j); 01951 // } 01952 // for(uint i = 0; i < currentObjectLocations.size(); i++) 01953 // { 01954 // LINFO("[%3d]: %3d %3d", i, 01955 // currentObjectLocations[i].i, 01956 // currentObjectLocations[i].j); 01957 // } 01958 01959 01960 if(side == CLOSER_SIDE) 01961 { 01962 // add to background 01963 currentObjectLocations.push_back(ptGrid2); 01964 assignmentMap.setVal(ptGrid2, CENTER_REGION); 01965 01966 LINFO(" adding %3d %3d to the center", 01967 ptGrid2.i, ptGrid2.j); 01968 } 01969 else if(side == FAR_SIDE) 01970 { 01971 // add to background 01972 currentBackgroundLocations.push_back(ptGrid2); 01973 assignmentMap.setVal(ptGrid2, SURROUND_REGION); 01974 01975 LINFO(" adding %3d %3d to the background", 01976 ptGrid2.i, ptGrid2.j); 01977 } 01978 01979 01980 // LINFO("UNASSIGNED after Background"); 01981 // for(uint i = 0; i < currentBackgroundLocations.size(); i++) 01982 // { 01983 // LINFO("[%3d]: %3d %3d", i, 01984 // currentBackgroundLocations[i].i, 01985 // currentBackgroundLocations[i].j); 01986 // } 01987 // for(uint i = 0; i < currentObjectLocations.size(); i++) 01988 // { 01989 // LINFO("[%3d]: %3d %3d", i, 01990 // currentObjectLocations[i].i, 01991 // currentObjectLocations[i].j); 01992 // } 01993 01994 } 01995 } 01996 } 01997 01998 // get the oversegmented regions 01999 02000 // assign regions next to the segment 02001 02002 02003 02004 // // region index from the underlying Felz-Hutt region 02005 // int regIndex = itsInitialRegionImage.getVal(currentSalPoint); 02006 02007 // FIXXX: LATER include superpixel underneath the region 02008 // calculate the overlap on the region: 02009 // anything over 50% of total bounding box is good 02010 // --> ok because the region is similar appearance-wise 02011 02012 02013 // ============================================= 02014 02015 //currentObjectRegList.push_back(regIndex); 02016 //for(uint i = 0; i < itsRegionAdjecencyList[regIndex].size(); i++) 02017 // currentUnassignedRegionsRegList.push_back 02018 // (itsRegionAdjecencyList[regIndex][i]); 02019 02020 02021 02022 02023 // // find the current starting growing point 02024 // uint pos = 0; 02025 // for(uint i = 0; i < currentUnassignedLocations.size(); i++) 02026 // if(startPt == currentUnassignedLocations[i]) 02027 // { pos = i; i = currentUnassignedLocations.size(); } 02028 // culItr = currentUnassignedLocations.begin(); 02029 // currentUnassignedLocations.erase(culItr+pos); 02030 02031 // and move it to the front of the unassigned list 02032 // even if that point is not there previously 02033 02034 // culItr = currentUnassignedLocations.begin(); 02035 // currentUnassignedLocations.insert(culItr, startPt); 02036 02037 02038 // // assign current location to object list 02039 // currentObjectLocations.push_back(ptGrid); 02040 // assignmentMap.setVal(ptGrid, CENTER_REGION); 02041 02042 // // add its neighbors to unassigned locations list 02043 // uint bSize = currentUnassignedLocations.size(); 02044 // addUnvisitedNeighbors 02045 // (currentUnassignedLocations, ptGrid, 02046 // assignmentMap); 02047 // uint aSize = currentUnassignedLocations.size(); 02048 // uint addN = aSize - bSize; 02049 02050 // // take out the location from unassigned list 02051 // culItr = currentUnassignedLocations.begin(); 02052 // currentUnassignedLocations.erase(culItr+currIndex+addN); 02053 02054 02055 02056 02057 } 02058 02059 // ###################################################################### 02060 void SalientRegionSegmenter::displayDistributionSetup 02061 (Segment segment, Point2D<int> pt, 02062 std::vector<Point2D<int> > pts2, 02063 std::vector<Point2D<int> > pts3) 02064 { 02065 // display stuff 02066 Image<PixRGB<byte> > ima = itsImage; 02067 uint w = ima.getWidth(); 02068 uint h = ima.getHeight(); 02069 02070 Image<float> fIma(luminance(ima)); 02071 Image<float> tempFIma = fIma; 02072 inplaceNormalize(tempFIma, 0.0f,255.0f); 02073 Image<byte> bIma(tempFIma); 02074 02075 // get the image 02076 float mVal = 32; 02077 float bVal = 255 - mVal; 02078 Image<byte> dImaR, dImaG, dImaB; 02079 getComponents(ima, dImaR, dImaG, dImaB); 02080 inplaceNormalize(dImaR, byte(0), byte(mVal)); 02081 inplaceNormalize(dImaG, byte(0), byte(mVal)); 02082 inplaceNormalize(dImaB, byte(0), byte(mVal)); 02083 Image<PixRGB<byte> > dIma = makeRGB(dImaR,dImaG,dImaB); 02084 02085 Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS); 02086 02087 inplacePaste (dispIma, ima, Point2D<int>(0,0)); 02088 02089 Image<float> stateMapR(w,h, ZEROS); 02090 Image<float> stateMapG(w,h, ZEROS); 02091 Image<float> stateMapB(w,h, ZEROS); 02092 02093 // draw core 02094 std::vector<Point2D<int> > cores; 02095 std::vector<Point2D<int> > center; 02096 std::vector<Point2D<int> > surround; 02097 std::vector<Point2D<int> > unassigned; 02098 02099 cores.push_back(Point2D<int>(152, 40)); 02100 02101 // // unassigned.push_back(Point2D<int>(144, 32)); 02102 // // unassigned.push_back(Point2D<int>(152, 32)); 02103 // // unassigned.push_back(Point2D<int>(160, 32)); 02104 02105 // // unassigned.push_back(Point2D<int>(144, 40)); 02106 // // unassigned.push_back(Point2D<int>(160, 40)); 02107 02108 // // unassigned.push_back(Point2D<int>(144, 48)); 02109 // // unassigned.push_back(Point2D<int>(152, 48)); 02110 // // unassigned.push_back(Point2D<int>(160, 48)); 02111 02112 // cores.push_back(Point2D<int>(144, 32)); 02113 // cores.push_back(Point2D<int>(152, 32)); 02114 // cores.push_back(Point2D<int>(160, 32)); 02115 02116 // cores.push_back(Point2D<int>(144, 40)); 02117 // cores.push_back(Point2D<int>(160, 40)); 02118 02119 // cores.push_back(Point2D<int>(144, 48)); 02120 // cores.push_back(Point2D<int>(152, 48)); 02121 // cores.push_back(Point2D<int>(160, 48)); 02122 02123 // center.push_back(Point2D<int>(136, 24)); 02124 // center.push_back(Point2D<int>(144, 24)); 02125 // center.push_back(Point2D<int>(152, 24)); 02126 // center.push_back(Point2D<int>(136, 32)); 02127 // center.push_back(Point2D<int>(136, 40)); 02128 02129 // center.push_back(Point2D<int>(128, 16)); 02130 // center.push_back(Point2D<int>(136, 16)); 02131 // center.push_back(Point2D<int>(128, 24)); 02132 // center.push_back(Point2D<int>(128, 32)); 02133 02134 // center.push_back(Point2D<int>(120, 8)); 02135 // center.push_back(Point2D<int>(120, 16)); 02136 // center.push_back(Point2D<int>(120, 24)); 02137 02138 // center.push_back(Point2D<int>( 96, 8)); 02139 // center.push_back(Point2D<int>(104, 8)); 02140 // center.push_back(Point2D<int>(112, 8)); 02141 // center.push_back(Point2D<int>(104, 16)); 02142 // center.push_back(Point2D<int>(112, 16)); 02143 02144 // unassigned.push_back(Point2D<int>( 88, 8)); 02145 // surround .push_back(Point2D<int>( 88, 16)); 02146 // unassigned.push_back(Point2D<int>( 96, 16)); 02147 // surround .push_back(Point2D<int>( 96, 24)); 02148 // unassigned.push_back(Point2D<int>(104, 24)); 02149 02150 // unassigned.push_back(Point2D<int>(112, 24)); 02151 // surround .push_back(Point2D<int>(112, 32)); 02152 // unassigned.push_back(Point2D<int>(120, 32)); 02153 // surround .push_back(Point2D<int>(120, 40)); 02154 // unassigned.push_back(Point2D<int>(128, 40)); 02155 02156 // surround .push_back(Point2D<int>(128, 48)); 02157 // unassigned.push_back(Point2D<int>(136, 48)); 02158 // surround .push_back(Point2D<int>(136, 56)); 02159 // unassigned.push_back(Point2D<int>(144, 56)); 02160 // unassigned.push_back(Point2D<int>(152, 56)); 02161 // unassigned.push_back(Point2D<int>(160, 56)); 02162 // unassigned.push_back(Point2D<int>(168, 56)); 02163 02164 // unassigned.push_back(Point2D<int>(128, 8)); 02165 // unassigned.push_back(Point2D<int>(136, 8)); 02166 02167 // unassigned.push_back(Point2D<int>(144, 16)); 02168 // unassigned.push_back(Point2D<int>(152, 16)); 02169 // unassigned.push_back(Point2D<int>(160, 16)); 02170 02171 // unassigned.push_back(Point2D<int>(160, 24)); 02172 // unassigned.push_back(Point2D<int>(168, 24)); 02173 02174 // unassigned.push_back(Point2D<int>(168, 32)); 02175 // unassigned.push_back(Point2D<int>(168, 40)); 02176 // unassigned.push_back(Point2D<int>(168, 48)); 02177 02178 for(uint i = 0; i < cores.size(); i++) 02179 { 02180 Rectangle r = Rectangle::tlbrO 02181 (cores[i].j-4, cores[i].i-4, 02182 cores[i].j+4, cores[i].i+4); 02183 drawFilledRect(stateMapB, r, 0.5F); 02184 } 02185 02186 for(uint i = 0; i < center.size(); i++) 02187 { 02188 Rectangle r = Rectangle::tlbrO 02189 (center[i].j-4, center[i].i-4, 02190 center[i].j+4, center[i].i+4); 02191 drawFilledRect(stateMapR, r, 0.5F); 02192 } 02193 02194 for(uint i = 0; i < surround.size(); i++) 02195 { 02196 Rectangle r = Rectangle::tlbrO 02197 (surround[i].j-4, surround[i].i-4, 02198 surround[i].j+4, surround[i].i+4); 02199 drawFilledRect(stateMapG, r, 0.5F); 02200 } 02201 02202 for(uint i = 0; i < unassigned.size(); i++) 02203 { 02204 Rectangle r = Rectangle::tlbrO 02205 (unassigned[i].j-4, unassigned[i].i-4, 02206 unassigned[i].j+4, unassigned[i].i+4); 02207 drawFilledRect(stateMapR, r, 0.5F); 02208 drawFilledRect(stateMapG, r, 0.5F); 02209 } 02210 02211 02212 // draw grid 02213 int grad = 8; 02214 for(uint i = grad; i < w; i++) 02215 for(uint j = grad; j < h; j++) 02216 { 02217 if(i%grad == 0 && j%grad == 0) 02218 { 02219 drawCross(stateMapR, Point2D<int>(i,j), 0.5F, 1); 02220 drawCross(stateMapG, Point2D<int>(i,j), 0.5F, 1); 02221 drawCross(stateMapB, Point2D<int>(i,j), 0.5F, 1); 02222 } 02223 } 02224 02225 // draw closer population 02226 //LINFO("pts2 size: %d", int(pts2.size())); 02227 for(uint i = 0; i < pts2.size(); i++) 02228 { 02229 //LINFO("pts2[%3d]: %3d %3d", i, pts2[i].i, pts2[i].j); 02230 if(stateMapR.coordsOk(pts2[i])) 02231 { 02232 stateMapR.setVal(pts2[i], 0.25F); 02233 //stateMapG.setVal(pts2[i], 0.25F); 02234 //stateMapB.setVal(pts2[i], 0.25F); 02235 } 02236 } 02237 02238 // draw farther population 02239 //LINFO("pts3 size: %d", int(pts3.size())); 02240 for(uint i = 0; i < pts3.size(); i++) 02241 { 02242 //LINFO("pts3[%3d]: %3d %3d", i, pts3[i].i, pts3[i].j); 02243 if(stateMapR.coordsOk(pts3[i])) 02244 { 02245 //stateMapR.setVal(pts3[i], 0.25F); 02246 stateMapG.setVal(pts3[i], 0.25F); 02247 //stateMapB.setVal(pts3[i], 0.25F); 02248 } 02249 } 02250 02251 // draw the point 02252 int rad = NEIGHBORHOOD_RADIUS; 02253 for(int i = -rad; i <= rad; i++) 02254 for(int j = -rad; j <= rad; j++) 02255 { 02256 bool isWithinCircle = ((i*i+j*j) <= (rad*rad)); 02257 02258 Point2D<int> pt2 = pt + Point2D<int>(i,j); 02259 if(itsImage.coordsOk(pt2) && isWithinCircle) 02260 { 02261 stateMapR.setVal(pt2, 0.5F); 02262 //stateMapG.setVal(pt2, 0.25F); 02263 //stateMapB.setVal(pt2, 0.25F); 02264 } 02265 } 02266 02267 drawDisk(stateMapR, pt, 2, 1.0F); 02268 drawDisk(stateMapG, pt, 2, 1.0F); 02269 drawDisk(stateMapB, pt, 2, 1.0F); 02270 02271 // drawLine(stateMapR, pt, Point2D<int>(90,14), 0.5F); 02272 // drawLine(stateMapG, pt, Point2D<int>(90,14), 0.5F); 02273 // drawLine(stateMapB, pt, Point2D<int>(90,14), 0.5F); 02274 02275 // draw the contour 02276 rutz::shared_ptr<Contour> contour = 02277 itsContourBoundaries[segment.contourIndex]; 02278 02279 int hstep = BOUNDARY_STEP_SIZE/2; 02280 uint start = segment.segStartIndex; 02281 uint end = segment.segEndIndex; 02282 //for(uint i = start; i <= end; i++) 02283 // { 02284 for(uint i = 0; i < contour->edgels.size(); i++) 02285 { 02286 rutz::shared_ptr<Edgel> edgel = contour->edgels[i]; 02287 02288 uint aind = edgel->angleIndex; 02289 float baind = 02290 fmod((aind+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS); 02291 02292 float dx = cos(baind * M_PI/4.0) * hstep; 02293 float dy = sin(baind * M_PI/4.0) * hstep; 02294 02295 Point2D<int> pt = edgel->pt; 02296 Point2D<int> p1 = pt + Point2D<int>( dx+.5, dy+.5); 02297 Point2D<int> p2 = pt + Point2D<int>(-dx-.5, -dy-.5); 02298 02299 if(i >= start && i <= end) 02300 { 02301 drawLine(stateMapR, p1, p2, 1.0F); 02302 drawLine(stateMapG, p1, p2, 1.0F); 02303 drawLine(stateMapB, p1, p2, 1.0F); 02304 } 02305 else 02306 { 02307 drawLine(stateMapR, p1, p2, 0.5F); 02308 drawLine(stateMapG, p1, p2, 0.5F); 02309 drawLine(stateMapB, p1, p2, 0.5F); 02310 } 02311 //drawDisk(stateMap, pt, 2, 1.0F); 02312 } 02313 02314 inplaceNormalize(stateMapR, 0.0f,bVal); 02315 inplaceNormalize(stateMapG, 0.0f,bVal); 02316 inplaceNormalize(stateMapB, 0.0f,bVal); 02317 Image<byte> dSMapR(stateMapR); 02318 Image<byte> dSMapG(stateMapG); 02319 Image<byte> dSMapB(stateMapB); 02320 Image<PixRGB<byte> > dSmap = makeRGB(dSMapR, dSMapG, dSMapB); 02321 inplacePaste 02322 (dispIma, Image<PixRGB<byte> >(dIma+dSmap), Point2D<int>(w,0)); 02323 02324 // Raster::WriteRGB(crop(Image<PixRGB<byte> >(dIma+dSmap), 02325 // Point2D<int>(50,0), Dims(150,100)), 02326 // std::string("starfish_algorithm_4.pnm")); 02327 02328 itsWin->drawImage(dispIma, 0,0); 02329 Raster::waitForKey(); 02330 } 02331 02332 // ###################################################################### 02333 void SalientRegionSegmenter::displayGrowMap 02334 (Image<int> assignmentMap, Point2D<int> currPoint, 02335 std::vector<Point2D<int> > currentObjectLocations, 02336 std::vector<Point2D<int> > currentObjectCoreLocations, 02337 std::vector<Point2D<int> > currentBackgroundLocations, 02338 std::vector<Point2D<int> > currentUnassignedLocations, 02339 Image<bool> isComparedWith, Segment segment) 02340 { 02341 // display stuff 02342 Image<PixRGB<byte> > ima = itsImage; 02343 uint w = ima.getWidth(); 02344 uint h = ima.getHeight(); 02345 02346 Image<float> fIma(luminance(ima)); 02347 Image<float> tempFIma = fIma; 02348 inplaceNormalize(tempFIma, 0.0f,255.0f); 02349 Image<byte> bIma(tempFIma); 02350 02351 // get the image 02352 float mVal = 32; 02353 float bVal = 255 - mVal; 02354 Image<byte> dImaR, dImaG, dImaB; 02355 getComponents(ima, dImaR, dImaG, dImaB); 02356 inplaceNormalize(dImaR, byte(0), byte(mVal)); 02357 inplaceNormalize(dImaG, byte(0), byte(mVal)); 02358 inplaceNormalize(dImaB, byte(0), byte(mVal)); 02359 Image<PixRGB<byte> > dIma = makeRGB(dImaR,dImaG,dImaB); 02360 02361 Image<PixRGB<byte> > dispIma(4*w,2*h,ZEROS); 02362 02363 inplacePaste (dispIma, ima, Point2D<int>(0,0)); 02364 02365 Image<float> stateMapR(w,h, ZEROS); 02366 Image<float> stateMapG(w,h, ZEROS); 02367 Image<float> stateMapB(w,h, ZEROS); 02368 02369 std::vector<Point2D<int> >::iterator oitr = 02370 currentObjectLocations.begin(); 02371 std::vector<Point2D<int> >::iterator citr = 02372 currentObjectCoreLocations.begin(); 02373 std::vector<Point2D<int> >::iterator sitr = 02374 currentBackgroundLocations.begin(); 02375 std::vector<Point2D<int> >::iterator uitr = 02376 currentUnassignedLocations.begin(); 02377 02378 for(uint i = 0; i < currentObjectLocations.size(); i++) 02379 { 02380 Point2D<int> pt((*oitr).i*BOUNDARY_STEP_SIZE, 02381 (*oitr).j*BOUNDARY_STEP_SIZE ); 02382 Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4); 02383 drawFilledRect(stateMapR, r, 0.5F); 02384 oitr++; 02385 } 02386 02387 for(uint i = 0; i < currentObjectCoreLocations.size(); i++) 02388 { 02389 Point2D<int> pt((*citr).i*BOUNDARY_STEP_SIZE, 02390 (*citr).j*BOUNDARY_STEP_SIZE ); 02391 Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4); 02392 drawFilledRect(stateMapB, r, 0.5F); 02393 citr++; 02394 } 02395 02396 for(uint i = 0; i < currentBackgroundLocations.size(); i++) 02397 { 02398 Point2D<int> pt((*sitr).i*BOUNDARY_STEP_SIZE, 02399 (*sitr).j*BOUNDARY_STEP_SIZE ); 02400 Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4); 02401 drawFilledRect(stateMapG, r, 0.5F); 02402 sitr++; 02403 } 02404 02405 for(uint i = 0; i < currentUnassignedLocations.size(); i++) 02406 { 02407 Point2D<int> pt((*uitr).i*BOUNDARY_STEP_SIZE, 02408 (*uitr).j*BOUNDARY_STEP_SIZE ); 02409 Rectangle r = Rectangle::tlbrO(pt.j-4, pt.i-4, pt.j+4, pt.i+4); 02410 drawFilledRect(stateMapR, r, 0.5F); 02411 drawFilledRect(stateMapG, r, 0.5F); 02412 uitr++; 02413 } 02414 02415 // draw grid 02416 int grad = 8; 02417 for(uint i = grad; i < w; i++) 02418 for(uint j = grad; j < h; j++) 02419 { 02420 if(i%grad == 0 && j%grad == 0) 02421 { 02422 drawCross(stateMapR, Point2D<int>(i,j), 0.5F, 1); 02423 drawCross(stateMapG, Point2D<int>(i,j), 0.5F, 1); 02424 drawCross(stateMapB, Point2D<int>(i,j), 0.5F, 1); 02425 } 02426 } 02427 02428 // draw the contour 02429 rutz::shared_ptr<Contour> contour = 02430 itsContourBoundaries[segment.contourIndex]; 02431 02432 int hstep = BOUNDARY_STEP_SIZE/2; 02433 uint start = segment.segStartIndex; 02434 uint end = segment.segEndIndex; 02435 //for(uint i = start; i <= end; i++) 02436 // { 02437 for(uint i = 0; i < contour->edgels.size(); i++) 02438 { 02439 rutz::shared_ptr<Edgel> edgel = contour->edgels[i]; 02440 02441 uint aind = edgel->angleIndex; 02442 float baind = 02443 fmod((aind+(NUM_RIDGE_DIRECTIONS/2)),NUM_RIDGE_DIRECTIONS); 02444 02445 float dx = cos(baind * M_PI/4.0) * hstep; 02446 float dy = sin(baind * M_PI/4.0) * hstep; 02447 02448 Point2D<int> pt = edgel->pt; 02449 Point2D<int> p1 = pt + Point2D<int>( dx+.5, dy+.5); 02450 Point2D<int> p2 = pt + Point2D<int>(-dx-.5, -dy-.5); 02451 02452 if(i >= start && i <= end) 02453 { 02454 drawLine(stateMapR, p1, p2, 1.0F); 02455 drawLine(stateMapG, p1, p2, 1.0F); 02456 drawLine(stateMapB, p1, p2, 1.0F); 02457 } 02458 else 02459 { 02460 drawLine(stateMapR, p1, p2, 0.5F); 02461 drawLine(stateMapG, p1, p2, 0.5F); 02462 drawLine(stateMapB, p1, p2, 0.5F); 02463 } 02464 //drawDisk(stateMap, pt, 2, 1.0F); 02465 } 02466 02467 inplaceNormalize(stateMapR, 0.0f,bVal); 02468 inplaceNormalize(stateMapG, 0.0f,bVal); 02469 inplaceNormalize(stateMapB, 0.0f,bVal); 02470 Image<byte> dSMapR(stateMapR); 02471 Image<byte> dSMapG(stateMapG); 02472 Image<byte> dSMapB(stateMapB); 02473 Image<PixRGB<byte> > dSmap = makeRGB(dSMapR, dSMapG, dSMapB); 02474 inplacePaste 02475 (dispIma, Image<PixRGB<byte> >(dIma+dSmap), Point2D<int>(w,0)); 02476 02477 // Raster::WriteRGB(crop(Image<PixRGB<byte> >(dIma+dSmap), 02478 // Point2D<int>(50,0), Dims(150,100)), 02479 // std::string("starfish_algorithm_4.pnm")); 02480 02481 itsWin->drawImage(dispIma, 0,0); 02482 Raster::waitForKey(); 02483 } 02484 02485 // ###################################################################### 02486 /* So things look consistent in everyone's emacs... */ 02487 /* Local Variables: */ 02488 /* indent-tabs-mode: nil */ 02489 /* End: */