图像处理添加盐噪声

2019-05-05 09:51:00 m0_37992521 阅读数 1117

椒盐噪声

  1. 什么是椒盐噪声
    椒盐噪声,就是椒噪声和盐噪声的混合噪声。其中,椒噪声的椒即是黑胡椒之意,在图像中表现为黑色点斑;而盐噪声则是取自食盐,在图像中表现为白色点状。一般两种噪声在图像中混合出现,表现为黑白混杂。
  2. 如何添加椒盐噪声
    因为椒噪声表现为黑色,属于低灰度图像;盐噪声表现为白色,属于高灰度图像。利用这种特性,可以在图像中随机选取像素点赋值为0或者255,通常为了便于人眼分辨,随机赋值为255.
  3. 如何去除椒盐噪声
    椒盐噪声的像素值为0或者255,用中值滤波的方法处理效果非常好。中值滤波是在对一个区域的像素值进行大小排序,取其中值代表这一区域的像素值。因此对于消弱高低频分量对图像的影响的效果非常明显。
    opencv实现程序:https://blog.csdn.net/m0_37992521/article/details/89840367
2016-11-17 15:38:54 u012936765 阅读数 45547

最近交了数图作业,mark一下。

1.添加高斯噪声

1.1 概率密度函数

这里写图片描述

σ为z的标准差,z为均值,用E。

1.2 生成高斯分布随机数序列

方法由Marsaglia和Bray在1964年提出,C++版本如下: mu是均值,sigma是方差,X服从N(0,1)分布

double generateGaussianNoise(double mu, double sigma)
{
    static double V1, V2, S;
    static int phase = 0;
    double X;
    double U1,U2;
    if ( phase == 0 ) {
        do {
            U1 = (double)rand() / RAND_MAX;
            U2 = (double)rand() / RAND_MAX;

            V1 = 2 * U1 - 1;
            V2 = 2 * U2 - 1;
            S = V1 * V1 + V2 * V2;
        } while(S >= 1 || S == 0);

        X = V1 * sqrt(-2 * log(S) / S);
    } else{
        X = V2 * sqrt(-2 * log(S) / S);
    }
    phase = 1 - phase;
    return mu+sigma*X;
}

1.3 添加高斯噪声

高斯噪声为加性噪声,在原图的基础上加上噪声即为加噪后的图象。
代码如下:

void AddNoise(Mat img,double mu, double sigma,int k){
    Mat outImage;
    outImage.create(img.rows,img.cols,img.type());
    for(int x=0;x<img.rows;x++){
        for(int y=0;y<img.cols;y++){
            double temp = img.at<uchar>(x, y)
                    +k*generateGaussianNoise(mu,sigma);
            if(temp>PixcelMax)
                    temp=PixcelMax;
            else if(temp<PixcelMin)
                    temp=PixcelMin;
            outImage.at<uchar>(x, y) = temp;
        }
    }
    Filter(outImage,Filter::NXBJZ,3,3,1);
    imshow("Output", outImage);
    cvWaitKey(0);
}

1.4 效果图

这里写图片描述

如图,k为高斯噪声的系数,系数越大,高斯噪声越强。

这里写图片描述

噪声服从高斯分布,所以方差越大,数据越分散,噪声也就越多。

这里写图片描述

均值决定着整个图像的明亮程度,均值大于0,表示图像加上一个使自己变亮的噪声,小 于0,表示图像加上一个使自己变暗的噪声。

2.添加椒盐噪声

2.1 概率密度函数

这里写图片描述

2.2 添加椒盐噪声

椒盐噪声是根据图像的信噪比,随机生成一些图像内的像素位置,并随机对这些像素点赋值为0或255.

代码如下:

void AddNoise(Mat img,double SNR ){
    Mat outImage;
    outImage.create(img.rows,img.cols,img.type());
    int SP = img.rows*img.cols;
    int NP = SP*(1-SNR);
    outImage = img.clone();
    for(int i=0; i<NP; i++) {

        int x = (int)(rand()*1.0/RAND_MAX* (double)img.rows);
        int y = (int)(rand()*1.0/RAND_MAX* (double)img.cols);
        int r = rand()%2;
       if(r){
            outImage.at<uchar>(x, y)=0;
        }
       else{
           outImage.at<uchar>(x, y)=255;
       }

    }
     Filter(outImage,Filter::NXBJZ,3,3,1);
    imshow("Output", outImage);
    cvWaitKey(0);
}

