如何利用python正確地為圖像添加高斯噪聲
開(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之間的像素)。
在很多應(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 要大。
所以,設(shè)置方差為0.1,噪聲要比設(shè)置標(biāo)準(zhǔn)差為0.1大不少。注意不要用混了就可以。
是否截?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>
疊加噪聲之后,圖片數(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)文章
Jupyter 無(wú)法下載文件夾如何實(shí)現(xiàn)曲線救國(guó)
這篇文章主要介紹了Jupyter 無(wú)法下載文件夾如何實(shí)現(xiàn)曲線救國(guó)?今天小編就為大家?guī)?lái)了解決方法,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04Python+OpenCV檢測(cè)燈光亮點(diǎn)的實(shí)現(xiàn)方法
這篇文章主要介紹了Python+OpenCV檢測(cè)燈光亮點(diǎn)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Python機(jī)器學(xué)習(xí)pytorch模型選擇及欠擬合和過(guò)擬合詳解
如何發(fā)現(xiàn)可以泛化的模式是機(jī)器學(xué)習(xí)的根本問(wèn)題,將模型在訓(xùn)練數(shù)據(jù)上過(guò)擬合得比潛在分布中更接近的現(xiàn)象稱為過(guò)擬合,用于對(duì)抗過(guò)擬合的技術(shù)稱為正則化2021-10-10Python實(shí)現(xiàn)自動(dòng)計(jì)算特定格式的時(shí)間差
這篇文章主要介紹了利用Python實(shí)現(xiàn)在輸入一個(gè)特定格式的時(shí)間后,自動(dòng)獲取前進(jìn)或者后退多少小時(shí)之后的時(shí)間。感興趣的朋友可以了解一下2021-12-12pyshp創(chuàng)建shp點(diǎn)文件的方法
今天小編就為大家分享一篇pyshp創(chuàng)建shp點(diǎn)文件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12python?pandas創(chuàng)建多層索引MultiIndex的6種方式
這篇文章主要為大家介紹了python?pandas創(chuàng)建多層索引MultiIndex的6種方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07從局部變量和全局變量開(kāi)始全面解析Python中變量的作用域
無(wú)論是以類為基礎(chǔ)的面相對(duì)象編程,還是單純函數(shù)內(nèi)部變量的定義,變量的作用域始終是Python學(xué)習(xí)中一個(gè)必須理解掌握的環(huán)節(jié),下面我們從局部變量和全局變量開(kāi)始全面解析Python中變量的作用域,需要的朋友可以參考下2016-06-06Python實(shí)現(xiàn)批量自動(dòng)整理文件
本文將利用Python制作一個(gè)批量自動(dòng)整理文件的小工具,可以自定義整理某一個(gè)路徑下面的所有需要被整理的文件。感興趣的小伙伴可以了解一下2022-03-03