Psychtoolbox

We don’t want to run this experiment on the Matlab figure window, since as you can see it is slow and clunky. So we are going to start using a group of Matlab programs developed especially for doing behavioral experiments. Many groups have developed similar sets of programs, but the ones we are going to use are called PsychToolbox.

Contents

What is Psychtoolbox?

Psychtoolbox is a free set of MATLAB functions which help researchers carry out vision research on Macintosh and Windows computers. It is a collection of matlab functions written to make presenting visual stimuli easier.It was written by David Brainard, Denis Pelli, Mario Kleiner and Allen Ingling.

The current version of Psychtoolbox is based on OpenGL commands. At its most basic level OpenGL is simply a document that describes a set of functions and the precise behaviours that they must perform. One of the important things about OpenGL is that functions are supposed to work across platforms. From this specification, hardware and software vendors create implementations — libraries of functions created to match the functions stated in the OpenGL specification. Vendors have to meet specific tests to be able to qualify their implementation as an OpenGL implementation. OpenGL is also used in CAD, virtual reality, scientific visualization, information visualization, and flight simulation, as well as (of course) video games.

Downloading Psychtoolbox

You need to download PsychToolbox from here:

http://psychtoolbox.org/

Make sure you download the right version (for MacOSX or PC). Once you have installed PsychToolbox, then you can carry on with this chapter.

Citing Psychtoolbox

Remember to cite the Toolbox. Citing the toolbox isn't just the right thing to do - it's a way of demonstrating that the toolbox is useful so that agencies like the NIH will keep funding it.

"We wrote our experiments in MATLAB, using the Psychophysics Toolbox extensions (Brainard, 1997; Pelli, 1997)."

Brainard, D. H. (1997) The Psychophysics Toolbox, Spatial Vision , 10:443-446. Pelli, D. G. (1997) The VideoToolbox software for visual psychophysics: Transforming numbers into movies, Spatial Vision 10:437-442.

Getting started with PsychToolbox Screen.m

Start with just 1 monitor

Try:

ScreenTest

If you get the screen going blank and then something like the following then screenTest worked

If not, then Psychtoolbox isn't working right on your computer

Writing code using Screen.m

The next stage is also very simple. We are simply going to open an experimental window, making it black, making it white, and then closing it again.

The script below uses a command called Screen, which is one of the core functions of PsychToolbox. Screen is actually not an m file (like the ones you have been writing till now). It is a mex file. This means that it is written in C (or C++) or some other programming language, and is then compiled to run in Matlab. The reason this was done is because Screen does some pretty funky stuff that would be impossible in Matlab.

Oddly, under certain circumstances the Screen command likes to have a capital letter (it is case sensitive unlike most commands in Matlab).

FlipScreen.m

% FlipScreen.m
% opens a window using Psychtoolbox,
% makes the window black, then white, and then closes
% the window again
%
% written for Psychtoolbox 3 on the PC by IF 3/2007
screen=0;
[wPtr,rect]=Screen('OpenWindow',screen, [], []);
HideCursor;
tic
while toc<2
end

black=BlackIndex(wPtr);
Screen('FillRect',wPtr,black, [100 200 300 700]);
Screen(wPtr, 'Flip');
tic
while toc<2
end

white=WhiteIndex(wPtr);
Screen('FillRect',wPtr,black);
Screen('FillRect',wPtr,white, [50 50 700 250] );
Screen(wPtr, 'Flip');

tic
while toc<2
end

Screen('Close', wPtr);

help with Screen

There are two ways of getting help with screen If you type:

help Screen

Screen

You get some general information about screen

If you type:

Screen

Commands within Screen

You get a list of all the subcommands that are contained within Screen. To get more information about a particular command type:

Screen OpenWindow?
Screen DrawText?

Caveat

You should bear in mind that you are entering the murky world of not-quite-professional code. Much of this code is written by people like you, in the middle of trying to do real science. This means that commands may not work as stated, help files may be out of date, commands may not even exist.

Code comments for FlipScreen

screen=0;

[wPtr,rect]=Screen('OpenWindow',screen); Currently the command Screen is taking two arguments.

