Code:
from PIL import Image
from numpy import asarray
import numpy as np
import math
import cv2
""" Add photon shot noise (poisson noise) and read noise (gaussian noise)
to the image
"""
def noisy(noise_typ,image):
if noise_typ == "gauss":
row,col,ch= image.shape
mean = 0
var = 0.1
sigma = var**0.5
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
noisy = image + gauss
return noisy
elif noise_typ == "poisson":
vals = len(np.unique(image))
vals = 2 ** np.ceil(np.log2(vals))
noisy = np.random.poisson(image * vals) / float(vals)
return noisy
""" Calculate image's mean, standard deviation, and SNR """
def mean_std_snr(img):
img_int = asarray(img)
img_float32 = img_int.astype('float32')
img_mean, img_std = img_float32.mean(), img_float32.std()
img_snr = 20*math.log10(img_mean/img_std)
return({'mean': img_mean, 'std': img_std, 'snr': img_snr})
files = [{'name': 'mgrey3840x2160_noiseless.jpg'},
{'name': 'mgrey3840x2160_poisson_gauss.jpg'},
{'name': 'mgrey1920x1080_poisson_gauss_downsampled.jpg'},
{'name': 'mgrey960x540_poisson_gauss_cropped.jpg'},
{'name': 'mgrey1920x1080_poisson_gauss_upsampled.jpg'}]
# Generate a 4K-size JPEG image
img0 = Image.new('RGB', (3840, 2160), color = (118, 118, 118))
img0_pix_float32 = asarray(img0).astype('float32')
files[0].update(mean_std_snr(img0))
img0.save(files[0]['name'], format='JPEG', quality=100)
# Add photon shot noise and read noise to the generated image
# and calculate the mean, stdev and SNR
img1_pix_poisson = noisy('poisson', img0_pix_float32)
img1_pix_poisson_gauss = noisy('gauss', img1_pix_poisson)
files[1].update(mean_std_snr(img1_pix_poisson_gauss))
img1_pix_int = img1_pix_poisson_gauss.astype('uint8')
img1 = Image.fromarray(img1_pix_int)
img1.save(files[1]['name'], format='JPEG', quality=100)
# Downsample image to FHD-size image for viewing on monitor
# and calculate the mean, stdev and SNR
img2 = img1.resize((1920, 1080), resample=Image.LANCZOS)
files[2].update(mean_std_snr(img2))
img2.save(files[2]['name'], format='JPEG', quality=100)
# Crop the original, noise-added image to 960x540 pixels
img3 = img1.crop((1440, 810, 2400, 1350))
files[3].update(mean_std_snr(img3))
img3.save(files[3]['name'], format='JPEG', quality=100)
# Upsample the cropped image to FHD-size for viewing on monitor
# and calculate the mean, stdev and SNR
img4 = img3.resize((1920, 1080), resample=Image.LANCZOS)
files[4].update(mean_std_snr(img4))
img4.save(files[4]['name'], format='JPEG', quality=100)
# Print the result
for file in files:
print(f'Filename: {file["name"]}\r\n' +
f'Mean: {str(round(file["mean"], 2))}\r\n' +
f'StdDev: {str(round(file["std"], 2))}\r\n' +
f'SNR: {str(round(file["snr"], 2))}\r\n\r\n')