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