The first argument is the text string 'OpenWindow' which is telling Screen what you want it to do - open a window.

The second argument tells the command Screen which computer monitor you want to use. If you are running more than one monitor on your computer then 0 means the monitor with the menu bar, 1 means any other monitor. For now, if you have any difficulty I would make sure you are only using one monitor.

Two arguments are returned. wPtr is a handle or window pointer to the window - almost like a variable name that refers to the window. We will use it later to poke things into the window.

rect describes the size of the window. You can see how big your monitor's window is by just typing:

rect

You'll learn more about rect a little later.

when using OpenWindow with Screen, you can use up to 9 arguments. they are listed in the first line of the help file when you type:

Screen OpenWindow?

Calling screen

[windowPtr,rect]=Screen('OpenWindow',windowPtrOrScreenNumber [,color] [,rect][,pixelSize][,numberOfBuffers][,stereomode][,multisample][,imaging mode]);

The square brackets [] mean that a command is optional - if you don't specify it then Screen will use a default value.

Arguments for Screen

Note that instead of using a single number that is an index into the colormap, we are using 3 values - for the red, green and blue guns. There is a weirdness here. If you look at the Display in the control panels you will notice that your monitor probably thinks that it is a 32 bit monitor, but these values are on an 8 bit scale. This is because allowing the red gun to take any number between 0-255 takes up 8 bits, allowing the green gun to take any number between 0-255 takes up 8 bits, allowing the blue gun to take any number between 0-255 takes up 8 bits. 3x8 is 24. The other 8 bits are padding – don’t ask me what they are used for.

HideCursor

HideCursor

gets rid of the cursor. It will be restored when you close the screen unless you have a crash in the middle. If so, you may need to type ShowCursor in the command window if your cursor remains missing

Pausing

tic
while toc<2
end

this simply pauses the program for 2 seconds

BlackIndex & WhiteIndex

black=BlackIndex(wPtr);

white=WhiteIndex(wPtr);

These commands find the color lookup table values (clut) given the screen depth of your computer that will that will give you black or white. Weirdly, the values of white and black depend on the screen depth, especially on Macs

FillRect

Screen('FillRect',wPtr,black); Screen('FillRect',wPtr,white);

FillRect fills a rectangle the size of the screen to be black or white

Screen('FillRect', windowPtr [,color] [,rect] )

You can also specify rgb values for the color Screen('FillRect', wPtr , [255 0 0 ]);

or draw a rectangle that is smaller than the window Screen('FillRect', wPtr [0 255 0 ] [0 0 50 50])

Flip

Screen(wPtr, 'Flip');

Whenever you draw something it is drawn offscreen You then need to Flip the screen so the offscreen window you drew on comes to the onscreen window – the one that is actually on the monitor.

Monitors have a refresh rate of something between 60Hz-120Hz (for a standard monitor). Every refresh begins at the top of the screen, and moves quickly down the screen in a matter of a few milliseconds. The flip command simply tells Matlab to refresh the screen with the image you have drawn offscreen.

Close

Screen('Close', wPtr);

This closes the screen and restores your normal working environment, including your cursor

If your screen freezes

The Screen window will hide the main menu bar and obscure the Matlab command window. That can be a problem if your program stops (perhaps due to an error) before closing the window. The keyboard will seem to be dead because the output of the keyboard is directed to the front most window, which belongs to Screen not Matlab, so Matlab won’t be aware of your typing.

Remain calm.

Force Quit in Windows

Ctrl-c

This halts any program. (Type a "c" while holding down the "Ctrl" key).

Alt-Tab brings the Matlab Command window forward. The screen might still be hard to make out (or invisible), if you’ve been playing with the lookup table. Don't let that worry you. Just type

clear Screen

This will cause Matlab to flush Screen. Screen.mex, as part of its exit procedure, cleans up everything it did, closing all its windows and restoring the lookup table of all its displays.

You might want to type:

clear all
clear mex

after killing a program, just to make sure everything is back to normal. clear mex kills any mex files that might be still running

If that didn't work?

