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

    技术2022-07-11  69

    目录

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

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

    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库来产生随机数,通过使用随机数引擎类和随机数分布类生成符合要求的随机数。

    random-number engines:随机数引擎类,生成均匀分布的无符号整数(需要设置种子,不然每次生成的随机数都一样)。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>。此类型生成均匀分布的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。
    Processed: 0.011, SQL: 9