Reputation: 11
I am trying to add noise to images in psychopy. I was using imread but do not appear able to read images in the format needed to add noise to individual pixels throughout the image. I'm hoping someone may have ideas of how I might be able to do this.
Specifically, my task presents stimuli to participants at their own perceptual threshold. I am using an adaptive staircasing procedure (the quest handler) to titrate between trials the amount of noise added to an image to reach this threshold. i.e., the participant identifies the image correctly, the next image has more noise; they identify an image incorrectly, the next trial has less noise. We do this over repeated trials to get the amount of noise needed for participants to answer a certain percentage of trials correctly.
I'm trying to add an amount of noise at each trial equal to the percent of noise passed from the quest handler by altering individual pixels to add gaussian noise. I do not wish to alter the original image. I envision this working by reading the image in as a matrix of pixels, copying it, adding noise to pixels in that matrix, and presenting that new stimulus for that trial. The imread function I was using to read in my images does not appear able to do this - does anyone have any suggestions?
Upvotes: 1
Views: 551
Reputation: 19310
I have demonstrated how one can read an image with cv2
and apply varying levels of noise to it. The noise addition does not modify the original image. As @Michael MacAskill wrote in his comments, you can apply noise to an image with a single vector operation. In my answer, I create a Gaussian with mean 1 and the same shape as the image, and I multiply it against the image. The level of noise can be increased by increasing the standard deviation of the Gaussian noise distribution.
import cv2
import matplotlib.pyplot as plt
import numpy as np
def apply_noise(image, scale):
"""Return image with noise.
Parameters
----------
image : ndarray, image to which noise is applied.
scale : positive float, standard deviation of Gaussian
noise distribution.
"""
image = np.asarray(image)
# Create a Gaussian noise array.
noise = np.random.normal(loc=1.0, scale=scale, size=image.shape)
# Apply the noise array.
noisy = image * noise
# Tranform to integer type.
noisy = noisy.astype(np.int32)
# Clip the values to RGB bounds.
noisy = noisy.clip(0, 255)
return noisy
I downloaded a sample image using
wget -qO "astronaut.jpg" https://live.staticflickr.com/8674/16504233985_9f1060624e_q_d.jpg
and here are sample results. The original image:
img = cv2.imread("astronaut.jpg")
# Transform from BGR to RGB
img = img[..., ::-1]
plt.imshow(img)
The image with some noise applied:
img_a = apply_noise(image=img, scale=0.1)
plt.imshow(img_a)
plt.title("Gaussian std. dev. = 0.1")
The image with more noise applied:
img_b = apply_noise(image=img, scale=0.5)
plt.imshow(img_b)
plt.title("Gaussian std. dev. = 0.5")
Upvotes: 0