import ij.IJ; import ij.ImagePlus; import ij.gui.GenericDialog; import ij.plugin.filter.PlugInFilter; import ij.process.*; import java.util.Random; import java.awt.Rectangle; /** * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: *

* 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. *

* 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. *

* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *

* This plugin adds Poisson distributed noise to each pixel of an image. This * plugin uses a simple way to generate random Poisson-distributed numbers given * by Knuth (http://en.wikipedia.org/wiki/Donald_Knuth). *

* Poisson noise or (particularly in electronics) as shot noise is a type of * electronic noise that occurs when the finite number of particles that carry * energy, such as electrons in an electronic circuit or photons in an optical * device, is small enough to give rise to detectable statistical fluctuations * in a measurement. It is important in electronics, telecommunications, and * fundamental physics. *

* Changes:
* 30/nov/2008
* - subtracted the mean value before adding the noise to the signal. This in * order to distribute the noise around the signal.
* - Added the MEAN_FACTOR constant to obtain a significant noise working with * float images and with a small Lambda (mean) value. * * @author Ignazio Gallo(ignazio.gallo@gmail.com, * http://www.dicom.uninsubria.it/~ignazio.gallo/) * @since 18/nov/2008 * * @version 1.1 */ public class Poisson_Noise implements PlugInFilter { final static double MEAN_FACTOR = 2.0; static double noiseMean = 2; ImagePlus imp; Random random = new Random(); public int setup(String arg, ImagePlus imp) { if (imp == null) { IJ.noImage(); return DONE; } this.imp = imp; if (!showDialog()) return DONE; return IJ.setupDialog(imp, DOES_ALL | SUPPORTS_MASKING); } public void run(ImageProcessor ip) { FloatProcessor fp = null; for (int i = 0; i < ip.getNChannels(); i++) { // grayscale: once. RBG: // once per color, i.e., 3 times fp = ip.toFloat(i, fp); // convert image or color channel to float addNoise(fp); ip.setPixels(i, fp); // convert back from float } } public void addNoise(ImageProcessor ip) { int width = ip.getWidth(); // width of the image int height = ip.getHeight(); // height of the image // double max = ip.getMax(); float[] pixels = (float[]) ip.getPixels(); int progress = Math.max(height / 25, 1); Rectangle r = ip.getRoi(); for (int y = r.y; y < (r.y + r.height); y++) { if (y % progress == 0) IJ.showProgress(y, height); for (int x = r.x; x < (r.x + r.width); x++) { // Creates additive poisson noise double newVal = (pixels[y * width + x]) + poissonValue() / MEAN_FACTOR - noiseMean; newVal = Math.max(newVal, 0); // if (newVal <= max) pixels[x + y * width] = (float) newVal; } } IJ.showProgress(1.0); ip.resetMinAndMax(); } /** * Algorithm poisson random number (Knuth). While simple, the complexity is * linear in λ (the mean). * * @return a random Poisson-distributed number. */ private int poissonValue() { // init: double L = Math.exp(-noiseMean * 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); return k - 1; } private boolean showDialog() { GenericDialog gd = new GenericDialog( "Additive Poisson Noise Parameters"); gd.addNumericField("Noise Mean (>0):", noiseMean, 2); gd.showDialog(); if (gd.wasCanceled()) return false; noiseMean = Math.max(gd.getNextNumber(), 0.01); return true; } }