图像处理学习笔记之空间滤波(1)图像的噪声

目录

  • 随机数
    • 随机数引擎
    • 设置随机数发生器种子
    • 分布
      • 均匀分布
      • 伯努利分布
      • 泊松分布
      • 正态分布

       图像噪声是图像在获取或传输过程中受到随机信号干扰,妨碍人们对图像理解及分析处理的信号。噪声一般分为分为加性噪声和乘性噪声:

f ( x , y ) = g ( x , y ) + q ( x , y ) f(x,y)=g(x,y)+q(x,y) f(x,y)=g(x,y)+q(x,y)
f ( x , y ) = g ( x , y ) × q ( x , y ) f(x,y)=g(x,y)\times q(x,y) f(x,y)=g(x,y)×q(x,y)

其中, f ( x , y ) f(x,y) f(x,y)表示图像, g ( x , y ) g(x,y) g(x,y)表示没有噪声的图像部分, q ( x , y ) q(x,y) q(x,y)表示噪声。
  很多时候将图像噪声看作是多维随机过程,因而描述图像噪声的方法完全可以借助随机过程的描述,即使用其概率密度函数和分布函数。在很多情况下,这些函数很难测定和描述,甚至无法得到,所以常用统计特征来描述噪声,如:均值,方差和相关函数。
  常见的几种噪声有: 高斯噪声瑞利噪声泊松噪声椒盐噪声。除椒盐噪声以外其他三种均属于加性噪声。椒盐噪声既不属于加性噪声也不属于乘性噪声。
  在实际应用中,为了验证滤波算法的有效性,有时需要在图像上模拟添加各种不同类型的噪声。MATLAB中的imnosie函数可以为图像添加不同类型的噪声,本节将介绍几种噪声的添加方法,代码实现借鉴了imnoise函数。

随机数

       为图像添加噪声既可以使用C++标准库random,也可以使用opencv提供的函数。无论哪一种方法都涉及到随机数的相关知识,这里进行简要介绍,主要是涉及C++中的random标准库,具体请参考《C++primer(第五版)》。理论上计算机只能产生均匀分布,其他分布都是通过对均匀分布进行各种变换得到的。常用的变换方法有逆变换、拒绝采样等等。具体算法可以参考Luc Devroye, Non-Uniform Random Variate Generation(Springer-Verlag, New York, 1986)、左飞的《图像处理中的数学修炼》(清华大学出版社)和维基百科。
  C++11新增了random库来产生随机数,通过使用随机数引擎类和随机数分布类生成符合要求的随机数。

  1. random-number engines:随机数引擎类,生成均匀分布的无符号整数(需要设置种子,不然每次生成的随机数都一样)。
  2. random-number distribution:随机数分布类,将生成器生成的数字序列转换为服从特定分布的数字序列,例如均匀分布,正态分布、二项分布、泊松分布。

随机数引擎

       随机数引擎是函数对象类,它们定义了一个调用运算符,该运算符不接受参数并返回一个随机无符号整数。我们可以通过调用一个随机数引擎对象来生成原始随机数。

default_random_engine e;
for(size_t i = 0; i < 10; i++)
{
    cout << e() << " ";
}

       标准库定义了多个随机数引擎类,区别在于性能和随机性质量不同。每个编译器都会指定其中一个作为default_random_engine类型。此类型一般具有最常用的特性。下表列出了随机数引擎操作。

操作 描述
Engine e; 默认构造函数:使用该引擎类型默认的种子
Engine e(s); 使用整型值s作为种子
e.seed(s) 使用种子s重置引擎状态
e.min() 此引擎可生成的最小值和最大值
e.max()
Engine::result_type 此引擎生成的unsigned整型类型
e.discard(u) 将此引擎推进u步;u的类型为unsigned long long

       大多数情况下,随机数引擎的输出是不能直接使用的,必须要转换为合适的范围、类型和分布。

设置随机数发生器种子

       一个给定的随机数发生器一直会生成相同的随机数序列,这一特性在调试中很有用。但是,一旦我们的程序调试完毕,我们通常希望每次运行程序都会生成不同的随机结果,可以通过提供一个种子(seed)来达到这个目的。种子就是一个数值,引擎可以利用它从序列中一个新位置重新开始生成随机数。
  为引擎设置种子有两种方式:在创建引擎对象时提供种子,或者调用引擎的 seed 成员:

