00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "Psycho/EyeLinkAscParser.H"
00040 #include "Util/Timer.H"
00041 #include "Raster/Raster.H"
00042
00043 #include <cstdio>
00044 #include <math.h>
00045
00046 #define trialLength 15.0
00047 #define frameRate 30.0
00048
00049 #define D_WIDTH 1024.0
00050 #define D_HEIGHT 768.0
00051 #define IM_WIDTH 640
00052 #define IM_HEIGHT 480
00053
00054 #define CREATE_EYE_S false
00055
00056
00057 EyeLinkAscParser::EyeLinkAscParser(std::string fileName)
00058 {
00059 std::string::size_type dpos = fileName.find_last_of('.');
00060 std::string::size_type spos = fileName.find_last_of('/');
00061 if(spos != std::string::npos)
00062 itsSubjectName = fileName.substr(spos+1, dpos-spos-1);
00063 else
00064 itsSubjectName = fileName.substr(0, dpos);
00065
00066 LDEBUG("<<%s>> -> <<%s>>", fileName.c_str(), itsSubjectName.c_str());
00067
00068 parse(fileName);
00069 }
00070
00071
00072 EyeLinkAscParser::~EyeLinkAscParser()
00073 { }
00074
00075
00076 void EyeLinkAscParser::parse(std::string fileName)
00077 {
00078 FILE *fp; char inLine[200];
00079 FILE *eyesFile = 0;
00080 bool createEyeS = CREATE_EYE_S;
00081
00082 LINFO("Parsing: %s", fileName.c_str());
00083 if((fp = fopen(fileName.c_str(),"rb")) == NULL)
00084 { LINFO("not found"); return; }
00085
00086 int ldpos = fileName.find_last_of('.');
00087 std::string eyeSfile_prefix = fileName.substr(0, ldpos);
00088 LINFO("string: %s", eyeSfile_prefix.c_str());
00089
00090
00091
00092 std::string recordedEye;
00093 while(fgets(inLine, 200, fp) != NULL)
00094 {
00095
00096 std::vector<std::string> currLine = tokenize(inLine);
00097
00098 if(currLine.size() >= 4 && !currLine[0].compare("EVENTS"))
00099 {
00100 if(!currLine[2].compare("RIGHT"))
00101 recordedEye = std::string("RIGHT");
00102 else if (!currLine[2].compare("LEFT") &&
00103 !currLine[3].compare("RIGHT"))
00104 recordedEye = std::string("BOTH");
00105 else
00106 recordedEye = std::string("LEFT");
00107 break;
00108 }
00109 }
00110 fclose(fp);
00111
00112 LINFO("Recorded Eye: %s", recordedEye.c_str());
00113
00114
00115
00116 if((fp = fopen(fileName.c_str(),"rb")) == NULL)
00117 { LINFO("not found"); return; }
00118
00119 uint iTrial = 0;
00120 uint iTime = 0;
00121 uint fTime = 0;
00122 uint iSacc = 0;
00123
00124 uint iFix = 0;
00125 bool isDriftCorrecting = false;
00126 bool isBlinking = false;
00127 bool isSaccading = false;
00128
00129
00130 float targetx = 0.0F;
00131 float targety = 0.0F;
00132 float amp = 0.0F;
00133 float pvel = 0.0F;
00134 double timeOn = 0.0F;
00135 double timeOff = 0.0F;
00136 float interval = 0.0F;
00137 double startTime = 0.0F;
00138
00139
00140 while(fgets(inLine, 200, fp) != NULL)
00141 {
00142
00143 std::vector<std::string> currLine = tokenize(inLine);
00144
00145 if(currLine.size() == 0) continue;
00146
00147
00148 if(currLine.size() == 3 && !currLine[2].compare("!CAL"))
00149 continue;
00150
00151
00152
00153
00154 if(currLine.size() > 0 && !currLine[0].compare("MSG"))
00155 {
00156
00157
00158
00159
00160
00161
00162
00163 if(currLine.size() > 6 &&
00164 !currLine[4].compare("SESSION") && !currLine[5].compare("START"))
00165 {
00166 fTime = 0;
00167 iTime = 0;
00168 iSacc = 0;
00169
00170 iFix = 0;
00171 iTrial = iTrial + 1;
00172 itsTrialStart.push_back(atoi(currLine[1].c_str()));
00173
00174
00175 itsTrialEnd.push_back(-1);
00176
00177 itsFlipTime.push_back(std::vector<int>());
00178 itsFlipFixations.push_back
00179 (std::vector<std::vector<Point2D<float> > >());
00180 itsFlipFrame.push_back(std::vector<int>());
00181
00182 itsSaccadeStart.push_back(std::vector<int>());
00183 itsSaccadeEnd.push_back(std::vector<int>());
00184 itsSaccadeDuration.push_back(std::vector<int>());
00185 itsSaccadeStartLocation.push_back(std::vector<Point2D<float> >());
00186 itsSaccadeEndLocation.push_back(std::vector<Point2D<float> >());
00187 itsSaccadeAmplitude.push_back(std::vector<float>());
00188 itsSaccadePeakVel.push_back(std::vector<float>());
00189
00190 itsFixationStart.push_back(std::vector<int>());
00191 itsFixationEnd.push_back(std::vector<int>());
00192 itsFixationDuration.push_back(std::vector<int>());
00193 itsFixationAvgLocation.push_back(std::vector<Point2D<float> >());
00194 itsFixationAvgPupilSize.push_back(std::vector<float>());
00195
00196 itsGazeTime.push_back(std::vector<int>());
00197 itsLeftGaze.push_back(std::vector<Point2D<float> >());
00198 itsLeftGazePupilSize.push_back(std::vector<float>());
00199
00200 itsRightGaze.push_back(std::vector<Point2D<float> >());
00201 itsRightGazePupilSize.push_back(std::vector<float>());
00202
00203 if(iTrial != uint(atoi(currLine[6].c_str())))
00204 LINFO("Trial Mismatch!");
00205 LDEBUG("%s",inLine);
00206 LDEBUG("Start trial %s", currLine[6].c_str());
00207
00208
00209 if(createEyeS)
00210 {
00211 std::string fName =
00212 sformat("%s_%d.eyeS", eyeSfile_prefix.c_str(), iTrial);
00213 eyesFile = fopen(fName.c_str(), "wt");
00214
00215 std::string period("period = 1000Hz\n");
00216 fputs (period.c_str(), eyesFile);
00217
00218 std::string ppd("ppd = 36.3\n");
00219 fputs (ppd.c_str(), eyesFile);
00220
00221 std::string trash("trash = 0\n");
00222 fputs (trash.c_str(), eyesFile);
00223
00224 std::string header("cols = x y pd status *targetx *targety "
00225 "*amp *pvel *timeon *timeoff "
00226 "*interval *typenum\n");
00227 fputs (header.c_str(), eyesFile);
00228
00229 LINFO("creating: %s", fName.c_str());
00230 }
00231 }
00232
00233
00234 if(iTrial == 0) continue;
00235
00236
00237 if(currLine.size() == 4 &&
00238 !currLine[2].compare("MARKERID") && !currLine[3].compare("Flip"))
00239 {
00240 itsFlipTime[iTrial-1].push_back(atof(currLine[1].c_str()));
00241
00242 if(fTime == 0)
00243 itsFlipFrame[iTrial-1].push_back(0);
00244 else
00245 {
00246 if((itsFlipTime[iTrial-1][fTime] - itsFlipTime[iTrial-1][0])
00247 > trialLength * 1000)
00248 {
00249
00250 itsFlipFrame[iTrial-1].push_back(trialLength * frameRate);
00251 }
00252 else
00253 {
00254 int tDiff =
00255 itsFlipTime[iTrial-1][fTime] - itsFlipTime[iTrial-1][0];
00256 float mspfr = 1000/frameRate;
00257 int frNum = floor(tDiff/mspfr);
00258 itsFlipFrame[iTrial-1].push_back(frNum);
00259 }
00260 }
00261
00262
00263 fTime = fTime + 1;
00264 itsFlipFixations[iTrial-1].push_back
00265 (std::vector<Point2D<float> >());
00266
00267 if(fTime == 1) startTime = atoi(currLine[1].c_str());
00268 }
00269
00270
00271 if (currLine.size() > 6 &&
00272 !currLine[4].compare("SESSION") && !currLine[5].compare("END"))
00273 {
00274 itsTrialEnd[iTrial-1] = atoi(currLine[1].c_str());
00275 if (iTrial != uint(atoi(currLine[6].c_str())))
00276 LINFO("Trial Mismatch!");
00277
00278 LDEBUG("%s",inLine);
00279 LDEBUG("trial: %d to %d",
00280 itsFlipTime[iTrial-1][0], itsFlipTime[iTrial-1][fTime-1]);
00281 LDEBUG("there are %"ZU" saccades and %"ZU" fixations",
00282 itsSaccadeStart[iTrial-1].size(),
00283 itsFixationStart[iTrial-1].size());
00284
00285 if(createEyeS)
00286 fclose (eyesFile);
00287 }
00288
00289
00290 if (itsTrialEnd[iTrial-1] != -1.0) continue;
00291
00292
00293 if (currLine.size() > 4 && !currLine[4].compare("CORRECTION"))
00294 {
00295 LINFO("in between drifting: %s",inLine);
00296
00297 if(currLine.size() == 5 && !currLine[3].compare("DRIFT"))
00298 {
00299 isDriftCorrecting = 1;
00300 itsDriftCorrectionStart.push_back(atoi(currLine[1].c_str()));
00301 LINFO("Start in between drifting correction at: %d",
00302 itsDriftCorrectionStart[iTrial-1]);
00303 }
00304 else if(currLine.size() == 6 && !currLine[5].compare("DONE"))
00305 {
00306 isDriftCorrecting = 0;
00307 itsDriftCorrectionDone.push_back(atoi(currLine[1].c_str()));
00308 LINFO("End in between drifting correction at: %d",
00309 itsDriftCorrectionDone[iTrial-1]);
00310 }
00311 else
00312 LINFO("Wrong Drift Correction Message!");
00313 }
00314 }
00315
00316
00317 else if (currLine.size() > 0 &&
00318 (!currLine[0].compare("SSACC") ||
00319 !currLine[0].compare("ESACC") ||
00320 !currLine[0].compare("SFIX") ||
00321 !currLine[0].compare("EFIX") ||
00322 !currLine[0].compare("SBLINK") ||
00323 !currLine[0].compare("EBLINK") ))
00324 {
00325
00326 if (iTrial == 0) continue;
00327
00328
00329 if (itsTrialEnd[iTrial-1] != -1.0) continue;
00330
00331
00332
00333
00334 if(!currLine[0].compare("SSACC"))
00335 {
00336 isSaccading = true;
00337 iSacc = iSacc + 1;
00338
00339
00340
00341
00342
00343 fpos_t pos;
00344 fgetpos(fp, &pos);
00345 char tline[200];
00346 bool foundESACC = false;
00347 while(!foundESACC && fgets(tline, 200, fp) != NULL)
00348 {
00349
00350 std::vector<std::string> cLine = tokenize(tline);
00351
00352
00353 if(cLine.size() > 0 && !cLine[0].compare("ESACC"))
00354 {
00355 targetx = atof(cLine[7].c_str())/D_WIDTH*IM_WIDTH;
00356 targety = atof(cLine[8].c_str())/D_HEIGHT*IM_HEIGHT;
00357 amp = atof(cLine[9].c_str());
00358 pvel = atof(cLine[10].c_str());
00359 timeOn = atof(cLine[2].c_str()) - startTime;
00360 timeOff = atof(cLine[3].c_str()) - startTime;
00361 interval = atof(cLine[4].c_str());
00362 foundESACC = true;
00363
00364 LDEBUG("%.1f %.1f %.1f %.1f %.1f %.1f %.1f %d",
00365 targetx, targety, amp, pvel,
00366 timeOn, timeOff, interval, iSacc);
00367 }
00368 }
00369
00370
00371 fsetpos(fp, &pos);
00372 }
00373
00374
00375 if(!currLine[0].compare("ESACC"))
00376 {
00377 itsSaccadeStart [iTrial-1].push_back(atoi(currLine[2].c_str()));
00378 itsSaccadeEnd [iTrial-1].push_back(atoi(currLine[3].c_str()));
00379 itsSaccadeDuration [iTrial-1].push_back(atoi(currLine[4].c_str()));
00380 itsSaccadeStartLocation[iTrial-1].push_back
00381 (Point2D<float>(atof(currLine[5].c_str()), atof(currLine[6].c_str())));
00382 itsSaccadeEndLocation [iTrial-1].push_back
00383 (Point2D<float>(atof(currLine[7].c_str()), atof(currLine[8].c_str())));
00384 itsSaccadeAmplitude [iTrial-1].push_back(atof(currLine[9].c_str()));
00385 itsSaccadePeakVel [iTrial-1].push_back(atof(currLine[10].c_str()));
00386
00387
00388 isSaccading = false;
00389 }
00390
00391
00392
00393
00394 else if(!currLine[0].compare("EFIX"))
00395 {
00396 iFix = iFix + 1;
00397
00398 itsFixationStart [iTrial-1].push_back(atoi(currLine[2].c_str()));
00399 itsFixationEnd [iTrial-1].push_back(atoi(currLine[3].c_str()));
00400 itsFixationDuration [iTrial-1].push_back(atoi(currLine[4].c_str()));
00401 itsFixationAvgLocation [iTrial-1].push_back
00402 (Point2D<float>(atof(currLine[5].c_str()), atof(currLine[6].c_str())));
00403 itsFixationAvgPupilSize[iTrial-1].push_back(atof(currLine[7].c_str()));
00404
00405 }
00406 else if(!currLine[0].compare("SBLINK"))
00407 isBlinking = true;
00408 else if(!currLine[0].compare("EBLINK"))
00409 isBlinking = false;
00410 }
00411
00412
00413 else if (currLine.size() > 0 &&
00414 (!currLine[0].compare("START") ||
00415 !currLine[0].compare("END") ||
00416 !currLine[0].compare("PRESCALER") ||
00417 !currLine[0].compare("VPRESCALER") ||
00418 !currLine[0].compare("PUPIL") ||
00419 !currLine[0].compare("SAMPLES") ||
00420 !currLine[0].compare(">>>>>>>") ))
00421 { continue; }
00422
00423 else if (currLine.size() > 0 && !currLine[0].compare("EVENTS"))
00424 {
00425
00426 if(!currLine[1].compare("GAZE"))
00427 {
00428 if(!currLine[2].compare("RIGHT"))
00429 recordedEye = std::string("RIGHT");
00430 else if(!currLine[2].compare("LEFT") && !currLine[3].compare("RIGHT"))
00431 recordedEye = std::string("BOTH");
00432 else
00433 recordedEye = std::string("LEFT");
00434 LDEBUG("Recorded Eye: %s", recordedEye.c_str());
00435 }
00436 }
00437
00438
00439
00440 else if (currLine.size() > 0 && !currLine[0].compare("INPUT"))
00441 { continue; }
00442
00443
00444 else if(atoi(currLine[0].c_str()) == 0)
00445 {
00446 LDEBUG("First Element Exception: Skipped: %s", inLine);
00447 continue;
00448 }
00449
00450
00451 else
00452 {
00453
00454 if (iTrial == 0) continue;
00455
00456
00457 if(itsTrialEnd[iTrial-1] != -1.0) continue;
00458
00459
00460 if (isDriftCorrecting) continue;
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 if(fTime != 0)
00472 {
00473 uint status = 0;
00474 if(!isBlinking && isSaccading) status = 1;
00475 if( isBlinking && !isSaccading) status = 2;
00476 if( isBlinking && isSaccading) status = 3;
00477
00478 uint freq = 0; if(targetx != 0.0F) freq = iSacc;
00479 std::string line =
00480 sformat("%.1f %.1f %.1f %d %.1f %.1f %.1f %.1f %.1f %.1f %.1f %d \n",
00481 atof(currLine[1].c_str())/D_WIDTH *IM_WIDTH,
00482 atof(currLine[2].c_str())/D_HEIGHT*IM_HEIGHT,
00483 atof(currLine[3].c_str()), status,
00484 targetx, targety, amp, pvel, timeOn, timeOff, interval, freq);
00485 if(createEyeS)
00486 fputs (line.c_str(), eyesFile);
00487
00488 if(targetx != 0.0F)
00489 {
00490 targetx = 0.0F;
00491 targety = 0.0F;
00492 amp = 0.0F;
00493 pvel = 0.0F;
00494 timeOn = 0.0F;
00495 timeOff = 0.0F;
00496 interval = 0.0F;
00497 }
00498 }
00499
00500
00501 if (isBlinking) continue;
00502
00503
00504
00505 iTime = iTime + 1;
00506
00507
00508 itsGazeTime[iTrial-1].push_back(atoi(currLine[0].c_str()));
00509 if(fTime != 0)
00510 {
00511 itsFlipFixations[iTrial-1][fTime-1].push_back
00512 (Point2D<float>(atof(currLine[1].c_str()), atof(currLine[2].c_str())));
00513 }
00514 LDEBUG("GAZE[%5d][%5d]: %s size: %"ZU,
00515 iTrial-1, fTime-1, inLine, itsGazeTime[iTrial-1].size());
00516
00517 if(!recordedEye.compare("LEFT") || !recordedEye.compare("BOTH"))
00518 {
00519
00520 if (!currLine[1].compare(".") || !currLine[2].compare("."))
00521 itsLeftGaze[iTrial-1].push_back(Point2D<float>(-1.0, -1.0));
00522 else
00523 itsLeftGaze[iTrial-1].push_back
00524 (Point2D<float>(atof(currLine[1].c_str()), atof(currLine[2].c_str())));
00525
00526
00527 if (!currLine[3].compare("."))
00528 itsLeftGazePupilSize[iTrial-1].push_back(-1.0);
00529 else
00530 itsLeftGazePupilSize[iTrial-1].push_back(atof(currLine[3].c_str()));
00531 }
00532
00533 if(!recordedEye.compare("BOTH"))
00534 {
00535
00536 if (!currLine[4].compare(".") || !currLine[5].compare("."))
00537 itsRightGaze[iTrial-1].push_back(Point2D<float>(-1.0, -1.0));
00538 else
00539 itsRightGaze[iTrial-1].push_back
00540 (Point2D<float>(atof(currLine[4].c_str()), atof(currLine[5].c_str())));
00541
00542
00543 if (!currLine[6].compare("."))
00544 itsRightGazePupilSize[iTrial-1].push_back(-1.0);
00545 else
00546 itsRightGazePupilSize[iTrial-1].push_back(atof(currLine[6].c_str()));
00547 }
00548
00549 if(!recordedEye.compare("RIGHT"))
00550 {
00551
00552 if (!currLine[1].compare(".") || !currLine[2].compare("."))
00553 itsRightGaze[iTrial-1].push_back(Point2D<float>(-1.0, -1.0));
00554 else
00555 itsRightGaze[iTrial-1].
00556 push_back(Point2D<float>(atof(currLine[1].c_str()), atof(currLine[2].c_str())));
00557
00558
00559 if (!currLine[3].compare("."))
00560 itsRightGazePupilSize[iTrial-1].push_back(-1.0);
00561 else
00562 itsRightGazePupilSize[iTrial-1].push_back(atof(currLine[3].c_str()));
00563 }
00564 }
00565 }
00566 }
00567
00568
00569 std::vector<std::string> EyeLinkAscParser::tokenize(std::string line)
00570 {
00571 bool endOfLine = false;
00572
00573
00574 if(!line.substr(line.length()-1).compare(std::string("\n")))
00575 line = line.substr(0, line.length()-2);
00576
00577 std::vector<std::string> currLine;
00578 while(!endOfLine)
00579 {
00580 std::string token; std::string rest;
00581 std::string::size_type fspos = line.find_first_of(' ');
00582 std::string::size_type ftpos = line.find_first_of('\t');
00583 if(ftpos != std::string::npos && ftpos < fspos) fspos = ftpos;
00584
00585 if(fspos != std::string::npos)
00586 {
00587 token = line.substr(0,fspos);
00588 rest = trim(line.substr(fspos));
00589
00590 LDEBUG("[[%s]] [[%s]]", token.c_str(), rest.c_str());
00591
00592 currLine.push_back(token);
00593 if(!rest.substr(0,1).compare(std::string("\t")))
00594 rest = trim(rest.substr(1));
00595 line = rest;
00596 }
00597 else
00598 {
00599 if(line.length() != 0)
00600 {
00601 currLine.push_back(line);
00602 LDEBUG("[[%s]]", line.c_str());
00603 }
00604 endOfLine = true;
00605 }
00606 }
00607
00608 return currLine;
00609 }
00610
00611
00612 std::string EyeLinkAscParser::trim(std::string str)
00613 {
00614 std::string::size_type pos = str.find_last_not_of(' ');
00615
00616 if(pos != std::string::npos) {
00617 str.erase(pos + 1);
00618 pos = str.find_first_not_of(' ');
00619 if(pos != std::string::npos) str.erase(0, pos);
00620 }
00621 else str.erase(str.begin(), str.end());
00622
00623 return str;
00624 }
00625
00626
00627
00628
00629
00630
00631
00632