I'm simulating some images corrupted with Poisson noise, but I'm encountering a few problems with performance. According to the documentation on ImageEffect
, one can add Poisson noise according to the following rule:
Loading up an example image, and running the code:
man256 = ImageAdjust[ImageResize[ExampleData[{"TestImage", "Man"}], {256, 256}]];
ImageAdjust[ImageEffect[man256, {"PoissonNoise", 0.8}]] // AbsoluteTiming
(* 10.839 seconds *)
Subsequently running it again in the same kernel, it only takes 0.196 seconds. Meanwhile, the Gaussian noise effect:
ImageAdjust[ImageEffect[man256, {"GaussianNoise", 4.}]] // AbsoluteTiming
(* 0.014 seconds *)
And then running it again once more, it only takes 0.006 seconds.
I tried defining my own functions for adding Poisson and Gaussian noise for comparison. Note that I define the amount of Poisson noise slightly differently to the Mathematica method (in a way that actually makes more sense to me).
addPoissonNoise[x_, peak_] :=
Block[{imagedata},
imagedata = peak*ImageData[x];
Map[If[# == 0., 0., RandomVariate[PoissonDistribution[#]]] &, imagedata, {2}]
];
addGaussianNoise[x_, sig_] :=
Block[{imagedata},
imagedata = ImageData[x];
Map[# + RandomVariate[NormalDistribution[0., sig]] &, imagedata, {2}]
];
ImageAdjust[Image[addPoissonNoise[man256, 40.]]] // AbsoluteTiming
(* 6.495 seconds *)
ImageAdjust[Image[addGaussianNoise[man256, 4.]]] // AbsoluteTiming
(* 0.007 seconds *)
So on an initial run, my code is faster than the built-in code in both cases. But on subsequent runs, it's slower than the built-in code. Considerably slower in the case of Poisson noise.
The Gaussian example is only for comparison - it's the Poisson noise I'm more interested in, and speeding up the initial run of the code, as ~10 seconds is considerably slower than I'd like, and in reality my images are bigger than 256x256 pixels.
Is there any way to speed-up the corruption of an image with Poisson noise?
Update #1
Replacing Map
with ParallelMap
speeds up my Poisson noise function, but it's still quite slow (taking about 1.89 seconds on my machine).
Avoiding multiple calls to RandomVariate
is hard to avoid, I think. It's a shame PoissonDistribution
can't be compiled (Which Distributions can be Compiled using RandomVariate).
Update #2
There's this question: Why is Poisson Random Deviate Generation so slow?
(For info, this is with v10 on Win8.1)
PoissonDistribution
can't be compiled. In fact the delay on the initial run is caused by compiling code to provide the Poisson distribution :-) You can look atImage`ColorOperationsDump`iImageEffectPoissonNoise
to see how it works internally. $\endgroup$Information[Image
ColorOperationsDumpPoissonNoise2D]
shows, it involvesRandomReal[NormalDistribution[]]
, which does compile. $\endgroup$