Search code examples
pythonnumpyimage-processingmatplotlibnoise

How to generate noise with a chosen spatial distribution with numpy?


I want to add noise to an image in a way similar to this :

import numpy as np
import matplotlib.pyplot as plt

myImage = plt.imread('Pikachu.png')
noise = np.random.normal(0, 0.1, (myImage.shape[0], myImage.shape[1]))

noisyImage = myImage + noise

However, I would need the noise to be more intense in the center of the image, and less intense as we get farther from the center.

Ideally, I could regulate the spatial distribution parameter of the noise so that my noise variable contains :

  • Initialization : Intense and uniform noise on all the image
  • Early stages : Intense noise in the center, less noise on the borders
  • Mid-stages : Noise in the center, no more noise on the border
  • Late stages : No more noise on all the image (all zeros)

Does anyone know a way to do it? Any help is really appreciated!


Solution

  • Something you could use as a starting point:

    import numpy as np
    import matplotlib.pyplot as plt
    
    def gauss2D(shape,sx=1,sy=1):
        """
        unnormalized 2D gauss centered on mean value, 
        given shape and standard dev (sx and sy).
        """
        mx = shape[0]/2
        my = shape[1]/2
    
        return np.exp( -0.5*(
            ((np.arange(shape[0])[:,None]-mx)/sx)**2+
            ((np.arange(shape[0])[None,:]-my)/sy)**2
            ))#/(2*np.pi*sx*sy)
    
    width,height = 64,64
    my_img = np.zeros((width,height,3))+0.9
    fig = plt.figure()
    ax = fig.gca()
    N=5
    for i in range(N):
        my_img[:,:,:]=0.5 #gray bg image
        w = N*100/(4**(2*i))
        A = (1-.1*(i+1))
        noise =A*np.random.normal(0,w,(width,height))*gauss2D((width,height),10,10)
        plt.imshow(my_img+noise[:,:,None]) #noise affects rgb equally
        plt.title(i)
        plt.show()
    

    with output:

    enter image description here enter image description here enter image description here enter image description here enter image description here

    Here the noise was sampled from a gaussian distribution, but a uniform distribution should work fine.

    The important part is to weight the noise by a gaussian to get the effect you desire.

    You might want to tweak A(amplitude), and w(spread) to fit your needs(it could just be two lists). You want high amplitude and spread early, then first decrease spread possibly increasing the amplitude, then decreasing the amplitude to zero.