噪音的产生

所谓噪音,就是指在原始信号中出现了我们不希望的信号,或者干扰。了解噪音的生成方法,是为了方便我们更好的评估去噪函数。通常,在图像学领域,由于传感器的原因,会出现3种比较常见的噪音。

分别是椒盐噪音、高斯噪音以及泊松噪音。现在就来分别了解下这些噪音的产生原因,以及手工实现噪音产生的方法。

噪音函数

之所以降噪,是因为在图像数据的存储、传输过程中,通常会因为电子元器件之间的电磁干扰产生,又或者图像数据在传输过程中遇到来自自然界、或者人为的干扰。

举个例子来说,过去黑白电视机经常由于电信号干扰,而在图像中产生雪花。又或者是拿一个强磁,对着电子管的电视机进行干扰,而在图像中出现一些水纹波。

那么,工程师们根据经验,把常见噪音进行了以下几种的分类。

1. 椒盐噪音(Salt Pepper Noise)

在这里插入图片描述
椒盐噪声(salt-and-pepper noise)又称脉冲噪声,它随机改变一些像素值,在二值图像上表现为使一些像素点变白,一些像素点变黑。 是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声,也就是老人们比较熟悉的所谓“雪花”。

N = { 0 p e p p e r 255 s a l t N = \left\{\begin{matrix} 0 & pepper\\ 255 & salt \end{matrix}\right. N={0255peppersalt

def salt_pepper_noise(image, ratio):
    output = np.zeros(image.shape, np.uint8)

    for i in range(image.shape[0]):
        for j in range(image.shape[1]):

            rand = random.random()
            if rand < ratio:  # salt pepper noise
                if random.random() > 0.5:  # change the pixel to 255
                    output[i][j] = 255
                else:
                    output[i][j] = 0
            else:
                output[i][j] = image[i][j]

    return output

输出效果:

在这里插入图片描述

2. 高斯噪音(Gaussian Noise)

文字的描述比较枯燥,我这里就直接贴一张图来说明什么叫高斯噪音

在这里插入图片描述
首先从一维来介绍,假设某一种有效信号它表示为 μ \mu μ,而随着时间的延续,比方说这个信号是来自某种温度传感器,由于传感器老化或者传输信号出现了某种干扰,这些干扰的信号范围在 [ − 3 σ , 3 σ ] [-3\sigma, 3\sigma] [3σ,3σ]之间,然后我们把这段时间内噪音的振幅收集并且整理后,发现它符合正态分布曲线,亦或者称为高斯曲线,那么这样的噪音就称为高斯噪音。

f ( x ) = 1 2 π σ e ( − ( x − μ ) 2 2 σ 2 ) f(x) = \frac{1}{ \sqrt {2 \pi } \sigma } e^(- \frac{(x- \mu )^2}{2 \sigma^2} ) f(x)=2π σ1e(2σ2(xμ)2)

这个公式简单的说一下:

  • 曲线关于 x = μ x = \mu x=μ 对称,通常这个值对应的是信号本号
  • x = μ x = \mu x=μ 处为正态分布的最大值,振幅为 1 2 π σ \frac{1}{ \sqrt {2 \pi } \sigma } 2π σ1,也就是信号本号自身的强度,亦或者说是期望值
  • σ \sigma σ所决定的,就是噪音信号的分布情况,数学上称这玩意为标准差
  • 当标准差越小,信号噪音就越集中在期望值附近,换句话说也就是信号受噪音影响程度越小,而标准差越大,信号就越模糊。

所以,如果将信号挪到了0上,而噪音分布的标准差为1的时候,这个就是小学二年级所说的标准正态分布了。

现在我们徒手撸一个高斯分布函数的实现:

def gaussian_noise_kernel(x, mu, sigma):
    exp = math.exp(-1 * (
                       math.pow(x - mu, 2) / (2 * math.pow(sigma, 2))
                   ))
    peak = (math.sqrt(2 * 3.14159) * sigma)

    return exp / peak

如果用numpy,代码可以写的更简单:

def gaussian_noise_kernel(x, mu, sigma):
	return np.exp(-1*((x-mu)**2)/(2*(sigma**2)))/(math.sqrt(2*np.pi) * sigma)

然后,我们使用numpy的linspace函数,生成X轴坐标,关于这个函数怎么使用的,你可以网上搜素一下它的函数说明。

用一种比较笨的方法计算Y轴坐标:

    mu1, sig1 = 0, 1  # standard distribution
    mu2, sig2 = 1, 1  # move the chart to right
    mu3, sig3 = 0, 0.5  # increase the noise coverage
    mu4, sig4 = 0, 2.5  # increase the noise coverage
    x = np.linspace(-5, 5, 100)

    y1, y2, y3, y4 = [], [], [], []
    for i in range(50):
        t1 = gaussian_noise_kernel(x[i], mu1, sig1)
        t2 = gaussian_noise_kernel(x[i], mu2, sig2)
        t3 = gaussian_noise_kernel(x[i], mu3, sig3)
        t4 = gaussian_noise_kernel(x[i], mu4, sig4)

        y1.append(t1)
        y2.append(t2)
        y3.append(t3)
        y4.append(t4)

    plt.plot(x, y1, 'r', label='mu1, sig1 = 0, 1')
    plt.plot(x, y2, 'g', label='mu2, sig2 = 1, 1')
    plt.plot(x, y3, 'b', label='mu3, sig3 = 0, 0.5')
    plt.plot(x, y4, 'm', label='mu4, sig4 = 0, 2.5')
    plt.legend()
    plt.grid()
    plt.show()
    plt.legend()
    plt.grid()
    plt.show()

在这里插入图片描述

现在我们已经成功的绘制处高斯分布曲线,然后把这个分布曲线函数引入到图像中,用来生成随机噪点。

首先明确一点,高斯噪音的特点是增加或减少原始信号,使得原始信号出现了随机“抖动”,并且抖动范围服从高斯分布(正态分布)。所以如果要生成高斯噪音,那么我们需要在原来高斯核的基础上,增加一个随机数生成器,并且把高斯函数调整为对于X=0轴上的正态分布(不一定是标准正态分布)。

在这里插入图片描述
所以,如果有一个正弦信号,那么叠加上高斯噪音后,输出的结果就会呈现上图所示的样子。现在放上实现的代码,它的执行效果不是最好的,但你应该是能看明白噪音的叠加方式。

在这里插入图片描述

def gaussian_noise(image, ratio, sigma):
    # generate gaussian kernel
    x = np.linspace(- 4 * sigma, 4 * sigma, 100)
    kernel = gaussian_noise_kernel(x, 0, sigma)

    # output image
    output = np.zeros(image.shape, np.uint8)

    for i in range(image.shape[0]):
        for j in range(image.shape[1]):

            rand = random.random()
            if rand < ratio:  # apply gaussian noise
                pos = int(100 * random.random()

                if x[pos] < 0:
                    temp = image[i][j] * (1 - kernel[pos])
                    if temp < 0:
                        output[i][j] = 0
                    else:
                        output[i][j] = temp
                    continue

                if x[pos] >= 0:
                    temp = image[i][j] * (1 + kernel[pos])
                    if temp > 255:
                        output[i][j] = 255
                    else:
                        output[i][j] = temp

            else:
                output[i][j] = image[i][j]

    return output

3. 泊松噪音(Poisson Noise)

简单的说就是满足泊松分布的噪音,你会觉得它和正态分布很相似,其实如果我们采集的数据越多,精度越密,其形态上它越发接近高斯分布函数,也就是正态分布,是常见的一种满足指数函数分布的离散模型。

泊松分布(Poisson Distribution)

泊松噪音存在的根本原因是因为光是由离散的光子构成(光的粒子性)。光源发出的光子打在CMOS上,从而形成一个可见的光点。光源每秒发射的光子到达CMOS的越多,则该像素的灰度值越大。但是因为光源发射和CMOS接收之间都有可能存在一些因素导致单个光子并没有被CMOS接收到或者某一时间段内发射的光子特别多,所以这就导致了灰度值会有波动,也就是所谓的散粒噪声。举例而言,在光源强度比较低的时候,比如说设定光强为每秒5个光子的时候,那么每秒实际CMOS接受到的光子数可能从0到10(服从泊松分布)1

在这里插入图片描述
那么,泊松分布或者泊松噪音的基本形式是怎样的呢?

P ( x = k ) = e − λ λ k k ! P(x=k) = \frac{e^{- \lambda} \lambda ^ k}{k!} P(x=k)=k!eλλk

这里, λ \lambda λ 表示的是期望值,既某过程中,在它的给定时间内,事件的发生次数,比方说假设世界杯赛场上,每场比赛的进球数大约在2.5个球,那么 λ = 2.5 \lambda=2.5 λ=2.5,因此假设对于一场比赛,分别发生0次进球,1次进球,2次进球的概率是2

出现0次进球
P ( x = 0 ) = 2. 5 0 0 ! e − 2.5 ≈ 0.082 P(x=0) = \frac{2.5^0}{0!} e^{-2.5} \approx 0.082 P(x=0)=0!2.50e2.50.082

出现1次进球
P ( x = 1 ) = 2. 5 1 1 ! e − 2.5 ≈ 0.205 P(x=1) = \frac{2.5^1}{1!} e^{-2.5} \approx 0.205 P(x=1)=1!2.51e2.50.205

出现2次进球
P ( x = 2 ) = 2. 5 2 2 ! e − 2.5 ≈ 0.257 P(x=2) = \frac{2.5^2}{2!} e^{-2.5} \approx 0.257 P(x=2)=2!2.52e2.50.257

出现3次进球
P ( x = 3 ) = 2. 5 3 3 ! e − 2.5 ≈ 0.213 P(x=3) = \frac{2.5^3}{3!} e^{-2.5} \approx 0.213 P(x=3)=3!2.53e2.50.213

⋯ \cdots

现在我们把数据绘制到图表上,根据我们推算的进球概率,这样一个概率分布,就是泊松分布了。
在这里插入图片描述

泊松分布与光通量

接下来,我们把这个进球的过程换成单位时间内,有多少光子打到像素传感器上的过程3。为了说明这个问题,我们先解释一下照片成像的过程。我们在初中阶段的光学课程上,知道以前的老式相机是光束通过透镜,与胶片上的光感材料作用,把影像印在了胶片上,这个过程和小孔成像很类似。

而现代数码相机的普及,最大的区别就是胶片变成了光传感器。也就是CMOS传感器。由于它是一种光敏材料,在被一定量的光子照射后会产生电子,继而引起数字信号的变化。而在一个CMOS传感器上,有极多的传感单元,而这些传感单元,你可以理解为我们平常提到的像素。
在这里插入图片描述
而光子作用在每一个传感单元上所产生的信号不同,最终组合在一起成为了像素照片。所以如果我们把这个过程简化后,假设在单位时间内,有一束光包含有400个光子打到了相机的CMOS传感器上,从微观上说,这些光子是随机的落入到不同的像素传感器内。

因此对应一个像素传感器来说,如果我们统计一个像素在单位时间 t t t内,会有多少个光子落入到一个像素传感器内,那么可能会得出 [ 0 , 4 ] [0,4] [0,4]这样的一个结果。那么统计平均落入的光子数,并且绘制它的落入分布情况,我们可能会得出一个泊松分布。
在这里插入图片描述
假设这个情况的 λ = 1.05 \lambda=1.05 λ=1.05,也就是平均每个像素传感器落入1.05个光子,那么它的概率分布图,也就是下面这个样子了:
在这里插入图片描述
那么这个模型的标准差 σ = ∑ ( x i − x ˉ ) n ≈ 1.024 \sigma = \sqrt{\frac{\sum (x_i - \bar{x})}{n}} \approx 1.024 σ=n(xixˉ) 1.024,而这里的1.024就是光子散粒噪音(photon shot noise)

由于光子极微小,尽管我们假设从物体反射进入到CMOS传感器上的光束在单位时间内为400个光子,但这数量本质上来说是估算,或者说是平均数。因此实际上在单位时间 t t t内,传入CMOS的光子数可能是401,也可能是387个光子。

尽管从宏观上光子传播沿直线传播,但在微观上也就是光子运动轨迹存在一定程度的不确定性,这必然导致了噪音的产生。

所以我们可以直观的凭本能知道,如果这样一些带着随机运动的粒子,在击打到某个平面位置时,尽管大范围上符合某个范围的分布区间,但如果细致的观察,每一个落点存在着一定的误差(“噪音”)。

这就像是用霞弹枪、或者抛洒石灰,或者颜料,即便用同一种颜料,同一个角度抛洒到画布上,任然无法做出两幅一样的画的那种奇妙的感觉。
在这里插入图片描述
那么,光子到达图像传感器的这些波动如何影响我们的图像?噪点会使照片的视觉细节失真。而下图显示了一组模拟的图像,其中指定了每个像素的平均粒子数或光子数。 这表明对于低数量的光子,噪声占主导地位,但是随着光子数量(光通量)的增加,图像结构变得更加明显。
在这里插入图片描述
所以,如果我们要试图模拟泊松噪音,也就是单位像素传感器 p p p在单位时间 t t t内捕捉到的有效光子量,那么这个过程就是一个所谓的 “泊松过程(Poisson Process)”

泊松过程(Poisson Process)

现在,我们已经知道了一个概率事件它的随机概率发生分布情况,如果近似符合二项分布的,就是一个泊松分布。现在我们需要反过来,去做一个符合这个分布的随机事件发生过程,而它就是所谓的泊松过程了。

回到上面的例子,如果在单位事件内 t t t,向CMOS传感器发射了(或者说物体反射了)一束包含400个光子光束,落在单个像素传感器上的光子数为 P s ∈ [ 0 , 4 ] P_s \in[0, 4] Ps[0,4] ,我们在不考虑这些光子激发的电子有效率的情况下,假设1个光子落入了像素传感器就会产生1个电子。

也就是说,在单位时间内,一个像素可能接收到0个、1个、2个、3个、4个光子4。而如果我们把观察时间微分为 Δ t \Delta t Δt,如果假设在某一个时间内,发生了1个光子击中像素传感器,那么接下来再发生一次光子击中像素传感器的概率就会下降;如果再次发生一次击中,那么等待第三次发生的概率就会更小,直到全部观察时间结束。

在这里插入图片描述
这一过程符合于指数,通常情况下,我们用下式表示这个过程,用通俗的话来描述:就是当某事件发生后,后续事件再次发生的概率,随着时间增加而减少

P ( t w a i t > t e v e n t ) = e − σ ⋅ t P(t_{wait} > t_{event}) = e^{- \sigma \cdot t} P(twait>tevent)=eσt

这里 t t t表示时间变量, σ \sigma σ表示单位时间内 Δ t \Delta t Δt事件怕平均发生次数,或者说是期望。那么,我们同样可以得出某事件发生前的前面的事件发生概率,随着时间减少而增加

P ( t w a i t ≤ t e v e n t ) = 1 − e − σ ⋅ t P(t_{wait} \leq t_{event}) = 1 - e^{- \sigma \cdot t} P(twaittevent)=1eσt

明白了这个公式的概念,接下来我们就可以来模拟这个泊松过程了,那么受限于篇幅,生成泊松随机数的过程我就放在下一章里进行介绍了。


  1. 《泊松噪音》 ↩︎

  2. Poisson Distribution, Alexander Katz, Andy Hayes, Tejas Suresh, etc. ↩︎

  3. How to Create Awesome Noise That Is Actually Real, Erez Posner
    ↩︎

  4. The Poisson Distribution and Poisson Process Explained, Will Koehresen ↩︎

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