| Reference | Downloads | Github

How to add visual noise to images in Builder?

Dear Psychopy Users,

this is my very first time using Psychopy. Until now it went pretty well, but now I have a problem and I hope that you can help me with it.
I am working in the Builder.
I have different visual stimuli (pictures of stars and circles) and I have to embedd them into a visual noise (that kind of noise you get on TV when there’s no signal) so that one cannot clearly see the shapes.
Until now i made this noise in Photoshop and then just presented the pictures, but the problem is that i have to change the noise according to every participants perception threshold. This would be nearly impossible to do if I make all the noises with photoshop.
That is why I need an easy way to create this noise directly in Psychpy and just put it on the picture.
Is there a possibility to do that in the Builder? I would also be thankful for some helpful code!

Thanks a lot in advance!



OS : Win 10
PsychoPy version : 1.85.2

Greetings Réka,

I may have a solution that you could use.

For starters, you can use an ImageStim in builder, but in a slightly different way than normal.
Rather than passing the ImageStim a file name in Image, you can pass it an array that has the RGB (or Grayscale) values you want.

# will use it for noise generation
import numpy as np
# will use it to load images
import scipy.ndimage as spi
# load the image and convert it to a 0.0 to 1.0 range (the range PsychoPy uses with RGB images)
img = spi.imread("stimuli/8.png", mode = "RGBA")/255.0

If you load your images as arrays, you can freely add noise to them.

noise_level = 1.
# generates noise from negative noise_level to positive noise_level (-1 to 1, in this case)
# because the shape of the np noise array is (width, height, 1), it can broadcast onto any number of dimensions, meaning you could use grayscale or RGB and still have the 'white static' look.
presented = img + 2*np.random.random((img.shape[0],img.shape[1], 1))*noise_level-noise_level 

However, the presented stimulus must not exceed the bounds of 0 and 1 or you will get a glitchy looking picture. So, use numpy’s where function to fix the out of bounds values.

# set values that are higher than 1 to 1
presented[np.where(presented >1)] = 1.
# set values that are lower than 0 to 0
presented[np.where(presented <0)] = 0.

You can make the ImageStim use $presented in the “Image” field that you should set to change during an ISI that runs the code each “begin routine”. Also, loading an image with scipy means that you need to make the Y value for the image Size field a negative value so it flips up/down.


Ideally, you would use a Builder view loop with a spreadsheet that had a list of filenames in a column called “filename” (no quotes). That way, a different filename would be loaded for each trial:

# changing the load code to allow trial by trial filenames
# "stimuli" is just a folder I made to test this.
img = spi.imread("stimuli/{0}".format(filename), mode = "RGBA")/255.0

That should cover it.

It’s my first post here, so I’m not sure if the Markdown will show properly.


1 Like

Hey Jason,

thanks a lot for your help. I tried it and it worked! :slight_smile:
The problem is that the noise in this case is rather in the background at it is not strong enough.
It should be stronger, such that I can only guess what shape I see in the picture.
Can I simply change the value for noise_level or what can I do about that?


@jhays006 has provided code that effectively provides noise at a pixel level for a greyscale images. You need to describe what you need for your particular images. e.g. if your images are black and white rather than greyscale, then it could be that you want the noise function to produce discrete black or white values rather than a continuous grey value.

My pictures are just black and white. White background with a black shape on it. Just like the attached picture. I need the noise to be strong enough, such that the shape is nearly invisible.


Thanks a lot for your help!
We changed something on the experiment and agreed on a version without the noise! :slight_smile: