| Reference | Downloads | Github

[Solved] Aperture Cannot Handle Concave/Complex Shape Vertices (Help/Suggestions)

Hi Everyone. I’m trying to write a script that will present colored shapes, both basic (i.e. rectangle) and complex (6-sided star), which are drawn on top of an image of some homogenous texture (i.e. photograph of bricks etc.). For shapes like circles, squares, trapezoids etc, it worked to draw an aperture and set the aperture shape to the vertices of the circle/rect/triangle that I created. Then, with the aperture enabled, I draw the texture image, then draw the colored shape (or any shape/size of color that would fully color the shape/size of the aperture).

However, when setting the aperture shape to a set of vertices from a complex image (the 6-sided star shape), the aperture drawn is unable to take the form of the 6-sided star. I assume that this has to do with the aperture.shape function not being able to handle complex/concave polygons. Does anyone have any suggestions to overcome this problem, either using aperture or a different method?

I’m wondering why you don’t just draw filled ShapeStims directly rather than using an aperture?

I want to draw a colored shape that acts as a transparency on top of some (black and white) texture image (i.e. image of brick lattice). There is no option that I am aware of in ShapeStim that allows for the designed shape to be filled by an image (e.g. .eps file). In addition, setting the color of the ImageStim leads to color negatives since the images being called are black and white. This led me to using Aperture. Since I started using PsychoPy only a few days ago, I hope I am not missing something basic about ImageStim and/or ShapeStim.

No, it’s perhaps just that the description of what you want is (still) maybe a little unclear, at least to me. i.e. it wasn’t clear that the image to be drawn second itself contained a texture, rather than just being a simple geometrical figure

I think what you want to do is create an ImageStim with a mask property in the shape you need.

Pardon the confusing description. My desired outcome is something like this for each of a series of shapes.

So I’ve been drawing both a black and white image pattern and then a colored opaque shape on top of it.

With this in mind, I would first use the aperture so that only visible part of the subsequently drawn shape and background pattern would be the area contained within the specified shape (like in the first image above).

In terms of using the mask parameter in ImageStim, I am struggling to find a way to feed it a matrix the represents only the locations on screen contained by the shape as feeding it the vertices of the shape is not permitted.

OK, I think I get it now. I think this could be done (in a few steps) by composing a BufferImageStim (which is sort of an off-screen screenshot), and then drawing that to the screen using an aperture or a mask to get just the coloured portion.

i.e. something like this:

Compose a BufferImageStim from your background bitmap and an overlaid coloured, semi-transparent ShapeStim. This would look like your second image above.

Then draw that stimulus to the screen, calculating a mask using the same vertices as for the overlaid ShapeStim. I think you’re right, that doesn’t seem to be possible directly (it would be very useful…)

But check out this thread for what looks like a solution (or two):!topic/psychopy-users/d0FPJaXIw_k

NB If you can post some examples of how the aperture doesn’t work with certain shapes, that might be very useful.

Yes, that’s what I am going for and that is the problem.

For the complex image, I am capable of drawing an opaque, colored star with ShapeStim like this:

However, when I use the vertices of the star ShapeStim as the aperture.shape, I get the following (ignore color and pattern differences):

You can vaguely see the 12 vertices being represented, but obviously the shape of the aperture is not understanding the vertex array in the same way as ShapeStim.vertices is.

Thank you for the thread reference listed at the bottom. Working on implementing something like that now (but am still all ears if another suggestion is provided).


At first glance it seems the order which you specified vertices might be the issue. Looking at the code, aperture uses ShapeStim to create the stencil so is should work if you can draw the polygon correctly. Please post the vertex list you’re passing to Aperture.

##   Star 6 Stimulus  ##
nVerts = 12
star_verts = np.zeros((nVerts,2))
for vert_num in np.arange(0,star_verts.shape[0]):
    main_radius = 5
    if vert_num % 2 == 1:
        main_radius = main_radius*.65
    star_verts[vert_num, 0] = main_radius*np.sin(np.deg2rad(360/nVerts * vert_num))
    star_verts[vert_num,1] = main_radius*np.cos(np.deg2rad(360/nVerts * vert_num))

star_six = visual.ShapeStim(
    win = win,
    vertices = star_verts,
    units = 'deg',
    lineWidth = line_width,
    lineColor = 'black',
    fillColor = RGB_colors[col_val,:],
    opacity = opa_val,


shape_list = [star_six]#, square, rectangle, triangle, pentagon, rhombus, trapezoid, circle]
imgstim = visual.ImageStim(win=win, image = '/Users/Eichenbaum/Desktop/Texture_1s.eps')
    for i in np.arange(0,2):
        for j in np.arange(0, len(shape_list)):
            shape_val = shape_list[j]
            aperture = visual.Aperture(win, size = 1.0, shape = shape_val.vertices)

When plotting the polygon by itself, as shown in the 1st image from the recent post (green star), there are no issues. And the vertices, as created in the for loop in the code above, draw the star from the top vertex, and proceed in a clock-wise manner.

So I figured out what the problem was, but I am still not sure why it was happening. As can be seen in the code snippet above, I use a loop to derive the 12 vertices of the 6-sided star. I then try to set the Aperture shape to the Star_ShapeStim.vertices array, and get the problematic figure as seen in 4th screen shot I posted. Looking at the Star_ShapeStim.vertices array, it appears that, for some reason that I do not yet understand, the array is 30 x 2, instead of nVertices x 2. To fix this problem, I simply set Aperture.shape to the nVertices x 2 array that I calculated myself, and the aperture works perfectly.

Thanks for the help Michael and mdc. If anyone has info on why passing ShapeStim.vertices isn’t the same sized array as the one passed to it during creation, please let me know.

P.S. Correct Star Figure: