前言

  • 图像处理的实验,用matlab捣鼓了一会最后还是觉得Java用的比较顺手,所以使用Java实现的给图像加噪声,分别给图像添加椒盐噪声、高斯噪声、泊松分布噪声。

    椒盐噪声(Salt And Pepper Noise)

  • 椒盐噪声是一种因为信号脉冲强度引起的噪声,信噪比(Signal NoiseRate)是衡量图像噪声的一个数字指标。
  • 给一副数字图像加上椒盐噪声的处理顺序应该如下:
    1. 指定信噪比 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)是随机数的高斯分布随机值。

  • 给一副数字图像加上高斯噪声的处理顺序如下:

    1. 输入参数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;
}
}