其中,SNR为信噪比,利用C++中的rand() 作为随机函数。

2.3 效果图

这里写图片描述

信噪比越小,噪声越多,信噪比为1时,图像不含噪声。 0为胡椒噪声,255为盐粒噪声

3.均值滤波器

3.1 算术均值滤波器

这里写图片描述

Sx,y为以(x,y)为中心,长为m宽为n的矩形范围。

3.1.1 滤除高斯噪声

这里写图片描述

3.1.2滤除椒盐噪声

这里写图片描述

总结:
只能在噪声较少的情况下去除些许噪声,并且只是平滑了图像的局部变化,令图像变得模
糊。

3.2 几何均值滤波器

这里写图片描述

Sx,y为以(x,y)为中心,长为m宽为n的矩形范围。

3.2.1 滤除高斯噪声

这里写图片描述

3.2.2 滤除椒盐噪声

这里写图片描述

总结:
处理高斯噪声时,噪声较少时,效果与算术均值滤波器基本一致。但是噪声较多时,
会对灰度值较小的噪声进行放大,导致图像出现许多黑点,使图像变暗。
处理椒盐噪声时,会对胡椒噪声放大,导致图像出现许多黑点,而对盐粒噪声有较好
的滤除作用。

3.3 谐波均值滤波器

这里写图片描述

3.3.1 滤除高斯噪声

这里写图片描述

3.3.2滤除椒盐噪声

这里写图片描述

总结:
与几何均值滤波器有相似的效果,处理高斯噪声时,会对灰度值较小的噪声进行放
大,导致图像出现许多黑点,使图像变暗。
处理椒盐噪声时,会对胡椒噪声放大,导致图像出现许多黑点,无法处理胡椒噪声,
而对盐粒噪声有较好的滤除作用。

3.4 逆谐波均值滤波器

这里写图片描述

3.4.1 滤除高斯噪声

这里写图片描述

3.4.2滤除椒盐噪声

这里写图片描述

总结:
Q为正时,会对灰度值较大的噪声进行放大,Q为负时,会对灰度值较小的噪声进行 放大。
处理椒盐噪声时,Q为正,对胡椒噪声有较好的滤除作用,Q为负,对盐粒噪声有较 好的滤除作用。

代码如下:

void Filter(Mat img,Filter f,int m,int n,int Q = 0){
    Mat outImage;
    outImage.create(img.rows,img.cols,img.type());
    int h = m/2,w=n/2;
    for(int x=0;x<img.rows;x++){
        for(int y=0;y<img.cols;y++){
            int cnt = 0;
            if(f== Filter::SSJZ){
                long double sum = 0;
                for(int i=x-h;i<=x+h;i++){
                    for(int j=y-w;j<=y+w;j++){
                        if(i<0||i>=img.rows||j<0||j>=img.cols)continue;
                        cnt++;
                        sum+=img.at<uchar>(i, j);
                    }
                }
                outImage.at<uchar>(x, y)=sum/cnt;
            }
            else if(f== Filter::JHJZ){
                long double sum = 1;
                for(int i=x-h;i<=x+h;i++){
                    for(int j=y-w;j<=y+w;j++){
                        if(i<0||i>=img.rows||j<0||j>=img.cols)continue;
                        cnt++;
                        sum*=img.at<uchar>(i, j);
                    }
                }
                outImage.at<uchar>(x, y)=pow(sum,1.0/cnt);
            }
            else if(f== Filter::XBJZ){
                long double sum = 0;
                for(int i=x-h;i<=x+h;i++){
                    for(int j=y-w;j<=y+w;j++){
                        if(i<0||i>=img.rows||j<0||j>=img.cols)continue;
                        cnt++;
                        sum+=1.0/img.at<uchar>(i, j);
                    }
                }
                outImage.at<uchar>(x, y)=cnt/sum;
            }
            else if(f== Filter::NXBJZ){
                long double sum1 = 0,sum2 = 0;
                for(int i=x-h;i<=x+h;i++){
                    for(int j=y-w;j<=y+w;j++){
                        if(i<0||i>=img.rows||j<0||j>=img.cols)continue;
                        cnt++;
                        sum1+=pow(img.at<uchar>(i, j),Q);
                        sum2+=pow(img.at<uchar>(i, j),Q+1);
                    }
                }
                outImage.at<uchar>(x, y)=sum2/sum1;
            }
        }
    }
    imshow("Output", outImage);
    imwrite("/Users/camellia/desktop/gaussnoise_NXBJZ.jpg", outImage);
    cvWaitKey(0);
}

