00001 /*!@file AppPsycho/test-parseScanpath.C Parses the eye scanpath and recognizes 00002 each fixation */ 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: Vidhya Navalpakkam <navalpak@usc.edu> 00039 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/test-parseScanpath.C $ 00040 // $Id: test-parseScanpath.C 9412 2008-03-10 23:10:15Z farhan $ 00041 // 00042 00043 #include "Image/Image.H" 00044 #include "Image/DrawOps.H" 00045 #include "Component/ModelManager.H" 00046 #include "Image/Pixels.H" 00047 #include "Image/Point2D.H" 00048 #include "Raster/Raster.H" 00049 #include "Util/log.H" 00050 00051 #include <cstdlib> 00052 #include <ctime> 00053 #include <fstream> 00054 #include <string> 00055 #include <unistd.h> 00056 #include <vector> 00057 00058 int main(const int argc, const char **argv) 00059 { 00060 MYLOGVERB = LOG_INFO; // suppress debug messages 00061 00062 // Instantiate a ModelManager: 00063 ModelManager manager("parse scanpath"); 00064 00065 // Parse command-line: 00066 if (manager.parseCommandLine(argc, argv, 00067 "<input.ppm> <rows> <columns> <coordsFile>" 00068 " <fixnsFile> <reco> <traj.ppm>" 00069 " <saccadeEndPoints>" 00070 " <target> <less> <same> <more>" 00071 " <'d' for draw / 'r' for recognize /" 00072 " 'g' for generate stimuli>", 00073 1, -1) == false) 00074 return(1); 00075 00076 // let's get all our ModelComponent instances started: 00077 manager.start(); 00078 00079 // ------------------ READ INPUT -------------------------- 00080 // get the arguments 00081 int rows = manager.getExtraArgAs<int>(1); 00082 int cols = manager.getExtraArgAs<int>(2); 00083 const char* coords = manager.getExtraArg (3).c_str(); 00084 const char* fixns = manager.getExtraArg (4).c_str(); 00085 const char* reco = manager.getExtraArg (5).c_str(); 00086 const char* output = manager.getExtraArg (6).c_str(); 00087 const char* saccTargets = manager.getExtraArg (7).c_str(); 00088 const char* targetName = manager.getExtraArg (8).c_str(); 00089 const char* lessName = manager.getExtraArg (9).c_str(); 00090 const char* sameName = manager.getExtraArg (10).c_str(); 00091 const char* moreName = manager.getExtraArg (11).c_str(); 00092 const char* option = manager.getExtraArg (12).c_str(); 00093 00094 // ------------------ INITIALIZE PARAMS ------------------------- 00095 if (option[0] == 'd') 00096 { 00097 Image<PixRGB< byte> > traj = 00098 Raster::ReadRGB(manager.getExtraArg (0)); 00099 // draw the scanpath 00100 LINFO (" image grid: %d x %d", cols, rows); 00101 int w = traj.getWidth(); 00102 int h = traj.getHeight(); 00103 // box size in the grid 00104 int bw = w / cols; 00105 int bh = h / rows; 00106 // draw the grid 00107 // draw the horizontal lines 00108 for (int i = 1; i < rows; i++) 00109 { 00110 Point2D<int> start (0, i * bh), end (w, i * bh); 00111 drawLine (traj, start, end, PixRGB<byte>(128, 128, 128), 1); 00112 } 00113 // draw the vertical lines 00114 for (int i = 1; i < cols; i++) 00115 { 00116 Point2D<int> start (i * bw, 0), end (i * bw, h); 00117 drawLine (traj, start, end, PixRGB<byte>(128, 128, 128), 1); 00118 } 00119 00120 // draw the scanpath 00121 std::ifstream fil (coords); 00122 if (fil == 0) LFATAL ("Couldn't open the coords file: %s", coords); 00123 // read all the coords 00124 std::string line; 00125 std::vector< std::string > xy; 00126 while (getline (fil, line)) 00127 { 00128 int x_idx = line.find (" "); 00129 std::string x = line.substr (0, x_idx); 00130 line = line.substr (x_idx + 1); 00131 int y_idx = line.find (" "); 00132 std::string y = line.substr (0, y_idx - 1); 00133 xy.push_back (x); 00134 xy.push_back (y); 00135 } 00136 00137 // set some loop params 00138 Point2D<int> prev_fixn (-1, -1); 00139 for (uint i = 0; i < xy.size(); i = i + 2) 00140 { 00141 Point2D<int> fixn (atoi (xy[i].c_str()), atoi (xy[i+1].c_str())); 00142 drawCircle(traj, fixn, 2, PixRGB<byte>(255, 0, 0) , 2); 00143 if (i != 0) 00144 drawLine(traj, prev_fixn, fixn, PixRGB<byte>(255, 255, 0), 1); 00145 prev_fixn = fixn; 00146 } 00147 00148 // draw fixations 00149 std::ifstream fix (fixns); 00150 if (fix == 0) LFATAL ("Couldn't open the fixations file: %s", fixns); 00151 xy.clear(); 00152 while (getline (fix, line)) 00153 { 00154 int x_idx = line.find (" "); 00155 std::string x = line.substr (0, x_idx); 00156 line = line.substr (x_idx + 1); 00157 int y_idx = line.find (" "); 00158 std::string y = line.substr (0, y_idx - 1); 00159 xy.push_back (x); 00160 xy.push_back (y); 00161 } 00162 // draw saccade targets 00163 std::ifstream sac (saccTargets); 00164 if (sac == 0) LFATAL ("Couldn't open the saccade targets file: %s", 00165 saccTargets); 00166 xy.clear(); 00167 while (getline (sac, line)) 00168 { 00169 int x_idx = line.find (" "); 00170 std::string x = line.substr (0, x_idx); 00171 line = line.substr (x_idx + 1); 00172 int y_idx = line.find (" "); 00173 std::string y = line.substr (0, y_idx - 1); 00174 xy.push_back (x); 00175 xy.push_back (y); 00176 } 00177 for (uint i = 0; i < xy.size(); i = i + 2) 00178 { 00179 Point2D<int> sacEndPt (atoi (xy[i].c_str()), atoi (xy[i+1].c_str())); 00180 drawCircle(traj, sacEndPt, 2, PixRGB<byte>(0, 255, 0) , 4); 00181 } 00182 Raster::WriteRGB (traj, output, RASFMT_PNM); 00183 } 00184 //***************** GENERATE STIMULI AND DRAW SCANPATHS ******************* 00185 if (option[0] == 'g') 00186 { 00187 Image<PixRGB< byte> > traj = 00188 Raster::ReadRGB(manager.getExtraArg (0)); 00189 // draw the scanpath 00190 LINFO (" image grid: %d x %d", cols, rows); 00191 int w = traj.getWidth(); 00192 int h = traj.getHeight(); 00193 // box size in the grid 00194 int bw = w / cols; 00195 int bh = h / rows; 00196 // draw the grid 00197 // draw the horizontal lines 00198 for (int i = 1; i < rows; i++) 00199 { 00200 Point2D<int> start (0, i * bh), end (w, i * bh); 00201 drawLine (traj, start, end, PixRGB<byte>(128, 128, 128), 1); 00202 } 00203 // draw the vertical lines 00204 for (int i = 1; i < cols; i++) 00205 { 00206 Point2D<int> start (i * bw, 0), end (i * bw, h); 00207 drawLine (traj, start, end, PixRGB<byte>(128, 128, 128), 1); 00208 } 00209 // mark each cell in the grid with less/mid/high 00210 std::ifstream rec (reco); 00211 if (rec == 0) LFATAL ("Couldn't open the reco file: %s", reco); 00212 std::string line; 00213 while (getline (rec, line)) 00214 { 00215 char msg[2]; 00216 int idx = line.find_last_of (" "); 00217 std::string itemName = line.substr (idx + 1); 00218 line = line.substr (0, idx); 00219 idx = line.find_last_of (" "); 00220 int y = atoi (line.substr (idx + 1).c_str()); 00221 line = line.substr (0, idx); 00222 idx = line.find_last_of (" "); 00223 int x = atoi (line.substr (idx + 1).c_str()); 00224 if (itemName.find(targetName,0) != std::string::npos) 00225 sprintf (msg, "T"); 00226 if (itemName.find(lessName,0) != std::string::npos) 00227 sprintf (msg, "L"); 00228 if (itemName.find(sameName,0) != std::string::npos) 00229 sprintf (msg, "M"); 00230 if (itemName.find(moreName,0) != std::string::npos) 00231 sprintf (msg, "H"); 00232 writeText (traj, Point2D<int>(x,y), msg,PixRGB<byte>(255),PixRGB<byte>(0)); 00233 } 00234 // draw the scanpath 00235 std::ifstream fil (coords); 00236 if (fil == 0) LFATAL ("Couldn't open the coords file: %s", coords); 00237 // read all the coords 00238 std::vector< std::string > xy; 00239 while (getline (fil, line)) 00240 { 00241 int x_idx = line.find (" "); 00242 std::string x = line.substr (0, x_idx); 00243 line = line.substr (x_idx + 1); 00244 int y_idx = line.find (" "); 00245 std::string y = line.substr (0, y_idx - 1); 00246 xy.push_back (x); 00247 xy.push_back (y); 00248 } 00249 00250 // set some loop params 00251 Point2D<int> prev_fixn (-1, -1); 00252 for (uint i = 0; i < xy.size(); i = i + 2) 00253 { 00254 Point2D<int> fixn (atoi (xy[i].c_str()), atoi (xy[i+1].c_str())); 00255 drawCircle(traj, fixn, 2, PixRGB<byte>(255, 0, 0) , 2); 00256 if (i != 0) 00257 drawLine(traj, prev_fixn, fixn, PixRGB<byte>(255, 255, 0), 1); 00258 prev_fixn = fixn; 00259 } 00260 00261 // draw fixations 00262 std::ifstream fix (fixns); 00263 if (fix == 0) LFATAL ("Couldn't open the fixations file: %s", fixns); 00264 xy.clear(); 00265 while (getline (fix, line)) 00266 { 00267 int x_idx = line.find (" "); 00268 std::string x = line.substr (0, x_idx); 00269 line = line.substr (x_idx + 1); 00270 int y_idx = line.find (" "); 00271 std::string y = line.substr (0, y_idx - 1); 00272 xy.push_back (x); 00273 xy.push_back (y); 00274 } 00275 /* 00276 for (uint i = 0; i < xy.size(); i = i + 2) 00277 { 00278 Point2D<int> fixn (atoi (xy[i].c_str()), atoi (xy[i+1].c_str())); 00279 drawCircle(traj, fixn, 2, PixRGB<byte>(0, 0, 255) , 4); 00280 } 00281 */ 00282 // draw saccade targets 00283 std::ifstream sac (saccTargets); 00284 if (sac == 0) LFATAL ("Couldn't open the saccade targets file: %s", 00285 saccTargets); 00286 xy.clear(); 00287 while (getline (sac, line)) 00288 { 00289 int x_idx = line.find (" "); 00290 std::string x = line.substr (0, x_idx); 00291 line = line.substr (x_idx + 1); 00292 int y_idx = line.find (" "); 00293 std::string y = line.substr (0, y_idx - 1); 00294 xy.push_back (x); 00295 xy.push_back (y); 00296 } 00297 for (uint i = 0; i < xy.size(); i = i + 2) 00298 { 00299 Point2D<int> sacEndPt (atoi (xy[i].c_str()), atoi (xy[i+1].c_str())); 00300 drawCircle(traj, sacEndPt, 2, PixRGB<byte>(0, 255, 0) , 4); 00301 } 00302 Raster::WriteRGB (traj, output, RASFMT_PNM); 00303 } 00304 00305 //***************** RECOGNIZE SACCADIC ENDPOINTS ********************* 00306 else if (option[0] == 'r') 00307 { 00308 // recognize the fixations 00309 std::ifstream rec (reco); 00310 if (rec == 0) LFATAL ("Couldn't open the reco file: %s", reco); 00311 /* 6 distractors: s2, s3, m2, m3, n2, n3 00312 4 item sper distractor 00313 x, y per item 00314 */ 00315 int d[3][8][2], t[2]; 00316 t[0] = 0; t[1] = 0; // avoid compiler warning 00317 //initialize the distances 00318 for (int i = 0; i < 3; i++) 00319 for (int j = 0; j < 8; j++){ 00320 d[i][j][0] = 1024;d[i][j][1]=1024; 00321 } 00322 std::string line; 00323 int num[3]; 00324 for (int i = 0; i < 3; i ++) 00325 num[i] = 0; // initialize 00326 00327 while (getline (rec, line)) 00328 { 00329 int idx = line.find_last_of (" "); 00330 std::string itemName = line.substr (idx + 1); 00331 line = line.substr (0, idx); 00332 idx = line.find_last_of (" "); 00333 int y = atoi (line.substr (idx + 1).c_str()); 00334 line = line.substr (0, idx); 00335 idx = line.find_last_of (" "); 00336 int x = atoi (line.substr (idx + 1).c_str()); 00337 //LINFO ("item %s at (%d, %d)", itemName.c_str(), x, y); 00338 if (itemName.find(targetName,0) != std::string::npos) 00339 { 00340 t[0] = x; 00341 t[1] = y; 00342 } 00343 if (itemName.find(lessName,0) != std::string::npos) 00344 { 00345 d[0][num[0]][0] = x; 00346 d[0][num[0]][1] = y; 00347 num[0] += 1; 00348 } 00349 if (itemName.find(sameName,0) != std::string::npos) 00350 { 00351 d[1][num[1]][0] = x; 00352 d[1][num[1]][1] = y; 00353 num[1] += 1; 00354 } 00355 if (itemName.find(moreName,0) != std::string::npos) 00356 { 00357 d[2][num[2]][0] = x; 00358 d[2][num[2]][1] = y; 00359 num[2] += 1; 00360 } 00361 } 00362 int score[4], count[4]; float nearest[4]; 00363 // 3 types of dtarctors, 1 target 00364 for (int i = 0; i < 4; i ++){ 00365 score[i] = 0; count[i] = 0; nearest[i] = 1024.0f; 00366 } 00367 std::ifstream sac (saccTargets); 00368 if (sac == 0) LFATAL ("Couldn't open the saccade targets file: %s", 00369 saccTargets); 00370 // read all the saccade targets 00371 int numFix = 1; 00372 // distance to the nearest category 00373 float minD = 1024.0f; 00374 00375 while (getline (sac, line)) 00376 { 00377 // recognize the current fixn 00378 // score: 1 for the nearest item, 0 for others 00379 int idx = line.find_last_of (" "); 00380 int y = atoi (line.substr (idx + 1).c_str()); 00381 int x = atoi (line.substr (0, idx).c_str()); 00382 // find distance btw fixn and distractors 00383 for (int i = 0; i < 3; i ++) 00384 for (int j = 0; j < 8; j ++) 00385 { 00386 float dist = sqrt ((d[i][j][0] - x)*(d[i][j][0] - x) + 00387 (d[i][j][1] - y)*(d[i][j][1] - y)); 00388 if (dist < nearest[i]) 00389 nearest[i] = dist; 00390 } 00391 // distance btw target and fixn 00392 nearest[3] = sqrt ((t[0] - x)*(t[0] - x) + (t[1] - y)*(t[1] - y)); 00393 00394 // find the nearest category 00395 for (int i = 0; i < 4; i ++) 00396 if (nearest[i] < minD) 00397 minD = nearest[i]; 00398 00399 // check if there are multiple nearest items 00400 for (int i = 0; i < 4; i ++){ 00401 if (nearest[i] == minD) count[i] ++; 00402 // assign the fixation to the nearest category 00403 score[i] += count[i]; 00404 } 00405 // display the results of the current fixn. 00406 //LINFO ("fix%d: %f %f %f %f", numFix, nearest[0], 00407 // nearest[1], nearest[2],nearest[3]); 00408 LINFO ("fix%d: %d %d %d %d", numFix, count[0], 00409 count[1], count[2], count[3]); 00410 00411 numFix ++; 00412 // reset count values 00413 for (int i = 0; i < 4; i ++){ 00414 count[i] = 0; nearest[i] = 1024.0f; 00415 } 00416 // reset distance to the nearest category 00417 minD = 1024.0f; 00418 } 00419 // display cumulative results 00420 LINFO ("total: %d %d %d %d", score[0], score[1], 00421 score[2], score[3]); 00422 00423 } 00424 manager.stop(); 00425 manager.saveConfig(); 00426 00427 } 00428 00429 // ###################################################################### 00430 /* So things look consistent in everyone's emacs... */ 00431 /* Local Variables: */ 00432 /* indent-tabs-mode: nil */ 00433 /* End: */