rand函数生成的随机数范围_【从零学习OpenCV 4】图像噪声的种类与生成

2dc34dd6db09aaf8e13e91760ba3b587.png

本文首发于“小白学视觉”微信公众号,欢迎关注公众号

本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究!


经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。

图像在获取或者传输过程中会受到随机信号的干扰产生噪声,例如电阻引起的热噪声、光子噪声、暗电流噪声以及光响应非均匀性噪声等。图像噪声会妨碍人们对图像的理解以及后续的处理工作,因此去除噪声的影响在图像处理中具有十分重要的作用图像中常见的噪声主要有四种,分别是:高斯噪声、椒盐噪声、泊松噪声和乘性噪声。想要去除噪声首先需要了解噪声产生原因以及特性,因此本节中将重点介绍高斯噪声和椒盐噪声产生的原因以及如何在图像中添加这两种噪声,生成的含有噪声的图像可以应用于后续的滤波处理中。

椒盐噪声

椒盐噪声又被称作脉冲噪声,它会随机改变图像中的像素值,是由相机成像、图像传输、解码处理等过程产生的黑白相间的亮暗点噪声,其样子就像在图像上随机的撒上一些盐粒和黑椒粒,因此被称为椒盐噪声。目前为止OpenCV 4中没有提供专门用于为图像添加椒盐噪声的函数,需要使用者根据自己需求去编写生成椒盐噪声的程序,本小节将会带领读者一起实现在图像中添加椒盐噪声。

考虑到椒盐噪声会随机产生在图像中的任何一个位置,因此对于椒盐噪声的生成需要使用到OpenCV 4中能够产生随机数的函数rand(),为了能够生成不同数据类型的随机数,该函数拥有多种演变形式,在代码清单5-3中给出了这几种形式的函数原型。

代码清单5-3 随机数函数原型
1.  int cvflann::rand()
2.  
3.  double cvflann::rand_double(double  high = 1.0,
4.                                    double  low = 0 
5.                                    )
6.  
7.  int cvflann::rand_int(int  high = RAND_MAX,
8.                            int  low = 0 
9.                            )
  • high:输出随机数的最大值
  • low:输出随机数的最小值

这三个函数都可以用来生成随机数,区别在于第一个函数rand()不需要输入任何的参数,返回的随机数为int类型;第二个函数rand_double()需要输入随机数的上下边界,默认状态下生成的随机数在0到1之间,返回的随机数为double类型;第三个函数rand_int()也需要输入随机数的上下边界,不同的是该函数默认状态下的最大值为RAND_MAX,这是一个由系统定义的宏变量,在笔者的计算机中这个变量表示的是整数32767,该函数会返回的随机数为int类型。这三个函数的功能和使用方式上都比较简单,这里有个小技巧,rand()函数虽然没有给出随机数的取值范围,但是可以采用求取余数的方式来实现对随机数范围的设置,例如使用rand()函数随机生成一个0到100之间的整数,可以使用“int a = rand()%100”语句来实现,因为无论任何数除以100后的余数一定在0到100之间。

注意

该函数与之前所有的函数不相同之处在于该函数并不在cv的命名空间中,而是在cvflann类中,因此在使用的时候一定要在函数前添加前缀,如cvflann::rand()。有些读者在使用rand()函数时不添加cvflann命名空间的前缀也可以使用,是因为该函数不仅在OpenCV 4中有,在stdlib.h头文件中同样有这个函数,只有在函数前面添加了命名空间前缀时使用的才是OpenCV 4中的随机数生成函数。

了解随机函数之后,在图像中添加椒盐噪声大致分为以下4个步骤:

  • Step1:确定添加椒盐噪声的位置。根据椒盐噪声会随机出现在图像中任何一个位置的特性,我们可以通过随机数函数生成两个随机数,分别用于确定椒盐噪声产生的行和列。
  • Step2:确定噪声的种类。不仅椒盐噪声的位置是随机的,噪声点是黑色的还是白色的也是随机的,因此可以再次生成的随机数,通过判断随机数的奇偶性确定该像素是黑色噪声点还是白色噪声点。
  • Step3:修改图像像素灰度值。判断图像通道数,通道数不同的图像中像素表示白色的方式也不相同。也可以根据需求只改变多通道图像中某一个通道的数值。
  • Step4:得到含有椒盐噪声的图像。

依照上述思想,在代码清单5-4中给出在图像中添加椒盐噪声的示例程序,程序中判断了输入图像是灰度图还是彩色图,但是没有对彩色图像的单一颜色通道产生椒盐噪声。如果需要对某一通道产生椒盐噪声,只需要单独处理彩色图像每个通道即可。程序在图像中添加椒盐噪声的结果如图5-6、图5-7所示,由于椒盐噪声是随机添加的,因此每次运行结果会有所差异。

