Skip to content

Commit 0193aed

Browse files
committed
Uniform Noise Adder
1 parent 61ca449 commit 0193aed

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

scijava-ops-image/src/main/java/org/scijava/ops/image/filter/addNoise/NoiseAdders.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@
3131

3232
import java.util.Random;
3333

34+
import net.imglib2.Localizable;
3435
import net.imglib2.RandomAccessibleInterval;
3536
import net.imglib2.loops.LoopBuilder;
3637
import net.imglib2.type.numeric.RealType;
3738

39+
import net.imglib2.util.Intervals;
40+
import org.scijava.common3.MersenneTwisterFast;
3841
import org.scijava.function.Computers;
42+
import org.scijava.ops.spi.Nullable;
3943

4044
/**
4145
* Contains Ops designed to add noise to populated images.
@@ -165,6 +169,60 @@ public static <I extends RealType<I>, O extends RealType<O>> void addNoise(final
165169
public final Computers.Arity1<RandomAccessibleInterval<I>, RandomAccessibleInterval<O>> addPoissonNoiseIntervalSeedless = (input,
166170
output) -> addPoissonNoise(input, new Random(0xabcdef1234567890L), output);
167171

172+
// -- UNIFORM NOISE -- //
173+
174+
/**
175+
* Sets the real component of an output real number to the addition of the real
176+
* component of an input real number with an amount of uniform noise.
177+
*
178+
* Note that this Op has changed relative to the older implementations; before
179+
* it operated on RealTypes, we now only provide the operation on
180+
* {@link RandomAccessibleInterval}s. This is due to the nature of {@link Random}: The old
181+
* implementation saved a {@link Random} and used it on each {@link RealType}
182+
* passed to the Op. This provided no deterministic output, as the same input
183+
* would yield two different outputs if called in succession. Thus in this
184+
* iteration of the Op we make it a requirement that the input must be an
185+
* {@link RandomAccessibleInterval}. Since the {@link Random} is created upon every call of the
186+
* Op it ensures that given the same seed and input data the output will always
187+
* be the same.
188+
*
189+
* @param input the input {@link RandomAccessibleInterval}
190+
* @param rangeMin the "most negative" value that can be added to each element
191+
* @param rangeMax the "most positive" value that can be added to each element
192+
* @param seed the seed to the random number generator
193+
* @param output the output {@link RandomAccessibleInterval}
194+
* @implNote op names='filter.addUniformNoise', type=Computer
195+
*/
196+
public static <I extends RealType<I>> void compute( //
197+
RandomAccessibleInterval<I> input, //
198+
I rangeMin, //
199+
I rangeMax, //
200+
@Nullable Long seed, //
201+
RandomAccessibleInterval<I> output //
202+
) {
203+
// Set seed to default if necessary
204+
if (seed == null) {
205+
seed = 0xabcdef1234567890L;
206+
}
207+
// Construct the Random Number Generator
208+
MersenneTwisterFast rng = new MersenneTwisterFast(seed);
209+
// Find the range
210+
I range = rangeMax.createVariable();
211+
range.set(rangeMax);
212+
range.sub(rangeMin);
213+
214+
// Loop over the images
215+
LoopBuilder.setImages(input, output).forEachPixel( (i, o) -> {
216+
// Random value = next double * range
217+
o.set(range);
218+
o.mul(rng.nextDouble(true, true));
219+
// Add the range minimum
220+
o.add(rangeMin);
221+
// Add the original value
222+
o.add(i);
223+
});
224+
225+
}
168226
// -- Static utility methods --
169227

170228
// Runs the below method on every element of the input iterables.

scijava-ops-image/src/test/java/org/scijava/ops/image/OpRegressionTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class OpRegressionTest {
4242

4343
@Test
4444
public void opDiscoveryRegressionIT() {
45-
long expected = 1868;
45+
long expected = 1870;
4646
long actual = ops.infos().size();
4747
assertEquals(expected, actual);
4848
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.scijava.ops.image.filter.addNoise;
2+
3+
import net.imglib2.img.array.ArrayImgs;
4+
import net.imglib2.type.numeric.integer.ByteType;
5+
import org.junit.jupiter.api.Assertions;
6+
import org.junit.jupiter.api.Test;
7+
import org.scijava.ops.image.AbstractOpTest;
8+
9+
import java.util.Arrays;
10+
import java.util.List;
11+
12+
public class NoiseAddersTest extends AbstractOpTest {
13+
14+
@Test
15+
public void testAddUniformNoiseRegression() {
16+
var input = ArrayImgs.bytes(2, 2);
17+
ops.unary("image.fill").input(new ByteType((byte) 1)).output(input).compute();
18+
var output = ArrayImgs.bytes(2, 2);
19+
var rangeMin = new ByteType((byte) -1);
20+
var rangeMax = new ByteType((byte) 1);
21+
ops.ternary("filter.addUniformNoise").input(input, rangeMin, rangeMax).output(output).compute();
22+
var cursor = output.cursor();
23+
List<Byte> expected = Arrays.asList((byte) 0, (byte) 2, (byte) 1, (byte) 1);
24+
for(var e : expected) {
25+
Assertions.assertEquals(e, cursor.next().get());
26+
}
27+
Assertions.assertFalse(cursor.hasNext());
28+
}
29+
}

0 commit comments

Comments
 (0)