2017.7.31更新——
补充
四种滤波器
SSJZ——算术均值滤波器
JHJZ——几何均值滤波器
XBJZ——谐波均值滤波器
NXBJZ——逆谐波均值滤波器

enum Filter{
    SSJZ,JHJZ,XBJZ,NXBJZ
};
int main()
{

    Mat image;
    image = imread("/Users/camellia/desktop/lena.jpg",0);// 测试图片路径
    if ( !image.data )
    {
        printf("No image data \n");
        return -1;
    }
    namedWindow("Display Image", WINDOW_AUTOSIZE );
    imshow("Display Image", image);
    imwrite("/Users/camellia/desktop/origin.jpg", image);

    waitKey(0);
  // AddNoise(image,0,1,64);
     AddNoise(image,0.98);
//     Filter(image,SSJZ,5,5);
//     Filter(image,JHJZ,5,5);
//     Filter(image,XBJZ,5,5);
//     Filter(image,NXBJZ,5,5);
    return 0;
}
2019-09-16 20:05:16 weixin_44225182 阅读数 8148

添加椒盐噪声
    椒盐噪声也称为脉冲噪声,是图像中经常见到的一种噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。盐和胡椒噪声的成因可能是影像讯号受到突如其来的强烈干扰而产生、类比数位转换器或位元传输错误等。例如失效的感应器导致像素值为最小值,饱和的感应器导致像素值为最大值。

方法一:利用imnoise()函数

t=imread('a1.jpg');
subplot(1,2,1),imshow(t),title('原图');
t1=imnoise(t,'salt & pepper',0.1);
subplot(1,2,2),imshow(t1),title('加入噪声密度:0.1的椒盐噪声');
t2=imnoise(t,'salt & pepper',0.2);
figure,subplot(1,2,1),imshow(t2),title('加入噪声密度:0.2的椒盐噪声');
t3=imnoise(t,'salt & pepper',0.3);
subplot(1,2,2),imshow(t3),title('加入噪声密度:0.3的椒盐噪声');

效果图:
在这里插入图片描述
在这里插入图片描述
注意:

  • 噪声类型是 ‘salt & pepper’ 一定注意空格的位置 这里比较严格
  • 当噪声类型是’salt & pepper’的时候,第三个参数的意思是噪声密度,比如0.1,那么总像素个数的10%为黑白点,当然是黑点还是白点都是随机的。

方法二:自己构造随机点

image=imread('a1.jpg');
[width,height,z]=size(image);

result2=image;
subplot(1,2,1)
imshow(image);
title('原图');

%k1、k2作为判断临界点
k1=0.2;
k2=0.2;
%rand(m,n)是随机生成m行n列的矩阵,每个矩阵元素都在0-1之间
%这里k都是0.2,所以小于k的元素在矩阵中为1,反之为0
a1=rand(width,height)<k1;
a2=rand(width,height)<k2;
%合成彩色图像
t1=result2(:,:,1);
t2=result2(:,:,2);
t3=result2(:,:,3);
%分成黑点 白点 随机
t1(a1&a2)=0;
t2(a1&a2)=0;
t3(a1&a2)=0;
t1(a1& ~a2)=255;
t2(a1& ~a2)=255;
t3(a1& ~a2)=255;
result2(:,:,1)=t1;
result2(:,:,2)=t2;
result2(:,:,3)=t3;
subplot(1,2,2)
imshow(result2);
title('加椒盐噪声后');

效果图:
在这里插入图片描述

