欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何利用python正確地為圖像添加高斯噪聲

 更新時(shí)間:2022年03月17日 09:44:29   作者:howlclat  
這篇文章主要給大家介紹了關(guān)于如何利用python正確地為圖像添加高斯噪聲的相關(guān)資料,需要的朋友可以參考下

開(kāi)門見(jiàn)山,直接使用 skimage 庫(kù)為圖像添加高斯噪聲是很簡(jiǎn)單的:

import skimage

origin = skimage.io.imread("./lena.png")
noisy = skimage.util.random_noise(origin, mode='gaussian', var=0.01)

但是如果不用庫(kù)函數(shù)而自己實(shí)現(xiàn)的話,有幾個(gè)問(wèn)題是值得注意的。

彩圖 or 灰度圖

讀取圖片時(shí),圖片可能是有三通道的RGB圖片,也有可能是單通道的灰度圖,甚至四通道的RGBA圖。

通道數(shù)不同會(huì)影響圖像數(shù)據(jù)的 shape ,例如: (256, 256, 3) 、(256, 256)

很多人按照MATLAB的習(xí)慣,使用 np.random.randn 來(lái)生成高斯噪聲,則需要根據(jù)通道數(shù)調(diào)整參數(shù)。

# RGB
noise = sigma * np.random.randn(256, 256, 3)
# GRAY
noise = sigma * np.random.randn(256, 256)

為了通用的處理,最好使用 np.random.normal 生成高斯噪聲。

noise = np.random.normal(mean, var ** 0.5, image.shape)

前兩個(gè)參數(shù)分別為 均值和標(biāo)準(zhǔn)差,第三個(gè)參數(shù)為生成數(shù)據(jù)的 shape,直接將圖像本身shape輸入進(jìn)去,更加優(yōu)雅。

uint8 or float64

一般遇到的圖像都是8bit的,用skimage或opencv讀取后會(huì)發(fā)現(xiàn)數(shù)據(jù)類型是uint8的ndarray,取值范圍是 [0, 255] 。

如果手賤直接在整型數(shù)據(jù)上添加高斯噪聲,如:

image = io.imread("lena.png")
noise = np.random.normal(0, 10, image.shape)
noisy = image + noise

你會(huì)發(fā)現(xiàn) plt.imshow 出來(lái)的是一片空白,或者有零星幾個(gè)噪點(diǎn)。

以一個(gè)像素為例分析原因:

  • 圖像本身是[0, 255]的整數(shù):[226 137 125]
  • 生成的噪聲是浮點(diǎn)數(shù):[-2.92864248 4.04786763 12.23436435]
  • 相加后最后的數(shù)據(jù):[223.07135752 141.04786763 137.23436435]

matplotlib 的 imshow 要求輸入是 (0-1 float or 0-255 int),所以上述不倫不類的數(shù)據(jù)是無(wú)法正確顯示的(只顯示了恰好落在0-1之間的像素)。

int or float

在很多應(yīng)用中,為了方便計(jì)算,都會(huì)將圖像數(shù)據(jù)轉(zhuǎn)換為浮點(diǎn)數(shù),float64,取值范圍為 [0, 1]。

為了轉(zhuǎn)換數(shù)據(jù)類型,最簡(jiǎn)單的方式是直接除以255:

image = io.imread("./lena.png")
print(image.dtype)					# uint8

image = image/255
print(image.dtype)					# float64

更穩(wěn)妥的做法,可以使用skimage的img_to_float()

image = img_as_float(image)

這樣再添加高斯噪聲就可以正確顯示。

方差 or 標(biāo)準(zhǔn)差

高斯噪聲符合一個(gè)均值為0,方差為 σ 2 \sigma^2 σ2 的高斯分布。

均值為0,是保證圖像的亮度不會(huì)有變化,而方差大小則決定了高斯噪聲的強(qiáng)度。

方差/標(biāo)準(zhǔn)差越大,噪聲越強(qiáng)。

這里有一點(diǎn)點(diǎn)初中數(shù)學(xué)的細(xì)節(jié),就是在[0, 1]區(qū)間內(nèi), y = x y=\sqrt{x} y=x ? 比 y = x y=x y=x 要大。

sqrtx

所以,設(shè)置方差為0.1,噪聲要比設(shè)置標(biāo)準(zhǔn)差為0.1大不少。注意不要用混了就可以。

sigma

是否截?cái)啵╟lip)

由于需要把噪聲疊加到原圖像中,因此疊加后的數(shù)據(jù)值就可能超出對(duì)應(yīng)數(shù)據(jù)類型的取值范圍。

如果用matplotlib顯示超出范圍的彩色圖像,則可能遇到以下提示:

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

matplotlib自動(dòng)將圖片做了截?cái)唷?/p>

而不知為何,matplotlib并不會(huì)自動(dòng)對(duì)灰度圖進(jìn)行截?cái)啵纾?/p>

clip

疊加噪聲之后,圖片數(shù)據(jù)的最小值和最大值分別為 -0.32 和 1.25,這明顯超過(guò)了[0, 1]的范圍。

這樣顯示出的圖片是不正確的(中間圖像),更像是重新將圖像縮放到了[0, 1]范圍內(nèi),就像將色階向外擴(kuò)了一樣,對(duì)比度也下降了。

使用 np.clip,將圖像截?cái)嗟?[0, 1]之間,如右圖所示,圖像明顯正常了很多。

總結(jié)

完整的代碼如下:

from skimage import io, img_as_float
import numpy as np

mean = 0
var = 0.01

image = io.imread("./lena.png")

image = img_as_float(image)
noise = np.random.normal(mean, var**0.5, image.shape)
noisy = image + noise
noisy = np.clip(noisy, 0.0, 1.0)

當(dāng)然,上述問(wèn)題在 skimage.util.random_noise 中都已解決,工程中可以直接使用。

import skimage

origin = skimage.io.imread("./lena.png")
noisy = skimage.util.random_noise(origin, mode='gaussian', var=0.01)

推薦學(xué)習(xí)skimage的源碼。

參考

https://zhuanlan.zhihu.com/p/50820267

http://www.dbjr.com.cn/article/241120.htm

https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.imshow.html

https://github.com/scikit-image/scikit-image/blob/v0.17.2/skimage/util/noise.py#L8

到此這篇關(guān)于如何利用python正確地為圖像添加高斯噪聲的文章就介紹到這了,更多相關(guān)python為圖像加高斯噪聲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論