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 "Component/ModelManager.H"
00040 #include "Image/DrawOps.H"
00041 #include "Image/Image.H"
00042 #include "Psycho/PsychoDisplay.H"
00043 #include "Psycho/EyeTrackerConfigurator.H"
00044 #include "Psycho/EyeTracker.H"
00045 #include "Psycho/PsychoOpts.H"
00046 #include "Component/EventLog.H"
00047 #include "Component/ComponentOpts.H"
00048 #include "GUI/GUIOpts.H"
00049 #include "Raster/Raster.H"
00050 #include "Util/MathFunctions.H"
00051 #include "Video/RgbConversion.H"
00052
00053
00054
00055 void createCloud (DOT* dots, int numDots, int x, int y, int r, int move);
00056
00057 void setCoherence (DOT* dots, int numDots, int numCoherent, int move);
00058
00059
00060 extern "C" int main(const int argc, char** argv)
00061 {
00062 MYLOGVERB = LOG_INFO;
00063
00064
00065 ModelManager manager("Psycho motion");
00066
00067
00068 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00069 manager.addSubComponent(d);
00070
00071 nub::soft_ref<EyeTrackerConfigurator>
00072 etc(new EyeTrackerConfigurator(manager));
00073 manager.addSubComponent(etc);
00074
00075 nub::soft_ref<EventLog> el(new EventLog(manager));
00076 manager.addSubComponent(el);
00077
00078
00079 manager.setOptionValString(&OPT_SDLdisplayDims, "640x480");
00080 d->setModelParamVal("PsychoDisplayBackgroundColor", PixRGB<byte>(0));
00081 d->setModelParamVal("PsychoDisplayTextColor", PixRGB<byte>(255));
00082 d->setModelParamVal("PsychoDisplayBlack", PixRGB<byte>(255));
00083 d->setModelParamVal("PsychoDisplayWhite", PixRGB<byte>(128));
00084 d->setModelParamVal("PsychoDisplayFixSiz", 5);
00085 d->setModelParamVal("PsychoDisplayFixThick", 5);
00086 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy");
00087 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00088
00089
00090
00091 if (manager.parseCommandLine(argc, argv, "<radius> <midCoherence> "
00092 "<targetCoherence> <numDots> <life> "
00093 "<waitFrames> <move> <startTrial#>",
00094 1, -1)==false)
00095 return(1);
00096
00097
00098 nub::soft_ref<EyeTracker> et = etc->getET();
00099 d->setEyeTracker(et);
00100 d->setEventLog(el);
00101 et->setEventLog(el);
00102
00103
00104 manager.start();
00105
00106
00107 d->clearScreen();
00108 d->displayISCANcalib();
00109 d->waitForKey();
00110
00111
00112 d->displayText("<SPACE> to calibrate; other key to skip");
00113 int c = d->waitForKey();
00114 if (c == ' ') d->displayEyeTrackerCalibration(3, 3);
00115
00116 d->clearScreen();
00117
00118
00119 int radius = manager.getExtraArgAs<int>(0);
00120 int midCoherence = manager.getExtraArgAs<int>(1);
00121 int targetCoherence = manager.getExtraArgAs<int>(2);
00122 int numDots = manager.getExtraArgAs<int>(3);
00123 int life = manager.getExtraArgAs<int>(4);
00124 int waitNum = manager.getExtraArgAs<int>(5);
00125 int move = manager.getExtraArgAs<int>(6);
00126 int startTrial = manager.getExtraArgAs<int>(7);
00127
00128
00129 d->clearScreen();
00130
00131 initRandomNumbers();
00132 int numTrial = 0;
00133 DOT clouds[25][numDots];
00134 Image< PixRGB<byte> > bufima(d->getDims(), NO_INIT);
00135
00136
00137 int leg = 15; int bgDots = 2 * leg - 1;
00138 DOT targetShape[bgDots], distractorShape[bgDots];
00139 for (int i = 0; i < bgDots; i++) {
00140 if (i < leg) {
00141 (targetShape[i]).x = 0; (targetShape[i]).y = -i;
00142 (distractorShape[i]).x = 0; (distractorShape[i]).y = -i;
00143 }
00144 else {
00145 (targetShape[i]).x = leg-i; (targetShape[i]).y = -leg;
00146 (distractorShape[i]).x = i-leg; (distractorShape[i]).y = 0;
00147 }
00148 }
00149 DOT bg[25][bgDots];
00150
00151 while (numTrial < 30)
00152 {
00153 d->createYUVoverlay(SDL_YV12_OVERLAY);
00154 char reco[10]; sprintf (reco, "reco-%d", startTrial + numTrial);
00155 numTrial ++;
00156 FILE* f = fopen (reco, "w");
00157
00158 d->displayText("hit any key when ready");
00159 d->waitForKey();
00160 d->waitNextRequestedVsync(false, true);
00161
00162 int targetCloud = -1;
00163
00164 int index[25];
00165 for (int i = 0; i < 25; i++)
00166 index[i] = i;
00167 randShuffle (index, 25);
00168
00169 int cenx[25], ceny[25];
00170 for (int i = 0; i < 25; i++){
00171 int idx = index[i];
00172 int col = idx % 5, row = idx / 5;
00173 cenx[idx] = col * 128 + 64 + (int) (randomDouble()*31) - 15;
00174 ceny[idx] = row * 96 + 48 + (int) (randomDouble()*25) - 12 ;
00175 DOT* dots = clouds[idx];
00176 createCloud (dots, numDots, cenx[idx], ceny[idx], radius, move);
00177 if (i == 24) {
00178 setCoherence (dots, numDots,
00179 (int) (targetCoherence*numDots/100), move);
00180 targetCloud = idx;
00181 LINFO ("target location: (%d,%d)", row, col);
00182 fprintf (f, "%d %d %d %d target\n", row, col, cenx[idx],ceny[idx]);
00183
00184 for (int j = 0; j < bgDots; j++){
00185 DOT* dot_bg = bg[idx] + j;
00186 dot_bg->x = (targetShape[j]).x + cenx[idx] + leg/2;
00187 dot_bg->y = (targetShape[j]).y + ceny[idx] + leg/2;
00188 }
00189 }
00190 else {
00191 for (int j = 0; j < bgDots; j++){
00192 DOT* dot_bg = bg[idx] + j;
00193 dot_bg->x = (distractorShape[j]).x + cenx[idx] - leg/2;
00194 dot_bg->y = (distractorShape[j]).y + ceny[idx] + leg/2;
00195 }
00196 if (i < 8){
00197 setCoherence (dots, numDots, 0, move);
00198 fprintf (f, "%d %d %d %d less\n",
00199 row, col, cenx[idx], ceny[idx]);
00200 }
00201 else if (i < 16){
00202 setCoherence (dots, numDots,
00203 (int) (midCoherence*numDots/100), move);
00204 fprintf (f, "%d %d %d %d mid\n", row, col, cenx[idx], ceny[idx]);
00205 }
00206 else if (i < 24){
00207 setCoherence (dots, numDots, numDots, move);
00208 fprintf (f, "%d %d %d %d high\n",
00209 row, col, cenx[idx], ceny[idx]);
00210 }
00211 }
00212 }
00213 fclose (f);
00214
00215
00216 et->track(true);
00217
00218
00219 d->displayFixationBlink();
00220
00221 int time = 0;
00222 while (d->checkForKey() == -1){
00223 time ++;
00224
00225 for (int i = 0; i < 25; i++){
00226 int idx = index[i];
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 for (int j = 0; j < numDots; j++){
00238 DOT *dot = &(clouds[idx][j]);
00239 int x1 = dot->x - cenx[idx];
00240 int y1 = dot->y - ceny[idx];
00241
00242
00243
00244
00245
00246
00247
00248 if (dot->coherent == 1) y1 += dot->dy;
00249 else {
00250
00251 if (dot->age > life){
00252
00253 dot->age = 0;
00254 double rand = randomDouble();
00255 if (rand <= 0.33) dot->dx = move;
00256 else if (rand <= 0.66) dot->dx = -move;
00257 else dot->dx = 0;
00258 rand = randomDouble();
00259 if (rand <= 0.33) dot->dy = move;
00260 else if (rand <= 0.66) dot->dy = -move;
00261 else dot->dy = 0;
00262 if (dot->dx == 0 && dot->dy == 0){
00263 if (randomDouble() <= 0.5) dot->dy = move;
00264 else dot->dy = -move;
00265 }
00266 }
00267 x1 += dot->dx;
00268 y1 += dot->dy;
00269 dot->age += 1;
00270 }
00271
00272 if (x1 < -radius) x1 = radius;
00273 else if (x1 > radius) x1 = -radius;
00274 if (y1 < -radius) y1 = radius;
00275 else if (y1 > radius) y1 = -radius;
00276
00277 dot->x = x1 + cenx[idx];
00278 dot->y = y1 + ceny[idx];
00279 }
00280 }
00281
00282
00283 bufima.clear();
00284
00285 for (int i = 0; i < 25; i++)
00286 for (int j = 0; j < numDots; j++){
00287 int x = (clouds[i][j]).x;
00288 int y = (clouds[i][j]).y;
00289 drawDisk(bufima, Point2D<int>(x, y), 2, PixRGB<byte>(120));
00290 }
00291 for (int i = 0; i < 25; i++)
00292 for (int j = 0; j < bgDots; j++){
00293 int x = (bg[i][j]).x;
00294 int y = (bg[i][j]).y;
00295 bufima.setVal(x, y, PixRGB<byte>(75));
00296 }
00297
00298
00299 SDL_Overlay *ovl = d->lockYUVoverlay();
00300 toVideoYUV422(bufima,
00301 ovl->pixels[0], ovl->pixels[1], ovl->pixels[2]);
00302 d->unlockYUVoverlay();
00303 d->displayYUVoverlay(time, SDLdisplay::NEXT_VSYNC);
00304
00305 d->waitFrames(waitNum);
00306 }
00307
00308 usleep(50000);
00309 et->track(false);
00310
00311
00312 int correctResponse = d->displayNumbers (targetCloud/5,
00313 targetCloud%5, true);
00314 d->pushEvent(std::string("===== Showing noCheat ====="));
00315
00316
00317 for (int j = 0; j < 10; j ++) d->waitNextRequestedVsync();
00318
00319
00320 d->displayText("Enter the number at the target location");
00321 c = d->waitForKey();
00322 int c2 = d->waitForKey();
00323
00324 int observedResponse = 10*(c-48) + c2-48;
00325 LINFO (" subject entered %d and correct response is %d",
00326 observedResponse, correctResponse);
00327 if (observedResponse == correctResponse)
00328 {
00329 d->displayText("Correct!");
00330 d->pushEvent(std::string("===== Correct ====="));
00331 }
00332 else
00333 {
00334 d->displayText("Wrong! ");
00335 d->pushEvent(std::string("===== Wrong ====="));
00336 }
00337
00338 for (int j = 0; j < 30; j ++) d->waitNextRequestedVsync();
00339 d->destroyYUVoverlay();
00340 }
00341
00342 d->clearScreen();
00343 d->displayText("Experiment complete. Thank you!");
00344 d->waitForKey();
00345
00346
00347
00348 manager.stop();
00349
00350
00351 return 0;
00352 }
00353
00354
00355
00356 void createCloud (DOT* dots, int numDots, int cx, int cy, int r, int move)
00357 {
00358 int i = 0;
00359 int size = 2 * r + 1;
00360 while (i < numDots){
00361
00362 int x = (int) (randomDouble()*size) - r;
00363 int y = (int) (randomDouble()*size) - r;
00364 dots[i].x = cx + x;
00365 dots[i].y = cy + y;
00366 dots[i].coherent = 0;
00367 dots[i].age = (int) (randomDouble() * 5);
00368 double rand = randomDouble();
00369 if (rand <= 0.33) dots[i].dx = move;
00370 else if (rand <= 0.66) dots[i].dx = -move;
00371 else dots[i].dx = 0;
00372 rand = randomDouble();
00373 if (rand <= 0.33) dots[i].dy = move;
00374 else if (rand <= 0.66) dots[i].dy = -move;
00375 else dots[i].dy = 0;
00376 if (dots[i].dx == 0 && dots[i].dy == 0){
00377 if (randomDouble() <= 0.5) dots[i].dy = move;
00378 else dots[i].dy = -move;
00379 }
00380 i++;
00381 }
00382 }
00383
00384
00385 void setCoherence (DOT* dots, int numDots, int numCoherent, int move)
00386 {
00387
00388 int index[numDots];
00389 for (int i = 0; i < numDots; i++)
00390 index[i] = i;
00391
00392
00393 randShuffle (index, numDots);
00394
00395
00396 for (int i = 0; i < numCoherent; i++){
00397 dots[index[i]].coherent = 1;
00398 dots[index[i]].dx = 0;
00399 dots[index[i]].dy = move;
00400 }
00401 }
00402
00403
00404
00405
00406
00407
00408
00409