添加椒盐噪声

椒盐噪声其实就是使图像的一些随机的像素为黑色(0) 或者 白色(255)

盐噪声又称白噪声,在图像中添加一些随机的白色像素点(255);
胡椒噪声是在图像中添加一些随机的黑色像素点(0);

盐椒噪声是在图像中既有白色像素点,又有黑色像素点

//图象模拟添加椒盐噪声是通过随机获取像素点斌那个设置为高亮度点来实现的
Mat addSaltNoise(const Mat src, int n) {
	Mat dst = src.clone();

	//1.添加盐噪声
	for (int k = 0; k < n; k++)
	{
		//随机获取图像的某行某列,取到该行列所对应的像素值
		int i = rand() % dst.rows;
		int j = rand() % dst.cols;

		//判断图像是否为单通道
		if (dst.channels() == 1) {
			//修改单通道的像素值
			dst.at<uchar>(i, j) = 255;
		}
		else
		{
			//修改三通道的像素值
			dst.at<Vec3b>(i, j)[0] = 255;
			dst.at<Vec3b>(i, j)[1] = 255;
			dst.at<Vec3b>(i, j)[2] = 255;
		}
	}

	//2.添加胡椒噪声(白色的像素点)
	for (int k = 0; k < n; k++)
	{
		//随机获取图像的某行某列,取到该行列所对应的像素值
		int i = rand() % dst.rows;
		int j = rand() % dst.cols;

		//判断图像是否为单通道
		if (dst.channels() == 1) {
			//修改单通道的像素值
			dst.at<uchar>(i, j) = 0;
		}
		else
		{
			//修改三通道的像素值
			dst.at<Vec3b>(i, j)[0] = 0;
			dst.at<Vec3b>(i, j)[1] = 0;
			dst.at<Vec3b>(i, j)[2] = 0;
		}

	}

	return dst;
}

int main() {
	Mat src = imread("D:/test/src.jpg");
	Mat dst1,dst2;
	imshow("src", src);

	//单通道椒盐噪声
	cvtColor(src, dst1, COLOR_BGR2GRAY);
	dst1 = addSaltNoise(dst1, 1000);

	//三通道椒盐噪声
	dst2 = addSaltNoise(src, 1000);

	imshow("GRAY_saltNoise", dst1);
	imshow("RGB_saltNoise", dst2);

	waitKey(0);
	return 0;
}

原图:

在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_椒盐噪声


单通道加盐处理:

在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_随机数_02


三通道加盐处理:

在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_随机数_03


在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_椒盐噪声_04

添加高斯噪声

高斯概率的概率密度函数服从高斯分布,与椒盐噪声一样,高斯噪声也是数字图像的一个常见噪声。

椒盐噪声是出现在随机位置、噪点深度基本固定的噪声;
高斯噪声则是几乎每个点上都出现噪声、噪点深度随机的噪声。

高斯噪声(法1)

原理

Box-Muller
目的:一般是要得到服从正态分布的随机数

基本思想: 先得到服从均匀分布的随机数; 然后再将服从均匀分布的随机数转变为服从正态分布。Box-Muller 是产生随机数的一种方法。

如果在 (0,1] 值域内有两个一致的随机数字 U1 和 U2,
可以使用以下两个等式中的任一个算出一个正态分布的随机数字 Z:
 在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_随机数_05
 其中, R = 在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_椒盐噪声_06
 
正态值 Z 有一个等于 0 的平均值和一个等于 1 的标准偏差,可使用以下等式将 Z 映射到一个平均值为 m、标准偏差为 sd 的统计量 X:  
在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_07

根据Box-Muller变换原理,假设随机变量U1,U2相互独立,且均服从(0,1)之间的均匀分布,则经过下面两个式子产生随机变量在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_随机数_08服从标高斯分布。
在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_高斯噪声_09
在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_椒盐噪声_10
上式中在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_像素点_11满足正态分布,其中均值为0,方差为1,变量在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_12可以修改为下式:
在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_13
在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_14
在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_12可以是随机值,经过上式产生的随机变量在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_像素点_11满足标准高斯分布。
若图片数据格式为uint8,也即数据的范围为[0,255],可以直接生成对应方差的噪声,然后加到图像上。

noise=src+np.random.rand(128,128)*sigma;

