00001 /*!@file Psycho/StimMaker.C make different kind of visual test stimuli 00002 */ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: T. Nathan Mundhenk <mundhenk@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Psycho/StimMaker.C $ 00036 // $Id: StimMaker.C 9412 2008-03-10 23:10:15Z farhan $ 00037 // 00038 00039 #ifndef STIM_MAKER_C_DEFINED 00040 #define STIM_MAKER_C_DEFINED 00041 00042 #include "Psycho/StimMaker.H" 00043 00044 StimMaker::StimMaker(const unsigned short ImageSizeX, 00045 const unsigned short ImageSizeY, 00046 const unsigned short frameCount, 00047 const char bgColor) 00048 { 00049 itsFrameCount = frameCount; 00050 itsSizeX = ImageSizeX; 00051 itsSizeY = ImageSizeY; 00052 itsSlowRate = SM_SLOW_RATE; 00053 itsFastRate = SM_FAST_RATE; 00054 itsStopRate = SM_STOP_RATE; 00055 itsRandomSeed = 0; 00056 00057 itsBlack.set(0.0F,0.0F,0.0F); 00058 itsColorVec.resize(SM_COLORS,itsBlack); 00059 00060 itsRed.set(255.0F,0.0F,0.0F); 00061 itsOrange.set(255.0F,128.0F,0.0F); 00062 itsYellow.set(255.0F,255.0F,0.0F); 00063 itsGreen.set(0.0F,255.0F,0.0F); 00064 itsBlue.set(0.0F,0.0F,255.0F); 00065 itsPurple.set(255.0F,0.0F,255.0F); 00066 itsWhite.set(255.0F,255.0F,255.0F); 00067 00068 itsColorVec[0] = itsRed; 00069 itsColorVec[1] = itsOrange; 00070 itsColorVec[2] = itsYellow; 00071 itsColorVec[3] = itsGreen; 00072 itsColorVec[4] = itsBlue; 00073 itsColorVec[5] = itsPurple; 00074 itsColorVec[6] = itsWhite; 00075 00076 itsGTtargetColor.set(255.0F,255.0F,255.0F); 00077 itsGTtargetColorPatch1.set(0.0F,128.0F,128.0F); 00078 itsGTtargetColorPatch2.set(0.0F,0.0F,255.0F); 00079 itsGTtargetColorPatch1off.set(128.0F,128.0F,0.0F); 00080 itsGTtargetColorPatch2off.set(255.0F,0.0F,0.0F); 00081 itsGTdistColor.set(128.0F,128.0F,128.0F); 00082 00083 SM_init(bgColor); 00084 } 00085 00086 /*****************************************************************************/ 00087 00088 StimMaker::~StimMaker() 00089 {} 00090 00091 /*****************************************************************************/ 00092 00093 // reset the frames and back ground truth to the background color 00094 void StimMaker::SM_init(const char bgColor) 00095 { 00096 Image<PixRGB<float> > baseImage; 00097 baseImage.resize(itsSizeX,itsSizeY); 00098 itsFrames.resize(itsFrameCount, baseImage); 00099 std::vector<Image<PixRGB<float> > >::iterator framesIter = itsFrames.begin(); 00100 while(framesIter != itsFrames.end()) 00101 { 00102 Image<PixRGB<float> >::iterator imgIter = framesIter->beginw(); 00103 while(imgIter != framesIter->endw()) 00104 { 00105 *imgIter = itsColorVec[itsBGcolor+1]; 00106 ++imgIter; 00107 } 00108 ++framesIter; 00109 } 00110 00111 itsGroundTruth.resize(itsFrameCount, baseImage); 00112 framesIter = itsGroundTruth.begin(); 00113 while(framesIter != itsGroundTruth.end()) 00114 { 00115 Image<PixRGB<float> >::iterator imgIter = framesIter->beginw(); 00116 while(imgIter != framesIter->endw()) 00117 { 00118 *imgIter = itsBlack; 00119 ++imgIter; 00120 } 00121 ++framesIter; 00122 } 00123 SM_setStandardBackGround(bgColor); 00124 00125 } 00126 00127 /*****************************************************************************/ 00128 00129 // reset the frames and back ground truth to the background color 00130 void StimMaker::SM_setStandardBackGround(const unsigned char bgColor) 00131 { 00132 itsBGcolor = bgColor; 00133 itsCustomBG = itsColorVec[itsBGcolor]; 00134 itsUseCustomColors = false; 00135 } 00136 00137 /*****************************************************************************/ 00138 00139 void StimMaker::SM_overRideRates(const unsigned char slowRate, 00140 const unsigned char fastRate, 00141 const unsigned char stopRate) 00142 { 00143 itsSlowRate = slowRate; 00144 itsFastRate = fastRate; 00145 itsStopRate = stopRate; 00146 } 00147 00148 /*****************************************************************************/ 00149 00150 void StimMaker::SM_setCustomColors(const PixRGB<float> BGcolor, 00151 const PixRGB<float> TargetColor, 00152 const PixRGB<float> DistColor) 00153 { 00154 itsCustomBG = BGcolor; 00155 itsCustomTarg = TargetColor; 00156 itsCustomDist = DistColor; 00157 itsUseCustomColors = true; 00158 } 00159 00160 /*****************************************************************************/ 00161 inline ushort StimMaker::SM_speedUpCheck(ushort currBlinkRate, 00162 const ushort frame, 00163 const ushort changeFrame, 00164 const unsigned char stimRate, 00165 const unsigned char useSmoothRateChange) const 00166 { 00167 if(frame > changeFrame) 00168 { 00169 // we are slow, go fast 00170 if(stimRate == SM_SLOW_STIM) 00171 { 00172 if(currBlinkRate > itsFastRate) 00173 { 00174 if(useSmoothRateChange == SM_USE_SMOOTH_RATE_CHANGE) 00175 currBlinkRate -= SM_SMOOTH_ACCEL; 00176 else 00177 currBlinkRate = itsFastRate; 00178 } 00179 else 00180 if(currBlinkRate < itsFastRate) 00181 currBlinkRate = itsFastRate; 00182 } 00183 // we are steady, start into slow 00184 else if(stimRate == SM_NSPD_STIM) 00185 { 00186 if(currBlinkRate != itsSlowRate) 00187 currBlinkRate = itsSlowRate; 00188 } 00189 } 00190 return currBlinkRate; 00191 } 00192 00193 /*****************************************************************************/ 00194 inline ushort StimMaker::SM_speedDownCheck(ushort currBlinkRate, 00195 const ushort frame, 00196 const ushort changeFrame, 00197 const unsigned char stimRate, 00198 const unsigned char useSmoothRateChange) const 00199 { 00200 if(frame > changeFrame) 00201 { 00202 // we are fast, go slow 00203 if(stimRate == SM_FAST_STIM) 00204 { 00205 if(currBlinkRate < itsSlowRate) 00206 { 00207 if(useSmoothRateChange == SM_USE_SMOOTH_RATE_CHANGE) 00208 currBlinkRate += SM_SMOOTH_ACCEL; 00209 else 00210 currBlinkRate = itsSlowRate; 00211 } 00212 else 00213 if(currBlinkRate > itsSlowRate) 00214 currBlinkRate = itsSlowRate; 00215 } 00216 // we are slow, then stop 00217 else if(stimRate == SM_SLOW_STIM) 00218 { 00219 if(currBlinkRate != itsStopRate) 00220 currBlinkRate = itsStopRate; 00221 } 00222 } 00223 return currBlinkRate; 00224 00225 } 00226 00227 00228 00229 /*****************************************************************************/ 00230 00231 inline void StimMaker::SM_drawGroundTruth(const ushort frame, 00232 const unsigned char stimSizeX, 00233 const unsigned char stimSizeY, 00234 const ushort PosX, 00235 const ushort PosY, 00236 const bool targetOn) 00237 { 00238 const Point2D<int> P1(PosX,PosY); 00239 if(targetOn) 00240 { 00241 drawDisk(itsGroundTruth[frame],P1,stimSizeX,itsGTtargetColorPatch1); 00242 drawDisk(itsGroundTruth[frame],P1,stimSizeX/2,itsGTtargetColorPatch2); 00243 00244 } 00245 else 00246 { 00247 drawDisk(itsGroundTruth[frame],P1,stimSizeX,itsGTtargetColorPatch1off); 00248 drawDisk(itsGroundTruth[frame],P1,stimSizeX/2,itsGTtargetColorPatch2off); 00249 } 00250 } 00251 00252 /*****************************************************************************/ 00253 00254 inline void StimMaker::SM_drawSingleTarget(const ushort frame, 00255 const unsigned char stimShape, 00256 const unsigned char stimColor, 00257 const unsigned char stimSizeX, 00258 const unsigned char stimSizeY, 00259 const ushort PosX, 00260 const ushort PosY, 00261 const float stimOri, 00262 const float shapePositionJitter, 00263 const float shapeOrientationJitter, 00264 const bool target) 00265 { 00266 // Compute random shape if any 00267 00268 unsigned char shape; 00269 00270 if(stimShape == SM_STIM_RAND) 00271 { 00272 shape = 1 + (unsigned char)(SM_SHAPES*rand()/(RAND_MAX+1.0)); 00273 } 00274 else 00275 { 00276 shape = stimShape; 00277 } 00278 00279 // Compute random color if needed 00280 if(stimColor == SM_COLOR_RAND) 00281 { 00282 unsigned char color = 1 + (unsigned char)(SM_COLORS*rand()/(RAND_MAX+1.0)); 00283 if(target) 00284 itsCustomTarg = itsColorVec[color]; 00285 else 00286 itsCustomDist = itsColorVec[color]; 00287 } 00288 else 00289 { 00290 if(stimColor != SM_COLOR_CUSTOM) 00291 { 00292 if(target) 00293 itsCustomTarg = itsColorVec[stimColor-1]; 00294 else 00295 itsCustomDist = itsColorVec[stimColor-1]; 00296 } 00297 } // compute jitter if any 00298 float posJitterX,posJitterY,oriJitter; 00299 00300 if(shapePositionJitter != 0.0F) 00301 { 00302 // some shapes are defined by a radius which is actaully 00303 // the diameter, as such we have to devide their size by 1/2 00304 float divider; 00305 if((stimShape == SM_STIM_DISK) || 00306 (stimShape == SM_STIM_CROSS) || 00307 (stimShape == SM_STIM_PATCH) || 00308 (stimShape == SM_STIM_CIRC)) 00309 divider = 4.0F; 00310 else 00311 divider = 2.0F; 00312 // jitter by as much as +/- .5 the size of the stim 00313 posJitterX = ((float)stimSizeX)*(shapePositionJitter*rand()) 00314 /(RAND_MAX+1.0F) - stimSizeX/divider; 00315 posJitterY = ((float)stimSizeY)*(shapePositionJitter*rand()) 00316 /(RAND_MAX+1.0F) - stimSizeY/divider; 00317 } 00318 else 00319 { 00320 posJitterX = 0.0F; 00321 posJitterY = 0.0F; 00322 } 00323 00324 if(shapeOrientationJitter != 0.0F) 00325 { 00326 // jitter by as much as +/- Pi degrees 00327 oriJitter = shapeOrientationJitter * 00328 (((2.0F*M_PI*rand())/(RAND_MAX+1.0F)) - M_PI); 00329 } 00330 else 00331 { 00332 oriJitter = 0.0F; 00333 } 00334 00335 const float newPosX = posJitterX + PosX; 00336 const float newPosY = posJitterY + PosY; 00337 00338 const float newOri = stimOri + oriJitter; 00339 00340 // Draw Disk 00341 if(shape == SM_STIM_DISK) 00342 { 00343 if(stimSizeX != stimSizeY) 00344 LINFO("WARNING: Disk size X and Y should be the same! Using X size."); 00345 if(stimOri != 0.0F) 00346 LINFO("WARNING: Disk cannot have orientation! Ignoring."); 00347 const Point2D<int> center((int)round(newPosX),(int)round(newPosY)); 00348 if(target) 00349 { 00350 drawDisk(itsFrames[frame],center,stimSizeX/2,itsCustomTarg); 00351 drawDisk(itsGroundTruth[frame],center,stimSizeX/2,itsGTtargetColor); 00352 } 00353 else 00354 { 00355 drawDisk(itsFrames[frame],center,stimSizeX/2,itsCustomDist); 00356 drawDisk(itsGroundTruth[frame],center,stimSizeX/2,itsGTdistColor); 00357 } 00358 } 00359 // Draw Rect 00360 else if(shape == SM_STIM_RECT) 00361 { 00362 const int coordX1 = (int)floor(newPosX + (float)stimSizeX/2.0F); 00363 const int coordX2 = (int)floor(newPosX - (float)stimSizeX/2.0F); 00364 const int coordY1 = (int)floor(newPosY + (float)stimSizeY/2.0F); 00365 const int coordY2 = (int)floor(newPosY - (float)stimSizeY/2.0F); 00366 Rectangle rect = Rectangle::tlbrI(coordY2,coordX2,coordY1,coordX1); 00367 00368 if(target) 00369 { 00370 drawRectOR(itsFrames[frame],rect,itsCustomTarg,2,newOri); 00371 drawRectOR(itsGroundTruth[frame],rect,itsGTtargetColor,2,newOri); 00372 } 00373 else 00374 { 00375 drawRectOR(itsFrames[frame],rect,itsCustomDist,2,newOri); 00376 drawRectOR(itsGroundTruth[frame],rect,itsGTdistColor,2,newOri); 00377 } 00378 } 00379 // Draw Line 00380 else if(shape == SM_STIM_LINE) 00381 { 00382 if(stimSizeX != stimSizeY) 00383 LINFO("WARNING: Line size X and Y should be the same! Using X size."); 00384 const float newX = stimSizeX/2 * sin(newOri); 00385 const float newY = stimSizeX/2 * cos(newOri); 00386 00387 const int coordX1 = (int)floor(newPosX + newX); 00388 const int coordX2 = (int)floor(newPosX - newX); 00389 const int coordY1 = (int)floor(newPosY + newY); 00390 const int coordY2 = (int)floor(newPosY - newY); 00391 const Point2D<int> P1(coordX1,coordY1); 00392 const Point2D<int> P2(coordX2,coordY2); 00393 00394 if(target) 00395 { 00396 drawLine(itsFrames[frame],P1,P2,itsCustomTarg,2); 00397 drawLine(itsGroundTruth[frame],P1,P2,itsGTtargetColor,2); 00398 } 00399 else 00400 { 00401 drawLine(itsFrames[frame],P1,P2,itsCustomDist,2); 00402 drawLine(itsGroundTruth[frame],P1,P2,itsGTdistColor,2); 00403 } 00404 } 00405 // Draw Cross 00406 else if(shape == SM_STIM_CROSS) 00407 { 00408 if(stimSizeX != stimSizeY) 00409 LINFO("WARNING: Cross size X and Y should be the same! Using X size."); 00410 const Point2D<int> P1((int)floor(newPosX),(int)floor(newPosY)); 00411 if(target) 00412 { 00413 drawCrossOR(itsFrames[frame],P1,itsCustomTarg,stimSizeX/2,2,newOri); 00414 drawCrossOR(itsGroundTruth[frame],P1,itsGTtargetColor,stimSizeX/2,2,newOri); 00415 } 00416 else 00417 { 00418 drawCrossOR(itsFrames[frame],P1,itsCustomDist,stimSizeX/2,2,newOri); 00419 drawCrossOR(itsGroundTruth[frame],P1,itsGTdistColor,stimSizeX/2,2,newOri); 00420 } 00421 } 00422 // Draw Patch 00423 else if(shape == SM_STIM_PATCH) 00424 { 00425 if(stimOri != 0.0F) 00426 LINFO("WARNING: Patch cannot have orientation! Net yet supported. Ignoring."); 00427 if(stimSizeX != stimSizeY) 00428 LINFO("WARNING: Patch size X and Y should be the same! Using X size."); 00429 const Point2D<int> P1((int)floor(newPosX),(int)floor(newPosY)); 00430 if(target) 00431 { 00432 drawPatch(itsFrames[frame],P1,stimSizeX/2,itsCustomTarg); 00433 drawPatch(itsGroundTruth[frame],P1,stimSizeX/2,itsGTtargetColor); 00434 } 00435 else 00436 { 00437 drawPatch(itsFrames[frame],P1,stimSizeX/2,itsCustomDist); 00438 drawPatch(itsGroundTruth[frame],P1,stimSizeX/2,itsGTdistColor); 00439 } 00440 } 00441 // Draw Arrow 00442 else if(shape == SM_STIM_ARROW) 00443 { 00444 if(stimSizeX != stimSizeY) 00445 LINFO("WARNING: Arrow size X and Y should be the same! Using X size."); 00446 const float newX = stimSizeX/2 * sin(newOri); 00447 const float newY = stimSizeX/2 * cos(newOri); 00448 00449 const int coordX1 = (int)floor(newPosX + newX); 00450 const int coordX2 = (int)floor(newPosX - newX); 00451 const int coordY1 = (int)floor(newPosY + newY); 00452 const int coordY2 = (int)floor(newPosY - newY); 00453 const Point2D<int> P1(coordX1,coordY1); 00454 const Point2D<int> P2(coordX2,coordY2); 00455 00456 if(target) 00457 { 00458 drawArrow(itsFrames[frame],P1,P2,itsCustomTarg,2); 00459 drawArrow(itsGroundTruth[frame],P1,P2,itsGTtargetColor,2); 00460 } 00461 else 00462 { 00463 drawArrow(itsFrames[frame],P1,P2,itsCustomDist,2); 00464 drawArrow(itsGroundTruth[frame],P1,P2,itsGTdistColor,2); 00465 } 00466 } 00467 // Draw Circle 00468 else if(shape == SM_STIM_CIRC) 00469 { 00470 if(stimSizeX != stimSizeY) 00471 LINFO("WARNING: Circle size X and Y should be the same! Using X size."); 00472 if(stimOri != 0.0F) 00473 LINFO("WARNING: Circle cannot have orientation! Ignoring."); 00474 00475 const Point2D<int> center((int)round(newPosX),(int)round(newPosY)); 00476 if(target) 00477 { 00478 drawCircle(itsFrames[frame],center,stimSizeX/2,itsCustomTarg); 00479 drawCircle(itsGroundTruth[frame],center,stimSizeX/2,itsGTtargetColor); 00480 } 00481 else 00482 { 00483 drawCircle(itsFrames[frame],center,stimSizeX/2,itsCustomDist); 00484 drawCircle(itsGroundTruth[frame],center,stimSizeX/2,itsGTdistColor); 00485 } 00486 } 00487 else 00488 { 00489 LFATAL("StimMaker tried to draw an unlisted shape %d. See list in StimMaker.H",shape); 00490 } 00491 } 00492 00493 /*****************************************************************************/ 00494 00495 void StimMaker::SM_makeUniformStim(const StimMakerParam &stim) 00496 { 00497 itsRandomSeed = stim.SMP_randomSeed; 00498 // set the random seed so we can mix it up a little 00499 srand(itsRandomSeed); 00500 LINFO("Setting up stim params"); 00501 // go through each frame 00502 uint frame = 0; 00503 // figure out where to place distractors 00504 const float divX = ceil((float)itsSizeX/(float)stim.SMP_distPerRow); 00505 const float divY = ceil((float)itsSizeY/(float)stim.SMP_distPerCol); 00506 const float startx = round(divX/2); 00507 const float starty = round(divY/2); 00508 const uint movieHalf = (uint)round((float)itsFrameCount/2.0F); 00509 const uint fastBlink = itsFastRate; 00510 const uint slowBlink = itsSlowRate; 00511 00512 uint targBlinkRate; 00513 uint distBlinkRate; 00514 00515 // slighly randomize the change time 00516 const uint changeFrame = (uint)floor((movieHalf/2)+(movieHalf*rand()/(RAND_MAX+1.0))); 00517 00518 // define the speed at which the target blinks 00519 if(stim.SMP_targetRate == SM_FAST_STIM) 00520 targBlinkRate = fastBlink; 00521 else if(stim.SMP_targetRate == SM_SLOW_STIM) 00522 targBlinkRate = slowBlink; 00523 else 00524 targBlinkRate = 0; 00525 00526 // define the speed at which the distractors blink 00527 if(stim.SMP_distRate == SM_FAST_STIM) 00528 distBlinkRate = fastBlink; 00529 else if(stim.SMP_distRate == SM_SLOW_STIM) 00530 distBlinkRate = slowBlink; 00531 else 00532 distBlinkRate = 0; 00533 00534 //const float Randy = (1.0*rand()/(RAND_MAX+1.0)); 00535 00536 //float targAccelBase; 00537 //float distAccelBase; 00538 00539 // Compute change rates as random over distractors or target 00540 /* 00541 if(targState > SM_STATE_STEADY) 00542 { 00543 targAccelBase = ((float)targBlinkRate/2.0F)*Randy; 00544 } 00545 00546 if(distState > SM_STATE_STEADY) 00547 { 00548 distAccelBase = ((float)distBlinkRate/2.0F)*Randy; 00549 } 00550 */ 00551 00552 // allocate target 00553 uint currTargBlinkRate = targBlinkRate; 00554 int currTargBlinkOffset = 0; 00555 //uint currTargBlinkCount = 0; 00556 uint currTargShape = stim.SMP_targetShape; 00557 uint currTargColor = stim.SMP_targetColor; 00558 uint currTargSizeX = stim.SMP_targetSizeX; 00559 uint currTargSizeY = stim.SMP_targetSizeY; 00560 bool currTargOn = stim.SMP_targetOn; 00561 00562 LINFO("Computing target values"); 00563 // Start the target randomly? 00564 if(stim.SMP_useRandomStart == SM_USE_RANDOM_START) 00565 { 00566 const float distRand = (1.0*rand()/(RAND_MAX+1.0)); 00567 currTargBlinkOffset = (uint)round((float)distBlinkRate*distRand); 00568 const float onRand = (1.0*rand()/(RAND_MAX+1.0)); 00569 if(onRand > .5) 00570 currTargOn = true; 00571 else 00572 currTargOn = false; 00573 } 00574 // assign the target a random shape? 00575 if(stim.SMP_targetShape == SM_STIM_RAND) 00576 { 00577 const float distRand = 1.0F + (((float)(SM_SHAPES))*rand()/ 00578 (RAND_MAX+1.0F)); 00579 currTargShape = (uint)distRand; 00580 } 00581 // assign the target a random color? 00582 if(stim.SMP_targetColor == SM_COLOR_RAND) 00583 { 00584 const float distRand = 1.0F + (((float)(SM_COLORS-1.0F))*rand()/ 00585 (RAND_MAX+1.0F)); 00586 currTargColor = (uint)distRand; 00587 } 00588 // do we need to give a random size to the target? 00589 if(stim.SMP_targetSizeX == 0) 00590 { 00591 const float maxSizeX = divX; 00592 const float distRandX = 1.0F + (((float)(maxSizeX-1.0F))*rand()/ 00593 (RAND_MAX+1.0F)); 00594 currTargSizeX = (uint)distRandX; 00595 const float maxSizeY = divY; 00596 const float distRandY = 1.0F + (((float)(maxSizeY-1.0F))*rand()/ 00597 (RAND_MAX+1.0F)); 00598 currTargSizeY = (uint)distRandY; 00599 } 00600 00601 LINFO("Setting up distractor vectors"); 00602 // allocate vectors for distractors 00603 std::vector<ushort> distInit(stim.SMP_distPerCol,0); 00604 std::vector<int> distInitS(stim.SMP_distPerCol,0); 00605 std::vector<float> distInitF(stim.SMP_distPerCol,0); 00606 00607 std::vector<std::vector<ushort> > 00608 currDistBlinkRate(stim.SMP_distPerRow,distInit); 00609 std::vector<std::vector<ushort> > 00610 currDistShape(stim.SMP_distPerRow,distInit); 00611 std::vector<std::vector<ushort> > 00612 currDistColor(stim.SMP_distPerRow,distInit); 00613 std::vector<std::vector<ushort> > 00614 currDistSizeX(stim.SMP_distPerRow,distInit); 00615 std::vector<std::vector<ushort> > 00616 currDistSizeY(stim.SMP_distPerRow,distInit); 00617 std::vector<std::vector<ushort> > 00618 currPosX(stim.SMP_distPerRow,distInit); 00619 std::vector<std::vector<ushort> > 00620 currPosY(stim.SMP_distPerRow,distInit); 00621 00622 std::vector<std::vector<int> > 00623 currDistBlinkOffset(stim.SMP_distPerRow,distInitS); 00624 00625 std::vector<std::vector<float> > 00626 currDistOrientation(stim.SMP_distPerRow,distInitF); 00627 00628 std::vector<bool> distOnInit(stim.SMP_distPerCol,stim.SMP_distOn); 00629 std::vector<std::vector<bool> > currDistOn(stim.SMP_distPerRow,distOnInit); 00630 00631 // (1) define the starting blink rate for each distractor 00632 // (2) define when its offset 00633 // (3) define its start state 00634 // (4) define shape 00635 // (5) define color 00636 00637 LINFO("Setting up distractors"); 00638 for(uint i = 0; i < stim.SMP_distPerRow; i++) 00639 { 00640 for(uint j = 0; j < stim.SMP_distPerCol; j++) 00641 { 00642 // determine start offset if random 00643 if(stim.SMP_useRandomStart == SM_USE_RANDOM_START) 00644 { 00645 const float distRand = (1.0F*rand()/(RAND_MAX+1.0)); 00646 currDistBlinkOffset[i][j] = (uint)round((float)distBlinkRate*distRand); 00647 const float onRand = (1.0F*rand()/(RAND_MAX+1.0)); 00648 if(onRand > 0.5F) 00649 currDistOn[i][j] = true; 00650 else 00651 currDistOn[i][j] = false; 00652 } 00653 else 00654 { 00655 currDistBlinkOffset[i][j] = 0; 00656 } 00657 00658 // determine distractor shape if random 00659 if(stim.SMP_distShape == SM_STIM_RAND) 00660 { 00661 const float distRand = 1.0F + (((float)(SM_SHAPES))*rand()/ 00662 (RAND_MAX+1.0F)); 00663 currDistShape[i][j] = (ushort)distRand; 00664 } 00665 else 00666 { 00667 currDistShape[i][j] = stim.SMP_distShape; 00668 } 00669 00670 // determine distractor color if random 00671 if(stim.SMP_distColor == SM_COLOR_RAND) 00672 { 00673 const float distRand = 1.0F + (((float)(SM_COLORS - 1.0F))*rand()/ 00674 (RAND_MAX+1.0F)); 00675 00676 //std::cerr << ">>>>>NEW COLOR IS " << distRand << "\n"; 00677 currDistColor[i][j] = (ushort)distRand; 00678 } 00679 else 00680 { 00681 currDistColor[i][j] = stim.SMP_distColor; 00682 } 00683 00684 // determine distractor size if random 00685 if(stim.SMP_distSizeX == 0) 00686 { 00687 const float maxSizeX = divX; 00688 const float distRandX = 1.0F + (((float)(maxSizeX-1.0))*rand()/ 00689 (RAND_MAX+1.0F)); 00690 currDistSizeX[i][j] = (ushort)distRandX; 00691 const float maxSizeY = divY; 00692 const float distRandY = 1.0F + (((float)(maxSizeY-1.0))*rand()/ 00693 (RAND_MAX+1.0F)); 00694 currDistSizeY[i][j] = (ushort)distRandY; 00695 } 00696 else 00697 { 00698 currDistSizeX[i][j] = stim.SMP_distSizeX; 00699 currDistSizeY[i][j] = stim.SMP_distSizeY; 00700 } 00701 00702 currDistBlinkRate[i][j] = distBlinkRate; 00703 00704 // determine if we need to jitter the position of the target 00705 if(stim.SMP_useHexagon == SM_USE_HEXAGON) 00706 { 00707 float newDiv = 0.0F; 00708 if(j%2 == 0) 00709 newDiv = divX/4; 00710 else 00711 newDiv = -1.0F*divX/4; 00712 // image pixel offset in X for target 00713 currPosX[i][j] = (uint)floor(newDiv + startx + i*divX); 00714 // image pixel offset in Y for target 00715 currPosY[i][j] = (uint)floor(starty + j*divY); 00716 } 00717 else 00718 { 00719 // image pixel offset in X for target 00720 currPosX[i][j] = (uint)floor(startx + i*divX); 00721 // image pixel offset in Y for target 00722 currPosY[i][j] = (uint)floor(starty + j*divY); 00723 } 00724 float posJitterX,posJitterY; 00725 if(stim.SMP_shapePositionJitterStatic != 0.0F) 00726 { 00727 float divider; 00728 if((j == stim.SMP_targetPosJ) && (i == stim.SMP_targetPosI)) 00729 { 00730 if((currTargShape == SM_STIM_DISK) || 00731 (currTargShape == SM_STIM_CROSS) || 00732 (currTargShape == SM_STIM_PATCH) || 00733 (currTargShape == SM_STIM_CIRC)) 00734 divider = 4.0F; 00735 else 00736 divider = 2.0F; 00737 00738 posJitterX = ((float)stim.SMP_targetSizeX) 00739 *(stim.SMP_shapePositionJitterStatic*rand()) 00740 /(RAND_MAX+1.0F) - stim.SMP_distSizeX/divider; 00741 posJitterY = ((float)stim.SMP_targetSizeY) 00742 *(stim.SMP_shapePositionJitterStatic*rand()) 00743 /(RAND_MAX+1.0F) - stim.SMP_distSizeY/divider; 00744 00745 } 00746 else 00747 { 00748 if((currDistShape[i][j] == SM_STIM_DISK) || 00749 (currDistShape[i][j] == SM_STIM_CROSS) || 00750 (currDistShape[i][j] == SM_STIM_PATCH) || 00751 (currDistShape[i][j] == SM_STIM_CIRC)) 00752 divider = 4.0F; 00753 else 00754 divider = 2.0F; 00755 00756 00757 posJitterX = ((float)stim.SMP_targetSizeX) 00758 *(stim.SMP_shapePositionJitterStatic*rand()) 00759 /(RAND_MAX+1.0F) - stim.SMP_distSizeX/divider; 00760 posJitterY = ((float)stim.SMP_targetSizeY) 00761 *(stim.SMP_shapePositionJitterStatic*rand()) 00762 /(RAND_MAX+1.0F) - stim.SMP_distSizeY/divider; 00763 } 00764 } 00765 else 00766 { 00767 posJitterX = 0.0F; 00768 posJitterY = 0.0F; 00769 } 00770 currPosX[i][j] = (ushort)(round(posJitterX + currPosX[i][j])); 00771 currPosY[i][j] = (ushort)(round(posJitterY + currPosY[i][j])); 00772 00773 // static jitter orientation if needed 00774 float oriJitter = 0.0F; 00775 if((j == stim.SMP_targetPosJ) && (i == stim.SMP_targetPosI)) 00776 { 00777 if(stim.SMP_shapeOrientationJitterStatic != 0.0F) 00778 { 00779 oriJitter = stim.SMP_shapeOrientationJitterStatic * 00780 (((2.0F*M_PI*rand())/(RAND_MAX+1.0F)) - M_PI); 00781 } 00782 currDistOrientation[i][j] = oriJitter + stim.SMP_targetOri; 00783 } 00784 else 00785 { 00786 if(stim.SMP_shapeOrientationJitterStatic != 0.0F) 00787 { 00788 oriJitter = stim.SMP_shapeOrientationJitterStatic * 00789 (((2.0F*M_PI*rand())/(RAND_MAX+1.0F)) - M_PI); 00790 } 00791 currDistOrientation[i][j] = oriJitter + stim.SMP_distOri; 00792 } 00793 } 00794 } 00795 00796 LINFO("Drawing stim images"); 00797 std::vector<Image<PixRGB<float> > >::iterator framesIter = itsFrames.begin(); 00798 while(framesIter != itsFrames.end()) 00799 { 00800 // go over each stim 00801 // be sure not to write over the target 00802 00803 for(uint i = 0; i < stim.SMP_distPerRow; i++) 00804 { 00805 for(uint j = 0; j < stim.SMP_distPerCol; j++) 00806 00807 { 00808 //std::cerr << "."; 00809 // insert the target 00810 if((j == stim.SMP_targetPosJ) && (i == stim.SMP_targetPosI)) 00811 { 00812 // is the target on or have no blink rate? 00813 if((currTargOn) || (currTargBlinkRate == 0)) 00814 { 00815 SM_drawGroundTruth((ushort)frame, 00816 (unsigned char)currTargSizeX, 00817 (unsigned char)currTargSizeY, 00818 (ushort)currPosX[i][j], (ushort)currPosY[i][j], 00819 true); 00820 //std::cerr << "+"; 00821 // draw the target on this image 00822 00823 SM_drawSingleTarget((ushort)frame, 00824 (unsigned char)currTargShape, 00825 (unsigned char)currTargColor, 00826 (unsigned char)currTargSizeX, 00827 (unsigned char)currTargSizeY, 00828 (ushort)currPosX[i][j], (ushort)currPosY[i][j], 00829 currDistOrientation[i][j], 00830 stim.SMP_shapePositionJitter, 00831 stim.SMP_shapeOrientationJitter, true); 00832 } 00833 else 00834 { 00835 SM_drawGroundTruth((ushort)frame, 00836 (unsigned char)currTargSizeX, 00837 (unsigned char)currTargSizeY, 00838 (ushort)currPosX[i][j], (ushort)currPosY[i][j], 00839 false); 00840 } 00841 00842 //std::cerr << "x"; 00843 00844 bool checkSpeed = false; 00845 if(currTargBlinkRate == 0) 00846 checkSpeed = true; 00847 else if(((frame+currTargBlinkOffset) 00848 %currTargBlinkRate) == 0) 00849 checkSpeed = true; 00850 00851 if(checkSpeed) 00852 { 00853 if(currTargBlinkRate != 0) 00854 { 00855 if(currTargOn) 00856 currTargOn = false; 00857 else 00858 currTargOn = true; 00859 } 00860 else 00861 currTargOn = true; 00862 // determin if we need to speed up the distractors 00863 // speed up or start (if possible) 00864 if(stim.SMP_targetState == SM_STATE_START) 00865 { 00866 const uint newRate = SM_speedUpCheck( 00867 currTargBlinkRate, 00868 frame,changeFrame, 00869 stim.SMP_targetRate, 00870 stim.SMP_useSmoothRateChange); 00871 if(newRate != currTargBlinkRate) 00872 { 00873 currTargBlinkOffset = -1*frame; 00874 currTargBlinkRate = newRate; 00875 } 00876 } 00877 // determin if we need to slow down the distractors 00878 // slow down or stop (if possible) 00879 if(stim.SMP_targetState == SM_STATE_STOP) 00880 { 00881 const uint newRate = SM_speedDownCheck( 00882 currTargBlinkRate, 00883 frame,changeFrame, 00884 stim.SMP_targetRate, 00885 stim.SMP_useSmoothRateChange); 00886 if(newRate != currTargBlinkRate) 00887 { 00888 currTargBlinkOffset = -1*frame; 00889 currTargBlinkRate = newRate; 00890 } 00891 } 00892 } 00893 } 00894 else 00895 { 00896 // is this target "on" in this frame 00897 // if the speed is set to zero, we are always "on" 00898 if((currDistOn[i][j]) || (currDistBlinkRate[i][j] == 0)) 00899 { 00900 //std::cerr << "-"; 00901 // draw the target on this image 00902 SM_drawSingleTarget((ushort)frame, 00903 (unsigned char)currDistShape[i][j], 00904 (unsigned char)currDistColor[i][j], 00905 (unsigned char)currDistSizeX[i][j], 00906 (unsigned char)currDistSizeY[i][j], 00907 (ushort)currPosX[i][j], (ushort)currPosY[i][j], 00908 currDistOrientation[i][j], 00909 stim.SMP_shapePositionJitter, 00910 stim.SMP_shapeOrientationJitter, false); 00911 } 00912 //std::cerr << "|"; 00913 // turn target on or off at interval 00914 // If the current frame plus the offset is modulo 0 with the 00915 // rate of blink then turn it on or off 00916 /* 00917 ======= 00918 bool checkSpeed = false; 00919 if(currTargBlinkRate == 0) 00920 checkSpeed = true; 00921 else if(((frame+currTargBlinkOffset) 00922 %currTargBlinkRate) == 0) 00923 checkSpeed = true; 00924 >>>>>>> .r6413 00925 00926 if(checkSpeed) 00927 { 00928 if(currTargBlinkRate != 0) 00929 { 00930 if(currTargOn) 00931 currTargOn = false; 00932 else 00933 currTargOn = true; 00934 } 00935 else 00936 currTargOn = true; 00937 // determin if we need to speed up the distractors 00938 // speed up or start (if possible) 00939 if(stim.SMP_targetState == SM_STATE_START) 00940 { 00941 const uint newRate = SM_speedUpCheck( 00942 currTargBlinkRate, 00943 frame,changeFrame, 00944 stim.SMP_targetRate, 00945 stim.SMP_useSmoothRateChange); 00946 if(newRate != currTargBlinkRate) 00947 { 00948 currTargBlinkOffset = -1*frame; 00949 currTargBlinkRate = newRate; 00950 } 00951 } 00952 // determin if we need to slow down the distractors 00953 // slow down or stop (if possible) 00954 if(stim.SMP_targetState == SM_STATE_STOP) 00955 { 00956 const uint newRate = SM_speedDownCheck( 00957 currTargBlinkRate, 00958 frame,changeFrame, 00959 stim.SMP_targetRate, 00960 stim.SMP_useSmoothRateChange); 00961 if(newRate != currTargBlinkRate) 00962 { 00963 currTargBlinkOffset = -1*frame; 00964 currTargBlinkRate = newRate; 00965 } 00966 } 00967 } 00968 00969 } 00970 else 00971 { 00972 // is this target "on" in this frame 00973 // if the speed is set to zero, we are always "on" 00974 if((currDistOn[i][j]) || (currDistBlinkRate[i][j] == 0)) 00975 { 00976 std::cerr << "-"; 00977 // draw the target on this image 00978 SM_drawSingleTarget((ushort)frame, 00979 (unsigned char)currDistShape[i][j], 00980 (unsigned char)currDistColor[i][j], 00981 (unsigned char)currDistSizeX[i][j], 00982 (unsigned char)currDistSizeY[i][j], 00983 (ushort)currPosX[i][j], (ushort)currPosY[i][j], 00984 stim.SMP_distOri, 00985 stim.SMP_shapePositionJitter, 00986 stim.SMP_shapeOrientationJitter, false); 00987 } 00988 std::cerr << "|"; 00989 */ 00990 // turn target on or off at interval 00991 // If the current frame plus the offset is modulo 0 with the 00992 // rate of blink then turn it on or off 00993 00994 00995 bool checkSpeed = false; 00996 if(currDistBlinkRate[i][j] == 0) 00997 checkSpeed = true; 00998 else if(((frame+currDistBlinkOffset[i][j]) 00999 %currDistBlinkRate[i][j]) == 0)checkSpeed = true; 01000 01001 if(checkSpeed) 01002 { 01003 01004 if(currDistBlinkRate[i][j] != 0) 01005 { 01006 01007 if(currDistOn[i][j]) 01008 currDistOn[i][j] = false; 01009 else 01010 currDistOn[i][j] = true; 01011 } 01012 else 01013 currDistOn[i][j] = true; 01014 // determin if we need to speed up the distractors 01015 // speed up or start (if possible) 01016 01017 if(stim.SMP_distState == SM_STATE_START) 01018 { 01019 01020 const uint newRate = SM_speedUpCheck( 01021 currDistBlinkRate[i][j], 01022 frame,changeFrame, 01023 stim.SMP_distRate, 01024 stim.SMP_useSmoothRateChange); 01025 if(newRate != currDistBlinkRate[i][j]) 01026 { 01027 currDistBlinkOffset[i][j] = -1*frame; 01028 currDistBlinkRate[i][j] = newRate; 01029 } 01030 } 01031 01032 // determin if we need to slow down the distractors 01033 // slow down or stop (if possible) 01034 if(stim.SMP_distState == SM_STATE_STOP) 01035 { 01036 01037 const uint newRate = SM_speedDownCheck( 01038 currDistBlinkRate[i][j], 01039 frame,changeFrame, 01040 stim.SMP_distRate, 01041 stim.SMP_useSmoothRateChange); 01042 if(newRate != currDistBlinkRate[i][j]) 01043 { 01044 currDistBlinkOffset[i][j] = -1*frame; 01045 currDistBlinkRate[i][j] = newRate; 01046 } 01047 } 01048 } 01049 } 01050 } 01051 } 01052 01053 frame++; ++framesIter; 01054 //std::cerr << "\n"; 01055 } 01056 LINFO("Drawing complete"); 01057 } 01058 01059 /*****************************************************************************/ 01060 01061 std::vector<Image<PixRGB<float> > > StimMaker::SM_getStim() const 01062 { 01063 return itsFrames; 01064 } 01065 01066 /*****************************************************************************/ 01067 01068 std::vector<Image<PixRGB<float> > > StimMaker::SM_getGroundTruth() const 01069 { 01070 return itsGroundTruth; 01071 } 01072 01073 #endif // STIM_MAKER_H_DEFINED 01074 01075 01076 01077