Sometimes, Ctrl-C fails to halt progams executing in a Matlab process run with the "-nojvm" option. To halt a runaway Psychtoolbox script in Psychtoolbox you might resort to the Windows Task Manager to kill the Screen program. (Use Ctrl-Alt-Delete to open the Task Manager.)

Force Quit in Mac

Ctrl-c

This halts any program. (Type a "c" while holding down the "Ctrl" key).

Cmd-0 (command-zero; command is the thing that looks like a four leaf clover) brings the Matlab Command window forward. The screen might still be hard to make out (or invisible), if you’ve been playing with the lookup table. Don't let that worry you. Just type

clear Screen

This will cause Matlab to flush Screen. Screen.mex, as part of its exit procedure, cleans up everything it did, closing all its windows and restoring the lookup table of all its displays.

You might want to type:

clear all
clear mex

after killing a program, just to make sure everything is back to normal. clear mex kills any mex files that might be still running

If that didn't work?

Sometimes, Ctrl-C fails to halt progams executing in a Matlab process. To halt a runaway Psychtoolbox script in you might resort to Apple-Command-Escape which executes "Force Quit" on Matlab, closing Matlab and all of its windows.

Force Quit in Linux

Ctrl-Alt-Escape , followed by a mouse click kills the onscreen windows and your Matlab session.

You might want to type:

clear all
clear mex

after killing a program, just to make sure everything is back to normal. clear mex kills any mex files that might be still running

FunkyScreen

Here is another more elaborate example of how you can use Screen

%  FunkyScreen.m
%
%  opens a window using psychtoolbox,
%  makes the window do some funky things
%
%  written for Psychtoolbox 3 on the PC by IF 3/2007

screenNum=0;
flipSpd=13; %  a flip every 13 frames

[wPtr,rect]=Screen('OpenWindow',screenNum);

monitorFlipInterval=Screen('GetFlipInterval', wPtr);

black=BlackIndex(wPtr);
white=WhiteIndex(wPtr);

% blank the Screen and wait a second
Screen('FillRect',wPtr,black);
Screen(wPtr, 'Flip');
HideCursor;
tic
while toc<1
end

% make a rectangle in the middle of the screen flip colors and size
Screen('FillRect',wPtr,black);
vbl=Screen(wPtr, 'Flip'); % collect the time for the first flip with vbl
for i=1:10
    Screen('FillRect',wPtr,[0 0 255], [100 150 200 250]);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
    % flip 13 frames after vbl
    Screen('FillRect',wPtr,[255 0 0], [100 150 400 450]);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
end

% blank the screen and wait a while
Screen('FillRect',wPtr,black);
Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
tic
while toc<1
end

% make circles flip colors & size
Screen('FillRect',wPtr,black);
vbl=Screen(wPtr, 'Flip');
for i=1:10
    Screen('FillOval',wPtr,[0 180 255], [ 500 500 600 600]);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
    Screen('FillOval',wPtr,[0 255 0], [ 400 400 900 700]);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
end

% blank the Screen and wait a second
Screen('FillRect',wPtr,black);
Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
tic
while toc<1
end

% make lines that flip colors size  & position
Screen('FillRect',wPtr,black);
vbl=Screen(wPtr, 'Flip');
for i=1:10
    Screen('DrawLine',wPtr,[0 255 255], 500, 200, 700 ,600, 5);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
    Screen('DrawLine',wPtr,[255 255 0], 100, 600, 600 ,100, 5);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
end

% blank the Screen and wait a second
Screen('FillRect',wPtr,black);
Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
tic
while toc<1
end

% combine the stimuli
Screen('FillRect',wPtr,black);
vbl=Screen(wPtr, 'Flip');
for i=1:10
    Screen('FillRect',wPtr,[0 0 255], [100 150 200 250]);
    Screen('DrawLine',wPtr,[0 255 255], 500, 200, 700 ,600, 5);
    Screen('FillOval',wPtr,[0 180 255], [ 500 500 600 600]);
    Screen('TextSize', wPtr , 150);
    Screen('DrawText', wPtr, 'FUNKY!!', 200, 20, [255 50 255]);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));

    Screen('FillRect',wPtr,[255 0 0], [100 150 400 450]);
    Screen('FillOval',wPtr,[0 255 0], [ 400 400 900 700]);
    Screen('DrawLine',wPtr,[255 255 0], 100, 600, 600 ,100, 5);
    vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