default_random_engine e1;       // 使用默认种子
default_random_engine e2(2147483646);       // 使用给定的种子值
// e3 和 e4 将会生成相同的序列,因为他们使用了相同的种子
default_random_engine e3;
e3.seed(32767);             //调用 seed 设置为一个新种子值
default_random_engine e4(32767);    // 将种子值设置为 32767
for(size_t i = 0; i != 10; i++)
{
   if (e1() == e2())
       cout << "unseeded match at iteeration: " << i << endl;
   if (e3() != e4())
       cout << "seeded differs at itertion: " << i << endl;
}

       设置种子最常用的方法是调用系统函数 time(),它返回一个特定时刻到当前经过了多少秒。函数 time 接受单个指针参数,它指向用于写入时间的数据结构。如果此指针为空,则函数简单的返回时间:

default_random_engine e1(time(0));  // 稍微随机些的种子

       由于 time 返回以秒计的时间,因此这种方式只适用于生成种子的间隔为秒级或更长的应用。

分布

       类似引擎类型,分布类型也是函数对象类。分布类型定义了一个调用运算符,它接受一个随机数引擎作为参数。分布对象使用它的引擎参数生成随机数,并将其映射到指定的分布。例如,为了得到一个在指定范围内的数,我们使用一个分布类型的对象

//生成 0 到 9 之间(包含)均匀分布的随机数
uniform_int_distribution<unsigned> u(0, 9);
default_random_engine e;    // 生成无符号随机整数
for (size_t i = 0; i < 10; i++)
 // 将 u 作为随机数源
 // 每个调用返回在指定范围内并服从均匀分布的值
cout << u(e) << " ";

上面的程序中,我们将 u 定义为 uniform_int_distribution。此类型生成均匀分布的unsigned值。当我们定义一个这种类型的对象时,可以提供想要的最小值和最大值。在上面这段代码中,u(0,9) 表示我们希望得到[0,9]之间的数。随机数分布类会使用包含的范围,从而我们可以得到给定整型类型的每个可能值。
  注意,我们传递给分布对象的是引擎对象本身,也就是 u(e)。如果我们将调用写为 u(e()),含义就变为将 e 生成的下一个值传递给 u,会导致一个编译错误。我们传递的是引擎本身,而不是它生成的下一个值,原因是某些分布可能需要调用引擎多次才能得到一个值。
       分布类型都是模板,通过设置类型参数,可以得到不同类型的随机数。实际上,random库定义了20种分布类型,分布的名字与他们的数学性质相对应。在下面的描述中,我们通过将类型说明为template_name来指出分布生成浮点数。对这些模板,可以使用float、double或long double代替RealT。类似的,IntT表示要求一个内置整型类型,但不包括bool类型或任何char类型。可以用来代替IntT的类型是short、int、long、long long、unsigned short、unsigned int、unsigend long或unsigned long long。
      分布模板定义了一个默认模板类型参数。整型分布的默认参数是int,生成浮点数的模板的默认参数是double。

均匀分布

uniform_int_distribution<IntT> u(m,n);
uniform_real_distribution<realT> u(x,y);

生成指定类型的,在给定包含范围内的值。m(或x)是可以返回的最小值;n(或y)是最大值。m默认为0;n默认为类型IntT对象可以表示的最大值。x默认为0.0,y默认为1.0。

伯努利分布

bernoulli_distribution b(p);//以给定概率p生成true;p的默认值为0.5。
binomial_distribution<IntT> b(t, p);//分布是按采样大小为整型值t,概率为p生成的;t的默认值为1,p的默认值为0.5
geometric_distribution<Intr> g(p);//每次试验成功的概率为p;p的默认值为0.5
negative_binomial_distribution<IntT> nb(k, p);//k(整型值)次试验成功的概率为p;k的默认值为1,p的默认值为0.5

泊松分布

poisson_distribution<Intr>p(x);//均值为 double值x的分布
exponential_distribution<RealT> e(lam);//指数分布,参数lambda通过浮点值lam给出;lam的默认值为1.0。
gamma_distribution<Realm> g(a, b);//alpha(形状参数)为a,beta(尺度参数)为b;两者的默认值均为1.0。
weibull_distribution<RealT> w(a, b);//形状参数为a,尺度参数为b的分布;两者的默认值均为1.0。
extreme_value distribution<RealT> e(a, b);//a的默认值为0.0,b的默认值为1.0。

正态分布

normal_distribution<RealT> n(m, s);//均值为m,标准差为s;m的默认值为0.0,s的默认值为1.0。
lognormal_distribution<RealT> ln(m, s);//均值为m,标准差为s;m的默认值为0.0,s的默认值为1.0。
chi_squared distribution<RealT> c(x);//自由度为x;默认值为1.0。
cauchy distribution<RealT> c(a, b);//位置参数a和尺度参数b的默认值分别为0.0和1.0。
fisher_f_distribution<RealT> f(m, n);//自由度为m和n;默认值均为1。
student_t_distribution<RealT> s(n);//自由度为n;n的默认值为1。

你可能感兴趣的:(opencv)