'Image noise estimation base on histogram

I want to estimate noise level of an input image.

I have made some histogram of noisy and original images and compared them, and by looking at histogram in two different stage of an image one can tell which one is noisy and what type of noise is present. (by saying noise, i mean common types of noise like Gaussian, Poisson, Speckle and so on)

I want to know if there is a way to detect noise model and then estimate level of noise (base on specific noise model like std for Gaussian) from image histogram? like identify density function? or maybe this task needs input in other form than spatial domain, like it needs to transform image and then maybe perform the task.

I am using an image with very low changes in pixel values like a gradient and then i apply noises myself to compare histograms of noise-free and noisy images.

Edit: For clearance, i know you can detect noise based on looking at histogram. I am looking for a way that i don't do this "visually" myself. I want to detect noise and maybe density function, after that do something if it is Gaussian or Poisson or... .

I appreciate if anyone can give any hints about what is the right path to solve this problem.



Solution 1:[1]

Generally speaking, its impossible to determine the noise distribution by means of analyzing the histogram. Because, its hard to determine whether the variations are due to image texture and lighting variation, or, the noise. Here is a simple example histogram of original and noisy image (Gaussian noise) of beach sand:

comparison of histogram of noisy and unnoisy images

As the image variance is considerable and has a Gaussian distribution itself, the noise does change the histogram slightly. Note that we do not have original image in real world for comparison.
For your case, as described, the original image is smooth, so the variance of image is low. Any noise can increase the variance considerably which is obvious in histogram. so for the basic part of question,

I want to estimate noise level of an input image.

The simplest technique used for estimating the noise of a image is by finding the most smooth part of the image, find histogram of that part and estimate noise distribution of the whole image based on the part. Here is an example of noise estimation using Opencv:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('cameraman.bmp',0)
row, col = img.shape
gauss = np.random.normal(10,10,(row,col))
noisy = img + gauss
smooth_part = noisy[:30, :30]

plt.subplot(221),plt.imshow(noisy,cmap = 'gray')
plt.title('Noisy Image'), plt.xticks([]), plt.yticks([])
plt.subplot(222),plt.imshow(smooth_part,cmap = 'gray')
plt.title('Smooth Part'), plt.xticks([]), plt.yticks([])
plt.subplot(223),plt.hist(noisy.ravel(),256,[0,256])#; plt.show()
plt.title('Noisy Image Histogram'), plt.xticks([]), plt.yticks([])
plt.subplot(224),plt.hist(smooth_part.ravel(),256,[0,256])#; plt.show()
plt.title('Estimated Noise Distribution'), plt.xticks([]), plt.yticks([])
plt.show()

and the result:

Estimated Noise

Solution 2:[2]

There is of course a way to detect noice and its a very simple one. The easiest way to detect noise is to take the difference of denoised image from a noisy image.

let me know if you need my code and maybe I can help.

For reference, i'll put down my whole program where i coded to take an averaged image from 16 images of the same pixel (to remove the noise) and then modify the code to detect the noise itself.

import glob
import cv2

# Reading all images in an array
images = []
for img in glob.glob("/<ADDRESS IF THE FOLDER WHERE YOU HAVE YOUR IMAGES STORED>/*.bmp"):
    n= cv2.imread(img)
    images.append(n)

imlist = images



import os, numpy, PIL
from PIL import Image

def Myimaver(imlist):
  # Showing the first image
  plt.imshow(imlist[0])
  plt.title('First Image')
  plt.show()

  # Assuming all images are the same size, get dimensions of first image
  w,h=Image.fromarray(imlist[0]).size
  N=len(imlist)

  # Create a numpy array of floats to store the average (assume RGB images)
  arr=numpy.zeros((h,w,3),numpy.float)

  # Build up average pixel intensities, casting each image as an array of floats
  for im in imlist:
      imarr=numpy.array(Image.fromarray(im),dtype=numpy.float)
      arr=arr+imarr/N

  # Round values in array and cast as 8-bit integer
  arr=numpy.array(numpy.round(arr),dtype=numpy.uint8)

  # Generate, save and preview final image
  out=Image.fromarray(arr,mode="RGB")

  plt.imshow(out)
  plt.title('Averaged Image')
  plt.show()

  showNoisedImage(imlist, arr, h, w)





def showNoisedImage(imlist, arr, h, w):
  # Create a numpy array of floats to store the noise
  arr2=numpy.zeros((h,w,3),numpy.float)

  # Noised image is the difference between the first image and the averaged image
  arr2 = imlist[0] - arr

  # Round values in array and cast as 8-bit integer
  arr2=numpy.array(numpy.round(arr2),dtype=numpy.uint8)

  # Display the noised image
  out=Image.fromarray(arr2,mode="RGB")

  plt.imshow(out)
  plt.title('Noised Image')
  plt.show()

Checkout my line

arr2 = imlist[0] - arr

here, imlist[0] is my noised image and arr is my denoised image (executed from the function 'Myimaver') So arr2 comes out to be the NOISE DETECTION.

and then you can use arr2 to to be displayed in a histogram!

Maybe by this:

# Displaying a histogram
  plt.hist(arr2.ravel(),256,[0,256])
  plt.title('Noise histogram')
  plt.show()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Masoud
Solution 2 abbujaansboy