C++版本OpenCv教程(二十六)图像中添加椒盐噪声

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

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

int cvflann::rand()
double cvflann::rand_double(double high = 1.0,double low = 0 )
int cvflann::rand_int(int high = RAND_MAX,int low = 0 )
  • 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所示,由于椒盐噪声是随机添加的,因此每次运行结果会有所差异。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;

//椒盐噪声函数
void saltAndPepper(Mat image,int n){
    
    
    for(int k=0;k<n;++k){
    
    
        //随机确定图像中位置
        int i,j;
        i=rand()%image.cols;//取余数运算,保证在图像的列数内
        j=rand()%image.rows;//取余数运算,保证在图像的行数内
        int write_black=rand()%2;//判定为白色噪声还是黑色噪声的变量
        if(write_black==0){
    
    //添加白色噪声
            if(image.type()==CV_8UC1) {
    
    //处理灰度图像
                image.at<uchar>(j,i)=255;//白色噪声
            }
            else if(image.type()==CV_8UC3){
    
    //处理彩色图像
                image.at<Vec3b>(j,i)[0]=255;//Vec3b为opencv定义的3个值的向量类型
                image.at<Vec3b>(j,i)[1]=255;//[]制定通道,B:0,G:1,R:2
                image.at<Vec3b>(j,i)[2]=255;
            }
        }
        else{
    
    //添加黑噪声
            if(image.type()==CV_8UC1){
    
    
                image.at<uchar>(j,i)=0;
            }
            else if(image.type()==CV_8UC3){
    
    
                image.at<Vec3b>(j,i)[0]=0;//Vec3b为opencv定义的3个值的向量类型
                image.at<Vec3b>(j,i)[1]=0;//[]制定通道,B:0,G:1,R:2
                image.at<Vec3b>(j,i)[2]=0;
            }
        }
    }
}

int main(){
    
    
    Mat img_=imread("luffy.jpg");
    Mat img;
    resize(img_,img,Size(img_.cols/2,img_.rows/2));
    Mat gray;
    cvtColor(img,gray,COLOR_BGR2GRAY);
    if(img.empty()||gray.empty()){
    
    
        cout<<"请确认输入的路径是否正确"<<endl;
        return -1;
    }
    imshow("luffy原图",img);
    imshow("luffy_gray原图",gray);
    saltAndPepper(img,10000);//彩色图像添加椒盐噪声
    saltAndPepper(gray,10000);//灰度图像添加椒盐噪声
    imshow("luffy添加噪声",img);
    imshow("luffy_gray添加噪声",gray);
    waitKey(0);
    return 0;
}

在这里插入图片描述

扫描二维码关注公众号,回复: 12415212 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_33287871/article/details/112337433