Display multiple images simultaneously

Hi,

I wonder what’s the best way to display multiple images on the screen simultaneously. (Preferably with only one image component)

I have 100 small images to display at the same time, with their file names in a condition file. The image position varies, and is calculated/randomized in a code component.

My guess is that some custom codes are needed so that the screen flips only after all images are placed on the screen, instead of flipping 100 times.

I appreciate any further comments.

If you added 100 image Components, I believe it would only flip the screen once, as the flip command happens at the end of the frame loop rather than after each component. I can see why you wouldn’t want to add all those components though…

What you could do is have all the file names in an excel cell separated by a delimeter (such as a comma), then use a Variable component to split them apart into a list. For example, if your excel sheet looked like this:
image

You could create a Variable component with the value:

$ImageFile.split(",")

This means the Variable, let’s call it imlist, will be a list of all the filenames there, as it splits the cell value at every comma.

The challenge then is creating all the Image components - but you could create one in Builder, then in a Code component you could make 100 copies using .copy() and set the image value of each to the corresponding image file, then store them in a list, something like:

for i in range(100):
    images[i] = MyImage.copy()
    images[i].image = imlist[i]

You’d then have to add code to draw each image rather than just draw the original, but if you give this first bit a go and let me know how you get on I can then help you further.

I got a bit lost starting at copying the component 100 times. What is MyImage in your example? I also wasn’t sure how you would use images[i] when you actually draw them. Some elaboration would be very helpful.
Thanks.

MyImage in this case is your placeholder Image component in Builder view, so when you say MyImage.copy() what you’re saying is “I’ve made this blank Image component in Builder, now make a copy of it”.

images will therefore be a list of Image objects, so you can do anything to images[i] that you would do to MyImage, if that makes sense? I think drawing it should be as simple as adding to the Each Frame tab:

for i in range(100):
    images[i].draw()

As you’re essentially saying “for each image in images, perform it’s draw command”

It’s starting to make sense, while it gives me an error with the copy() command:
'ImageStim' object has no attribute 'copy'

Any thought?

Oops, my mistake! Some objects in Python have a copy method, I thought ImageStim did too… So instead you’ll need to add:

import copy

to the Begin Experiment tab, then rather than MyImage.copy() use copy.copy(MyImage) - so essentially you’re importing a method to copy it rather than using its own method. Does the same thing though!

Ok, it makes sense. Now there’s one last issue, I believe. When we copy the image component, we are copying an “ImageStim” object in PsychoPy. It seems though the indexing is having a problem -

for i in range(3):
    images[i] = copy.copy(imageSample)
    images[i].image = imList[i]

IndexError: list assignment index out of range

Another similar error -
'ImageStim' object does not support indexing

When I tried this method with only one image (so no indexing), it worked fine.

Ah, I guess you need to initialise a blank list first… You could try adding this to the beginning:

images = []*len(imList)

or you could do this:

for i in range(len(imList)):
    images.append(copy.copy(imageSample))
    images[i].image = imList[i]

which should work too. Which you go with is personal preference really!

Oh yes, of course I should do it this way. Silly question.
Now the images are drawn on screen properly. Glad that I don’t need to create 100 components in the builder. :grinning:

Thanks Todd.

Hi,

I had a similar siuation as describen here and followed the advices. However, here I have some porblems:

for i in range(100):
images[i].draw()

The end it only shows me the last image of the images list. Any idea of what I need to change?

Many thanks in advance!
Annkathrin

How are the images spaced out?

They should be dispalyed in a 5x5 grif with each image being 0.9x0.9 and a spacing of 0.1 between them.

Is this in norm/height units? If the image is 0.9x0.9 and there’s a gap of 0.1 between it and the next one, the next one would likely be off the screen

No, the spatial units are from the exp settings and I can actually see the images for a very short time and then it ends with only showing the last image. My impression is that for every frame it changes which images is shown but it is not showing all images. I am not really sure if that is possible and how to change that.

What spatial units do you have in experiment settings? If you could share your experiment file that would be helpful

EBIST_01_08_23.psyexp (80.7 KB)

Hi, this is the current version of my experiment. What I actaully want to archieve is to have a 5x5 grid of grey images and change them on a mouse click.

I think the problem is probably with using copy - copy.copy is only a surface level copy, so it probably still keeps the same stuff underneath, meaning when you set the position it sets it for all copies. Instead I’d recommend just initialising a new image with the relevant parameters:

images.append(visual.ImageStim(
    win,
    image=imList[i],
    mask=stimuli_image.mask,
    units=stimuli_image.units,
    pos=positionList[i],
    size=stimuli_image.size,
    anchor=stimuli_image.anchor,
    ori=stimuli_image.ori,
    ...etc
)

Thank you so much. It now worked! :slight_smile: