利用skimage.util.random_noise函數(shù),我們可以很方便的實(shí)現(xiàn)對(duì)圖像添加高斯,泊松,椒鹽噪聲等常見噪聲。下面是函數(shù)的使用幫助:
random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs)
Function to add random noise of various types to a floating-point image.
Parameters
----------
image : ndarray
Input image data. Will be converted to float.
mode : str, optional
One of the following strings, selecting the type of noise to add:
- 'gaussian' Gaussian-distributed additive noise.
- 'localvar' Gaussian-distributed additive noise, with specified
local variance at each point of `image`.
- 'poisson' Poisson-distributed noise generated from the data.
- 'salt' Replaces random pixels with 1.
- 'pepper' Replaces random pixels with 0 (for unsigned images) or
-1 (for signed images).
- 's&p' Replaces random pixels with either 1 or `low_val`, where
`low_val` is 0 for unsigned images or -1 for signed
images.
- 'speckle' Multiplicative noise using out = image + n*image, where
n is uniform noise with specified mean & variance.
seed : int, optional
If provided, this will set the random seed before generating noise,
for valid pseudo-random comparisons.
clip : bool, optional
If True (default), the output will be clipped after noise applied
for modes `'speckle'`, `'poisson'`, and `'gaussian'`. This is
needed to maintain the proper image data range. If False, clipping
is not applied, and the output may extend beyond the range [-1, 1].
mean : float, optional
Mean of random distribution. Used in 'gaussian' and 'speckle'.
Default : 0.
var : float, optional
Variance of random distribution. Used in 'gaussian' and 'speckle'.
Note: variance = (standard deviation) ** 2. Default : 0.01
local_vars : ndarray, optional
Array of positive floats, same shape as `image`, defining the local
variance at every image point. Used in 'localvar'.
amount : float, optional
Proportion of image pixels to replace with noise on range [0, 1].
Used in 'salt', 'pepper', and 'salt & pepper'. Default : 0.05
salt_vs_pepper : float, optional
Proportion of salt vs. pepper noise for 's&p' on range [0, 1].
Higher values represent more salt. Default : 0.5 (equal amounts)
Returns
-------
out : ndarray
Output floating-point image data on range [0, 1] or [-1, 1] if the
input `image` was unsigned or signed, respectively.
由上述說明可見,函數(shù)的輸入是一個(gè)ndarray image。
但是在將16bit圖像歸一化作為輸入加泊松噪聲時(shí),發(fā)現(xiàn)函數(shù)輸出觀察不到噪聲。而換用8bit圖像,用[0, 255]區(qū)間圖像和歸一化后圖像作為輸入,輸出都可觀察到明顯噪聲。
將16bit圖像歸一化后再轉(zhuǎn)換到[0, 255]區(qū)間輸入,則可觀察到明顯噪聲。
I = imageio.imread('16bit.tif')/(2**16-1)
I_conv = (255*I).astype(np.uint8) #np.array
I_p = util.random_noise(I,mode='poisson')
I_conv_p = util.random_noise(I_conv,mode='poisson')
plt.imshow(I_p)
plt.show()
plt.imshow(I_conv_p)
plt.show()


如果換成加gaussian,椒鹽,speckle噪聲等其他與圖像信息無關(guān)的噪聲,則輸入圖像比特?cái)?shù)沒有影響
I = imageio.imread('16bit.tif')/(2**16-1)
I_conv = (255*I).astype(np.uint8) #np.array
I_p = util.random_noise(I,mode='gaussian')
I_conv_p = util.random_noise(I_conv,mode='gaussian')
plt.imshow(I_p)
plt.show()
plt.imshow(I_conv_p)
plt.show()


問題解決:
函數(shù)說明中表示‘poisson’噪聲是和圖像數(shù)據(jù)相關(guān): Poisson-distributed noise generated from the data. 因此我去scikit-image: Image processing in Python
搜索了該段的源碼,位于master/skimage/util/noise.py,poisson噪聲部分定義如下:
def img_as_float(image, force_copy=False):
"""Convert an image to floating point format.
This function is similar to `img_as_float64`, but will not convert
lower-precision floating point arrays to `float64`.
Notes
-----
The range of a floating point image is [0.0, 1.0] or [-1.0, 1.0] when
converting from unsigned or signed datatypes, respectively.
If the input image has a float type, intensity values are not modified
and can be outside the ranges [0.0, 1.0] or [-1.0, 1.0].
"""
return _convert(image, np.floating, force_copy)
## ----------------------- util.random_noise -----------------------------
# Detect if a signed image was input
if image.min() < 0:
low_clip = -1.
else:
low_clip = 0.
image = img_as_float(image)
## ...
elif mode == 'poisson':
# Determine unique values in image & calculate the next power of two
vals = len(np.unique(image))
vals = 2 ** np.ceil(np.log2(vals))
# Ensure image is exclusively positive
if low_clip == -1.:
old_max = image.max()
image = (image + 1.) / (old_max + 1.)
# Generating noise for each unique value in image.
out = np.random.poisson(image * vals) / float(vals)
# Return image to original range if input was signed
if low_clip == -1.:
out = out * (old_max + 1.) - 1.
## ...
if clip:
out = np.clip(out, low_clip, 1.0)
return out
對(duì)于16 bit圖像 val=65536,對(duì)于8 bit圖像,val=256(max)。
繪制np.random.poisson和lamda關(guān)系圖:
import scipy.stats as stats
import matplotlib.pyplot as plt
plt.plot(np.arange(256),stats.poisson.pmf(np.arange(256),mu=10))
plt.plot(np.arange(256),stats.poisson.pmf(np.arange(256),mu=50))
plt.plot(np.arange(256),stats.poisson.pmf(np.arange(256),mu=100))
plt.plot(np.arange(256),stats.poisson.pmf(np.arange(256),mu=256))
#LEGEND 圖例
plt.xlim(0,256)
plt.legend(["$λ=10$", "$λ=50$", "$λ=100$", "$λ=256$"])
plt.show()
對(duì)于歸一化后的16 bit圖像輸入,我們使用val=256,輸出圖像則可看到明顯的噪聲。因此是由于val值過大導(dǎo)致np.random.poisson(lamda) 的lamda較大,因此值較小。
