00001 /*! @file Landmark/test-segmentLandmark.C [put description here] */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2002 // 00005 // by the 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; filed July 23, 2001, following provisional applications // 00013 // No. 60/274,674 filed March 8, 2001 and 60/288,724 filed May 4, 2001).// 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: Vidhya Navalpakkam <navalpak@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Landmark/test-segmentLandmark.C $ 00035 // $Id: test-segmentLandmark.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 00039 #include "Image/ColorOps.H" 00040 #include "Image/FilterOps.H" 00041 #include "Image/Image.H" 00042 #include "Image/ImageSet.H" 00043 #include "Image/ImageSetOps.H" 00044 #include "Image/MathOps.H" // for binaryReverse() 00045 #include "Image/Pixels.H" 00046 #include "Image/ShapeOps.H" 00047 #include "Image/Transforms.H" // for learningCoeff() 00048 #include "Image/fancynorm.H" 00049 #include "Landmark/Tree.H" 00050 #include "Landmark/density.H" 00051 #include "Raster/Raster.H" 00052 #include "Util/Timer.H" 00053 #include "Util/log.H" 00054 00055 #include <cstdio> 00056 #include <iostream> 00057 #include <map> 00058 #include <vector> 00059 00060 int countClusters(Image<float> input, float thresh) 00061 { 00062 // get image details 00063 int w = input.getWidth(); 00064 int h = input.getHeight(); 00065 00066 int count = 0; 00067 for(int i = 0; i < w; i++) 00068 for(int j = 0; j < h; j++) 00069 { 00070 if(input.getVal(i,j) > thresh) 00071 { 00072 // flood starting at seed upto thresh 00073 Image<float> output; 00074 flood(input, output, Point2D<int>(i,j), thresh, 255.0f); 00075 input -= output; 00076 inplaceClamp(input, 0.0f, 255.0f); 00077 count++; 00078 } 00079 } 00080 return count; 00081 } 00082 00083 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00084 00085 int main (int argc, char **argv) 00086 { 00087 if (argc != 3) 00088 { 00089 std::cerr << "usage: test-segmentLandmark <option> <weight>\n\n \ 00090 where <option> is f (flat) or h (heirarchy)\n \ 00091 where <weight> is y (weight maps) or n (use all maps)\n"; 00092 exit(2); 00093 } 00094 std::map<int, Object*> list; // list of all objects 00095 00096 // to initialise the edges, invoke density once 00097 Image<byte> img = density("feature1.input", list); 00098 int global_edge[list.size()][list.size()]; // clique of objects 00099 for(uint i = 0; i < list.size(); i++) 00100 for(uint j = 0; j < list.size(); j++) 00101 global_edge[i][j] = 0; 00102 00103 int edge[list.size()][list.size()][42]; 00104 for(uint i = 0; i < list.size(); i++) 00105 for(uint j = 0; j < list.size(); j++) 00106 for(uint k = 0; k < 42; k++) 00107 edge[i][j][k] = 0; 00108 00109 //################### FIND CLUSTERS IN ALL FEATURES ################### 00110 00111 for(int features = 1; features < 42; features++) 00112 { 00113 char filename[256]; 00114 sprintf(filename, "feature%d.input", features); 00115 list.clear(); 00116 Image<byte> img = density(filename, list); 00117 Raster::WriteGray(img, sformat("density_%d.pgm",features)); 00118 00119 Image<float> input = (Image<float>)(img); 00120 input = lowPass9(input); 00121 PixRGB<float> color(1, 0, 0); 00122 Raster::WriteRGB( stain(input, color),"input.ppm"); 00123 00124 //inplaceNormalize(input, 0.0f, 255.0f); 00125 int targets = countClusters(input, 0.0f); 00126 LDEBUG("# of targets = %d", targets); 00127 00128 // statistics of the input image 00129 const int w = input.getWidth(); 00130 const int h = input.getHeight(); 00131 float min, max; 00132 getMinMax(input, min, max); 00133 00134 // analyze the options 00135 bool flat = false, heirarchy = false; 00136 if(strcmp(argv[1],"f") == 0) 00137 { 00138 flat = true; 00139 std::cout<<"just get the members of each cluster"<<std::endl; 00140 } 00141 else if(strcmp(argv[1], "h") == 0) 00142 { 00143 heirarchy = true; 00144 std::cout<<"get the complete heirarchy"<<std::endl; 00145 } 00146 else 00147 std::cout<<"unrecognized option!"; 00148 00149 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00150 00151 // maintain the forest of trees or islands 00152 std::multimap<float, Tree*, std::greater<float> > forest; 00153 00154 00155 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00156 00157 // find the local maxima and store in a map (val, locn) 00158 00159 std::multimap<float, Point2D<int>, std::greater<float> > maxima; 00160 int lm_num = 0; // num of local maxima or peaks 00161 00162 // we want to detect quickly local maxes, but avoid getting local mins 00163 float thresh = (min + (max - min) / 10.0); 00164 // this is a 1d image 00165 for (int index = 1; index < w - 1; index ++) 00166 { 00167 float val = input.getVal(index, 0); 00168 if (val >= thresh && 00169 val >= input.getVal(index - 1 , 0) && 00170 val >= input.getVal(index + 1, 0)) 00171 { 00172 // insert into map 00173 Point2D<int> p(index, 0); 00174 maxima.insert(std::pair<float, Point2D<int> >(val, p)); 00175 lm_num ++; 00176 } 00177 } 00178 00179 LDEBUG(" # of local maxima = %"ZU"", maxima.size()); 00180 00181 if(maxima.size() == 0) 00182 { 00183 LERROR(" there r no maxima in this image!"); 00184 break; 00185 } 00186 // to consider every peak above the ground level, insert a new member 00187 std::multimap<float, Point2D<int>, std::greater<float> >::iterator 00188 min_peak = maxima.end(); 00189 min_peak --; 00190 maxima.insert(std::pair<float, Point2D<int> >(min_peak->first / 2, 00191 Point2D<int>(0, 0))); 00192 00193 00194 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00195 00196 // choose one local maxima at a time and flood upto the next local maxima 00197 00198 std::multimap<float, Point2D<int>, std::greater<float> >::iterator itr; 00199 00200 int iter = 0; 00201 Image< PixRGB<float> > cat; 00202 for( itr = maxima.begin(); itr != maxima.end(); iter++) 00203 { 00204 float thresh; 00205 00206 if(heirarchy) 00207 { 00208 thresh = itr->first; 00209 } 00210 00211 else if(flat) 00212 { 00213 // add all members to the forest except the last 00214 std::multimap<float, Point2D<int>, std::greater<float> >::iterator 00215 last = maxima.end(); 00216 last --; 00217 while( itr != last) 00218 { 00219 Tree* new_peak = new Tree(itr->second, itr->first); 00220 forest.insert(std::pair<float, Tree*>(itr->first, new_peak)); 00221 itr++; 00222 } 00223 // set thresh to the height of the last member 00224 thresh = last->first; 00225 } 00226 00227 else break; 00228 00229 Image<float> output = highThresh( input, thresh, 255.0f); 00230 00231 // consider the maxima that are equal; 00232 // advance to the next lowest maxima 00233 while (itr != maxima.end() && itr->first == thresh ) 00234 { 00235 // this peak is the start of a potential island: add a new tree 00236 Tree* new_peak = new Tree(itr->second, itr->first); 00237 forest.insert(std::pair<float, Tree*>(thresh, new_peak)); 00238 itr++; 00239 00240 } 00241 00242 // recompute clusters: brute force 00243 00244 cat.clear(PixRGB<float>(0.0f)); // an image containing all clusters 00245 int count = 0; 00246 00247 // ################## FIND CLUSTERS ############################ 00248 // now find all the connected components in the forest 00249 00250 std::multimap<float, Tree*, std::greater<float> >::iterator tree, 00251 curr_peak; 00252 for(tree = forest.begin(); tree != forest.end(); ) 00253 { 00254 Tree* current = tree->second; 00255 00256 Image<float> output; 00257 Point2D<int> seed = current->node->loc; 00258 LDEBUG("current peak ======== (%d, %d)", 00259 seed.i, seed.j); 00260 flood(input, output, seed, thresh, -255.0f); 00261 00262 // find all member peaks of the current cluster 00263 std::vector<Tree* > to_merge; 00264 std::multimap<float, Tree*, std::greater<float> >::iterator 00265 member = forest.begin(); 00266 while(member != forest.end()) 00267 { 00268 for(member = forest.begin(); member != forest.end(); 00269 member++) 00270 { 00271 if(output.getVal(member->second->node->loc) == -255.0f && 00272 member->second->node->loc != seed) 00273 { 00274 // this peak belongs to the cluster 00275 to_merge.push_back(member->second); 00276 /* erase it from the forest since it will be part of 00277 the new merged tree 00278 */ 00279 LDEBUG(" --------- (%d, %d)", 00280 member->second->node->loc.i, 00281 member->second->node->loc.j); 00282 /* 00283 FIXME: why does forest.erase give problems? 00284 */ 00285 forest.erase(member); 00286 break; 00287 } 00288 } 00289 } 00290 00291 if(to_merge.size() > 0) 00292 { 00293 // merge the current tree with this member of the forest 00294 to_merge.push_back(current); 00295 00296 Tree* new_tree = new Tree(seed, current->node->height); 00297 new_tree->mergeTrees(to_merge); 00298 00299 // erase the old tree 00300 float height = tree->first; 00301 forest.erase(tree); 00302 00303 // add the new merged tree to the forest 00304 current = new_tree; 00305 tree = forest.insert(std::pair<float, Tree*> 00306 (height, current)); 00307 tree++; // advance to the next tree in the forest 00308 } 00309 00310 else 00311 { 00312 // i am a loner:( 00313 to_merge.push_back(current); 00314 tree++; // advance to the next tree in the forest 00315 } 00316 00317 std::vector<Object*> siblings; 00318 // find objects that belong to this cluster 00319 for(uint l = 0; l < list.size(); l++) 00320 { 00321 if(output.getVal((int)list[l]->mu1, 0) == -255.0f) 00322 { 00323 siblings.push_back(list[l]); 00324 //LDEBUG("sibling %s",list[l]->name.c_str()); 00325 } 00326 00327 } 00328 00329 // set edge weights for siblings 00330 int size = siblings.size(); 00331 for(int k = 0; k < size; k++) 00332 for(int l = 0; l < size; l++) 00333 { 00334 edge[siblings[k]->tag][siblings[l]->tag][features] += 1; 00335 global_edge[siblings[k]->tag][siblings[l]->tag] += 1; 00336 //LDEBUG("%d-%d :edge = %d, global_edge = %d", 00337 // siblings[k]->tag,siblings[l]->tag, 00338 // edge[siblings[k]->tag][siblings[l]->tag], 00339 // global_edge[siblings[k]->tag][siblings[l]->tag]); 00340 } 00341 // reset the output (flooded image) to its normal state 00342 for(int k = 0; k < w; k ++) 00343 for(int l = 0; l < h; l ++) 00344 if(output.getVal(k,l) == -255.0f) 00345 { 00346 output.setVal(k, l, input.getVal(k, l)); 00347 } 00348 00349 //LDEBUG(" size of cluster = %d", to_merge.size()); 00350 00351 // draw this cluster 00352 Image<PixRGB<float> > cluster; 00353 if(to_merge.size() > 0) 00354 { 00355 count++; 00356 // generate colors of clusters 00357 float red = 0.0f, green = 0.0f, blue = 0.0f; 00358 00359 if(count % 3 == 1) 00360 { 00361 red = 1.0f ; // / count; 00362 green = 0.0f; 00363 blue = 0.0f; 00364 //LDEBUG("red...."); 00365 } 00366 else if(count % 3 == 2) 00367 { 00368 green = 1.0f ; // / (count - 1); 00369 blue = 0.0f; 00370 red = 0.0f; 00371 //LDEBUG("green..."); 00372 } 00373 else if(count % 3 == 0) 00374 { 00375 blue = 1.0f ; // / (count - 2); 00376 green = 0.0f; 00377 red = 0.0f; 00378 //LDEBUG("blue...."); 00379 } 00380 00381 PixRGB<float> color(red, green, blue); 00382 //LDEBUG("color = (%f, %f, %f)", red, green, blue); 00383 cluster = stain(output, color); 00384 00385 if(cluster.initialized()) 00386 Raster::WriteRGB(cluster,sformat("clusters_%d.ppm", count-1)); 00387 else 00388 LDEBUG("cluster not initialized!"); 00389 00390 if(!cat.initialized()) 00391 cat = cluster; 00392 else 00393 cat += cluster; 00394 } 00395 00396 // FIXME 00397 //tree ++; 00398 } 00399 00400 if(cat.initialized()) 00401 Raster::WriteRGB((Image< PixRGB<byte> >)cat, 00402 sformat("iter_%d_%d.ppm", 00403 iter, 00404 features)); 00405 else 00406 LDEBUG("iter not initialized!"); 00407 //LDEBUG(" # of clusters = %d", count); 00408 //LDEBUG("\n****************************************\n"); 00409 } 00410 00411 00412 std::multimap<float, Tree*, std::greater<float> >::iterator tree; 00413 Image<PixRGB<byte> > plot = (Image< PixRGB<byte> >)cat; 00414 for(tree = forest.begin(); tree != forest.end(); tree++) 00415 tree->second->traverse(input, plot); 00416 00417 Raster::WriteRGB(plot,"plot.ppm"); 00418 00419 00420 // print out all the siblings 00421 // use law of transitivity :-) 00422 std::map<int, Object*>::iterator tr, jtr, start, stop; 00423 std::map<int, Object*> bak = list; 00424 for(tr = bak.begin(); tr != bak.end(); tr++) 00425 { 00426 start = tr; 00427 stop = bak.end(); 00428 LINFO("%s", tr->second->name.c_str()); 00429 for(jtr = tr ; jtr != stop; jtr ++) 00430 { 00431 if(edge[tr->second->tag][jtr->second->tag][features] == 1 00432 && tr != jtr) 00433 { 00434 LINFO("%s", jtr->second->name.c_str()); 00435 bak.erase(jtr); 00436 } 00437 } 00438 LINFO("---------------------------"); 00439 } 00440 00441 } 00442 if(strcmp(argv[2], "n") == 0) 00443 { 00444 // dont weight the maps; just add them uniformly 00445 std::map<int, Object*>::iterator tr, jtr, start, stop; 00446 for(int conf = 42; conf > 0; conf -- ) 00447 { 00448 // evaluate the clusters with decreasing order of confidence 00449 LDEBUG("CONFIDENCE LEVEL = %d", conf); 00450 std::map<int, Object*> bak = list; 00451 for(tr = bak.begin(); tr != bak.end(); tr++) 00452 { 00453 start = tr; 00454 stop = bak.end(); 00455 LINFO("%s", tr->second->name.c_str()); 00456 for(jtr = tr ; jtr != stop; jtr ++) 00457 { 00458 if(global_edge[tr->second->tag][jtr->second->tag] >= conf 00459 && tr != jtr) 00460 { 00461 LINFO("%s", jtr->second->name.c_str()); 00462 bak.erase(jtr); 00463 } 00464 } 00465 LINFO("---------------------------"); 00466 } 00467 LINFO("################################################"); 00468 } 00469 } 00470 else if(strcmp(argv[2], "y") == 0) 00471 { 00472 // weight the maps according to the channels 00473 for(uint i = 0; i < list.size(); i++) 00474 for(uint j = 0; j < list.size(); j++) 00475 { 00476 global_edge[i][j] = 0; 00477 } 00478 // use weighting 00479 for(uint i = 0; i < list.size(); i++) 00480 for(uint j = 0; j < list.size(); j++) 00481 { 00482 // color : 2 (rg and by) 00483 for(uint k = 0; k < 12; k++) 00484 global_edge[i][j] += edge[i][j][k]; 00485 global_edge[i][j] /= 2; 00486 00487 // intensity : 1 00488 for(uint k = 12; k < 18; k++) 00489 global_edge[i][j] += edge[i][j][k]; 00490 00491 // orientation: 4 00492 for(uint k = 18; k < 42; k++) 00493 global_edge[i][j] += edge[i][j][k]; 00494 global_edge[i][j] /= 4; 00495 } 00496 00497 // hence, max edge weight = 18 00498 std::map<int, Object*>::iterator tr, jtr, start, stop; 00499 for(int conf = 18; conf > 0; conf -- ) 00500 { 00501 // evaluate the clusters with decreasing order of confidence 00502 LDEBUG("CONFIDENCE LEVEL = %d", conf); 00503 std::map<int, Object*> bak = list; 00504 for(tr = bak.begin(); tr != bak.end(); tr++) 00505 { 00506 start = tr; 00507 stop = bak.end(); 00508 LINFO("%s", tr->second->name.c_str()); 00509 for(jtr = tr ; jtr != stop; jtr ++) 00510 { 00511 if(global_edge[tr->second->tag][jtr->second->tag] >= conf 00512 && tr != jtr) 00513 { 00514 LINFO("%s", jtr->second->name.c_str()); 00515 bak.erase(jtr); 00516 } 00517 } 00518 LINFO("---------------------------"); 00519 } 00520 LINFO("################################################"); 00521 } 00522 } 00523 00524 } 00525 00526 00527 // ###################################################################### 00528 /* So things look consistent in everyone's emacs... */ 00529 /* Local Variables: */ 00530 /* indent-tabs-mode: nil */ 00531 /* End: */