28

I want to estimate the noise in an image.

Let's assume the model of an Image + White Noise. Now I want to estimate the Noise Variance.

My method is to calculate the Local Variance (3*3 up to 21*21 Blocks) of the image and then find areas where the Local Variance is fairly constant (By calculating the Local Variance of the Local Variance Matrix). I assume those areas are "Flat" hence the Variance is almost "Pure" noise.

Yet I don't get constant results.

Is there a better way?

Thanks.

P.S. I can't assume anything about the Image but the independent noise (Which isn't true for real image yet let's assume it).

Royi
  • 4,640
  • 6
  • 46
  • 64

3 Answers3

34

You can use the following method to estimate the noise variance (this implementation works for grayscale images only):

def estimate_noise(I):

  H, W = I.shape

  M = [[1, -2, 1],
       [-2, 4, -2],
       [1, -2, 1]]

  sigma = np.sum(np.sum(np.absolute(convolve2d(I, M))))
  sigma = sigma * math.sqrt(0.5 * math.pi) / (6 * (W-2) * (H-2))

  return sigma

Reference: J. Immerkær, “Fast Noise Variance Estimation”, Computer Vision and Image Understanding, Vol. 64, No. 2, pp. 300-302, Sep. 1996 [PDF]

user2398029
  • 6,699
  • 8
  • 48
  • 80
  • 2
    This actually works! If you get sigma > 10.0, then you have a noisy image, otherwise - not. Also, to make it work on colored images as well, just convert them to grayscale like this: `import cv2` `img = cv2.imread(img_path)` `img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)` `noise = estimate_noise(img_gray)` – tsveti_iko Jun 15 '18 at 13:47
  • 3
    And don't forget to `import math`, `import numpy as np` and `from scipy.signal import convolve2d` ;) – tsveti_iko Jun 15 '18 at 13:50
  • 2
    Also the provided PDF link doesn't work - use this instead: https://www.sciencedirect.com/science/article/pii/S1077314296900600 – tsveti_iko Jun 15 '18 at 13:57
  • "sigma" what does this value means ?? It should we high or low ?? Is it possible to capture image without any noise if we are using DSLR ???? @tsveti_iko – M. D. P Feb 02 '19 at 04:57
  • `sigma` is the noise factor, so it should be low (lower than 10) if you want an image without noise. I didn't experiment with DSLR, so I can't tell about that – tsveti_iko Feb 04 '19 at 10:35
  • can we use the sigma as a parameter for denosing the same image ? – pylearner May 06 '20 at 09:22
  • original PDF link does not work, information from original paper can be found in other [article](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.173.1644&rep=rep1&type=pdf) – yves Jan 26 '22 at 10:37
8

Scikit Image has an estimate sigma function that works pretty well:

http://scikit-image.org/docs/dev/api/skimage.restoration.html#skimage.restoration.estimate_sigma

it also works with color images, you just need to set multichannel=True and average_sigmas=True:

import cv2
from skimage.restoration import estimate_sigma

def estimate_noise(image_path):
    img = cv2.imread(image_path)
    return estimate_sigma(img, multichannel=True, average_sigmas=True)

High numbers mean low noise.

lotif
  • 3,401
  • 2
  • 19
  • 18
  • 1
    Hi, There is indeed Donoho's method based on wavelet (Median of the power of the HH). I might add its implementation in MATLAB. Thank You. – Royi Jun 27 '18 at 05:34
7

The problem of characterizing signal from noise is not easy. From your question, a first try would be to characterize second order statistics: natural images are known to have pixel to pixel correlations that are -by definition- not present in white noise.

In Fourier space the correlation corresponds to the energy spectrum. It is known that for natural images, it decreases as 1/f^2 . To quantify noise, I would therefore recommend to compute the correlation coefficient of the spectrum of your image with both hypothesis (flat and 1/f^2), so that you extract the coefficient.

Some functions to start you up:

import numpy
def get_grids(N_X, N_Y):
    from numpy import mgrid
    return mgrid[-1:1:1j*N_X, -1:1:1j*N_Y]

def frequency_radius(fx, fy):
    R2 = fx**2 + fy**2
    (N_X, N_Y) = fx.shape
    R2[N_X/2, N_Y/2]= numpy.inf

    return numpy.sqrt(R2)

def enveloppe_color(fx, fy, alpha=1.0):
    # 0.0, 0.5, 1.0, 2.0 are resp. white, pink, red, brown noise
    # (see http://en.wikipedia.org/wiki/1/f_noise )
    # enveloppe
    return 1. / frequency_radius(fx, fy)**alpha #

import scipy
image = scipy.lena()
N_X, N_Y = image.shape
fx, fy = get_grids(N_X, N_Y)
pink_spectrum = enveloppe_color(fx, fy)

from scipy.fftpack import fft2
power_spectrum = numpy.abs(fft2(image))**2

I recommend this wonderful paper for more details.

meduz
  • 3,903
  • 1
  • 28
  • 40
  • To make things clearer, Let's say I have an Image Matrix - I. In Matlab syntax I would write: NoisyImage = I + 5 * randn(size(I)); Now, I want to estimate the variance of the noise - 25 (Assuming no noise at I). Now, the method should be reliable with much smaller factors (Variance) of the noise and later on to estimate at some degree the noise level of an practical image (With the Independent Noise Model) Thanks. P.S. Could you point me where should I look for it at the article? Do you know any others? – Royi Mar 15 '10 at 00:00
  • Would you care giving a full reference of the paper? The link you provided is now dead. Thx. – P-Gn Aug 19 '15 at 10:56
  • 2
    @user1735003 Maybe it's this paper: http://redwood.berkeley.edu/w/images/6/69/08-atick-nc-1992.pdf (just assumption from dead link url) – olha Dec 09 '16 at 14:34