前言
- 图像处理的实验,用matlab捣鼓了一会最后还是觉得Java用的比较顺手,所以使用Java实现的给图像加噪声,分别给图像添加椒盐噪声、高斯噪声、泊松分布噪声。
椒盐噪声(Salt And Pepper Noise)
- 椒盐噪声是一种因为信号脉冲强度引起的噪声,信噪比(Signal NoiseRate)是衡量图像噪声的一个数字指标。
- 给一副数字图像加上椒盐噪声的处理顺序应该如下:
- 指定信噪比 SNR 其取值范围在[0, 1]之间
- 计算总像素数目 SP, 得到要加噪的像素数目 NP = SP * (1-SNR)
- 随机获取要加噪的每个像素位置P(i, j)
- 指定像素值为255或者0。
- 重复3, 4两个步骤完成所有像素的NP个像素
- 输出加噪以后的图像
代码如下:
/*
* 椒盐噪声
*/
private BufferedImage addSaltAndPepperNoise(BufferedImage src, BufferedImage dst) {
int width = src.getWidth();
int height = src.getHeight();
if ( dst == null )
dst = createCompatibleDestImage( src, null );
int[] inPixels = new int[width*height];
getRGB( src, 0, 0, width, height, inPixels );
int index = 0;
int size = (int)(inPixels.length * (1-SNR));
for(int i=0; i<size; i++) {
int row = (int)(Math.random() * (double)height);
int col = (int)(Math.random() * (double)width);
index = row * width + col;
inPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;
}
setRGB( dst, 0, 0, width, height, inPixels );
return dst;
}
高斯噪声(Gaussian Noise)
高斯噪声的密度取决于公式G(x, sigma) 其中X是代表平均值,sigma代表的标准方差,每个输入像素 Pin,
一个正常的高斯采样分布公式G(d), 得到输出像素Pout.Pout = Pin + XMeans + sigma *G(d)
其中d为一个线性的随机数,G(d)是随机数的高斯分布随机值。
给一副数字图像加上高斯噪声的处理顺序如下:
- 输入参数sigam 和 X mean
- 系统时间为种子产生一个伪随机数
- 将伪随机数带入G(d)得到高斯随机数
- 根据输入像素计算出输出像素
- 重新将像素值防缩在[0 ~ 255]之间
- 循环所有像素
- 输出图像
代码如下:
/*
* 添加高斯噪声
*/
private int addGNoise(int tr, Random random) {
int v, ran;
boolean inRange = false;
do {
ran = (int)Math.round(random.nextGaussian()*_mNoiseFactor); //均值为0.0,标准差为1.0的高斯分布
v = tr + ran;
// check whether it is valid single channel value
inRange = (v>=0 && v<=255);
if (inRange) tr = v;
} while (!inRange);
return tr;
}
public static int clamp(int p) {
return p > 255 ? 255 : (p < 0 ? 0 : p);
}
泊松噪声
- 泊松噪声,就是噪声分布符合泊松分布模型。泊松分布(Poisson Di)的公式如下:
关于泊松分布的详细解释看这里:http://zh.wikipedia.org/wiki/泊松分佈.
代码如下:
/*
* 泊松噪声
*/
private int addPNoise(int pixel, Random random) {
// init:
double L = Math.exp(-_mNoiseFactor * MEAN_FACTOR);
int k = 0;
double p = 1;
do {
k++;
// Generate uniform random number u in [0,1] and let p ← p × u.
p *= random.nextDouble();
} while (p >= L);
double retValue = Math.max((pixel + (k - 1) / MEAN_FACTOR - _mNoiseFactor), 0);
return (int)retValue;
}
程序效果
- 原图
- 高斯噪声
- 椒盐噪声
全部代码
package lab3;
import java.awt.image.BufferedImage;
import java.util.Random;
public class NoiseAdditionFilter extends AbstractBufferedImageOp {
public final static double MEAN_FACTOR = 2.0;
public final static int POISSON_NOISE_TYPE = 2; //泊松噪声
public final static int GAUSSION_NOISE_TYPE = 1; //高斯噪声
public final static int Salt_NOISE_TYPE = 3; //椒盐噪声
private double _mNoiseFactor = 100; //高斯分布数值大小
private int _mNoiseType = 2; //选择噪声
private static final double SNR = 0.5; //椒盐噪声信噪比
public NoiseAdditionFilter() {
System.out.println("Adding Poisson/Gaussion Noise");
}
public void setNoise(double power) {
this._mNoiseFactor = power;
}
public void setNoiseType(int type) {
this._mNoiseType = type;
}
@Override
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
int width = src.getWidth();
int height = src.getHeight();
Random random = new Random();
if ( dest == null )
dest = createCompatibleDestImage( src, null );
int[] inPixels = new int[width*height];
int[] outPixels = new int[width*height];
getRGB( src, 0, 0, width, height, inPixels );
int index = 0;
for(int row=0; row<height; row++) {
int ta = 0, tr = 0, tg = 0, tb = 0;
for(int col=0; col<width; col++) {
index = row * width + col;
ta = (inPixels[index] >> 24) & 0xff;
tr = (inPixels[index] >> 16) & 0xff;
tg = (inPixels[index] >> 8) & 0xff;
tb = inPixels[index] & 0xff;
if(_mNoiseType == Salt_NOISE_TYPE) {
return this.addSaltAndPepperNoise(src,dest);
}
if(_mNoiseType == POISSON_NOISE_TYPE) {
tr = clamp(addPNoise(tr, random));
tg = clamp(addPNoise(tg, random));
tb = clamp(addPNoise(tb, random));
} else if(_mNoiseType == GAUSSION_NOISE_TYPE) {
tr = clamp(addGNoise(tr, random));
tg = clamp(addGNoise(tg, random));
tb = clamp(addGNoise(tb, random));
}
outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
}
}
System.out.println("fd");
setRGB( dest, 0, 0, width, height, outPixels );
return dest;
}
/*
* 添加高斯噪声
*/
private int addGNoise(int tr, Random random) {
int v, ran;
boolean inRange = false;
do {
ran = (int)Math.round(random.nextGaussian()*_mNoiseFactor); //均值为0.0,标准差为1.0的高斯分布
v = tr + ran;
// check whether it is valid single channel value
inRange = (v>=0 && v<=255);
if (inRange) tr = v;
} while (!inRange);
return tr;
}
public static int clamp(int p) {
return p > 255 ? 255 : (p < 0 ? 0 : p);
}
/*
* 泊松噪声
*/
private int addPNoise(int pixel, Random random) {
// init:
double L = Math.exp(-_mNoiseFactor * MEAN_FACTOR);
int k = 0;
double p = 1;
do {
k++;
// Generate uniform random number u in [0,1] and let p ← p × u.
p *= random.nextDouble();
} while (p >= L);
double retValue = Math.max((pixel + (k - 1) / MEAN_FACTOR - _mNoiseFactor), 0);
return (int)retValue;
}
/*
* 椒盐噪声
*/
private BufferedImage addSaltAndPepperNoise(BufferedImage src, BufferedImage dst) {
int width = src.getWidth();
int height = src.getHeight();
if ( dst == null )
dst = createCompatibleDestImage( src, null );
int[] inPixels = new int[width*height];
getRGB( src, 0, 0, width, height, inPixels );
int index = 0;
int size = (int)(inPixels.length * (1-SNR));
for(int i=0; i<size; i++) {
int row = (int)(Math.random() * (double)height);
int col = (int)(Math.random() * (double)width);
index = row * width + col;
inPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;
}
setRGB( dst, 0, 0, width, height, inPixels );
return dst;
}
}