The Psychophysics Toolbox (PTB) is a package for
psychophysics research developed by David Brainard and Denis Pelli
(Brainard 1997; Pelli
1997) and recently by Mario Kleiner
(Kleiner et al. 2007). The PTB
toolbox can be freely downloaded from the follwing website
http://psychtoolbox.org/PsychtoolboxDownload.
This toolbox has been used extensively over the last decade (the
first version was released in 1995), and it is very useful for
running experiments needing audiovisual stimuli. PTB routines treat
the computer (Linux, Mac, or Windows) as a display device, i.e., a
frame buffer, a portion of memory generally placed within the
graphics card where images are temporally stored. To do this, PTB
interfaces MATLAB with a low-level computer language such as C.
Hence, besides a number of.m functions, PTB includes low-level
information included in MEX files. The most important MEX file is
Screen.mex, which will be described in the current chapter.
PTB includes a great number of functions, whose
documentation is displayed at http://docs.psychtoolbox.org/Psychtoolbox.
The Screen Function
As you may have anticipated, the core of PTB is
the Screen function. It includes a number of subfunctions allowing
for accurate control of the images presented on the computer
screen. To see all the subfunctions of Screen (and a partial help),
type “Screen” with no
arguments at the MATLAB prompt (if you type “help Screen” you get a
general introduction about the function). Each time you call the
Screen function it outputs, at the MATLAB prompt, information about
your graphics hardware. Before running any experiment it is
important to read this information to make sure you are equipped
for your needs. However, you may not want to have this information
repeatedly prompted each time the Screen function is called. In
this case, you can use the following code1 to suppress it:
Screen(′Preference′,′SuppressAllWarnings′,1);
The general call of the Screen function is the
following:
[v1, v2, …] =
Screen(‘Sub-functionName’,
parameter1, parameter2, …)
The Screen function always needs the sub-function
name together with the parameters of the sub-function. Moreover,
the function returns a number of variables (from zero to many)
according to the specific subfunction. The help of its subfunctions
can be seen by typing Screen(‘Sub-functionName?’)
at the MATLAB prompt. For example:
Screen(‘OpenWindow?’)
Screen(‘FillRect?’)
Or equivalently
Screen
OpenWindow?
Screen FillRect?
In the displayed help, optional input arguments
are preceded by a comma, whereas nonoptional arguments are not. For
example:
[VBLTimestamp
StimulusOnsetTime FlipTimestamp Missed Beampos] = Screen(’Flip’,
windowPtr [, when] [, dontclear] [, dontsync] [,
multiflip]);
Here when, dontclear,
dontsync
and, multiflip are optional
arguments (i.e., they have default values), whereas windowPtr is not.
Since the order of the function arguments cannot be modified, empty
square brackets can be used to reach the desired position. Hence,
in the above example, to change the dontsync default
value, we need to write:
Screen(‘Flip’, windowPtr, [],
[], dontsync)
The following is an unsorted list of the things
that can be done with Screen, which are
usually done by a specific subfunction. Screen can be used to
get information about the screen such as the refresh rate or the
size in pixels. Screen can also be
used to show strings (very useful in psycholinguistics
experiments), to draw shapes such as lines, ovals, rectangles, or
any other kind of geometrical shape you may want to draw.
Screen can
also import pictures from graphics files (such as.jpg, or.tif)
saved on the hard drive and can be used to create video clips. But
probably the most interesting feature of Screen is that
everything is done with maximal timing accuracy. This is because
the stimulus presentation is synchronized with the monitor refresh
rate.
In the current chapter we first show how to use
Screen to get information about the hardware and software
characteristics. Then we show how to draw figures and text, and how
to import pictures from external files. Finally, we show how to
create a sequence of events and how to present them with great
timing accuracy.
As anticipated, the Screen function, the
main function of PTB, is written in a low-level computer language.
Because of this, when you use Screen, if your code
crashes it may be difficult to go back into your script or to the
MATLAB prompt (for example, you might need to quit MATLAB from the
task manager or, even worse, to switch off your computer!). To
avoid this problem, we recommend writing all code within a
try and
catch
block (see Chap.
3). This trick bypasses some of the problems that
may arise if your program crashes. The following example shows how
you should use the try–catch commands.
Listing 9.1
![A978-1-4614-2197-9_9_Figa_HTML.gif](A978-1-4614-2197-9_9_Figa_HTML.gif)
Analysis
Lines: 1, 3–6 are to catch any error after a
Screen has been opened.
Line 2: the script written in the chapter.
Lines 4–5: closes all screens in case the program
written in the try section crashes. Moreover, it reports the last
error found in the try section. This is useful for debugging the
code.
Another option is to use an auxiliary monitor so
to keep the MATLAB command window on one monitor and display the
figures created with PTB on the other one. In this way, if the code
crashes, it would be possible reading at the MATLAB prompt the
error generating the crash and, in most of the cases, it would be
possible to “close” the screen code.
How to Use Screen to Get Information
The function Screen can be used to
get information about the PTB itself as well as the characteristics
of the computer in use. In particular, the Screen subfunctions are
useful for increasing a program’s portability. For example, if you
are displaying a video clip, it is important to get the screen
refresh rate of the computer in use to produce the same visual
effect in terms of timing when different machines are used. The
following table explains some of these subfunctions.
Sub function
|
Command
|
Example
|
---|---|---|
Version
|
struct=Screen(′Version′);
|
Return a structure with the characteristics
of the PTB
|
Computer
|
comp=Screen(′Computer′);
|
Return a structure with the characteristics
of the computer
|
Screen
|
screens=Screen(′Screens′);
|
Return an array of numbers (0, 1, 2, …).
Each number identifies one screen connected to the computer. The
default, 0, is the screen with the menu bar
|
Rect
|
rect=Screen(‘Rect’,
screenNumber);
|
Return an array with the top left corner
(always 0, 0) and the bottom right corner (n, m) coordinates of the
screen. The number of the bottom right corner coincides with the
screen’s resolution (e.g., 1,024 × 768). ScreenNumber is a
pointer (i.e., the one returned by the Screens subfunction) that
tells the function which screen-rect is to be returned
|
FrameRate
|
hz=Screen(‘FrameRate’,
screenNumber);
|
Returns the refresh rate of the screen
identified by the pointer screenNumber
|
GetFlipinterval
|
[monitorFlipInterval
nrValidSamples
stddev]=Screen(‘GetFlipInterval’,
windowPtr
[, nrSamples] [,
stddev] [,
timeout]);
|
Returns the flip interval (in seconds),
i.e., the interval in seconds between two consecutive vertical
retraces of the screen identified by the pointer. This subfunction
has to be run after the OpenWindow subfunction
|
How to Use Screen to Draw Figures
Preliminary Notions: Drawing Figures in Three Steps—Opening, Drawing, and Closing
The main thing Screen is used for is to draw
figures and to present them with maximal timing accuracy. Generally
speaking, there are three main figure types: figures drawn with
PTB, imported figures (e.g.,.jpg,.tif, …) and text figures.
Independently from the type of figure you are drawing, the drawing
is done in three steps that we can call opening, drawing, and
closing. These steps are normally found in any program that
displays figures.
Opening the Window
The “opening” step is controlled by the
subfunction ′OpenWindow′:
[MyScreen, rect] =
screen(‘OpenWindow’, 0, [0, 255, 0]);
When the opening is done, we take control of the
screen where we are going to draw the figure. The first argument of
the ′OpenWindow’
subfunction indicates the screen we want to refer to. Indeed, many
screens can be connected to the same computer at the same time. The
screen with the menu bar is identified with the default number
“0”.
Therefore, with the command line above, we get
control of the screen with the menu bar. To this particular screen
we also assign a name (i.e., the returned pointer MyScreen). Therefore,
later in the code, every time we need to access this screen, we use
screen’s name (MyScreen) rather than
0. The above code paints the whole screen in green color using the
RGB triplet [0,
255, 0]. In the Screen function, the
color argument is passed either with a single gray value (i.e.,
0–255) or with a RGB triplet. By default, if the color argument is
omitted, the screen is white, i.e., the default value for this
argument is [255
255 255]. Last but not least, ‘OpenWindow’ returns
the screen size, which above we saved in the rect variable. The
rect
variable is an array of the screen coordinates in pixels. The first
two coordinates are those of the top left corner; the second two
coordinates are those of the bottom right corner. The top left
coordinates are 0,0, whereas those of
the bottom right depend on screen resolution.
The full list of arguments for the OpenWindow subfunction
is the following:
Screen(‘OpenWindow’,0[,color][,rect][,pixelSize][,numberOfBuffers]…
[,stereomode][,multisample][,imagingmode]);
The following table outlines the use of these
arguments.
Opt.
argument
|
Color
|
Description
|
Can be a scalar, if you want an achromatic
screen or a 1 × 3 vector with the unnormalized RGB values (i.e.
1–256). For an RGB color description, refer to Chap.
5
|
Example
|
Screen(’OpenWindow’, 0,
[255,0,0])
% it turns the screen
red
|
Opt.
argument
|
Rect
|
Description
|
Specifies the size, in pixels, of your
window (this option works better under Mac OS). This is a 1 × 4
vector with the coordinates of the window. The first two numbers
refer to the x and y coordinates (in pixels) of the upper left
corner, respectively; the last two numbers refer to the x and y
coordinates of the bottom right corner of the window, respectively.
Hence, there is the possibility to draw the stimuli even in a
portion of your screen instead of the whole screen, although you’ll
probably never use it. The following example turns the screen red
using the specified coordinates
|
Example
|
Screen(’OpenWindow’, 0, [255,
0, 0],[250,250,450,650])
|
Opt.
argument
|
pixelSize
|
Description
|
Specifies the number of bits per pixel
devoted to creating colors in the screen. Usual numbers of bits are
8, 16, or 32 per pixel, corresponding to 256, thousands, or
millions of colors, respectively. This depends on the graphics
card. If you do not know how many bits per pixel your graphics card
can use, you can ask PTB using the Screen subfunction PixelSizes.
By default, PTB works with 8 bits, and therefore colors are coded
within the 0–255 (i.e., 2^8) range. If a different number of bits
is used, the range defining the color also changes. For example,
with 16 bits, the triplet for the red color is [65535, 0, 0]
|
Example
|
Screen(’Openwindow’,0,[],[],16)
|
Opt.
argument
|
numberOfBuffers
|
Description
|
Determines the number of buffers to use.
You normally use one or two buffers (see next chapter) to run your
experiments, so you don’t change this parameter except for testing
or debugging reasons
|
Example
|
Screen(’Openwindow’,0,[],[],[],2)
|
Opt.
argument
|
Stereomode
|
Description
|
PTB offers different stereo possibilities.
The default value of this argument is 0, that is, Monoscopic
viewing. If you are equipped with stereo hardware, such as shutter
glasses, you can opt for values from 1 to 3 of stereomode according
to where you want the images for the left and right eyes appearing
on the screen
|
If you want a stereogram, then set
stereomode to 4. In this way you split the screen into two halves,
where the left view is for the left eye; set stereomode to 5 for
cross-fusion. If you are equipped with color glasses for anaglyph
stereo vision, then set stereomode to 6, 7, 8, or 9 for different
combinations of colors
|
|
Finally, set stereomode to 10 if you have
two monitors: you will have one image per monitor
|
|
Example
|
Screen(’Openwindow’,0,[],[],[],[],4)
|
Opt.
argument
|
“multisample”
|
Description
|
This parameter enables an antialiasing
procedure. In brief, when you design your stimuli for a screen,
aliasing is a problem that occurs when the approximation due to
pixel size is not good enough. When you draw a disc, for example,
its smoothness can be very poor if the resolution of the screen in
not high enough. Or, when you create video clips, you may have a
temporal aliasing problem resulting from the limited frame rate.
When multisample is greater than 0, PTB looks for the best
antialiasing solution that can be obtained by your hardware. This
will improve the quality of the stimuli; however, the downside in
doing this is the increase of video memory use, leading to loss of
precision in terms of time. You might not want this if you are
collecting reaction times
|
Example
|
Screen(’Openwindow’,0,[],[],[],[],[],5)
|
Opt.
argument
|
Imagingmode
|
Description
|
This parameter enables PTB’s internal
image-processing pipeline. The pipeline is off by default. By
setting this parameter to 1, you enable this feature to perform
image-processing operations that are executed on the graphics
processor itself
|
Example
|
Screen(’Openwindow’,0,[],[],[],[],[],[],0)
|
Drawing: An Introduction
This is the step where we actually design the
figures. We’ll see later in the chapter how to program some figures
that may be drawn directly within the PTB environment. But first,
we have to introduce another subfunction. Indeed, in order for a
drawing to be effective, it has to be followed by the subfunction
Flip.
The figure is automatically drawn in the
background memory (also called backbuffer), which is not visible.
The Flip
subfunction moves the previously drawn figure from the backbuffer
to the foreground memory (the frontbuffer) so that it becomes
visible on screen. This “flip” of the figure from the backbuffer to
the frontbuffer occurs at a specific time, which is the first
available vertical retrace of the screen. The flip action is
performed on any figure found in the background memory. In other
words, if you have drawn, let’s say, a square, a circle, and a
triangle and you want to show them on the screen, you do not need
to flip each object, but instead, you can flip all objects at once.
The Flip
subfunction needs to be addressed to a particular screen (i.e., to
a particular screen pointer). In everyday situations, the screen we
address to is the only screen connected to the computer. However,
if you are using two or more screens, you could decide on which
screen the figure has to be flipped. When the Flip subfunction is
executed, the background memory is cleared. Therefore, if you have
nothing in the background and you call the Flip subfunction,
everything that is currently in your foreground is deleted, because
it is replaced with an empty object.
The complete Flip command is the following:
[VBLTimestamp
StimulusOnsetTime FlipTimestamp Missed Beampos] = Screen(’Flip’,
windowPtr [, when] [, dontclear] [, dontsync] [,
multiflip]);
We will see later how to use some of the Flip
options to control the timing of the stimuli.
Closing
Closing ends the code, and in the majority of
cases may look simply like the following command:
screen(′CloseAll′);
The CloseAll subfunction
closes all the figures created during code execution and sets the
screen back to normality, returning control to MATLAB. It is
important to close everything, otherwise, the control is not
returned to MATLAB. In PTB, you can close all objects at once (for
example, with the subfunction CloseAll) or close only specific
objects (remember, however, that at the end of your code you need
to close all the objects created). This can be done as
follows:
screen(‘Close’,
objectPointer)
where objectPointer is the pointer to the object
you want to close. The possibility of closing selected objects is
particularly interesting if the code you are writing needs a lot of
memory. Overall, the amount of memory you are using depends on the
number of objects and on their size. If memory consumption becomes
critical for your program, then it might be helpful closing the
objects no longer in use.
Drawing: Reprise
Now that the preliminaries are out of the way, we
can have a go at doing some drawing. Replace the text comment in
the try–catch example (presented in Listing 9.1) as in Listing
9.2.
Listing 9.2
![A978-1-4614-2197-9_9_Figb_HTML.gif](A978-1-4614-2197-9_9_Figb_HTML.gif)
Analysis
This short script does a few things:
On line 2: It looks for how many screens are
connected to the computer.
On line 3: if there is more than one screen, it
selects one of them without the menu bar and assigns an arbitrary
name to it. Later, we’ll open this screen and turn it green.
On line 4: the screen assumes the name
myscreen
(i.e., its pointer), and we save the coordinates of the screen in
the variable rect. Moreover, we
paint the full screen myscreen green.
On line 5: we make the program wait for a
key-press event. This is done by means of the KbWait command, which
stops the execution of the code until the user presses a keyboard
key.
On line 6: The subfunction “CloseAll” returns
control to MATLAB.
In the previous example, we did not draw any
figures on the screen. In the next section we will extend the code
by drawing some objects.
Drawing Shapes
To understand how to draw geometric shapes on the
screen, we extend Listing 9.2 to make the stimulus for a color
afterimage. To do this, we want to draw a red square (400 by 400
pixels) on a green background, and to do this we use the
subfunction FillRect, which draws
a filled rectangle; use the subfunction FrameRect to get a
framed rectangle. Both the FillRect and
FrameRect
subfunctions take as parameters the screen pointer followed by the
color (in RGB triplet form) and finally the coordinates of the
rectangle we want to draw. When the FillRect or
FrameRect
subfunctions are called, a rectangle is drawn in the backbuffer. To
actually see the rectangle on the screen, we need to call the Flip
subfunction.
Listing 9.3
![A978-1-4614-2197-9_9_Figc_HTML.gif](A978-1-4614-2197-9_9_Figc_HTML.gif)
Now if you look at the red square long enough
(e.g., 20 s) and then move your eyes to a white sheet of paper, you
can see the afterimage of the red color.
You may have noticed in the script above that we
used the very handy function CenterRect. It
calculates the coordinates to include one figure within the center
of another one whose coordinates are known. In the example, the
external figure is the entire screen; therefore, the function
centers the figure within the screen.
CenterRect and the
other functions for manipulating coordinates (type help
PsychRets
at the MATLAB prompt or see below) can also be used in a nested
way. Let us now display a simultaneous lightness contrast display.
We divide the screen into two sectors, one white and one black, and
at the center of each sector we need to place a gray square.
Everything is done in the following example.
Listing 9.4
![A978-1-4614-2197-9_9_Figd_HTML.gif](A978-1-4614-2197-9_9_Figd_HTML.gif)
The script is very similar to Listing 9.3. In the
example, we also introduced the AdjoinRect function
which adds a rectangle at the right of the specified sector. Note also that
here we used CenterRect in a nested
way, because now “center” is the center of the defined sector, not
the center of the screen. When you are drawing the stimuli for your
experiment, our suggestion is to proceed as follows. First, set the
size of the shape, regardless of its position on the screen, by
setting its size starting from the top-left corner. Then use the
PsychRect
function to define the actual coordinates on the screen.
In the following table can be found a complete
list of the functions that can be used to simplify your work that
uses the rect coordinates. Please refer to the Psychtoolbox help
for more complete information on how to use them.
Function
|
Description
|
---|---|
AdjoinRect
|
Moves a rect next to another one
|
AlignRect
|
Aligns a rect over another one
|
ArrangeRects
|
Arranges an array of rects in a pleasant
way
|
CenterRect
|
Centers a rect within a second one
|
CenterRectOnPoint
|
Centers a rect around given x,y
coordinates
|
CenterRectOnPointd
|
Centers rect around an x,y coordinate
pair
|
ClipRect
|
Returns the intersection of two rects
|
ClipRect
|
Returns the intersection of two rects
|
InsetRect
|
Shrinks/expands rect by additive
insets
|
IsEmptyRect
|
Returns 1 if empty, returns 0
otherwise
|
IsInRect
|
Is the point inside a rect?
|
OffsetRect
|
Shifts rect vertically and
horizontally
|
RectBottom
|
Returns index of yBottom entry of a
rect
|
RectCenter
|
Returns the integer x,y coordinates of
center
|
RectCenterd
|
Returns the exact x,y coordinates of
center
|
RectOfMatrix
|
Accept an image as a matrix and returns a
PTB rect specifying the bounds
|
RectHeight
|
Returns the height of a rect
|
RectLeft
|
Returns index of xLeft entry of a
rect
|
RectRight
|
Returns index of xRight entry of a
rect
|
RectTop
|
Returns index of yTop entry of a rect
|
RectWidth
|
Returns width of a rect
|
RectSize
|
Returns the width and the height of a
rect
|
ScaleRect
|
Scales a rect by multiplicative
factors
|
SetRect
|
Creates a rect (i.e., a vector) from four
input coordinates
|
SizeOfRect
|
Accepts a Psychtoolbox rect [left, top,
right, bottom] and returns the size [rows columns] of a MATLAB
array (i.e. image) just big enough to hold all the pixels
|
UnionRect
|
Smallest rect containing two given
rects
|
To draw filled ovals (including circles) we use
the subfunction FillOvals instead of
the subfunction FillRects. The
counterpart of FrameRect is
FrameOvals. In the
following table, we present a list of the shapes that can be drawn
with PTB. More-complex graphical shapes can be drawn by combining
two or more figures.
Sub/Function
|
Command
|
Description
|
---|---|---|
DrawLine
|
Screen(′DrawLine′, windowPtr
[,color], fromH, fromV, toH, toV [,penWidth]);
|
draws a line
|
DrawArc
|
Screen(′DrawArc′,windowPtr,[color],[rect],startAngle,arcAngle)
|
draws a circular arc unfilled
with color (i.e., a Pac-Man-like figure)
|
FrameArc
|
Screen(′FrameArc′,windowPtr,[color],[rect],startAngle,arcAngle[,penWidth]
[,penHeight] [,penMode])
|
as above
|
FillArc
|
Screen(′FillArc′,windowPtr,[color],[rect],startAngle,arcAngle)
|
as above but filled with
color
|
FillRect
|
Screen(′FillRect′, windowPtr
[,color] [,rect] );
|
draws a rectangle filled with
color
|
FrameRect
|
Screen(′FrameRect′, windowPtr
[,color] [,rect] [,penWidth]);
|
draws a rectangle unfilled
with color
|
FillOval
|
Screen(′FillOval′, windowPtr
[,color] [,rect] [,perfectUpToMaxDiameter]);
|
draws a filled
oval
|
FrameOval
|
Screen(′FrameOval′, windowPtr
[,color] [,rect] [,penWidth] [,penHeight] [,penMode]);
|
draws a framed
oval
|
FramePoly
|
Screen(′FramePoly′, windowPtr
[,color], pointList [,penWidth]);
|
draws a framed
polygon
|
FillPoly
|
Screen(′FillPoly′, windowPtr
[,color], pointList [, isConvex]);
|
draws a filled
polygon
|
Batch Processing: Drawing Multiple Figures at Once
It is often useful to be able to draw multiple
figures at once. This operation is not only useful, but it is also
an efficient operation to do with PTB 3. The repeated drawing is
achieved using the functions that we have used so far. Instead of
writing repeatedly the same drawing subfunctions:
Screen(′FillRect′, win, [red1
green1 blue1], [left1 top1 right1 bot1]);
Screen(′FillRect′, win, [red2
green2 blue2], [left2 top2 right2 bot2]);
…
Screen(‘FillRect’, win, [redn
greenn bluen], [leftn topn rightn botn]);
you can write in the following:
mycolors = [red1, red2,… ;
green1, green2,… ; blue1, blue2,…];
myrects = [xtop_1, xtop_2,…;
ytop_1, ytop_2,…; xbottom_1, xbottom_2,…; ybottom_1,
ybottom_2,…];
Screen(′FillRect′, win,
mycolors, myrects);
In other words, you first write a 3 × n matrix
for the RGB values, and then a 4 × n matrix for the figures’
coordinates. These matrices are then passed to the desired
subfunction to draw the shapes. In the 3 × n color matrix, each
row identifies the RGB values for the corresponding figure. In the
same way, in the 4 × n matrix for the figures’ coordinates, each
column identifies the coordinates of the corresponding figure; odd
rows are the x coordinates, and
even rows are the y coordinates.
In the following example, we draw a setting that
could be used for a Posner-like experiment by drawing three frames
placed one after the other in the middle of the screen. The left
and the right frames are gray, while the middle frame is black so
that it cannot be seen. Note that colors and coordinates are
transposed when they are passed to the FrameRect
subfunction.
Listing 9.5
![A978-1-4614-2197-9_9_Fige_HTML.gif](A978-1-4614-2197-9_9_Fige_HTML.gif)
Drawing Text
‘DrawText’ is the
subfunction to draw text on the screen. The subfunction’s options
are the following:
[newX,newY]=Screen(′DrawText′,
windowPtr, text [,x] [,y] [,color] [,backgroundColor]
[,yPositionIsBaseline]);
where windowPtr is the
pointer to the screen, and text is the string of text you want to
draw. Optional arguments are the x and y coordinates where
the text starts (these coordinates refer to the top left corner)
and the text color. Note that in this subfunction the color
argument is passed after the coordinates, instead of before, as was
the case for rectangles and ovals. Further optional arguments are
backgroundColor and
yPositionIsBaseline.
backgroundColor is the
color behind the text (It does not seem to work properly under
Windows and Linux. However, this problem can be easily solved by
drawing a colored rectangle before drawing the text.) yPositionIsBaseline is
a logical value; if true, the y coordinate
for the text refers to the bottom, instead of the upper, part of
the text.
The Drawtext subfunction
returns the x and y coordinates of the end of the text. This is
useful because the strings you are writing could be of a different
lengths, covering a different number of pixels. Therefore,
knowledge of the ending coordinates of a string is important for
arranging two or more strings of text. If you simply need to write
one string in the middle of the screen, you can use the function
DrawFormattedText:
[nx, ny, textbounds] =
DrawFormattedText(win, tstring [, sx][, sy][, color] [, wrapat][,
flipHorizontal][, flipVertical][, vSpacing])
DrawText accepts not
only coordinates expressed in pixels but also the option
′center′,
which can be used to center the text on the screen either on the
horizontal or vertical axis. The following code writes a string
starting from the middle of the screen.
Listing 9.6
![A978-1-4614-2197-9_9_Figf_HTML.gif](A978-1-4614-2197-9_9_Figf_HTML.gif)
PTB provides additional writing subfunctions
specifying the style, font, mode, and size of the text. To get
these features the corresponding subfunctions have to be called
before DrawText or
DrawFormattedText is
called. These subfunctions allow for getting and setting text features at the same time;
that is, the same function gets the type of text that is currently
on and sets the desired
text type. Let us see how they work.
‘TextStyle’ specifies
the text style. 0 is normal, 1 is bold, 2 is italic, 3 is bold and
italic, 4 is underline, 5 is bold and underline, 6 is italic and
underline, and 7 is italic, bold, and underline.
For example, the command:
previous_style =
Screen(’TextStyle’, w, 2);
returns the style that was previously in use (0
is the default style) and sets the style to bold for next
text.
‘TextFont’ specifies
the text font; it can be invoked by passing the font name or via
the font number. The subfunction returns two arguments, which are
the number and name of the font that is currently in use (this is
because to each font there also corresponds a number). Use the
following syntax:
[previousFontName,
previousFontNumber] = Screen (′TextFont′,w,
’Verdana’);
The function returns both previous name and
number style and sets Verdana as the style for future text.
′TextMode′ specifies
the text mode; there are 16 different modes, ranging from normal to
dashed, dot-dashed, and so on. It works only with Mac OS. Use the
following syntax to get the previous mode and to set the new
one:
previous_mode =
Screen(’TextMode’, w,10);
‘TextSize’ specifies
the text size. Use the following syntax to get the previous size
and to set the new one:
previous_size=Screen(′TextSize′,
w,40) ;
Finally, there is the ‘TextWidth’
subfunction, which returns the horizontal offset, that is, the
change in the horizontal pen position that will be produced by the
string. That is, if you are not sure how many bytes your string is,
use ‘TextWidth’ to get it.
Use the following syntax:
Width=Screen(’TextWidth’, w,
mystring);
where mystring is the string
that you are to type. It returns a negative number of bytes if you
write from right to left. Mystring may include
2-byte characters (e.g., Chinese).
The following code listing shows how to use some
of these subfunctions. Moreover, it provides an example of changing
text. The word MATLAB is written three times in three different
colors that are continuously changing. The word is also vertically
and horizontally flipped using some of the options of DrawFormattedText.
Listing 9.7
![A978-1-4614-2197-9_9_Figg_HTML.gif](A978-1-4614-2197-9_9_Figg_HTML.gif)
Importing Images
Screen can be used to
import and to show images stored on the hard drive. Images are
shown in three steps. First you need to load the image in the
MATLAB workspace (see Chap.
5); then, you need to create a texture of the picture, and finally,
you can show the texture on the screen. Let us analyze these steps
by running the code in Listing 9.8.
Listing 9.8
![A978-1-4614-2197-9_9_Figh_HTML.gif](A978-1-4614-2197-9_9_Figh_HTML.gif)
Analysis
On lines 2 and 3 we load the image, get its size,
and store it in the MATLAB workspace.
On line 4 we set a rectangle as large as the
picture, and change its coordinates so that it is set at the center
of the screen.
On line 7 we change the indexed image format into
an RGB format using the MATLAB function ind2rgb. We need to do
this because PTB works with intensity matrices (i.e., gray-scale or
RGB) instead of indexed matrices.
On line 8 we multiply the resulting RGB matrix by
256. This is because PTB expects integers ranging from 0 to 255,
while the values returned by ind2rgb are in the 0–1
range.
On line 9 we transform the picture into a PTB
texture. PTB uses OpenGL2 commands, and a texture can be seen
as a sort of image in OpenGL. A discussion of OpenGL technology is
beyond the scope of the present text. However, it is important to
know that we need to ‘remap’ every image into a texture element.
On line 10 we draw the texture image in the
background memory.
On line 11 we show the picture on the
screen.
It has to be stressed that the matrix of an image
cannot be directly displayed: the matrix has to be converted into a
texture before being displayed.
Video Clips
PTB functions can be used to create video clips
such as a figure moving along the screen, where a video clip is a
succession of static pictures. Each picture is called frame. The
possibility of drawing video depends on the refresh rate and on the
pixel size. These two factors affect the granularity of the motion.
A displacement cannot be lower than the size of one pixel.
Similarly, frames cannot be presented at a faster rate than the
refresh rate.
In the majority of cases, video clips are drawn
using for loops, as in the following example. Here, a black disc on
a white background moves horizontally from left to right on the
screen.
Listing 9.9
![A978-1-4614-2197-9_9_Figi_HTML.gif](A978-1-4614-2197-9_9_Figi_HTML.gif)
Analysis
On line 6 we implement the variable disc, which is a
quadruplet of coordinates for the disc; on lines 7 and 8 we
implement rectinrect, which is a
quadruplet of the coordinates for the frame within which the disc
will move.
From line 10 to line 14 we implement the “for
loop” in which the x coordinates of the disc change. At the first
iteration (i = 0) the disc is placed at the left border of the
frame. When i equals 1, the x coordinate of
the disc is augmented of one unit; therefore the disc is drawn 1
pixel further to the right than the previous disc. When
i equals
2, the
shift of the discs becomes 2 pixels, and so on up to i = 600, when the discs
disappear behind the frame.
In practice, every time you iterate a loop you
need to redraw the object you want to move in a different position
by specifying the new x and y coordinates where you want the figure
to be drawn. Of course you can set into motion any figure you want.
Moreover, motion can be done not only along a straight line but
also with a certain fuzziness. Here the string “hello” moves from
left to right in an “uncertain” way.
Listing 9.10
![A978-1-4614-2197-9_9_Figj_HTML.gif](A978-1-4614-2197-9_9_Figj_HTML.gif)
Analysis
In the current example, the x and y coordinates
of the string “hello world!” are modulated by a random factor
(using the function rand on
lines 13 and 14). On line 14, y is made to change by either −1 (a
displacement to the upper part of the screen), 0 (no displacement),
or +1 (a displacement toward the bottom part of the screen).
Therefore, on average, the figure oscillates along the y axis
without progressing in any particular direction. However, on line
13, the x coordinate can change by −1, 0, +1, +2, or +3. Negative
changes move the string toward the left, whereas positive changes
move the string toward the right. Because the randomly generated
number is more likely to be positive than negative, the string
eventually moves toward the right of the screen.
Drawing Things at the Right Time
Up to now, we have not paid yet much attention to
timing. However, on many occasions, timing is an important issue
for our stimuli, because we need to be able to control their
duration.
Timing is intrinsically connected to the screen
refresh rate. For example, you cannot present objects whose
duration lasts less than one refresh per cycle. By the same token,
you cannot present a stimulus for a duration that is not an exact
multiple of the screen refresh rate. The reason is the following.
Let’s suppose you are showing one stimulus (s1) and that this
stimulus has to be replaced by the next stimulus (s2). If the
duration of s1 on screen is not a multiple of the refresh rate, it
may happen that the drawing of s2 begins when s1 is still on
screen. Therefore, when you are deeply concerned about timing,
always use durations that are multiples of the screen refresh
rate.
Independently from the stimulus type, timing is
controlled by two optional arguments of the subfunction
Flip.
These arguments are “when” and
“VBLTimestamp”.
“when”
tells the flip subfunction when the flip from foreground to
background is to be done. “VBLTimestamp” is the
time when the flip has actually been done. Both “when” and
“VBLTimestamp”
are expressed in seconds and refer to the system time, a timer that
is switched on when you switch on your computer.
The following example illustrates how to control
the timing. We first generate a fixation point which stays on the
screen for 0.5 seconds and then a red square appears. After 0.75
seconds the red square is cleared, and after 1 seconds a green
square appears for 0.6 seconds.
Listing 9.11
![A978-1-4614-2197-9_9_Figk_HTML.gif](A978-1-4614-2197-9_9_Figk_HTML.gif)
Analysis
In the example, the timing is achieved by getting
the onset/offset times of each stimulus. For example:
On line 15 we flip the first stimulus at a time
that is the sum of the onset of the fixation point and 0.5 s.
On line 17 we flip again after a period of 0.75
s. However, because there is nothing in the background, the screen
is cleared after such a period. In this way, the presence of the
first stimulus on the screen is controlled by this second
flip.
On line 24 the second stimulus is switched 1 s
after the offset time of the first stimulus.
On line 26 the second stimulus is cleared after
0.6 s due to the second flip.
Note the use of the subfunction ‘GetFlipInterval’
on line 6. This subfunction returns an estimate of the monitor flip
interval for the specified onscreen window. This allows for maximum
control of the display time. We use such slack in the computation
of the “when” time in the flip
subfunction.
Finally, there is another operation you can do to
obtain maximal timing accuracy. When we use the computer there are
several software processes running at the same time. The CPU does
calculations for all of them. These activities reduce the resources
that are available to MATLAB and PTB. PTB, however, has a set of
functions for redirecting all available CPU resources to MATLAB to
improve timing accuracy. These functions will be presented in the
next chapter.
Summary
-
The Psychophysics Toolbox (PTB) is a package specifically developed for psychophysics research.
-
The core of the PTB is the Screen function.
-
PTB uses a double buffering system (back and front buffers = ‘background and foreground memory’) that provides great timing control for visual stimuli.
-
PTB can be used to draw objects (geometric figures, figures imported from graphics files or text) onscreen. The drawing of objects onscreen is performed in three steps: opening, drawing, and closing.
-
The spatial arrangements of objects can be manipulated with the PsychRects functions, and the drawing can be done in batch-processing mode.
-
The Screen subfunction flip can be used to control the timing of your stimuli and to synchronize the drawing with the screen’s vertical retrace.
-
The Screen function can be used to create movies.
Exercises
Exercise 1
Draw the Kanizsa triangle by designing three
Pac-Men shaping the illusory contour.
Solution 1
![A978-1-4614-2197-9_9_Figl_HTML.gif](A978-1-4614-2197-9_9_Figl_HTML.gif)
Exercise 2
Draw a Kanizsa triangle equal to the previous one
but “dishonestly” (by shaping a white triangle on a white
background whose vertex covers three black discs). Besides
reviewing how to draw polygons, the purpose of this exercise is to
realize that depending on where in your code listing you put a
function, it can give rise to different results. Indeed, to solve
this exercise, the triangle has to be drawn after, instead of
before, the discs.
Solution 2
![A978-1-4614-2197-9_9_Figm_HTML.gif](A978-1-4614-2197-9_9_Figm_HTML.gif)
A Brick for an Experiment
The stimulus for our experiment is simple: two
discs that move with identical motions (one rightward, one
leftward) and that start from one position and each end at the
other disc’s starting point. A stimulus similar to this has been
shown previously in this chapter. Here we just reduce the size of
the frame within which the discs are moving so that is a square of
300 by 300 pixels. The following script (slightly optimized in
comparison to that of the chapter) shows the motion display used by
Sekuler et al. (1997). In the
example, two discs move: disc1 moves from left to right, disc2 from
right to left.
![A978-1-4614-2197-9_9_Fign_HTML.gif](A978-1-4614-2197-9_9_Fign_HTML.gif)
A few comments about this script. First of all,
please note how we set the starting coordinates of all objects in a
nested way. The coordinates of the frame within which the movement
takes place are calculated according to the screen coordinates. The
starting coordinates of the discs are calculated according to the
coordinates of the frame. Note also that we flipped once before the
for loop showing the motion. This simple operation enables us to
synchronize the subsequent for loop (thus the successive flips)
with the refresh rate. In a certain sense, we could say that we are
“getting the pace” of the refresh rate. Note also how the i index
is changed: in 2-unit steps. This increases the velocity of the
motion (2 pixels per frame) in comparison to that originally shown
in the chapter. The x coordinates of disc1 are increased by i (so
that the discs moves toward the right), whereas the x coordinates
of discs2 are decreased by i (so that the disc moves toward the
left). At the end of the for loop, we again flip the frame only
(but not the disc) so that the frame does not disappear after the
motion.
We have now to build the second motion display,
where the discs at the overlap point stop the motion for a few
frames. Here we will stop the motion for two frames. In order to do
this, we need the i index to remain for more than one cycle at the
value 140. When i is equal to 140, the discs overlap completely.
Everything can be done simply by modifying the beginning of the for
loop as follows:
for i = [0:2:140, 140,
140:2:280]
Now the i index, the variable that lets us move
the discs, increases from 0 to 140 (when the discs overlap), then
is equal to 140, then increases from 140 to 280.
We can now write everything into the scripts and
the function we wrote for the previous bricks. The opening and
closing operations will be written into the SekulerExp function.
The generation/presentation of the motion display will be written
in a separate script that will be called MakeVideoStimulus.m. In
this way we will not overload the text content of the SekulerExp
function.
This is the script:
![A978-1-4614-2197-9_9_Figo_HTML.gif](A978-1-4614-2197-9_9_Figo_HTML.gif)
The following is the modified SekulerExp
function. Note that we have written the KbWait command after the
presentation of the stimulus.
![A978-1-4614-2197-9_9_Figp_HTML.gif](A978-1-4614-2197-9_9_Figp_HTML.gif)
In the next chapter we will play the sound and
substitute the command KbWait with a more appropriate command that
will enable us to get the participant’s response. Moreover, we will
see how to get maximal priority before running a movie, and
finally, we will see how to get rid of the mouse pointer, which is
unnecessary (and perhaps annoying) in the current experiment.
References
Kleiner M, Brainard DH, Pelli
DG (2007) What’s new in psychtoolbox-3? Perception (ECVP Abstract
Supplement) 14
Sekuler R, Sekuler AB, Lau R
(1997) Sound alters visual motion perception. Nature 385:308
Suggested Readings
Tutorials for the
Psychtoolbox can be found at the following web pages:
Footnotes
2
OpenGL’s main purpose is to render two- and
three-dimensional figures into a frame buffer. These figures are
described as sequences of vertices (which define geometric objects)
or pixels (which define images). OpenGL performs several processing
steps on these data to convert them into pixels to create the image
in the frame buffer.