-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjumpingstandorientation.m
executable file
·519 lines (466 loc) · 15.1 KB
/
jumpingstandorientation.m
1
% jumpingstandorientation.m% Version 1.6 2012-08-27% Copyright (c) 2003-2008 David Jones All Rights Reserved.function jumpingstandorientation(stim,NOISE,coarse,training,hv)fprintf('Jumping Stand Visual Stimulus Display ');fprintf('... Gratings and Orientation-in-Noise\n');fprintf('Version 1.6 2012-08-27, ');fprintf('Copyright (c) 2003-2012 David Jones. All Rights Reserved.\n\n');%% Revisions:%% 1.6 27aug12 - added dialog box to select viewing angle% - increased font size to 30 (for displaying signal levels)%% 1.54 18jul08 - for grating stimulus, numeric keys step down staircase by multiple steps%% 1.53 14may08 - target grating is always vertical, but new "hv" parameter selects alternative ...% - hv == 1, selects horizontal distractor% - hv == 0, selects "blank" distractor ... noise scrambled%% 1.52 17apr08 - display spatial frequencies in a table% fixed spatfreq calculation to use viewdist_cm% 1.51 26feb08 - added 'create_perm_table' function% to precompute row permutations used in scramble_rows% this speeds up the stimulus computation in the GRATING condition% 1.5 09feb08 - added 'scramble_rows' function% - img2 in grating condition is scrambled version of grating% (to keep same mean luminance)% 1.4 12jun07 - allow even lower signal levels%% 1.3 18feb07 - switched to 16 steps per octave% - increase font size to 20 (for displaying signal levels)% - print list of various signal levels%% 1.2 22feb07 - added support for 10-bit clut% - hide cursor during experiment% - display signal value as percentage% - edges of circular mask are now anti-aliased% - added explicit "steps_per_octave" variable% - allow "step" variable to go negative%% 1.1 19jun03 - fixed grey lookup table problem% - added parameters for screen dimensions and viewing distance% - added calculations for viewing angle and spatial frequency of stimulus% 1.0 17jun03 - original version% - - - - -% Jumpingstand Display of Local Orientation Noise Stimulus%% There are 2 main versions of this program:%% jumpingstandorientation(1,...);% This displays a simple example in a MATLAB figure%% jumpingstandorientation(2,...);% This uses PsychToolbox routines to display the stimulus.% ... use arrow keys to change signal level UP or DOWN% ... use arrow keys to move signal to LEFT or RIGHT side% ... hit RETURN to quit the demo%% NOISE == 0 -> grating% NOISE == 1 -> local orientation noise%% coarse == 0 -> fine orientation noise% coarse == 1 -> coarse orientation noise% Check argumentsif stim < 1 | stim > 2 fprintf('jumpingstandorientation: stim parameter must be 1 or 2\n'); return;endif NOISE < 0 | NOISE > 1 fprintf('jumpingstandorientation: NOISE parameter must be 0 or 1\n');endif coarse < 0 | coarse > 1 fprintf('jumpingstandorientation: coarse parameter should be 0 or 1\n');endif exist('hv','var') if hv ~= 0 & hv ~= 1 fprintf('jumpingstandorientation: hv parameter should be 0 or 1\n'); endelse hv = 0;end% Parameters range (default)background = 128; % background grey level, 0 .. 255 (128)contrast = 0.95; % contrast, 0.0 .. 1.0 (1)signal = 1.0; % orientation signal, 0.0 .. 1.0 (0.9)block = 9; % block size, in pixels, 1 .. 10 (4) % ... make "block" bigger for coarser patterndiameter = 0.8; % diameter of circle, 0.1 .. 1.0 (0.8) % ... diameter is fraction of half-width of screenPTB = 1; % use Psychtoolbox 1/0 (1) % ... should be 1 when running experiment % ... should be 0 when testing/debugging DONALD = 0;if DONALD screen_width_cm = 32.5; % Donald's screen width in centimetres (32.5) screen_width_pixels = 1024; % Donald's screen width in pixels (1024) screen_height_pixels = 758; if coarse block = 9; else block = 4; endelse screen_width_cm = 48; % Kathy's screen width in centimetres (48) screen_width_pixels = 2304; % Kathy's screen width in pixels (2304) screen_height_pixels = 1440; if coarse block = 13; else block = 6; endendviewdist_cm = 57; % default viewing distance in centimetressteps_per_octave = 16; %step_max = 4 * steps_per_octave; %% NOISE = 0; % 1 = NOISE, 0 = GRATINGgamma_exp = 1.4; % 1.730;gamma_min = 0.025; % 0.131;% simply display stimulus in MATLAB figureif stim == 1 n = 100; mask = circular_mask(n, diameter*n); img1 = local_ori_stim(n,contrast,signal); img1 = background*(1-mask) + img1.*mask; img2 = local_ori_stim(n,contrast,0); img2 = background*(1-mask) + img2.*mask; grey = repmat((0:255)'/255,1,3); % grey ramp lookup table figure(1); imagesc([img1, img2]), colormap(grey), axis image; %% period = signal * 0.33 * diameter * n; img1 = grating_stim(n,contrast,period); img1 = background*(1-mask) + img1.*mask; img2 = grating_stim(n,0,period); img2 = background*(1-mask) + img2.*mask; figure(2); imagesc([img1, img2]), colormap(grey), axis image; % display stimulus using PsychToolbox routineselseif stim == 2 if PTB w = SCREEN(0,'OpenWindow',background); bits = ScreenDacBits(0); grey = round((0:255) * (2^bits - 1) / 255); grey = gamma_corrected_ramp(gamma_exp,gamma_min,bits); grey = repmat(grey',1,3); % grey ramp lookup table LoadClut(w,grey); viewdist_cm = SCREEN(w,'Dialog','Type a value for viewing distance in centimetres', viewdist_cm);% if NOISE% block=SCREEN(w,'Dialog','Type a value for block size in pixels', block);% end HideCursor; res = SCREEN(0,'Resolution'); if res.width ~= screen_width_pixels fprintf('warning: PsychToolbox says screen resolution is %d x %d pixels\n', res.width, res.height); fprintf('warning: but screen resolution is supposed to be %d x %d pixels\n\n', screen_width_pixels, screen_height_pixels); end else w = 0;% viewdist_cm = 65; res = []; res.width = screen_width_pixels; res.height = screen_height_pixels; end % Create a 'Rect' on screen where the stimulus will be displayed. % The stimulus will be expanded (by a factor of "block") to fill the 'Rect' % The 'Rect' is centered on the screen. n = min(res.width/2,res.height); if NOISE n = floor(n/block); rect = ScaleRect([0 0 2*n n], block,block); stimulus_width_pixels = block*floor(diameter*n); else rect = [0 0 2*n n]; stimulus_width_pixels = floor(diameter*n); end %% "diameter" adjustment ... begin % to achieve desired stimulus size (in degrees of visual angle) viewangle_degrees = viewingangle((stimulus_width_pixels/screen_width_pixels)*screen_width_cm, viewdist_cm); if PTB viewangle_degrees = SCREEN(w,'Dialog','Type a value for viewing angle in degrees', viewangle_degrees); else fprintf('(debug) For viewing distance %.1f cm, max viewing angle is %.2f degrees\n', viewdist_cm, viewangle_degrees); viewangle_degrees = 15; end stimulus_width_cm = stimwidth(viewdist_cm, viewangle_degrees); stimulus_width_pixels = (stimulus_width_cm / screen_width_cm) * screen_width_pixels; if NOISE diameter = stimulus_width_pixels / (block*n); stimulus_width_pixels = block*floor(diameter*n); else diameter = stimulus_width_pixels / n; stimulus_width_pixels = floor(diameter*n); end if diameter > 0.90 fprintf('ERROR: Stimulus is too large to display.\n'); fprintf('\tviewing distance = %.1f cm\n', viewdist_cm); fprintf('\tviewing angle = %.2f degrees\n', viewangle_degrees); fprintf('\t"diameter" variable = %.2f (max = 0.90)\n', diameter); SCREEN('CloseAll'); ShowCursor; return end viewangle_degrees = viewingangle((stimulus_width_pixels/screen_width_pixels)*screen_width_cm, viewdist_cm); % "diameter" adjusment ... end %% check viewing angle calculation% fprintf('check viewing angle calculation: 1 cm @ 57 cm = %5.2f degrees (should be about 1 degree)\n', ...% viewingangle(1,57));% for d = [viewdist_cm 43, 60, 90]% angle = viewingangle((stimulus_width_pixels/screen_width_pixels)*screen_width_cm,d);% spatfreq = (n/2)/angle;% fprintf('viewing distance = %d, diameter = %5.2f degrees, spatial frequency = %6.3f cycles/degree\n', ...% d, angle, spatfreq);% end %% rect = CenterRect(rect, SCREEN(w,'Rect')); mask = circular_mask(n, floor(diameter*n)); background_mask = background * (1 - mask); % print out the stimulus dimensions fprintf('Stimulus Viewing Parameters:\n'); fprintf('n = %d, block = %d, stimulus diameter = %g pixels\n', ... n,block,stimulus_width_pixels); fprintf('viewing distance = %.1f cm, viewing angle = %.2f degrees\n', ... viewdist_cm, viewangle_degrees); %% Print list of signal levels if NOISE fprintf('\nSignal Levels used in Experiment: (%d steps per octave)\n', steps_per_octave); pos = 1; for step = step_max : -1 : 1 signal = 0.01*(6.25*(2.^(step/steps_per_octave))); fprintf(' %5.1f', signal*100); pos = pos + 1; if pos > 8 fprintf('\n'); pos = 1; end end else fprintf('\nSpatial Frequencies used in Experiment: (%d steps per octave)\n', steps_per_octave); pos = 1; for step = step_max : -1 : -step_max signal = 0.01*(6.25*(2.^(step/steps_per_octave))); period = signal * 0.33 * diameter * n; spatfreq = 1/viewingangle(period*screen_width_cm/screen_width_pixels, viewdist_cm); fprintf(' %7.4f', spatfreq); pos = pos + 1; if pos > 8 fprintf('\n'); pos = 1; end if period < 5 fprintf('\n'); break end end end if ~PTB return end %% Done printing list of signal levels side = 1; % 1 = left, 2 = right KeyLeft = KbName('left'); KeyRight = KbName('right'); KeyUp = KbName('up'); KeyDown = KbName('down'); KeyPageUp = KbName('PageUp'); KeyPageDown = KbName('PageDown'); KeyReturn = KbName('return'); KeyNumeric = zeros(9,1); for i = 1:9 KeyNumeric(i) = KbName(sprintf('%d',i)); end%% BUG in PsychToolbox, KbName gives: [ 84 ... 93 ]%% KeyNumeric = [ 19 20 21 22 24 23 27 29 26 ]; SCREEN(w,'TextFont', 'Courier'); SCREEN(w,'TextSize', 30); if ~NOISE create_perm_table(n); end % grating: start at lowest spatial frequency % noise: start with 100% signal step = step_max; signal = 1.0; stepsize = 1; while 1 if NOISE img1 = local_ori_stim(n,contrast,signal); if training img2 = local_ori_stim(n,0,0); else img2 = local_ori_stim(n,contrast,0); end else period = signal * 0.33 * diameter * n; img1 = grating_stim(n,contrast,period); if hv == 0 img2 = scramble_rows(n,img1); else img2 = img1'; end % img2 = grating_stim(n,0,4); %% img2 = grating_stim(n,contrast,4); end img1 = background_mask + img1.*mask; img2 = background_mask + img2.*mask; if side == 1 stimulus = [img1, img2]; loc = 'Left '; else stimulus = [img2, img1]; loc = 'Right'; end SCREEN(w,'FillRect',background); SCREEN(w,'PutImage',stimulus,rect); if NOISE msg = sprintf('%s, dist = %.1f cm, angle = %.1f deg, signal = %6.2f percent', ... loc, viewdist_cm, viewangle_degrees, signal*100); else spatfreq = 1/viewingangle(period*screen_width_cm/screen_width_pixels, viewdist_cm); msg = sprintf('%s, dist = %.1f cm, angle = %.1f deg, period = %.2f pixels = %.2f cm, step = %d/%d octave, spat freq = %.3f cyc/deg', ... loc, viewdist_cm, viewangle_degrees, period, period * screen_width_cm / screen_width_pixels, stepsize, steps_per_octave, spatfreq); end SCREEN(w,'DrawText',msg,30,30,255); FlushEvents('KeyDown'); t = KbWait; % wait for a key press [ KeyIsDown, t, KeyCode ] = KbCheck; if KeyCode(KeyLeft) side = 1; elseif KeyCode(KeyRight); side = 2; elseif KeyCode(KeyUp) step = step+2*stepsize; if step >= 64 step=64; end signal = 0.01*(6.25*(2.^(step/steps_per_octave))); elseif KeyCode(KeyDown) step=step-stepsize; % if NOISE & step <= 0 % step=0; % end signal = 0.01*(6.25*(2.^(step/steps_per_octave))); elseif KeyCode(KeyPageUp) step = step + steps_per_octave; if step >= 64 step = 64; end signal = 0.01*(6.25*(2.^(step/steps_per_octave))); elseif KeyCode(KeyPageDown) step = step - steps_per_octave; % if NOISE & step <= 0 % step=0; % end signal = 0.01*(6.25*(2.^(step/steps_per_octave))); elseif KeyCode(KeyReturn) break; else% fprintf('KeyCode = ');% for i = 1:128% if KeyCode(i)% fprintf('%d ', i);% end% end% fprintf('\n'); for i = 1:9 if KeyCode(KeyNumeric(i)) step = step - i*stepsize; signal = 0.01*(6.25*(2.^(step/steps_per_octave))); break end end end while Kbcheck; end % wait until key is released end SCREEN('CloseAll'); ShowCursor;else fprintf('oridemo: stim must be 1 or 2\n');endreturn% viewingangle% ... calculates viewing angle of stimulus% ... given stimulus width in centimetres% ... and viewing distance in centimetresfunction angle = viewingangle(width_cm,viewdist_cm)angle = 2*(180/pi)*atan2(width_cm/2, viewdist_cm);return% stimwidth% ... calculates stimulus width in centimetres% ... given viewing distance in centimetres% ... and viewing angle in degreesfunction width = stimwidth(viewdist_cm,viewangle_degrees)width = 2*viewdist_cm*tan((pi/180)*(viewangle_degrees/2));return% circular_mask% ... creates n x n image% ... with pixels inside a circle set to 1% ... and pixels outside the circle set to 0function mask = circular_mask(n,diameter)% mask = repmat(((1:n)-(n/2)).^ 2, n,1); % mask = (mask + mask') < (diameter/2)^2;mask = repmat(((1:n)-((1+n)/2)).^ 2, n,1); mask = max(0, min(1, (((diameter+1)/2) - sqrt(mask + mask'))*(1/2) ));return% local_ori_stim% ... creates n x n image% ... containing vertical orientation stimulus% ... the strength of the function stimulus = local_ori_stim(n,contrast,signal)stimulus = zeros(n,n);oldpixel = 128 + 255*contrast*(rand(1,n)-0.5);for i = 1:n change = rand(1,n) > signal; newpixel = 128 + 255*contrast*(rand(1,n)-0.5); oldpixel = change .* newpixel + (1-change) .* oldpixel; stimulus(i,:) = oldpixel;endreturn% grating_stim% ... creates n x n image% ... containing vertical grating% ...function stimulus = grating_stim(n,contrast,period)% wave = square_wave(n,period);wave = sine_wave(n,period);stimulus = 128 + 127 * contrast * repmat(wave, n,1);% stimulus = stimulus';returnfunction wave = sine_wave(n,period)wave = sin(2*pi*(rand + (1:n)/period));returnfunction wave = square_wave(n,period)s = sign(sine_wave(4*n,4*period));wave = zeros(1,n);for i = 1:n wave(i) = sum(s((i-1)*4+(1:4)))/4;endreturn% gamma_corrected_ramp% ...function g = gamma_corrected_ramp(gamma_exp, gamma_min, bits)g = zeros(1,256);for i = 0:255 g(i+1) = ((i/255) ^ (1/gamma_exp) * (1 - gamma_min) + gamma_min) * (2^bits - 1);endreturn% scramble_rows% ... function new = scramble_rows(n,img)global perm;new = img;p = randperm(n);pixels = img(1,:);for i = 1:n new(i,:) = pixels(perm(p(i),:));endreturn% create_perm_table% ...function create_perm_table(n)global perm;perm = zeros(n);for i = 1:n perm(i,:) = randperm(n);endreturn