00001 /*!@file Component/RawGistEstimatorStd.C extract estimated gist 00002 using available features of the image */ 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Sophie Marat <sophie.marat.ilab@gmail.com> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/RawGistEstimatorStd.C $ 00035 // $Id: RawGistEstimatorStd.C $ 00036 // 00037 00038 // ###################################################################### 00039 /*! Extract gist of image */ 00040 00041 #include "Neuro/GistEstimatorStd.H" 00042 #include "Component/ModelManager.H" 00043 #include "Channels/ChannelMaps.H" 00044 //#include "Channels/BlueYellowChannel.H" 00045 //#include "Channels/ColorChannel.H" 00046 //#include "Channels/GaborChannel.H" 00047 //#include "Channels/IntensityChannel.H" 00048 //#include "Channels/OrientationChannel.H" 00049 //#include "Channels/RedGreenChannel.H" 00050 #include "GUI/XWinManaged.H" 00051 #include "Image/CutPaste.H" 00052 #include "Image/DrawOps.H" 00053 #include "Image/FilterOps.H" 00054 #include "Image/MathOps.H" 00055 #include "Image/ShapeOps.H" 00056 #include "Neuro/gistParams.H" 00057 #include "Raster/Raster.H" 00058 00059 #include "Simulation/SimEventQueue.H" 00060 #include "Neuro/NeuroSimEvents.H" 00061 #include "Simulation/SimEvents.H" 00062 #include "Channels/ChannelOpts.H" 00063 #include "Channels/SingleChannel.H" 00064 00065 #include "Util/Timer.H" 00066 #include "Util/StringUtil.H" 00067 00068 // ###################################################################### 00069 // get subsum of an image - more efficient implementation 00070 Image<double> getSubSum(Image<float> img) 00071 { 00072 Image<float> res(1, 21, ZEROS); 00073 00074 int w = img.getWidth(); int h = img.getHeight(); 00075 std::vector<float> tempRes(21); 00076 00077 for (int i = 0; i < 21; i++) tempRes[i] = 0.0; 00078 std::vector<int> counts(16); 00079 for (int i = 0 ; i < 16; i++) counts[i] = 0; 00080 00081 Image<float>::const_iterator itr = img.begin(); 00082 for (int y = 0; y < h; ++y) 00083 { 00084 int suby = (4*y)/h; 00085 for (int x = 0; x < w; ++x) 00086 { 00087 int subx = (4*x)/w; 00088 int subpos = 4*suby + subx; 00089 tempRes[subpos+5] += *itr; 00090 00091 ++(counts[subpos]); 00092 ++itr; 00093 } 00094 } 00095 00096 int order[] = { 5,6,9,10, 7,8,11,12, 13,14,17,18, 15,16,19,20 }; 00097 for (int i = 0 ; i < 16; ++i) 00098 if (counts[i] > 0) 00099 res[i+5] = tempRes[order[i]] / (counts[order[i] - 5]+ 0.0); 00100 00101 float tre1 = tempRes[5] + tempRes[6] + tempRes[9] + tempRes[10]; 00102 int ct1 = counts[0] + counts[1] + counts[4] + counts[5]; 00103 00104 float tre2 = tempRes[7] + tempRes[8] + tempRes[11] + tempRes[12]; 00105 int ct2 = counts[2] + counts[3] + counts[6] + counts[7]; 00106 00107 float tre3 = tempRes[13] + tempRes[14] + tempRes[17] + tempRes[18]; 00108 int ct3 = counts[8] + counts[9] + counts[12] + counts[13]; 00109 00110 float tre4 = tempRes[15] + tempRes[16] + tempRes[19] + tempRes[20]; 00111 int ct4 = counts[10] + counts[11] + counts[14] + counts[15]; 00112 00113 res[1] = tre1/ct1; 00114 res[2] = tre2/ct2; 00115 res[3] = tre3/ct3; 00116 res[4] = tre4/ct4; 00117 00118 res[0] = (tre1 + tre2 + tre3 + tre4)/(ct1 + ct2 + ct3 + ct4); 00119 00120 LDEBUG("lev1 : %14.4f", res[0]); 00121 LDEBUG("lev2 : %14.4f, %14.4f", res[1], res[2]); 00122 LDEBUG(" : %14.4f, %14.4f", res[3], res[4]); 00123 LDEBUG("lev3 : %14.4f, %14.4f, %14.4f, %14.4f", 00124 res[ 5], res[ 6], res[ 9], res[10]); 00125 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f", 00126 res[ 7], res[ 8], res[11], res[12]); 00127 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f", 00128 res[13], res[14], res[17], res[18]); 00129 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f", 00130 res[15], res[16], res[19], res[20]); 00131 00132 return res; 00133 } 00134 00135 // ###################################################################### 00136 // get subsum of an image - less efficient but can change to stdev easily 00137 /*Image<double> getSubSum2(Image<float> img) 00138 { 00139 Image<double> res(1, 21, ZEROS); 00140 00141 int w = img.getWidth(); int h = img.getHeight(); 00142 00143 int useMean = 1; 00144 // first level 00145 res[0] = mean(img); //sum(img); 00146 00147 // second level 00148 // 1 2 00149 // 3 4 00150 Image<float> img1 = crop(img, Rectangle::tlbrI(0 , 0 , h/2-1, w/2-1)); 00151 Image<float> img2 = crop(img, Rectangle::tlbrI(0 , w/2, h/2-1, w-1 )); 00152 Image<float> img3 = crop(img, Rectangle::tlbrI(h/2, 0 , h-1 , w/2-1)); 00153 Image<float> img4 = crop(img, Rectangle::tlbrI(h/2, w/2, h-1 , w-1 )); 00154 00155 if(useMean) 00156 { 00157 res[1] = mean(img1); //sum(img1); 00158 res[2] = mean(img2); //sum(img2); 00159 res[3] = mean(img3); //sum(img3); 00160 res[4] = mean(img4); //sum(img4); 00161 } 00162 else 00163 { 00164 res[1] = stdev(img1);//mean(img1); //sum(img1); 00165 res[2] = stdev(img2);//mean(img2); //sum(img2); 00166 res[3] = stdev(img3);//mean(img3); //sum(img3); 00167 res[4] = stdev(img4);//mean(img4); //sum(img4); 00168 } 00169 00170 // third level 00171 // 1 2 00172 // 3 4 00173 int wX = img1.getWidth(); int hX = img1.getHeight(); 00174 Image<float> imgX_1 = crop(img1, Rectangle::tlbrI(0 , 0 , hX/2-1, wX/2-1)); 00175 Image<float> imgX_2 = crop(img1, Rectangle::tlbrI(0 , wX/2, hX/2-1, wX-1 )); 00176 Image<float> imgX_3 = crop(img1, Rectangle::tlbrI(hX/2, 0 , hX-1 , wX/2-1)); 00177 Image<float> imgX_4 = crop(img1, Rectangle::tlbrI(hX/2, wX/2, hX-1 , wX-1 )); 00178 if(useMean) 00179 { 00180 res[5] = mean(imgX_1); //sum(imgX_1); 00181 res[6] = mean(imgX_2); //sum(imgX_2); 00182 res[7] = mean(imgX_3); //sum(imgX_3); 00183 res[8] = mean(imgX_4); //sum(imgX_4); 00184 } 00185 else 00186 { 00187 res[5] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1); 00188 res[6] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2); 00189 res[7] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3); 00190 res[8] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4); 00191 } 00192 00193 wX = img2.getWidth(); hX = img2.getHeight(); 00194 imgX_1 = crop(img2, Rectangle::tlbrI(0 , 0 , hX/2-1, wX/2-1)); 00195 imgX_2 = crop(img2, Rectangle::tlbrI(0 , wX/2 , hX/2-1, wX-1 )); 00196 imgX_3 = crop(img2, Rectangle::tlbrI(hX/2 , 0 , hX-1 , wX/2-1)); 00197 imgX_4 = crop(img2, Rectangle::tlbrI(hX/2 , wX/2 , hX-1 , wX-1 )); 00198 if(useMean) 00199 { 00200 res[ 9] = mean(imgX_1); //sum(imgX_1); 00201 res[10] = mean(imgX_2); //sum(imgX_2); 00202 res[11] = mean(imgX_3); //sum(imgX_3); 00203 res[12] = mean(imgX_4); //sum(imgX_4); 00204 } 00205 else 00206 { 00207 res[ 9] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1); 00208 res[10] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2); 00209 res[11] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3); 00210 res[12] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4); 00211 } 00212 00213 wX = img3.getWidth(); hX = img3.getHeight(); 00214 imgX_1 = crop(img3, Rectangle::tlbrI(0 , 0 , hX/2-1, wX/2-1)); 00215 imgX_2 = crop(img3, Rectangle::tlbrI(0 , wX/2 , hX/2-1, wX-1 )); 00216 imgX_3 = crop(img3, Rectangle::tlbrI(hX/2 , 0 , hX-1 , wX/2-1)); 00217 imgX_4 = crop(img3, Rectangle::tlbrI(hX/2 , wX/2 , hX-1 , wX-1 )); 00218 if(useMean) 00219 { 00220 res[13] = mean(imgX_1); //sum(imgX_1); 00221 res[14] = mean(imgX_2); //sum(imgX_2); 00222 res[15] = mean(imgX_3); //sum(imgX_3); 00223 res[16] = mean(imgX_4); //sum(imgX_4); 00224 } 00225 else 00226 { 00227 res[13] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1); 00228 res[14] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2); 00229 res[15] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3); 00230 res[16] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4); 00231 } 00232 00233 wX = img4.getWidth(); hX = img4.getHeight(); 00234 imgX_1 = crop(img4, Rectangle::tlbrI(0 , 0 , hX/2-1, wX/2-1)); 00235 imgX_2 = crop(img4, Rectangle::tlbrI(0 , wX/2 , hX/2-1, wX-1 )); 00236 imgX_3 = crop(img4, Rectangle::tlbrI(hX/2 , 0 , hX-1 , wX/2-1)); 00237 imgX_4 = crop(img4, Rectangle::tlbrI(hX/2 , wX/2 , hX-1 , wX-1 )); 00238 if(useMean) 00239 { 00240 res[17] = mean(imgX_1); //sum(imgX_1); 00241 res[18] = mean(imgX_2); //sum(imgX_2); 00242 res[19] = mean(imgX_3); //sum(imgX_3); 00243 res[20] = mean(imgX_4); //sum(imgX_4); 00244 } 00245 else 00246 { 00247 res[17] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1); 00248 res[18] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2); 00249 res[19] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3); 00250 res[20] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4); 00251 } 00252 00253 LDEBUG("lev1 : %14.4f", res[0]); 00254 LDEBUG("lev2 : %14.4f, %14.4f", res[1], res[2]); 00255 LDEBUG(" : %14.4f, %14.4f", res[3], res[4]); 00256 LDEBUG("lev3 : %14.4f, %14.4f, %14.4f, %14.4f", res[ 5], res[ 6], res[ 9], res[10]); 00257 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f", res[ 7], res[ 8], res[11], res[12]); 00258 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f", res[13], res[14], res[17], res[18]); 00259 LDEBUG(" : %14.4f, %14.4f, %14.4f, %14.4f", res[15], res[16], res[19], res[20]); 00260 00261 return res; 00262 } 00263 */ 00264 00265 // ###################################################################### 00266 // get the mean of the image insige the polygon 00267 double getMeanPoly(Image<float> img, std::vector<Point2D<int> > polygon) 00268 { 00269 double res; 00270 double sum = 0; 00271 int countP = 0; 00272 //res = mean(img); 00273 Point2D<int> P; 00274 for (int i = 0; i < img.getWidth(); i++) 00275 { 00276 for (int j = 0; j < img.getHeight(); j++) 00277 { 00278 P = Point2D<int> (i,j); 00279 if (pnpoly(polygon,P)) 00280 { 00281 sum = sum + img.getVal(P); 00282 countP ++; 00283 } 00284 } 00285 } 00286 00287 res = sum/countP; 00288 return res; 00289 } 00290 00291 00292 00293 // ###################################################################### 00294 RawGistEstimatorStd::RawGistEstimatorStd(OptionManager& mgr, 00295 const std::string& descrName, 00296 const std::string& tagName) : 00297 ModelComponent(mgr, descrName, tagName) 00298 { 00299 itsGistVector.resize(1,NUM_GIST_FEAT * NUM_GIST_CHAN, NO_INIT); 00300 } 00301 00302 // ###################################################################### 00303 RawGistEstimatorStd::~RawGistEstimatorStd() 00304 { } 00305 00306 // ###################################################################### 00307 Image<float> RawGistEstimatorStd::compute(rutz::shared_ptr<ChannelMaps> chmp) 00308 { 00309 computeFeatureVector(chmp); 00310 return itsGistVector; 00311 } 00312 00313 // ###################################################################### 00314 std::vector<float> RawGistEstimatorStd::computeOnPolygon(rutz::shared_ptr<ChannelMaps> chanMaps, std::vector<Point2D<float> > polygonFS) 00315 { 00316 //create a gist vector 00317 std::vector<float> gistPolyVector; 00318 00319 //rescale the polygon to be at the same level than the subMaps 00320 std::vector<Point2D<int> > polygon(polygonFS.size()); 00321 Point2D<int> Ppoly; 00322 for(uint k=0; k<polygonFS.size(); k++) 00323 { 00324 Ppoly.i = (int) floor(polygonFS[k].i/16); 00325 Ppoly.j = (int) floor(polygonFS[k].j/16); 00326 polygon[k] = Ppoly; 00327 } 00328 //test wheter the polygon contain at least one pixel 00329 double areaPoly = area(polygon); 00330 if (areaPoly<=0) 00331 { 00332 LINFO("The given polygon is too small for the gist computation!"); 00333 //find a bounding box with at leat one pixel 00334 int minx, miny, maxx, maxy; 00335 minx = miny =100000000; 00336 maxx = maxy =-100000000; 00337 for (uint k=0; k<polygonFS.size(); k++) 00338 { 00339 if(minx > (int) polygonFS[k].i) minx = (int) polygonFS[k].i; 00340 if(miny > (int) polygonFS[k].j) miny = (int) polygonFS[k].j; 00341 if(maxx < (int) polygonFS[k].i) maxx = (int) polygonFS[k].i; 00342 if(maxy < (int) polygonFS[k].j) maxy = (int) polygonFS[k].j; 00343 } 00344 int minxR, minyR, maxxR, maxyR; 00345 minxR = floor(minx/16.0); 00346 minyR = floor(miny/16.0); 00347 maxxR = ceil(maxx/16.0); 00348 maxyR = ceil(maxy/16.0); 00349 00350 polygon.clear(); 00351 polygon.resize(4); 00352 polygon[0] = Point2D<int> (minxR, minyR); 00353 polygon[1] = Point2D<int> (maxxR, minyR); 00354 polygon[2] = Point2D<int> (maxxR, maxyR); 00355 polygon[3] = Point2D<int> (minxR, maxyR); 00356 } 00357 00358 rutz::shared_ptr<ChannelMaps> orientationMaps; 00359 rutz::shared_ptr<ChannelMaps> colorMaps; 00360 rutz::shared_ptr<ChannelMaps> intensityMaps; 00361 00362 for(uint i=0; i < chanMaps->numSubchans(); i++) 00363 { 00364 //Grab the current channel 00365 rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i); 00366 00367 //Determine the name of the channel 00368 std::vector<std::string> chanNameVec; 00369 split(currChan->getMap().name(), ":", std::back_inserter(chanNameVec)); 00370 std::string chanName = chanNameVec[1]; 00371 00372 //Assign the channel maps based on their name 00373 if(chanName == "orientation") 00374 orientationMaps = currChan; 00375 else if(chanName == "color") 00376 colorMaps = currChan; 00377 else if(chanName == "intensity") 00378 intensityMaps = currChan; 00379 } 00380 00381 LDEBUG("Orientation Subchans: %d", orientationMaps->numSubchans()); 00382 LDEBUG("Color Subchans: %d", colorMaps->numSubchans()); 00383 LDEBUG("Intensity Subchans: %d", intensityMaps->numSubchans()); 00384 00385 //For now, we are expecting the default number of features in the channel maps, as per Siagian_Itti07pami. 00386 //TODO:This should be generalized later when things are more stable 00387 ASSERT(orientationMaps->numSubchans() == 4); 00388 ASSERT(colorMaps->numSubchans() == 2); 00389 ASSERT(intensityMaps->numSubchans() == 0); 00390 00391 //Grab the individual orientation channels 00392 rutz::shared_ptr<ChannelMaps> orientation_0 = orientationMaps->subChanMaps(0); 00393 rutz::shared_ptr<ChannelMaps> orientation_45 = orientationMaps->subChanMaps(1); 00394 rutz::shared_ptr<ChannelMaps> orientation_90 = orientationMaps->subChanMaps(2); 00395 rutz::shared_ptr<ChannelMaps> orientation_135 = orientationMaps->subChanMaps(3); 00396 00397 //Grab the different color channels 00398 rutz::shared_ptr<ChannelMaps> rg; 00399 rutz::shared_ptr<ChannelMaps> by; 00400 for(uint i=0; i<colorMaps->numSubchans(); i++) 00401 { 00402 std::vector<std::string> chanNameVec; 00403 split(colorMaps->subChanMaps(i)->getMap().name(), ":", std::back_inserter(chanNameVec)); 00404 std::string chanName = chanNameVec[2]; 00405 00406 if(chanName == "rg") 00407 rg = colorMaps->subChanMaps(i); 00408 else if(chanName == "by") 00409 by = colorMaps->subChanMaps(i); 00410 } 00411 00412 ASSERT(rg.is_valid()); 00413 ASSERT(by.is_valid()); 00414 00415 //For the Gist computed on the Polygon, no more subsum (=sum on grid) are done, the polygon is comnsidered as one cell, the mean is tacken on the whole polygon 00416 00417 // orientation channel 0 degree 00418 int count = 0; 00419 for(int i = 0; i < NUM_GIST_LEV; i++) 00420 { 00421 float meanPoly = getMeanPoly(orientation_0->getSubmap(i), polygon); 00422 gistPolyVector.push_back(meanPoly); 00423 count += 1; 00424 } 00425 // orientation channel 45 degree 00426 for(int i = 0; i < NUM_GIST_LEV; i++) 00427 { 00428 float meanPoly = getMeanPoly(orientation_45->getSubmap(i), polygon); 00429 gistPolyVector.push_back(meanPoly); 00430 count += 1;; 00431 } 00432 // orientation channel 90 degree 00433 for(int i = 0; i < NUM_GIST_LEV; i++) 00434 { 00435 float meanPoly = getMeanPoly(orientation_90->getSubmap(i), polygon); 00436 gistPolyVector.push_back(meanPoly); 00437 count += 1; 00438 } 00439 // orientation channel 135 degree 00440 for(int i = 0; i < NUM_GIST_LEV; i++) 00441 { 00442 float meanPoly = getMeanPoly(orientation_135->getSubmap(i), polygon); 00443 gistPolyVector.push_back(meanPoly); 00444 count += 1; 00445 } 00446 00447 //For the Red/Green and Blue/Yellow Channels, 00448 //Christian's model uses levels: (2,5), (2,6), (3,6), (3,7), (4,7), (4,8) 00449 //However, this method will use: (2,5), (3,6), (4,7), (2,6), (3,7), (4,8) 00450 //Same channels, just a different order... does this matter? 00451 00452 // red / green opponency 00453 for(uint i=0; i<rg->numSubmaps(); i++) 00454 { 00455 float meanPoly = getMeanPoly(rg->getSubmap(i), polygon); 00456 gistPolyVector.push_back(meanPoly); 00457 count += 1; 00458 } 00459 // blue / yellow opponency 00460 for(uint i=0; i<by->numSubmaps(); i++) 00461 { 00462 float meanPoly = getMeanPoly(by->getSubmap(i), polygon); 00463 gistPolyVector.push_back(meanPoly); 00464 count += 1; 00465 } 00466 //intensity 00467 for(uint i=0; i<intensityMaps->numSubmaps(); i++) 00468 { 00469 float meanPoly = getMeanPoly(intensityMaps->getSubmap(i), polygon); 00470 gistPolyVector.push_back(meanPoly); 00471 count += 1; 00472 } 00473 00474 return gistPolyVector; 00475 } 00476 00477 // ###################################################################### 00478 void RawGistEstimatorStd::computeFeatureVector(rutz::shared_ptr<ChannelMaps> chanMaps) 00479 { 00480 rutz::shared_ptr<ChannelMaps> orientationMaps; 00481 rutz::shared_ptr<ChannelMaps> colorMaps; 00482 rutz::shared_ptr<ChannelMaps> intensityMaps; 00483 00484 for(uint i=0; i < chanMaps->numSubchans(); i++) 00485 { 00486 //Grab the current channel 00487 rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i); 00488 00489 //Determine the name of the channel 00490 std::vector<std::string> chanNameVec; 00491 split(currChan->getMap().name(), ":", std::back_inserter(chanNameVec)); 00492 std::string chanName = chanNameVec[1]; 00493 00494 //Assign the channel maps based on their name 00495 if(chanName == "orientation") 00496 orientationMaps = currChan; 00497 else if(chanName == "color") 00498 colorMaps = currChan; 00499 else if(chanName == "intensity") 00500 intensityMaps = currChan; 00501 } 00502 00503 LDEBUG("Orientation Subchans: %d", orientationMaps->numSubchans()); 00504 LDEBUG("Color Subchans: %d", colorMaps->numSubchans()); 00505 LDEBUG("Intensity Subchans: %d", intensityMaps->numSubchans()); 00506 00507 LINFO("Orientation Subchans: %d", orientationMaps->numSubchans()); 00508 LINFO("Color Subchans: %d", colorMaps->numSubchans()); 00509 LINFO("Intensity Subchans: %d", intensityMaps->numSubchans()); 00510 00511 //For now, we are expecting the default number of features in the channel maps, as per Siagian_Itti07pami. 00512 //TODO:This should be generalized later when things are more stable 00513 ASSERT(orientationMaps->numSubchans() == 4); 00514 ASSERT(colorMaps->numSubchans() == 2); 00515 ASSERT(intensityMaps->numSubchans() == 0); 00516 00517 //Grab the individual orientation channels 00518 rutz::shared_ptr<ChannelMaps> orientation_0 = orientationMaps->subChanMaps(0); 00519 rutz::shared_ptr<ChannelMaps> orientation_45 = orientationMaps->subChanMaps(1); 00520 rutz::shared_ptr<ChannelMaps> orientation_90 = orientationMaps->subChanMaps(2); 00521 rutz::shared_ptr<ChannelMaps> orientation_135 = orientationMaps->subChanMaps(3); 00522 00523 //Grab the different color channels 00524 rutz::shared_ptr<ChannelMaps> rg; 00525 rutz::shared_ptr<ChannelMaps> by; 00526 for(uint i=0; i<colorMaps->numSubchans(); i++) 00527 { 00528 std::vector<std::string> chanNameVec; 00529 split(colorMaps->subChanMaps(i)->getMap().name(), ":", std::back_inserter(chanNameVec)); 00530 std::string chanName = chanNameVec[2]; 00531 00532 if(chanName == "rg") 00533 rg = colorMaps->subChanMaps(i); 00534 else if(chanName == "by") 00535 by = colorMaps->subChanMaps(i); 00536 } 00537 00538 ASSERT(rg.is_valid()); 00539 ASSERT(by.is_valid()); 00540 00541 //Start calculating the individual subsums on the channels, and pasting them into the gist vector 00542 // orientation channel 0 degree 00543 int count = 0; 00544 for(int i = 0; i < NUM_GIST_LEV; i++) 00545 { 00546 Image<float> subSum = getSubSum(orientation_0->getSubmap(i)); 00547 inplacePaste(itsGistVector, subSum, 00548 Point2D<int>(0, count)); 00549 count += subSum.getHeight(); 00550 } 00551 00552 // orientation channel 45 degree 00553 for(int i = 0; i < NUM_GIST_LEV; i++) 00554 { 00555 Image<float> subSum = getSubSum(orientation_45->getSubmap(i)); 00556 inplacePaste(itsGistVector, subSum, 00557 Point2D<int>(0, count)); 00558 count += subSum.getHeight(); 00559 } 00560 00561 // orientation channel 90 degree 00562 for(int i = 0; i < NUM_GIST_LEV; i++) 00563 { 00564 Image<float> subSum = getSubSum(orientation_90->getSubmap(i)); 00565 inplacePaste(itsGistVector, subSum, 00566 Point2D<int>(0, count)); 00567 count += subSum.getHeight(); 00568 } 00569 00570 // orientation channel 135 degree 00571 for(int i = 0; i < NUM_GIST_LEV; i++) 00572 { 00573 Image<float> subSum = getSubSum(orientation_135->getSubmap(i)); 00574 inplacePaste(itsGistVector, subSum, 00575 Point2D<int>(0, count)); 00576 count += subSum.getHeight(); 00577 } 00578 00579 //For the Red/Green and Blue/Yellow Channels, 00580 //Christian's model uses levels: (2,5), (2,6), (3,6), (3,7), (4,7), (4,8) 00581 //However, this method will use: (2,5), (3,6), (4,7), (2,6), (3,7), (4,8) 00582 //Same channels, just a different order... does this matter? 00583 00584 // red / green opponency 00585 for(uint i=0; i<rg->numSubmaps(); i++) 00586 { 00587 Image<float> subSum = getSubSum(rg->getSubmap(i)); 00588 inplacePaste(itsGistVector, subSum, 00589 Point2D<int>(0, count)); 00590 count += subSum.getHeight(); 00591 } 00592 00593 // blue / yellow opponency 00594 for(uint i=0; i<by->numSubmaps(); i++) 00595 { 00596 Image<float> subSum = getSubSum(by->getSubmap(i)); 00597 inplacePaste(itsGistVector, subSum, 00598 Point2D<int>(0, count)); 00599 count += subSum.getHeight(); 00600 } 00601 00602 00603 //intensity 00604 for(uint i=0; i<intensityMaps->numSubmaps(); i++) 00605 { 00606 Image<float> subSum = getSubSum(intensityMaps->getSubmap(i)); 00607 inplacePaste(itsGistVector, subSum, 00608 Point2D<int>(0, count)); 00609 count += subSum.getHeight(); 00610 } 00611 } 00612 00613 // ###################################################################### 00614 // get gist histogram to visualize the data 00615 Image<float> RawGistEstimatorStd::getGistImage(int sqSize, 00616 float minO, float maxO, 00617 float minC, float maxC, 00618 float minI, float maxI) 00619 { 00620 // square size 00621 int s = sqSize; 00622 Image<float> img(NUM_GIST_COL * s, NUM_GIST_FEAT * s, ZEROS); 00623 float range; 00624 00625 // setup range for orientation channel if necessary 00626 if(maxO == minO) 00627 { 00628 minO = itsGistVector.getVal(0); 00629 maxO = itsGistVector.getVal(0); 00630 for(int i = 0; i < 16; i++) 00631 for(int j = 0; j < NUM_GIST_FEAT; j++) 00632 { 00633 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j); 00634 if(val < minO) 00635 minO = val; 00636 else if(val > maxO) 00637 maxO = val; 00638 } 00639 LDEBUG("Orientation Channel Min: %f, max: %f", minO, maxO); 00640 } 00641 range = maxO - minO; 00642 00643 // orientation channel 00644 for(int a = 0; a < 4; a++) 00645 for(int b = 0; b < 4; b++) 00646 for(int j = 0; j < NUM_GIST_FEAT; j++) 00647 { 00648 int i = b*4 + a; 00649 int ii = a*4 + b; 00650 float val = itsGistVector.getVal(ii*NUM_GIST_FEAT+j); 00651 drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minO)/range); 00652 } 00653 00654 // setup range for color channel if necessary 00655 if(maxC == minC) 00656 { 00657 minC = itsGistVector.getVal(16*NUM_GIST_FEAT); 00658 maxC = itsGistVector.getVal(16*NUM_GIST_FEAT); 00659 for(int i = 16; i < 28; i++) 00660 for(int j = 0; j < NUM_GIST_FEAT; j++) 00661 { 00662 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j); 00663 if(val < minC) 00664 minC = val; 00665 else if(val > maxC) 00666 maxC = val; 00667 } 00668 LDEBUG("Color Channel Min: %f, max: %f", minC, maxC); 00669 } 00670 range = maxC - minC; 00671 00672 // color channel 00673 for(int i = 16; i < 28; i++) 00674 for(int j = 0; j < NUM_GIST_FEAT; j++) 00675 { 00676 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j); 00677 drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minC)/range); 00678 } 00679 00680 // setup range for intensity channel if necessary 00681 if(maxI == minI) 00682 { 00683 minI = itsGistVector.getVal(28*NUM_GIST_FEAT); 00684 maxI = itsGistVector.getVal(28*NUM_GIST_FEAT); 00685 for(int i = 28; i < 34; i++) 00686 for(int j = 0; j < NUM_GIST_FEAT; j++) 00687 { 00688 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j); 00689 if(val < minI) 00690 minI = val; 00691 else if(val > maxI) 00692 maxI = val; 00693 } 00694 LDEBUG("Intensity Channel Min: %f, max: %f", minI, maxI); 00695 } 00696 range = maxI - minI; 00697 00698 // intensity channel 00699 for(int i = 28; i < NUM_GIST_COL; i++) 00700 for(int j = 0; j < NUM_GIST_FEAT; j++) 00701 { 00702 float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j); 00703 drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minI)/range); 00704 } 00705 00706 // draw the delineation 00707 // spatially 00708 float max = 1.0f; 00709 drawLine(img, Point2D<int>(0, 1*s), Point2D<int>(NUM_GIST_COL*s, 1*s), max, 1); 00710 drawLine(img, Point2D<int>(0, 5*s), Point2D<int>(NUM_GIST_COL*s, 5*s), max, 1); 00711 drawLine(img, Point2D<int>(0, 9*s), Point2D<int>(NUM_GIST_COL*s, 9*s), max/2, 1); 00712 drawLine(img, Point2D<int>(0, 13*s), Point2D<int>(NUM_GIST_COL*s, 13*s), max/2, 1); 00713 drawLine(img, Point2D<int>(0, 17*s), Point2D<int>(NUM_GIST_COL*s, 17*s), max/2, 1); 00714 00715 // channelwise 00716 drawLine(img, Point2D<int>( 4*s, 0), Point2D<int>( 4*s, NUM_GIST_FEAT*s), max, 1); 00717 drawLine(img, Point2D<int>( 8*s, 0), Point2D<int>( 8*s, NUM_GIST_FEAT*s), max, 1); 00718 drawLine(img, Point2D<int>(12*s, 0), Point2D<int>(12*s, NUM_GIST_FEAT*s), max, 1); 00719 drawLine(img, Point2D<int>(16*s, 0), Point2D<int>(16*s, NUM_GIST_FEAT*s), max, 1); 00720 drawLine(img, Point2D<int>(22*s, 0), Point2D<int>(22*s, NUM_GIST_FEAT*s), max, 1); 00721 drawLine(img, Point2D<int>(28*s, 0), Point2D<int>(28*s, NUM_GIST_FEAT*s), max, 1); 00722 00723 return img; 00724 } 00725 00726 // ###################################################################### 00727 // get gist difference: Jeffrey Divergence 00728 Image<double> RawGistEstimatorStd::diffGist(Image<double> in) 00729 { 00730 LFATAL("fix"); 00731 double total = 0.0; 00732 double a,b,c,d; 00733 00734 for(int i = 0; i < NUM_GIST_COL; i++) 00735 { 00736 for(int j = 0; j < NUM_GIST_FEAT; j++) 00737 { 00738 a = itsGistVector.getVal(i*NUM_GIST_FEAT +j) / 00739 itsGistVector.getVal(i*NUM_GIST_FEAT); 00740 b = in.getVal(i*NUM_GIST_FEAT +j) / in.getVal(i*NUM_GIST_FEAT); 00741 c = itsGistVector.getVal(i*NUM_GIST_FEAT) + 00742 in.getVal(i*NUM_GIST_FEAT); 00743 d = (a - b) * c/2; 00744 LINFO("%6.3f - %6.3f = %f",a,b,fabs(d)); 00745 00746 if((j-5)%4 == 3) LINFO("-:-:-"); 00747 total += sqrt((d*d)); 00748 } 00749 LINFO(" "); 00750 } 00751 LINFO("Diff = %f -> %f\n",total,total/NUM_GIST_COL/NUM_GIST_FEAT); 00752 Raster::waitForKey(); 00753 00754 return Image<double>(); 00755 } 00756 00757 // ###################################################################### 00758 /* So things look consistent in everyone's emacs... */ 00759 /* Local Variables: */ 00760 /* indent-tabs-mode: nil */ 00761 /* End: */