代码说明:
1.c=rand(10,10)
在这里插入图片描述
2.a=c<0.2
凡是第一步生成的10*10矩阵中元素小于0.2的元素都变成1,其余为0(和c++的0假1真差不多),这一步就是模拟噪声密度,小于0.2相当于有20%的像素点。
在这里插入图片描述
3.b=rand(10,10)<0.2
在这里插入图片描述
4.在分别a&b a&~b
a&b:a和b队员元素都为1的时候,则结果为1,反正为0. 显示白点或者黑点
a&~b:a为1 b为0时,结果为1 显示黑点或者白点
这里都是以a为基准,只有a为1的点才可能成为黑白点,而a为1的点就是通过限制临界值获得的,其实就是imnoise中的噪声密度值。

更多

获取更多资料、代码,微信公众号:海轰Pro
回复 海轰 即可

2017-08-03 11:49:49 u010368556 阅读数 18488

 http://blog.csdn.net/qq_34784753/article/details/69379135

 

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

1.椒盐噪声

       椒盐噪声也称为脉冲噪声,是图像中经常见到的一种噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。盐和胡椒噪声的成因可能是影像讯号受到突如其来的强烈干扰而产生、类比数位转换器或位元传输错误等。例如失效的感应器导致像素值为最小值,饱和的感应器导致像素值为最大值。图像模拟添加椒盐噪声是通过随机获取像素点并设置为高亮度点和低灰度点来实现的

2.高斯噪声

       高斯噪声是指高绿密度函数服从高斯分布的一类噪声。特别的,如果一个噪声,它的幅度分布服从高斯分布,而它的功率谱密度有事均匀分布的,则称这个噪声为高斯白噪声。高斯白噪声二阶矩不相关,一阶矩为常数,是指先后信号在时间上的相关性。高斯噪声包括热噪声和三里噪声。高斯噪声万有由它的事变平均值和两瞬时的协方差函数来确定,若噪声是平稳的,则平均值与时间无关,而协方差函数则变成仅和所考虑的两瞬时之差有关的相关函数,在意义上它等同于功率谱密度。高斯早生可以用大量独立的脉冲产生,从而在任何有限时间间隔内,这些脉冲中的每一个买充值与所有脉冲值得总和相比都可忽略不计。

        根据Box-Muller变换原理,建设随机变量U1、U2来自独立的处于(0,1)之间的均匀分布,则经过下面两个式子产生的随机变量Z0,Z1服从标准高斯分布。


上式中Z0,Z1满足正态分布,其中均值为0,方差为1,变量U1和U2可以修改为下式:


给图像添加两种噪声的程序如下:

#include <cstdlib>  
#include <iostream>  
#include <opencv2\core\core.hpp>  
#include <opencv2\highgui\highgui.hpp>  
#include <opencv2\imgproc\imgproc.hpp>  

using namespace cv;
using namespace std;

double generateGaussianNoise(double m, double sigma);
Mat addSaltNoise(const Mat srcImage, int n);
Mat addGaussianNoise(Mat &srcImag);

int main()
{
	Mat srcImage = imread("imL.png");
	if (!srcImage.data)
	{
		cout << "读入图像有误!" << endl;
		system("pause");
		return -1;
	}
	imshow("原图像", srcImage);
	Mat dstImage1 = addSaltNoise(srcImage, 3000);
	Mat dstImage2 = addGaussianNoise(srcImage);
	imshow("添加椒盐噪声的图像", dstImage1);
	imshow("添加高斯噪声的图像", dstImage2);
	//存储图像  
	imwrite("salt_pepper_Image.jpg", dstImage1);
	imwrite("GaussianNoise_Image.jpg", dstImage2);
	waitKey();
	return 0;
}

Mat addSaltNoise(const Mat srcImage, int n)
{
	Mat dstImage = srcImage.clone();
	for (int k = 0; k < n; k++)
	{
		//随机取值行列  
		int i = rand() % dstImage.rows;
		int j = rand() % dstImage.cols;
		//图像通道判定  
		if (dstImage.channels() == 1)
		{
			dstImage.at<uchar>(i, j) = 255;       //盐噪声  
		}
		else
		{
			dstImage.at<Vec3b>(i, j)[0] = 255;
			dstImage.at<Vec3b>(i, j)[1] = 255;
			dstImage.at<Vec3b>(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<uchar>(i, j) = 0;     //椒噪声  
		}
		else
		{
			dstImage.at<Vec3b>(i, j)[0] = 0;
			dstImage.at<Vec3b>(i, j)[1] = 0;
			dstImage.at<Vec3b>(i, j)[2] = 0;
		}
	}
	return dstImage;
}
//生成高斯噪声  
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<uchar>(i)[j] +
				generateGaussianNoise(0, 2.235) * 32;
			if (val < 0)
				val = 0;
			if (val>255)
				val = 255;
			dstImage.ptr<uchar>(i)[j] = (uchar)val;
		}
	}
	return dstImage;
}


