27、图像中加入噪声

1、图像中加入椒盐噪声

  椒盐噪声又被称作脉冲噪声,它会随机改变图像中的像素值,是由相机成像、图像传输、解码处理等过程产生的黑白相间的亮暗点噪声,其样子就像在图像上随机的撒上一些盐粒和黑椒粒,因此被称为椒盐噪声。考虑到椒盐噪声会随机产生在图像中的任何一个位置,因此对于椒盐噪声的生成需要使用到OpenCV 4中能够产生随机数的函数rand(),为了能够生成不同数据类型的随机数,该函数拥有多种演变形式。

代码清单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之间。

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

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

 2、图像中加入高斯噪声

代码清单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 myGaussNoise.cpp图像中添加高斯噪声
1.  #include <opencv2\opencv.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.  }

 

posted @ 2023-04-11 11:30  夏蝉沐雪  阅读(341)  评论(0编辑  收藏  举报