end

% blank the screen and wait a second
Screen('FillRect',wPtr,black);
Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));
tic
while toc<1
end

Screen('CloseAll');
ShowCursor

Code comments on FunkyScreen

flipSpd=13;

Here you define flipSpd, you are going to make the display flip every 13 frames.

monitorFlipInterval=Screen('GetFlipInterval', wPtr)

You can find out how fast your monitor flips using 'GetFlipInterval'. 1/monitorFlipInterval will tell you the frame rate in Hz of your monitor.

vbl=Screen(wPtr, 'Flip');

This time when you flipped the window you made Screen return the time (according to the computer clock) that it did the flip. That time is saved as vbl.

Screen('FillRect',wPtr,[0 0 255], [100 150 200 250]);

Here we are using FillRect again, but this time we are defining the rect as only being a subset of the entire screen and we are using a color. Remember that the rect is defined as LeTteRBox.

vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));

We flip the screen, but this time we are telling it to flip at time | vbl + (13 * monitorFlipInterval)|

This means it will flip 13 frames after the flip where we saved the time of the flip in the variable vbl.

We keep doing the same thing again, but each time vbl refers to the flip that happened on the previous flip. So between each flip there is a 13 frame delay.

Screen('FillOval',wPtr,[0 180 255], [ 500 500 600 600]);

FillOval works just like FillRect except that it draws ovals instead of squares.

Screen('DrawLine',wPtr,[0 255 255], 500, 200, 700 ,600, 5);

DrawLine doesn’t take a rect as an argument. Instead it takes in four separate arguments

  1. starting horizontal position
  2. starting vertical position
  3. ending horizontal position
  4. ending vertical position I guess the mnemonic for that could be HumVee?

Screen('TextSize', wPtr , 150);

Screen('DrawText', wPtr, 'FUNKY!!', 200, 20, [255 50 255]);

Here we are drawing text on the screen. First we define the size of the text as having a font size of 150. Then we draw it on the screen. 200 and 20 refer to the starting horizontal and vertical positions of where you want the text placed (HumVee again).

[255 50 255] refers to the color of the text.

Screen('FillRect',wPtr,[0 0 255], [100 150 200 250]);

Screen('DrawLine',wPtr,[0 255 255], 500, 200, 700 ,600, 5);

Screen('FillOval',wPtr,[0 180 255], [ 500 500 600 600]);

Screen('TextSize', wPtr , 150);

Screen('DrawText', wPtr, 'FUNKY!!', 200, 20, [255 50 255]);

vbl=Screen(wPtr, 'Flip', vbl+(flipSpd*monitorFlipInterval));

Here we are drawing more than one thing on the offscreen window before we flip it to the front. The order you draw things in matters, since things will be drawn on top of each other.

Here's a version of funkyscreen done by a student.

FunkyJon.m

%  FunkyJon.m
%  This is my Funky li'l m_file written to demonstrate psychtoolbox
%
%  Written by Jon D. Howe 4/16/2007

clear all

% Initialize variables
screenNum=0;
flipSpd=25; % flip every 13 frames

[wPtr,rect]=Screen('OpenWindow',screenNum);
texHouse=Screen('MakeTexture',wPtr,rect);

monitorFlipInterval=Screen('GetFlipInterval',wPtr);
black=BlackIndex(wPtr);
white=WhiteIndex(wPtr);

HideCursor;

% blank screen and wait a second
Screen('FillRect',wPtr,black);
Screen('Flip',wPtr);
tic
while toc<.1
end

% Flip and collect the time of the flip in vbl
vbl=Screen('Flip', wPtr);

% Draw Background
Screen('FillRect', wPtr, [100 255 255]);
Screen('FillRect', wPtr, [0 255 0], [0 2*rect(4)/3 rect(3) rect(4)])
vbl=Screen('Flip', wPtr, vbl*(flipSpd*monitorFlipInterval),1);

