如何利用python正確地為圖像添加高斯噪聲
開門見山,直接使用 skimage 庫為圖像添加高斯噪聲是很簡單的:
import skimage origin = skimage.io.imread("./lena.png") noisy = skimage.util.random_noise(origin, mode='gaussian', var=0.01)
但是如果不用庫函數(shù)而自己實現(xiàn)的話,有幾個問題是值得注意的。
彩圖 or 灰度圖
讀取圖片時,圖片可能是有三通道的RGB圖片,也有可能是單通道的灰度圖,甚至四通道的RGBA圖。
通道數(shù)不同會影響圖像數(shù)據(jù)的 shape ,例如: (256, 256, 3) 、(256, 256)
很多人按照MATLAB的習慣,使用 np.random.randn 來生成高斯噪聲,則需要根據(jù)通道數(shù)調整參數(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)
前兩個參數(shù)分別為 均值和標準差,第三個參數(shù)為生成數(shù)據(jù)的 shape,直接將圖像本身shape輸入進去,更加優(yōu)雅。
uint8 or float64
一般遇到的圖像都是8bit的,用skimage或opencv讀取后會發(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
你會發(fā)現(xiàn) plt.imshow 出來的是一片空白,或者有零星幾個噪點。
以一個像素為例分析原因:
- 圖像本身是[0, 255]的整數(shù):[226 137 125]
- 生成的噪聲是浮點數(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ù)是無法正確顯示的(只顯示了恰好落在0-1之間的像素)。
在很多應用中,為了方便計算,都會將圖像數(shù)據(jù)轉換為浮點數(shù),float64,取值范圍為 [0, 1]。
為了轉換數(shù)據(jù)類型,最簡單的方式是直接除以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 標準差
高斯噪聲符合一個均值為0,方差為 σ 2 \sigma^2 σ2 的高斯分布。
均值為0,是保證圖像的亮度不會有變化,而方差大小則決定了高斯噪聲的強度。
方差/標準差越大,噪聲越強。
這里有一點點初中數(shù)學的細節(jié),就是在[0, 1]區(qū)間內, y = x y=\sqrt{x} y=x ? 比 y = x y=x y=x 要大。
所以,設置方差為0.1,噪聲要比設置標準差為0.1大不少。注意不要用混了就可以。
是否截斷(clip)
由于需要把噪聲疊加到原圖像中,因此疊加后的數(shù)據(jù)值就可能超出對應數(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自動將圖片做了截斷。
而不知為何,matplotlib并不會自動對灰度圖進行截斷,例如:
疊加噪聲之后,圖片數(shù)據(jù)的最小值和最大值分別為 -0.32 和 1.25,這明顯超過了[0, 1]的范圍。
這樣顯示出的圖片是不正確的(中間圖像),更像是重新將圖像縮放到了[0, 1]范圍內,就像將色階向外擴了一樣,對比度也下降了。
使用 np.clip,將圖像截斷到 [0, 1]之間,如右圖所示,圖像明顯正常了很多。
總結
完整的代碼如下:
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)
當然,上述問題在 skimage.util.random_noise
中都已解決,工程中可以直接使用。
import skimage origin = skimage.io.imread("./lena.png") noisy = skimage.util.random_noise(origin, mode='gaussian', var=0.01)
推薦學習skimage的源碼。
參考
https://zhuanlan.zhihu.com/p/50820267
http://chabaoo.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
到此這篇關于如何利用python正確地為圖像添加高斯噪聲的文章就介紹到這了,更多相關python為圖像加高斯噪聲內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python+OpenCV檢測燈光亮點的實現(xiàn)方法
這篇文章主要介紹了Python+OpenCV檢測燈光亮點的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11Python機器學習pytorch模型選擇及欠擬合和過擬合詳解
如何發(fā)現(xiàn)可以泛化的模式是機器學習的根本問題,將模型在訓練數(shù)據(jù)上過擬合得比潛在分布中更接近的現(xiàn)象稱為過擬合,用于對抗過擬合的技術稱為正則化2021-10-10python?pandas創(chuàng)建多層索引MultiIndex的6種方式
這篇文章主要為大家介紹了python?pandas創(chuàng)建多層索引MultiIndex的6種方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07