此处 np.random.rand(128, 128) 生成一个均值为 0 ,方差为 1 的正态分布,然后我们乘以 在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_高斯噪声_17,将方差调整到 在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_18,再加到图片上即可。

//生成一个服从正态分布的随机数
//生成高斯噪声值
//sigma:标准差  mu:平均值
double gaussionNoiseSignal(double mu, double sigma) {
	//定义小值
	//返回目标数据类型能表示的最逼近1的正数和1的差的绝对值
	const double epsilon = numeric_limits<double>::min();
	//正态分布的随机数字 Z0,Z1
	static double z0, z1;
	static bool flag = false;
	flag = !flag;

	//float为假构造高斯随机变量X
	if (!flag) {
		return z1 * sigma + mu;
	}

	//(0,1]值域内有两个一致的随机数字u1和u2
	double u1, u2;
	do {
		u1 = rand() * (1.0 / RAND_MAX);
		u2 = rand() * (1.0 / RAND_MAX);
	} while (u1 <= epsilon);

	//flag为真构造高斯随机变量
	//可以使用以下两个等式中的任一个算出一个正态分布的随机数字 Z
	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& src,double mu,double sigma) {
	//深拷贝,克隆
	Mat dst = src.clone();
	//获取图像的通道
	int channels = dst.channels();
	//图像的行数
	int row = dst.rows;
	//图像的总列数
	//例如:rgb是3通道,每个像素由3个值(即3列)形成。
	int col = dst.cols*channels;

	//判断图像连续性
	//判断矩阵是否连续,若连续,我们相当于只需要遍历一个一维数组 
	if (dst.isContinuous()) {
		col *= row;
		row = 1;
	}
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			//添加高斯噪声
			int val = dst.ptr<uchar>(i)[j] + gaussionNoiseSignal(mu, sigma) * 32;//此处32 可以随意设置-----
			if (val < 0) {
				val = 0;
			}
			if(val>255) {
				val = 255;
			}
			dst.ptr<uchar>(i)[j] = (uchar)val;
		}
	}
	return dst;
}

int main() {
	
	Mat src = imread("D:/test/src.jpg");
	imshow("src", src);
	
	Mat dst1, dst2;
	dst1=addGaussianNoise(src,2,0.8);
	imshow("dst", dst1);
	
	waitKey(0);
	return 0;
}

在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_随机数_19


在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_20

在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_正态分布_21

添加高斯噪声(法2)

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

  • 用RNG类产生均匀分布和正态分布(高斯分布)的随机数。
  • 用RNG类的成员函数fill,为图像添加高斯噪声。
  • 函数说明
    用fill构造一个均值为a,标准差为b的噪声矩阵(与原图像大小,类型相同),将噪声矩阵与原图像相加,即可得到高斯噪声图像
  • 函数声明

void fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange = false );

  • 函数参数

mat二维或多维矩阵,目前版本中,维数不能超过4。distType随机数的分布类型。有两种,即RNG::UNIFORM 或 RNG::NORMAL。前者表示均匀分布,后者表示正态分布(即高斯分布)。a分布规律参数之一。在均匀分布中表示下限(包含);在正态分布(即高斯分布)中,表示均值。b分布规律参数之一。在均匀分布中表示上限(包含);在正态分布(即高斯分布)中,表示标准差。saturateRange这个参数只对均匀分布时有用。

Mat addGuassianNoise2(Mat& src,double a,double b) {
	Mat temp = src.clone();
	Mat dst(src.size(), src.type());

	//构造含有高斯噪声的矩阵
	Mat noise(temp.size(), temp.type());
	RNG rng(time(NULL));
	//高斯分布;均值为10,标准差为36
	rng.fill(noise, RNG::NORMAL, a, b);

	add(temp, noise, dst);
	return dst;
}
int main() {
	
	Mat src = imread("D:/test/src.jpg");
	imshow("src", src);
	Mat dst;
	dst = addGuassianNoise2(src, 2, 32);
	imshow("dst_fill", dst);

	waitKey(0);
	return 0;
}

在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_高斯噪声_22


在同一图像窗口中展示原图添加噪声图及均值滤波中值滤波高斯滤波处理后的结 如何给图像加噪声_像素点_23

学习:正态分布与均匀分布之间的变换使用 C / C++ 产生符合正态分布的随机数如何正确地给图像添加高斯噪声给图像添加各种噪声