% Draw house
Screen('FillRect', wPtr, [0 0 255], [420 300 680 600]);
Screen('FillPoly', wPtr, [100 0 0], [420 300; 540 200; 680 300]);
vbl=Screen('Flip', wPtr, vbl+(flipSpd*monitorFlipInterval),1);

% Draw roof
Screen('DrawLine', wPtr, [50 50 50], 410, 310, 540, 200, 5);
Screen('DrawLine', wPtr, [50 50 50], 690, 310, 540, 200, 5);
vbl=Screen('Flip', wPtr, vbl+(flipSpd*monitorFlipInterval),1);

% Draw doors and windows
% door
Screen('FillRect', wPtr, [200 200 0], [520 450 600 600]);
% window
Screen('FillRect', wPtr, [175 200 256], [440 380 500 440]);
Screen('FrameRect', wPtr, [0 0 0], [440 380 500 440], 3);
Screen('DrawLine', wPtr, [0 0 0], 470, 380, 470, 440, 3);
Screen('DrawLine', wPtr, [0 0 0], 440, 410, 500, 410, 3);

% gable window
Screen('FillArc', wPtr, [175 200 256], [520, 260, 600, 320],270,180);
Screen('FrameArc', wPtr, [0 0 0], [520 260 600 320],270,180,3);
Screen('Flip', wPtr, vbl+(flipSpd*monitorFlipInterval),1);

% Draw tree
Screen('FillRect', wPtr, [100 100 0], [200 400 230 700]);
Screen('FillOval', wPtr, [0 150 0], [50 250 370 550]);
vbl=Screen('Flip', wPtr, vbl+(flipSpd*monitorFlipInterval),1);

% Draw sun
Screen('FillOval', wPtr, [256 256 0], [760 20 920 180]);
Screen('DrawLine', wPtr, [0 0 0], 850, 75, 870, 75, 2);
Screen('FrameOval', wPtr, [0 0 0], [800 65 820 85], 2);
Screen('FrameArc', wPtr, [0 0 0], [800 85 870 160], 90, 180, 2);
vbl=Screen('Flip', wPtr, vbl+(flipSpd*monitorFlipInterval),1);

% Draw name
Screen('TextSize', wPtr, 72);
Screen('DrawText', wPtr, 'Funky Jon''s House', 200, 100, [256 256 256]);
vbl=Screen('Flip', wPtr, vbl+(flipSpd*monitorFlipInterval),1);

tic;
while toc<3
end

Screen('CloseAll');
ShowCursor;

Putting up Matrix Images

% PutUpImage.m
% opens a window using Psychtoolbox,
% puts up a 2D image and then a 3D image
%
% written for Psychtoolbox 3 on the PC by IF 3/2007

screen=0;
[wPtr,rect]=Screen('OpenWindow',screen);
HideCursor;
black=BlackIndex(wPtr);
Screen('FillRect',wPtr,black);
Screen(wPtr, 'Flip');
tic
while toc<1
end

image2D=255*rand(100, 100);
textureIndex=Screen('MakeTexture', wPtr, image2D);
Screen('DrawTexture', wPtr, textureIndex);
Screen(wPtr, 'Flip');

tic
while toc<2
end

image3D=255*rand(100, 100, 3);
textureIndex=Screen('MakeTexture', wPtr, image3D);
Screen('DrawTexture', wPtr, textureIndex, [], rect, [],0 );
Screen(wPtr, 'Flip');
tic
while toc<2
end

Screen('Close', wPtr);

Note that putting up a matrix is slightly different from drawing a rectangle or an oval. You can't directly put the matrix onto the window.

There is instead an extra step where you need to create a textureIndex using the Screen command 'MakeTexture'. This textureIndex is an index (this might be a moment to re-read the section on 'references', 'indices', 'handles' and 'pointers') into an OpenGL structure that contains the matrix transformed into an image. Once you have created the texture, you can then draw it on the screen.

Make sure you remember this - it's one of the mistakes that beginners with Psychtoolbox often make.