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;
}
输出结果: