给图像添加各种噪声



1. 简介

下面简单介绍两种图像噪声,即椒盐噪声和高斯噪声。

(1) 椒盐噪声
椒盐噪声也称脉冲噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。
图像模拟添加椒盐噪声是通过:随机获取像素点,并设置为高亮度点和低亮度点来实现的。

(2) 高斯噪声
高斯噪声是指概率密度函数服从高斯分布的一类噪声。
特别的,如果一个噪声,它的幅度分布服从高斯分布,而它的功率谱密度服从均匀分布,则称这个噪声为高斯白噪声。
高斯白噪声 功率谱密度频谱图 和 噪声幅值分布图的图片如下:

这里写图片描述
这里写图片描述


2. 代码

(1) 为图像添加椒盐噪声

//给原图像增加椒盐噪声
//图象模拟添加椒盐噪声是通过随机获取像素点,并设置为高亮度点和低亮度点来实现的
//srcImage为源图像,n为椒/盐像素点个数,返回含噪图像
Mat addSaltNoise(const Mat srcImage, int n)
{
    Mat dstImage = srcImage.clone();

    for (int k = 0; k < n; k++)
    {
        //随机取值行列,得到像素点(i,j)
        int i = rand() % dstImage.rows;
        int j = rand() % dstImage.cols;

        //图像通道判定
        if (dstImage.channels() == 1)//修改像素点(i,j)的像素值
        {
            dstImage.at(i, j) = 255;     //盐噪声
        }
        else
        {
            dstImage.at(i, j)[0] = 255;
            dstImage.at(i, j)[1] = 255;
            dstImage.at(i, j)[2] = 255;
        }
    }

    for (int k = 0; k < n; k++)
    {
        //随机取值行列
        int i = rand() % dstImage.rows;
        int j = rand() % dstImage.cols;
        //图像通道判定
        if (dstImage.channels() == 1)
        {
            dstImage.at(i, j) = 0;       //椒噪声
        }
        else
        {
            dstImage.at(i, j)[0] = 0;
            dstImage.at(i, j)[1] = 0;
            dstImage.at(i, j)[2] = 0;
        }
    }
    return dstImage;
}

(2) 为图像增加高斯噪声 方法1

此算法原理我没仔细看,但是能够成功为图像增加高斯噪声。相比来说,方法2简单得多。
参考网址:【OpenCV】给图像添加噪声

原理:

根据Box-Muller变换原理,假设随机变量U1、U2相互独立,且均服从(0,1)之间的均匀分布,则经过下面两个式子产生的随机变量Z0,Z1服从标准高斯分布。
这里写图片描述
上式中Z0,Z1满足正态分布,其中均值为0,方差为1,变量U1和U2可以修改为下式:
这里写图片描述

代码:

//生成高斯噪声
double generateGaussianNoise(double mu, double sigma)
{
    //定义小值
    const double epsilon = numeric_limits<double>::min();
    static double z0, z1;
    static bool flag = false;
    flag = !flag;
    //flag为假构造高斯随机变量X
    if (!flag)
        return z1 * sigma + mu;
    double u1, u2;
    //构造随机变量
    do
    {
        u1 = rand() * (1.0 / RAND_MAX);
        u2 = rand() * (1.0 / RAND_MAX);
    } while (u1 <= epsilon);
    //flag为真构造高斯随机变量
    z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
    z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI*u2);
    return z0*sigma + mu;
}


//为图像添加高斯噪声
Mat addGaussianNoise(Mat &srcImag)
{
    Mat dstImage = srcImag.clone();
    int channels = dstImage.channels();
    int rowsNumber = dstImage.rows;
    int colsNumber = dstImage.cols*channels;
    //判断图像的连续性
    if (dstImage.isContinuous())
    {
        colsNumber *= rowsNumber;
        rowsNumber = 1;
    }
    for (int i = 0; i < rowsNumber; i++)
    {
        for (int j = 0; j < colsNumber; j++)
        {
            //添加高斯噪声
            int val = dstImage.ptr(i)[j] + generateGaussianNoise(2, 0.8) * 32;
            if (val < 0)
                val = 0;
            if (val>255)
                val = 255;
            dstImage.ptr(i)[j] = (uchar)val;
        }
    }
    return dstImage;
}

(3) 为图像增加高斯噪声 方法2(简单)

原理:用OpenCV的RNG类,为图像添加高斯噪声。

  • 在OpenCV中,可用RNG (Random number generator) 类来产生均匀分布和正态分布(高斯分布)的随机数。

  • 可以用RNG类的成员函数fill,来为图像添加高斯噪声。fill的原型(C++)如下:

void RNG::fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false )
  • 参数意义如下:

    • mat:二维或多维矩阵,目前版本中,维数不能超过4。
    • distType:随机数的分布类型。有两种,即RNG::UNIFORM 或 RNG::NORMAL。前者表示均匀分布,后者表示正态分布(即高斯分布)。
    • a:分布规律参数之一。在均匀分布中表示下限(包含);在正态分布(即高斯分布)中,表示均值。
    • b:分布规律参数之一。在均匀分布中表示上限(包含);在正态分布(即高斯分布)中,表示标准差。
    • saturateRange:这个参数只对均匀分布时有用。
  • 用fill构造一个均值为a,标准差为b的噪声矩阵(与原图像大小,类型相同),将噪声矩阵与原图像相加,即可得到含噪图像。

代码:

Mat anotherAddGaussianNoise(Mat &srcImg)
{
    Mat tempSrcImg = srcImg.clone();
    Mat img_output(tempSrcImg.size(), tempSrcImg.type());

    //构造高斯噪声矩阵
    Mat noise(tempSrcImg.size(), tempSrcImg.type());//创建一个噪声矩阵
    RNG rng(time(NULL));
    rng.fill(noise, RNG::NORMAL, 10, 36);//高斯分布;均值为10,标准差为36

    //将高斯噪声矩阵与原图像叠加得到含噪图像
    cv::add(tempSrcImg, noise, img_output);

    return img_output;
}

(4) 测试代码:

#include 
#include 
#include 
#include 
#include 
#include  

using namespace std;

Mat addSaltNoise(const Mat srcImage, int n);
Mat addGaussianNoise(Mat &srcImag);
Mat anotherAddGaussianNoise(Mat &srcImg);


int main()
{
    Mat srcImage = imread("F:/test_photo/zhongshuo.jpg");
    if (!srcImage.data)
    {
        cout << "读入图像有误!" << endl;
        system("pause");
        return -1;
    }
    imshow("原图像", srcImage);

    Mat dstSaltImage = addSaltNoise(srcImage, 3000);
    imshow("添加椒盐噪声的图像", dstSaltImage);
    imwrite("F:/test_photo/zhongshuoSalt.jpg", dstSaltImage);//存储图像

    Mat dstGaussImage = addGaussianNoise(srcImage);
    imshow("添加高斯噪声后的图像1", dstGaussImage);
    imwrite("F:/test_photo/zhongshuoGauss1.jpg", dstGaussImage);//存储图像

    Mat anotherDstGaussImage = anotherAddGaussianNoise(srcImage);
    imshow("添加高斯噪声后的图像2", anotherDstGaussImage);
    imwrite("F:/test_photo/zhongshuoGauss2.jpg", anotherDstGaussImage);//存储图像

    waitKey();
    return 0;
}

输出结果:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述