2015-05-18 15:22:33 caiwencongwyj 阅读数 14795
1、盐椒噪声

图像加入椒盐噪声开始,椒盐噪声其实就是使图像的一些随机的像素为黑色(0)或者白色(255):
盐噪声又称白噪声,在图像中添加一些随机的白色像素点(255);胡椒噪声是在图像中添加一些随机的黑色像素点(0);盐椒噪声是在图像中既有白色像素点,又有黑色像素点。

添加代码如下:

//盐噪声
void salt(Mat& image,int n)
{
    for(int k=0; k<n; k++){
        int i = rand()%image.cols;
        int j = rand()%image.rows;
        
        if(image.channels() == 1){
            image.at<uchar>(j,i) = 255;
        }else{
	    image.at<Vec3b>(j,i)[0] = 255;
            image.at<Vec3b>(j,i)[1] = 255;
            image.at<Vec3b>(j,i)[2] = 255;
        }
    }
}
//椒盐噪声
void peppersalt(Mat& image,int n)
{
    for(int k=0; k<n/2; k++){
        int i = rand()%image.cols;
        int j = rand()%image.rows;
        
        if(image.channels() == 1){
            image.at<uchar>(j,i) = 255;
        }else{
            image.at<Vec3b>(j,i)[0] = 255;
            image.at<Vec3b>(j,i)[1] = 255;
	    image.at<Vec3b>(j,i)[2] = 255;
        }
    }
	for(int k=n/2;k<n;k++){
		int i = rand()%image.cols;
        int j = rand()%image.rows;
        
        if(image.channels() == 1){
            image.at<uchar>(j,i) = 0;
        }else{
            image.at<Vec3b>(j,i)[0] = 0;
            image.at<Vec3b>(j,i)[1] = 0;
	    image.at<Vec3b>(j,i)[2] = 0;
        }
	}
}

2、高斯噪声

Box-Muller变换:假设随机变量x1, x2来自独立的处于[0,1]之间的均匀分布,则经过下面两个式子产生的随机变量z1, z2服从标准高斯分布:



#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

#define TWO_PI 6.2831853071795864769252866
 
double generateGaussianNoise()
{
	static bool hasSpare = false;
	static double rand1, rand2;
 
	if(hasSpare)
	{
		hasSpare = false;
		return sqrt(rand1) * sin(rand2);
	}
 
	hasSpare = true;
 
	rand1 = rand() / ((double) RAND_MAX);
	if(rand1 < 1e-100) rand1 = 1e-100;
	rand1 = -2 * log(rand1);
	rand2 = (rand() / ((double) RAND_MAX)) * TWO_PI;
 
	return sqrt(rand1) * cos(rand2);
}


void AddGaussianNoise(Mat& I)
{

	CV_Assert(I.depth() != sizeof(uchar));
	int channels = I.channels();
	int nRows = I.rows;
	int nCols = I.cols * channels;

	if(I.isContinuous()){
		nCols *= nRows;
		nRows = 1;
	}

	int i,j;
	uchar* p;
	for(i = 0; i < nRows; ++i){
		p = I.ptr<uchar>(i);
		for(j = 0; j < nCols; ++j){
			double val = p[j] + generateGaussianNoise() * 128;
			if(val < 0)
				val = 0;
			if(val > 255)
				val = 255;
			p[j] = (uchar)val;

		}
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
    Mat image;
    image = imread(argv[1], 1); // Read the file

    if(! image.data ) // Check for invalid input
    {
        cout << "Could not open or find the image" << std::endl ;
        return -1;
    }

	namedWindow( "高斯噪声", WINDOW_AUTOSIZE ); // Create a window for display.
        imshow( "高斯噪声", image ); // Show our image inside it.
	AddGaussianNoise(image);

	namedWindow( "高斯噪声", WINDOW_AUTOSIZE ); 
        imshow( "高斯噪声", image ); 
        waitKey(0); 
        return 0;
}