00001 /*!@file AppPsycho/searcharray2d_lumin.C Creates a randomized search array from 00002 image patches of a single target and many distractors occuring in 00003 randomized luminance*/ 00004 00005 // //////////////////////////////////////////////////////////////////// 00006 // // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 00007 // 2000-2002 // by the University of Southern California (USC) 00008 // and the iLab at USC. // See http://iLab.usc.edu for 00009 // information about this project. // 00010 // //////////////////////////////////////////////////////////////////// 00011 // // Major portions of the iLab Neuromorphic Vision Toolkit 00012 // are protected // under the U.S. patent ``Computation of 00013 // Intrinsic Perceptual Saliency // in Visual Environments, 00014 // and Applications'' by Christof Koch and // Laurent Itti, 00015 // California Institute of Technology, 2001 (patent // 00016 // pending; application number 09/912,225 filed July 23, 2001; 00017 // see // http://pair.uspto.gov/cgi-bin/final/home.pl for 00018 // current status). // 00019 // //////////////////////////////////////////////////////////////////// 00020 // // This file is part of the iLab Neuromorphic Vision C++ 00021 // Toolkit. // // The iLab Neuromorphic Vision C++ Toolkit is 00022 // free software; you can // redistribute it and/or modify it 00023 // under the terms of the GNU General // Public License as 00024 // published by the Free Software Foundation; either // 00025 // version 2 of the License, or (at your option) any later 00026 // version. // // The iLab Neuromorphic Vision C++ Toolkit is 00027 // distributed in the hope // that it will be useful, but 00028 // WITHOUT ANY WARRANTY; without even the // implied warranty 00029 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 00030 // See the GNU General Public License for more details. // // 00031 // You should have received a copy of the GNU General Public 00032 // License // along with the iLab Neuromorphic Vision C++ 00033 // Toolkit; if not, write // to the Free Software Foundation, 00034 // Inc., 59 Temple Place, Suite 330, // Boston, MA 02111-1307 00035 // USA. // 00036 // //////////////////////////////////////////////////////////////////// 00037 // // 00038 // 00039 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00040 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/searcharray2d_lumin.C $ 00041 // $Id: searcharray2d_lumin.C 12074 2009-11-24 07:51:51Z itti $ 00042 // 00043 00044 #include "Image/Image.H" 00045 #include "Image/Pixels.H" 00046 #include "Component/ModelManager.H" 00047 #include "Raster/Raster.H" 00048 #include "Util/Assert.H" 00049 #include "Util/MathFunctions.H" 00050 #include "Util/StringConversions.H" 00051 #include "Util/log.H" 00052 00053 #include <cstdio> 00054 #include <vector> 00055 00056 void image_patch(const Image< PixRGB<byte> >& patch, const int ti, 00057 const int tj, Image< PixRGB<byte> >& image, 00058 const double alpha, const float FACTOR, 00059 Image<byte>& targets, 00060 bool do_target, Image< PixRGB<byte> >& randomGrid, 00061 const Image< PixRGB<byte> >& randomNum, 00062 int& center_x, int& center_y); 00063 00064 00065 /*! This program generates a randomized search array (and associated 00066 target mask) from several image patches (1 for target and the rest 00067 for distractors). */ 00068 00069 int main(const int argc, const char **argv) 00070 { 00071 MYLOGVERB = LOG_INFO; // suppress debug messages 00072 00073 // Instantiate a ModelManager: 00074 ModelManager manager("search array"); 00075 00076 // Parse command-line: 00077 if (manager.parseCommandLine(argc, argv, 00078 "<target> <w> <alpha> <noise> <space>" 00079 " <output>" 00080 "<reco> <noCheat> <checkResponse> <pathNumbers>" 00081 "<distractor_1> ... <distractor_3>" 00082 "<lumin_1> ... <lumin_k>", 00083 1, -1)==false) 00084 return(1); 00085 00086 // let's get all our ModelComponent instances started: 00087 manager.start(); 00088 00089 // ------------------ READ INPUT -------------------------- 00090 // get the arguments 00091 const char* targetName = manager.getExtraArg (0).c_str(); 00092 int w = manager.getExtraArgAs<int>(1); 00093 float alpha = manager.getExtraArgAs<float>(2); 00094 float noise = manager.getExtraArgAs<float>(3); 00095 float FACTOR = manager.getExtraArgAs<float>(4); 00096 const char* output = manager.getExtraArg (5).c_str(); 00097 const char* reco = manager.getExtraArg (6).c_str(); 00098 const char* noCheat = manager.getExtraArg (7).c_str(); 00099 const char* checkResponse = manager.getExtraArg (8).c_str(); 00100 std::string pathNumbers = manager.getExtraArg (9); 00101 // number of luminance values 00102 uint numL = manager.numExtraArgs() - 13; 00103 // total number of distractors 00104 Image<PixRGB<byte> >* distractor[3][numL], *target[numL]; 00105 // read the distractor patches 00106 for (uint j = 0; j < 3; j++) 00107 { 00108 const char* distrName = manager.getExtraArg (10 + j).c_str(); 00109 for (uint i = 0; i < numL; i++) 00110 { 00111 char itemName[30]; 00112 sprintf(itemName, "%s_%s.ppm", distrName, 00113 manager.getExtraArg (13 + i).c_str()); 00114 distractor[j][i] = new Image<PixRGB<byte> > 00115 (Raster::ReadRGB(itemName)); 00116 } 00117 } 00118 // read target patches 00119 for (uint i = 0; i < numL; i++) 00120 { 00121 char itemName[30]; 00122 sprintf(itemName, "%s_%s.ppm", targetName, 00123 manager.getExtraArg (13 + i).c_str()); 00124 target[i] = new Image<PixRGB<byte> > 00125 (Raster::ReadRGB(itemName)); 00126 } 00127 int pw = target[0]->getWidth(), ph = target[0]->getHeight(); 00128 00129 // ------------------ INITIALIZE PARAMS ------------------------- 00130 for (uint j = 0; j < 3; j++) 00131 for (uint i = 0; i < numL; i++) 00132 { 00133 //all distractors equal size 00134 ASSERT(pw == distractor[j][i]->getWidth() && 00135 ph == distractor[j][i]->getHeight()); 00136 } 00137 00138 initRandomNumbers(); 00139 00140 // initialize results: 00141 Image<PixRGB<byte> > image(w, w, ZEROS); 00142 Image<PixRGB<byte> > randomGrid(w, w, ZEROS); 00143 Image<byte> targets(w, w, ZEROS); 00144 00145 int cols = int(w / (FACTOR * pw)), 00146 rows = int(w / (FACTOR * ph)), 00147 numBox = cols * rows; 00148 int numPerD = int((numBox - 1) / 3); 00149 int remainder = (numBox - 1) % 3; 00150 LINFO (" image grid: %d x %d, number per distractor type = %d, " 00151 " remainder = %d", 00152 cols, rows, numPerD, remainder); 00153 00154 // read the 2 digit randomNumber patches: to avoid any head 00155 // movements while entering the digits, we restrict each digit to 00156 // 1..5, hence a max of 25 numbers 00157 int numR, numRows, numCols; 00158 if (numBox > 25) 00159 { 00160 numRows = 5; 00161 numCols = 5; 00162 numR = 25; 00163 } 00164 else 00165 { 00166 numRows = rows; 00167 numCols = cols; 00168 numR = numBox; 00169 } 00170 Image<PixRGB<byte> >* numbers[numR]; 00171 std::vector <std::string> names; 00172 00173 for (int i = 1; i <= numRows; i ++) 00174 for (int j = 1; j <= numCols; j++) 00175 { 00176 int k = (i - 1) * numCols + j - 1; 00177 names.push_back (pathNumbers + "/" + toStr (i) + toStr (j) + 00178 ".ppm"); 00179 numbers[k] = new Image<PixRGB<byte> > 00180 (Raster::ReadRGB(names[k])); 00181 //all numbers equal size 00182 ASSERT(pw == numbers[k]->getWidth() && 00183 ph == numbers[k]->getHeight()); 00184 } 00185 00186 00187 // --------------- MAKE THE SEARCH ARRAY AND RANDOM GRID -------------- 00188 // keep a list of all locns in the grid where items can appear 00189 int locn[numBox][2]; 00190 // we will first create a dummy with values 1...numBox and then 00191 // randomize it and allocate items according to its randomized 00192 // contents 00193 int dummy[numBox]; 00194 00195 // list of indices that will be randomized for flashing numbers 00196 int random[numBox]; 00197 FILE* f = fopen (reco, "w"); 00198 FILE* check = fopen (checkResponse, "w"); 00199 uint idx = 0; 00200 for (int j = 0; j < cols; j++) 00201 for (int i = 0; i < rows; i++) 00202 { 00203 int k = i * cols + j; 00204 dummy[k] = k; // intialize with index 00205 // the above item is at locn. <i+1, j+1> in the grid 00206 locn[k][0] = i + 1; 00207 locn[k][1] = j + 1; 00208 00209 // random number to be flashed is btw 0..24 00210 if (idx == 25) 00211 idx = 0; 00212 random[k] = idx; // intialize now: randomize later 00213 idx ++; 00214 } 00215 00216 // shuffle the grid to randomize the locn of items 00217 randShuffle (dummy, numBox); 00218 00219 // also randomize the display of numbers in the grid 00220 randShuffle (random, numBox); 00221 00222 // allocate the target to the randomized contents of dummy 00223 idx = 0; // index for the box and random array 00224 int r = locn[dummy[idx]][0]; 00225 int c = locn[dummy[idx]][1]; 00226 int center_x = 0; 00227 int center_y = 0; 00228 // find a random luminance for the target 00229 int randomL = dummy[idx] % numL; 00230 LINFO("-- TARGET, lum %d AT (%d, %d)", randomL, r, c); 00231 image_patch (*target[randomL], c-1, r-1, image, alpha, FACTOR, targets, 1, 00232 randomGrid, *numbers[random[idx]], center_x, center_y); 00233 fprintf (f, "%d %d %d %d %s_%d.ppm\n", r, c, center_x, center_y, 00234 targetName, randomL); 00235 00236 // record the random number at the target locn to compare response 00237 int start = names[random[idx]].rfind ("/"); 00238 int end = names[random[idx]].rfind (".ppm"); 00239 fprintf (check, "%s", names[random[idx]]. 00240 substr (start+1, end-start-1).c_str()); 00241 fclose (check); 00242 idx++; 00243 00244 // allocate the items to the randomized contents of dummy 00245 for (uint disType = 0; disType < 3; disType ++) 00246 for (int count = 0; count < numPerD; count ++) 00247 { 00248 r = locn[dummy[idx]][0]; 00249 c = locn[dummy[idx]][1]; 00250 // find a random luminance for the target 00251 int randomL = dummy[idx] % numL; 00252 LINFO("-- distractor %d, lum %d AT (%d, %d)", disType + 1, randomL, 00253 r, c); 00254 image_patch (*distractor[disType][randomL], c-1, r-1, 00255 image, alpha, FACTOR, 00256 targets, 0, randomGrid, *numbers[random[idx]], 00257 center_x, center_y); 00258 fprintf (f, "%d %d %d %d %s_%d.ppm\n", r, c, center_x, center_y, 00259 manager.getExtraArg(10 + disType).c_str(), randomL); 00260 idx++; 00261 } 00262 // allocate the remaining items (if any) to the randomized boxes 00263 uint disType = 0; 00264 for (int count = 0; count < remainder; count ++, disType ++) 00265 { 00266 r = locn[dummy[idx]][0]; 00267 c = locn[dummy[idx]][1]; 00268 // find a random luminance for the target 00269 int randomL = dummy[idx] % numL; 00270 LINFO("-- distractor %d, lum %d AT (%d, %d)", disType + 1, randomL, 00271 r, c); 00272 image_patch (*distractor[disType][randomL], c-1, r-1, 00273 image, alpha, FACTOR, 00274 targets, 0, randomGrid, *numbers[random[idx]], 00275 center_x, center_y); 00276 fprintf (f, "%d %d %d %d %s_%d.ppm\n", r, c, center_x, center_y, 00277 manager.getExtraArg(10 + disType).c_str(), randomL); 00278 idx++; 00279 } 00280 00281 // ------------------- ADD NOISE ----------------------------------- 00282 /* add noise */ 00283 Image< PixRGB<byte> >::iterator iptr = image.beginw(), 00284 stop = image.endw(); 00285 while(iptr != stop) 00286 { 00287 if (randomDouble() <= noise) 00288 { 00289 if (randomDouble() >= 0.5) iptr->setRed(255); 00290 else iptr->setRed(0); 00291 if (randomDouble() >= 0.5) iptr->setGreen(255); 00292 else iptr->setGreen(0); 00293 if (randomDouble() >= 0.5) iptr->setBlue(255); 00294 else iptr->setBlue(0); 00295 } 00296 iptr ++; 00297 } 00298 00299 // ----------------------- WRITE OUTPUT ------------------------------- 00300 fclose (f); 00301 Raster::WriteRGB(image, output, RASFMT_PNM); 00302 Raster::WriteRGB(randomGrid, noCheat, RASFMT_PNM); 00303 Raster::WriteGray(targets, output, RASFMT_PNM); 00304 00305 // erase the memory used 00306 for (uint j = 0; j < 3; j++) 00307 for (uint i = 0; i < numL; i++) 00308 delete (distractor[j][i]); 00309 00310 for (int i = 0; i < numR; i++) 00311 delete (numbers[i]); 00312 manager.stop(); 00313 return 0; 00314 } 00315 00316 // ###################################################################### 00317 void image_patch(const Image< PixRGB<byte> >& patch, const int ti, 00318 const int tj, Image< PixRGB<byte> >& image, 00319 const double alpha, const float FACTOR, 00320 Image<byte>& targets, 00321 bool do_target, Image< PixRGB<byte> >& randomGrid, 00322 const Image< PixRGB<byte> >& randomNum, 00323 int& center_x, int& center_y) 00324 { 00325 int pw = patch.getWidth(), ph = patch.getHeight(); 00326 int w = image.getWidth(); 00327 00328 int jitx = int(randomDouble() * (FACTOR - 2.0) * pw); 00329 int jity = int(randomDouble() * (FACTOR - 2.0) * ph); 00330 00331 float jita = float(alpha * 3.14159 / 180.0 * (randomDouble() - 0.5) * 2.0); 00332 int offset = int(w - floor(w / (pw * FACTOR)) * (pw * FACTOR)) / 2; 00333 00334 PixRGB<byte> zero(0, 0, 0); 00335 int px = 0, py = 0; 00336 int minx = w, maxx = 0, miny = w, maxy = 0; 00337 00338 for (double y = int(tj * ph * FACTOR); y < int(tj * ph * FACTOR + ph); y ++) 00339 { 00340 for (double x = int(ti * pw * FACTOR); x < int(ti * pw * FACTOR + pw); 00341 x ++) 00342 { 00343 int x2 = int(x + jitx + offset); 00344 int y2 = int(y + jity + offset); 00345 00346 /* Shifting back and forth the center of rotation.*/ 00347 double px2 = px - pw / 2.0F; 00348 double py2 = py - ph / 2.0F; 00349 00350 float px3 = float(cos(jita) * px2 + sin(jita) * py2 + pw / 2.0F); 00351 float py3 = float(-sin(jita) * px2 + cos(jita) * py2 + pw / 2.0F); 00352 00353 if (px3 < 0 || px3 >= pw || py3 < 0 || py3 >= ph ) 00354 { 00355 image.setVal(x2, y2, zero); 00356 randomGrid.setVal(x2, y2, zero); 00357 } 00358 else 00359 { 00360 image.setVal(x2, y2, patch.getValInterp(px3, py3)); 00361 randomGrid.setVal(x2, y2, randomNum.getVal((int)px3, (int)py3)); 00362 if (do_target) 00363 { 00364 if (patch.getVal(int(px3), int(py3)) == zero) 00365 targets.setVal(x2, y2, 0); 00366 else 00367 targets.setVal(x2, y2, 255); 00368 } 00369 // find the extremities of this item 00370 minx = std::min (minx, x2); 00371 maxx = std::max (maxx, x2); 00372 miny = std::min (miny, y2); 00373 maxy = std::max (maxy, y2); 00374 } 00375 px ++; 00376 } 00377 py ++; 00378 px = 0; 00379 } 00380 // find the center of this item 00381 center_x = (minx + maxx) / 2; 00382 center_y = (miny + maxy) / 2; 00383 } 00384 00385 // ###################################################################### 00386 /* So things look consistent in everyone's emacs... */ 00387 /* Local Variables: */ 00388 /* indent-tabs-mode: nil */ 00389 /* End: */