代码清单5-4 mySaltAndPepper.cpp图像中添加椒盐噪声
1.  #include <opencv2opencv.hpp>
2.  #include <iostream>
3.  
4.  using namespace cv;
5.  using namespace std;
6.  
7.  //盐噪声函数
8.  void saltAndPepper(cv::Mat image, int n)
9.  {
10.     for (int k = 0; k<n / 2; k++)
11.     {
12.         //随机确定图像中位置
13.         int i, j;
14.         i = std::rand() % image.cols;  //取余数运算,保证在图像的列数内 
15.         j = std::rand() % image.rows;  //取余数运算,保证在图像的行数内 
16.         int write_black = std::rand() % 2;  //判定为白色噪声还是黑色噪声的变量
17.         if (write_black == 0)  //添加白色噪声
18.         {
19.             if (image.type() == CV_8UC1)  //处理灰度图像
20.             {
21.                 image.at<uchar>(j, i) = 255;  //白色噪声
22.             }
23.             else if (image.type() == CV_8UC3)  //处理彩色图像
24.             {
25.                 image.at< Vec3b>(j, i)[0] = 255; //Vec3b为opencv定义的3个值的向量类型  
26.                 image.at<Vec3b>(j, i)[1] = 255; //[]指定通道,B:0,G:1,R:2  
27.                 image.at<Vec3b>(j, i)[2] = 255;
28.             }
29.         }
30.         else  //添加黑色噪声
31.         {
32.             if (image.type() == CV_8UC1)
33.             {
34.                 image.at<uchar>(j, i) = 0;
35.             }
36.             else if (image.type() == CV_8UC3)
37.             {
38.                 image.at< Vec3b>(j, i)[0] = 0; //Vec3b为opencv定义的3个值的向量类型  
39.                 image.at<Vec3b>(j, i)[1] = 0; //[]指定通道,B:0,G:1,R:2  
40.                 image.at<Vec3b>(j, i)[2] = 0;
41.             }
42.         }
43. 
44.     }
45. }
46. 
47. int main()
48. {
49.     Mat lena = imread("lena.png");
50.     Mat equalLena = imread("equalLena.png", IMREAD_ANYDEPTH);
51.     if (lena.empty()||equalLena.empty())
52.     {
53.         cout << "请确认图像文件名称是否正确" << endl;
54.         return -1;
55.     }
56.     imshow("lena原图", lena);
57.     imshow("equalLena原图", equalLena);
58.     saltAndPepper(lena, 10000);  //彩色图像添加椒盐噪声
59.     saltAndPepper(equalLena, 10000);  //灰度图像添加椒盐噪声
60.     imshow("lena添加噪声", lena);
61.     imshow("equalLena添加噪声", equalLena);
62.     waitKey(0);
63.     return 0;
64. }

f73e9b0e20d0f7881772957dadb8fa78.png
图5-6 mySaltAndPepper.cpp程序中灰度图添加椒盐噪声结果

cc2742ed76de1962d4089196bd21c037.png
图5-7 mySaltAndPepper.cpp程序中彩色图添加椒盐噪声结果

高斯噪声

高斯噪声是指噪声分布的概率密度函数服从高斯分布(正态分布)的一类噪声,其产生的主要原因是由于相机在拍摄时视场较暗且亮度不均匀造成的,同时相机长时间工作使得温度过高也会引起高斯噪声,另外电路元器件自身噪声和互相影响也是造成高斯噪声的重要原因之一。高斯噪声的概率密度函数如式(5.2)所示,其中$z$表示图像像素的灰度值,

表示像素值的平均值或者期望值,
表示像素值的标准差,标准差的平方
称为方差。区别于椒盐噪声随机出现在图像中的任意位置,高斯噪声出现在图像中的所有位置。

OpenCV 4中同样没有专门为图像添加高斯噪声的函数,对照在图像中添加椒盐噪声的过程,我们可以根据需求利用能够产生随机数的函数来完成在图像中添加高斯噪声的任务。在OpenCV 4中提供了fill()函数可以产生均匀分布或者高斯分布(正态分布)的随机数,我们可以利用该函数产生符合高斯分布的随机数,之后在图像中加入这些随机数即可,我们首先了解该函数的使用方式,该函数的函数原型在代码清单5-5中给出。

代码清单5-5 fill()函数原型
1.  void cv::RNG::fill(InputOutputArray  mat,
2.                         int  distType,
3.                         InputArray  a,
4.                         InputArray  b,
5.                         bool  saturateRange = false 
6.                         )
  • mat:用于存放随机数的矩阵,目前只支持低于5通道的矩阵。
  • distType:随机数分布形式选择标志,目前生成的随机数支持均匀分布(RNG::UNIFORM,0)和高斯分布(RNG::NORMAL,1)。
  • a:确定分布规律的参数。当选择均匀分布时,该参数表示均匀分布的最小下限;当选择高斯分布时,该参数表示高斯分布的均值。
  • b:确定分布规律的参数。当选择均匀分布时,该参数表示均匀分布的最大上限;当选择高斯分布时,该参数表示高斯分布的标准差。
  • saturateRange:预饱和标志,仅用于均匀分布。

