Search code examples
pythonsignal-processingwhitenoise

Add white-noise on image based on SNR


I would like to add white noise to an original image with different SNR levels, but not sure how to do.

The original image is (256, 128) I am using acoustics package to add noise.

original = cv2.imread(path)
white = acoustics.generator.white(256*128).reshape(256, 128)
out = original + white*255

cv2.imwrite(path, out)

My questions:

  1. Does log10(mean(original)/ std(original + white*255)) count as SNR?(according to wiki)

  2. If so, can I just modify *255 this number to modify SNR?

  3. If not, how can I calculate the SNR value?


Solution

  • The key fact is that (this is maths, not code)

    SNR = mean(s) / std(n)
    

    Multiplying the noise by some constant A results in a new SNR -- SNR_new

    mean(s) / std(A*n) 
    = mean(s) / (A * std(n)) 
    = (1 / A) * (mean(s) / std(n)) 
    = SNR / A
    = SNR_new
    

    So working backwards, I think this is the correct approach in python is:

    def add_noise(signal, snr):
        ''' 
        signal: np.ndarray
        snr: float
    
        returns -> np.ndarray
        '''
    
        # Generate the noise as you did
        noise = acoustics.generator.white(signal.size).reshape(*signal.shape)
        # For the record I think np.random.random does exactly the same thing
    
        # work out the current SNR
        current_snr = np.mean(signal) / np.std(noise)
    
        # scale the noise by the snr ratios (smaller noise <=> larger snr)
        noise *= (current_snr / snr)
    
        # return the new signal with noise
        return signal + noise