该函数用于生成指定分布形式的随机数填充矩阵,可以生成符合均匀分布的随机数和符合高斯分布随机数。函数的第一个参数输入用于存储生成随机数的矩阵,但是矩阵的通道数必须小于等于4。第二个参数是选择随机数分布形式的标志,该函数目前只支持两种分布形式,分别是均匀分布(RNG::UNIFORM,简记0)和高斯分布(RNG::NORMAL,简记1)。函数的第三个和第四个参数为确定随机数分布规律的参数,第三个参数在均匀分布时表示均匀分布的最小下限,在高斯分布时表示高斯分布的均值;第四个参数在均匀分布时表示均匀分布的最大上限,在高斯分布时表示高斯分布的标准差。最后一个参数是预饱和标志,仅用于均匀分布,我们使用其默认式即可。需要注意的是该函数属于OpenCV 4的RNG类,是一个非静态成员函数,因此在使用的时候不能像使用正常函数一样的直接使用,而需要首先创建一个RNG类的变量,之后通过访问这个变量中函数进行调用这个函数,具体使用方式在代码清单5-6中给出。

代码清单5-6 RNG::fill()函数的使用
1.  cv::RNG rng;
2.  rng.fill(mat, RNG::NORMAL, 10, 20);

在图像中添加高斯噪声大致分为以下4个步骤:

  • Step1:首先需要创建一个与图像尺寸、数据类型以及通道数相同的Mat类变量.
  • Step2:通过调用fill()函数在Mat类变量中产生符合高斯分布的随机数。
  • Step3:将原图像和含有高斯分布的随机数矩阵相加。
  • Step4:得到添加高斯噪声之后的图像。

依照上述思想,在代码清单5-7中给出了在图像中添加高斯噪声的示例程序,程序实现了对灰度图像和彩色图像添加高斯噪声,在图像中添加高斯噪声的结果如图5-8、图5-9所示,由于高斯噪声是随机生成的,因此每次运行结果会有差异。

代码清单5-7 myGaussNoise.cpp图像中添加高斯噪声
1.  #include <opencv2opencv.hpp>
2.  #include <iostream>
3.  
4.  using namespace cv;
5.  using namespace std;
6.  
7.  int main()
8.  {
9.      Mat lena = imread("lena.png");
10.     Mat equalLena = imread("equalLena.png", IMREAD_ANYDEPTH);
11.     if (lena.empty()||equalLena.empty())
12.     {
13.         cout << "请确认图像文件名称是否正确" << endl;
14.         return -1;
15.     }
16.     //生成与原图像同尺寸、数据类型和通道数的矩阵
17.     Mat lena_noise = Mat::zeros(lena.rows, lena.cols, lena.type());
18.     Mat equalLena_noise = Mat::zeros(lena.rows, lena.cols, equalLena.type());
19.     imshow("lena原图", lena);
20.     imshow("equalLena原图", equalLena);
21.     RNG rng;  //创建一个RNG类
22.     rng.fill(lena_noise, RNG::NORMAL, 10, 20);  //生成三通道的高斯分布随机数
23.     rng.fill(equalLena_noise, RNG::NORMAL, 15, 30);  //生成三通道的高斯分布随机数
24.     imshow("三通道高斯噪声", lena_noise);
25.     imshow("单通道高斯噪声", equalLena_noise);
26.     lena = lena + lena_noise;  //在彩色图像中添加高斯噪声
27.     equalLena = equalLena + equalLena_noise;  //在灰度图像中添加高斯噪声
28.     //显示添加高斯噪声后的图像
29.     imshow("lena添加噪声", lena);
30.     imshow("equalLena添加噪声", equalLena);
31.     waitKey(0);
32.     return 0;
33. }

cd143c84c59c86e44b733b0bd4717b6f.png
图5-8 myGaussNoise.cpp程序中灰度图添加高斯噪声结果

ef82066d0a122915244bb22a47202c13.png
图5-9 myGaussNoise.cpp程序中彩色图添加高斯噪声结果

经过几个月的努力,市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》将春节后由人民邮电出版社发行。如果小伙伴觉得内容有帮助,希望到时候多多支持!

关注小白的小伙伴可以提前看到书中的内容,我们创建了学习交流群,欢迎各位小伙伴添加小白微信加入交流群,添加小白时请备注“学习OpenCV 4”。

https://u.wechat.com/MJ-57nVtXgxUyL3dTwWd014 (二维码自动识别)

f9ce11ebefd94fc62db0a47005fa2243.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值