From e037b90eb8bdbe17f332d36b8bf9b379f97499cd Mon Sep 17 00:00:00 2001 From: Stefan Helfrich Date: Thu, 11 Jan 2018 11:13:50 +0100 Subject: [PATCH 1/4] Add (P)SNR, RMSE, and MAE implementations Adds various metrics for comparing reference images with (noisy) test images. --- .../net/imagej/ops/image/ImageNamespace.java | 75 +++++++++++++ .../imagej/ops/image/quality/DefaultMAE.java | 93 ++++++++++++++++ .../imagej/ops/image/quality/DefaultPSNR.java | 101 ++++++++++++++++++ .../imagej/ops/image/quality/DefaultRMSE.java | 95 ++++++++++++++++ .../imagej/ops/image/quality/DefaultSNR.java | 95 ++++++++++++++++ src/main/templates/net/imagej/ops/Ops.list | 4 + .../ops/image/quality/QualityTests.java | 93 ++++++++++++++++ 7 files changed, 556 insertions(+) create mode 100644 src/main/java/net/imagej/ops/image/quality/DefaultMAE.java create mode 100644 src/main/java/net/imagej/ops/image/quality/DefaultPSNR.java create mode 100644 src/main/java/net/imagej/ops/image/quality/DefaultRMSE.java create mode 100644 src/main/java/net/imagej/ops/image/quality/DefaultSNR.java create mode 100644 src/test/java/net/imagej/ops/image/quality/QualityTests.java diff --git a/src/main/java/net/imagej/ops/image/ImageNamespace.java b/src/main/java/net/imagej/ops/image/ImageNamespace.java index f16372bb73..56a1eec830 100644 --- a/src/main/java/net/imagej/ops/image/ImageNamespace.java +++ b/src/main/java/net/imagej/ops/image/ImageNamespace.java @@ -42,6 +42,7 @@ import net.imglib2.type.Type; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.integer.IntType; +import net.imglib2.type.numeric.real.DoubleType; import org.scijava.plugin.Plugin; @@ -456,6 +457,80 @@ > IterableInterval normalize( return result; } + // -- quality -- + + @OpMethod(op = net.imagej.ops.image.quality.DefaultMAE.class) + public > DoubleType mae(final DoubleType out, + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultMAE.class, out, reference, test); + return result; + } + + @OpMethod(op = net.imagej.ops.image.quality.DefaultMAE.class) + public > DoubleType mae( + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultMAE.class, reference, test); + return result; + } + + @OpMethod(op = net.imagej.ops.image.quality.DefaultPSNR.class) + public > DoubleType psnr(final DoubleType out, + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultPSNR.class, out, reference, test); + return result; + } + + @OpMethod(op = net.imagej.ops.image.quality.DefaultPSNR.class) + public > DoubleType psnr( + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultPSNR.class, reference, test); + return result; + } + + @OpMethod(op = net.imagej.ops.image.quality.DefaultRMSE.class) + public > DoubleType rmse(final DoubleType out, + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultRMSE.class, out, reference, test); + return result; + } + + @OpMethod(op = net.imagej.ops.image.quality.DefaultRMSE.class) + public > DoubleType rmse( + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultRMSE.class, reference, test); + return result; + } + + @OpMethod(op = net.imagej.ops.image.quality.DefaultSNR.class) + public > DoubleType snr(final DoubleType out, + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultSNR.class, out, reference, test); + return result; + } + + @OpMethod(op = net.imagej.ops.image.quality.DefaultSNR.class) + public > DoubleType snr( + final IterableInterval reference, final IterableInterval test) + { + final DoubleType result = (DoubleType) ops().run( + net.imagej.ops.image.quality.DefaultSNR.class, reference, test); + return result; + } + // -- watershed -- /** Executes the "watershed" operation on the given arguments. */ diff --git a/src/main/java/net/imagej/ops/image/quality/DefaultMAE.java b/src/main/java/net/imagej/ops/image/quality/DefaultMAE.java new file mode 100644 index 0000000000..6238bb8c93 --- /dev/null +++ b/src/main/java/net/imagej/ops/image/quality/DefaultMAE.java @@ -0,0 +1,93 @@ +/* + * #%L + * ImageJ software for multidimensional image processing and analysis. + * %% + * Copyright (C) 2014 - 2018 ImageJ developers. + * %% + * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDERS OR CONTRIBUTORS 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. + * #L% + */ + +package net.imagej.ops.image.quality; + +import net.imagej.ops.Contingent; +import net.imagej.ops.Ops; +import net.imagej.ops.map.Maps; +import net.imagej.ops.special.hybrid.AbstractBinaryHybridCF; +import net.imglib2.Cursor; +import net.imglib2.IterableInterval; +import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.Intervals; + +import org.scijava.plugin.Plugin; + +/** + * Computes the mean absolute error (MAE) between a reference image and a + * (noisy) test image. + *

+ * Computations are based on the definitions of Gonzalez (R.C. Gonzalez and R.E. + * Woods, "Digital Image Processing," Prentice Hall 2008). + *

+ * + * @author Stefan Helfrich (University of Konstanz) + * @param type of input elements + */ +@Plugin(type = Ops.Image.MAE.class) +public class DefaultMAE> extends + AbstractBinaryHybridCF, IterableInterval, DoubleType> + implements Ops.Image.MAE, Contingent +{ + + @Override + public void compute(final IterableInterval input1, + final IterableInterval input2, final DoubleType output) + { + final Cursor cursor = input1.cursor(); + final Cursor cursor2 = input2.cursor(); + + double denominatorSum = 0d; + while (cursor.hasNext()) { + final double r = cursor.next().getRealDouble(); + final double t = cursor2.next().getRealDouble(); + final double abs = Math.abs(r - t); + denominatorSum += abs; + } + + denominatorSum *= 1d / Intervals.numElements(input1); + output.setReal(denominatorSum); + } + + @Override + public boolean conforms() { + return Intervals.equalDimensions(in1(), in2()) && // + Maps.compatible(in1(), in2()); + } + + @Override + public DoubleType createOutput(final IterableInterval input1, + final IterableInterval input2) + { + return new DoubleType(); + } + +} diff --git a/src/main/java/net/imagej/ops/image/quality/DefaultPSNR.java b/src/main/java/net/imagej/ops/image/quality/DefaultPSNR.java new file mode 100644 index 0000000000..c5398f1a3f --- /dev/null +++ b/src/main/java/net/imagej/ops/image/quality/DefaultPSNR.java @@ -0,0 +1,101 @@ +/* + * #%L + * ImageJ software for multidimensional image processing and analysis. + * %% + * Copyright (C) 2014 - 2018 ImageJ developers. + * %% + * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDERS OR CONTRIBUTORS 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. + * #L% + */ + +package net.imagej.ops.image.quality; + +import net.imagej.ops.Contingent; +import net.imagej.ops.OpService; +import net.imagej.ops.Ops; +import net.imagej.ops.map.Maps; +import net.imagej.ops.special.hybrid.AbstractBinaryHybridCF; +import net.imglib2.Cursor; +import net.imglib2.IterableInterval; +import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.Intervals; + +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; + +/** + * Computes peak signal-to-noise ratio (PSNR) between a reference image and a + * (noisy) test image. The resulting PSNR is expressed in decibel. + *

+ * Computations are based on the definitions of Gonzalez (R.C. Gonzalez and R.E. + * Woods, "Digital Image Processing," Prentice Hall 2008). + *

+ * + * @author Stefan Helfrich (University of Konstanz) + * @param type of input elements + */ +@Plugin(type = Ops.Image.PSNR.class) +public class DefaultPSNR> extends + AbstractBinaryHybridCF, IterableInterval, DoubleType> + implements Ops.Image.PSNR, Contingent +{ + + @Parameter + private OpService opService; + + @Override + public void compute(final IterableInterval input1, + final IterableInterval input2, final DoubleType output) + { + final Cursor cursor = input1.cursor(); + final Cursor cursor2 = input2.cursor(); + double max = opService.stats().max(input1).getRealDouble(); + max *= max; + + double denominatorSum = 0d; + while (cursor.hasNext()) { + final double r = cursor.next().getRealDouble(); + final double t = cursor2.next().getRealDouble(); + denominatorSum += Math.pow(r - t, 2); + } + + denominatorSum *= 1d / Intervals.numElements(input1); + final double psnr = 10 * Math.log10(max / denominatorSum); + + output.setReal(psnr); + } + + @Override + public boolean conforms() { + return Intervals.equalDimensions(in1(), in2()) && // + Maps.compatible(in1(), in2()); + } + + @Override + public DoubleType createOutput(final IterableInterval input1, + final IterableInterval input2) + { + return new DoubleType(); + } + +} diff --git a/src/main/java/net/imagej/ops/image/quality/DefaultRMSE.java b/src/main/java/net/imagej/ops/image/quality/DefaultRMSE.java new file mode 100644 index 0000000000..bd8f2c3f02 --- /dev/null +++ b/src/main/java/net/imagej/ops/image/quality/DefaultRMSE.java @@ -0,0 +1,95 @@ +/* + * #%L + * ImageJ software for multidimensional image processing and analysis. + * %% + * Copyright (C) 2014 - 2018 ImageJ developers. + * %% + * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDERS OR CONTRIBUTORS 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. + * #L% + */ + +package net.imagej.ops.image.quality; + +import net.imagej.ops.Contingent; +import net.imagej.ops.Ops; +import net.imagej.ops.map.Maps; +import net.imagej.ops.special.hybrid.AbstractBinaryHybridCF; +import net.imglib2.Cursor; +import net.imglib2.IterableInterval; +import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.Intervals; + +import org.scijava.plugin.Plugin; + +/** + * Computes the root mean square error (RMSE) between a reference image and a + * (noisy) test image. + *

+ * Computations are based on the definitions of Gonzalez (R.C. Gonzalez and R.E. + * Woods, "Digital Image Processing," Prentice Hall 2008). + *

+ * + * @author Stefan Helfrich (University of Konstanz) + * @param type of input elements + */ +@Plugin(type = Ops.Image.RMSE.class) +public class DefaultRMSE> extends + AbstractBinaryHybridCF, IterableInterval, DoubleType> + implements Ops.Image.RMSE, Contingent +{ + + @Override + public void compute(final IterableInterval input1, + final IterableInterval input2, final DoubleType output) + { + final Cursor cursor = input1.cursor(); + final Cursor cursor2 = input2.cursor(); + + double denominatorSum = 0d; + while (cursor.hasNext()) { + final double r = cursor.next().getRealDouble(); + final double t = cursor2.next().getRealDouble(); + denominatorSum += Math.pow(r - t, 2); + } + + denominatorSum *= 1d / Intervals.numElements(input1); + + final double rmse = Math.sqrt(denominatorSum); + + output.setReal(rmse); + } + + @Override + public boolean conforms() { + return Intervals.equalDimensions(in1(), in2()) && // + Maps.compatible(in1(), in2()); + } + + @Override + public DoubleType createOutput(final IterableInterval input1, + final IterableInterval input2) + { + return new DoubleType(); + } + +} diff --git a/src/main/java/net/imagej/ops/image/quality/DefaultSNR.java b/src/main/java/net/imagej/ops/image/quality/DefaultSNR.java new file mode 100644 index 0000000000..b6e0c4919a --- /dev/null +++ b/src/main/java/net/imagej/ops/image/quality/DefaultSNR.java @@ -0,0 +1,95 @@ +/* + * #%L + * ImageJ software for multidimensional image processing and analysis. + * %% + * Copyright (C) 2014 - 2018 ImageJ developers. + * %% + * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDERS OR CONTRIBUTORS 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. + * #L% + */ + +package net.imagej.ops.image.quality; + +import net.imagej.ops.Contingent; +import net.imagej.ops.Ops; +import net.imagej.ops.map.Maps; +import net.imagej.ops.special.hybrid.AbstractBinaryHybridCF; +import net.imglib2.Cursor; +import net.imglib2.IterableInterval; +import net.imglib2.type.numeric.RealType; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.util.Intervals; + +import org.scijava.plugin.Plugin; + +/** + * Computes signal-to-noise ratio (SNR) between a reference image and a (noisy) + * test image. The resulting SNR is expressed in decibel. + *

+ * Computations are based on the definitions of Gonzalez (R.C. Gonzalez and R.E. + * Woods, "Digital Image Processing," Prentice Hall 2008). + *

+ * + * @author Stefan Helfrich (University of Konstanz) + * @param type of input elements + */ +@Plugin(type = Ops.Image.SNR.class) +public class DefaultSNR> extends + AbstractBinaryHybridCF, IterableInterval, DoubleType> + implements Ops.Image.SNR, Contingent +{ + + @Override + public void compute(final IterableInterval input1, + final IterableInterval input2, final DoubleType output) + { + final Cursor cursor = input1.cursor(); + final Cursor cursor2 = input2.cursor(); + double numeratorSum = 0; + double denominatorSum = 0; + while (cursor.hasNext()) { + final double r = cursor.next().getRealDouble(); + numeratorSum += Math.pow(r, 2); + + final double t = cursor2.next().getRealDouble(); + denominatorSum += Math.pow(r - t, 2); + } + + final double snr = 10 * Math.log10(numeratorSum / denominatorSum); + + output.setReal(snr); + } + + @Override + public boolean conforms() { + return Intervals.equalDimensions(in1(), in2()) && // + Maps.compatible(in1(), in2()); + } + + @Override + public DoubleType createOutput(final IterableInterval input1, + final IterableInterval input2) + { + return new DoubleType(); + } + +} diff --git a/src/main/templates/net/imagej/ops/Ops.list b/src/main/templates/net/imagej/ops/Ops.list index e38e8c72f6..f4c6372843 100644 --- a/src/main/templates/net/imagej/ops/Ops.list +++ b/src/main/templates/net/imagej/ops/Ops.list @@ -199,7 +199,11 @@ namespaces = ``` [name: "histogram", iface: "Histogram"], [name: "integral", iface: "Integral"], [name: "invert", iface: "Invert"], + [name: "mae", iface: "MAE"], [name: "normalize", iface: "Normalize", aliases: ["norm"]], + [name: "psnr", iface: "PSNR"], + [name: "rmse", iface: "RMSE"], + [name: "snr", iface: "SNR", aliases: ["signal-to-noise"]], [name: "squareIntegral", iface: "SquareIntegral"], [name: "watershed", iface: "Watershed"], ]], diff --git a/src/test/java/net/imagej/ops/image/quality/QualityTests.java b/src/test/java/net/imagej/ops/image/quality/QualityTests.java new file mode 100644 index 0000000000..276cdbdf52 --- /dev/null +++ b/src/test/java/net/imagej/ops/image/quality/QualityTests.java @@ -0,0 +1,93 @@ +/* + * #%L + * ImageJ software for multidimensional image processing and analysis. + * %% + * Copyright (C) 2014 - 2018 ImageJ developers. + * %% + * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDERS OR CONTRIBUTORS 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. + * #L% + */ + +package net.imagej.ops.image.quality; + +import static org.junit.Assert.assertEquals; + +import net.imagej.ops.AbstractOpTest; +import net.imglib2.img.Img; +import net.imglib2.img.array.ArrayImgs; +import net.imglib2.type.numeric.integer.ByteType; +import net.imglib2.type.numeric.real.DoubleType; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for (P)SNR, RMSE, and MAE. + * + * @author Stefan Helfrich (University of Konstanz) + */ +public class QualityTests extends AbstractOpTest { + + Img reference; + Img test; + + @Override + @Before + public void setUp() { + super.setUp(); + reference = ArrayImgs.bytes(new byte[] { 9, 5, 8, 0, 9, 5, 2, 3, 7 }, 3, 3); + test = ArrayImgs.bytes(new byte[] { 8, 4, 9, 3, 2, 7, 1, 3, 7 }, 3, 3); + } + + @Test + public void testSNR() { + final DoubleType snr = new DoubleType(); + ops.image().snr(snr, reference, test); + + assertEquals(7.0937, snr.getRealDouble(), 0.0001); + } + + @Test + public void testPSNR() { + final DoubleType psnr = new DoubleType(); + ops.image().psnr(psnr, reference, test); + + assertEquals(10.4319, psnr.getRealDouble(), 0.0001); + } + + @Test + public void testRMSE() { + final DoubleType rmse = new DoubleType(); + ops.image().rmse(rmse, reference, test); + + assertEquals(2.7080, rmse.getRealDouble(), 0.0001); + } + + @Test + public void testMAE() { + final DoubleType mae = new DoubleType(); + ops.image().mae(mae, reference, test); + + assertEquals(1.7777, mae.getRealDouble(), 0.0001); + } + +} From 16c1a5f006bf49eb9e3abaff3c63bdcf7dc74632 Mon Sep 17 00:00:00 2001 From: Alison Walter Date: Wed, 6 Jun 2018 10:19:42 +0200 Subject: [PATCH 2/4] Rename QualityTests to QualityTest Maven will only execute unit tests whose class name begins or ends with "Test". --- .../ops/image/quality/{QualityTests.java => QualityTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/net/imagej/ops/image/quality/{QualityTests.java => QualityTest.java} (98%) diff --git a/src/test/java/net/imagej/ops/image/quality/QualityTests.java b/src/test/java/net/imagej/ops/image/quality/QualityTest.java similarity index 98% rename from src/test/java/net/imagej/ops/image/quality/QualityTests.java rename to src/test/java/net/imagej/ops/image/quality/QualityTest.java index 276cdbdf52..75accf3c7e 100644 --- a/src/test/java/net/imagej/ops/image/quality/QualityTests.java +++ b/src/test/java/net/imagej/ops/image/quality/QualityTest.java @@ -45,7 +45,7 @@ * * @author Stefan Helfrich (University of Konstanz) */ -public class QualityTests extends AbstractOpTest { +public class QualityTest extends AbstractOpTest { Img reference; Img test; From 250397e6d6055b051e3b4c1ea8eae6b2d07ddbf0 Mon Sep 17 00:00:00 2001 From: Stefan Helfrich Date: Fri, 8 Jun 2018 13:24:53 +0200 Subject: [PATCH 3/4] Fix namespace methods to use interface instead of implementation --- .../net/imagej/ops/image/ImageNamespace.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/imagej/ops/image/ImageNamespace.java b/src/main/java/net/imagej/ops/image/ImageNamespace.java index 56a1eec830..f3e35671f9 100644 --- a/src/main/java/net/imagej/ops/image/ImageNamespace.java +++ b/src/main/java/net/imagej/ops/image/ImageNamespace.java @@ -464,7 +464,7 @@ public > DoubleType mae(final DoubleType out, final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultMAE.class, out, reference, test); + net.imagej.ops.Ops.Image.MAE.class, out, reference, test); return result; } @@ -473,7 +473,7 @@ public > DoubleType mae( final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultMAE.class, reference, test); + net.imagej.ops.Ops.Image.MAE.class, reference, test); return result; } @@ -482,7 +482,7 @@ public > DoubleType psnr(final DoubleType out, final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultPSNR.class, out, reference, test); + net.imagej.ops.Ops.Image.PSNR.class, out, reference, test); return result; } @@ -491,7 +491,7 @@ public > DoubleType psnr( final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultPSNR.class, reference, test); + net.imagej.ops.Ops.Image.PSNR.class, reference, test); return result; } @@ -500,7 +500,7 @@ public > DoubleType rmse(final DoubleType out, final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultRMSE.class, out, reference, test); + net.imagej.ops.Ops.Image.RMSE.class, out, reference, test); return result; } @@ -509,7 +509,7 @@ public > DoubleType rmse( final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultRMSE.class, reference, test); + net.imagej.ops.Ops.Image.RMSE.class, reference, test); return result; } @@ -518,7 +518,7 @@ public > DoubleType snr(final DoubleType out, final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultSNR.class, out, reference, test); + net.imagej.ops.Ops.Image.SNR.class, out, reference, test); return result; } @@ -527,7 +527,7 @@ public > DoubleType snr( final IterableInterval reference, final IterableInterval test) { final DoubleType result = (DoubleType) ops().run( - net.imagej.ops.image.quality.DefaultSNR.class, reference, test); + net.imagej.ops.Ops.Image.SNR.class, reference, test); return result; } From a8c8f7675b92b41ed2ea4b8d2ddd23cabc616825 Mon Sep 17 00:00:00 2001 From: Stefan Helfrich Date: Fri, 8 Jun 2018 13:25:39 +0200 Subject: [PATCH 4/4] Fix tests to use implementation instead of namespace methods --- .../java/net/imagej/ops/image/quality/QualityTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/net/imagej/ops/image/quality/QualityTest.java b/src/test/java/net/imagej/ops/image/quality/QualityTest.java index 75accf3c7e..356c488422 100644 --- a/src/test/java/net/imagej/ops/image/quality/QualityTest.java +++ b/src/test/java/net/imagej/ops/image/quality/QualityTest.java @@ -61,7 +61,7 @@ public void setUp() { @Test public void testSNR() { final DoubleType snr = new DoubleType(); - ops.image().snr(snr, reference, test); + ops.run(net.imagej.ops.image.quality.DefaultSNR.class, snr, reference, test); assertEquals(7.0937, snr.getRealDouble(), 0.0001); } @@ -69,7 +69,7 @@ public void testSNR() { @Test public void testPSNR() { final DoubleType psnr = new DoubleType(); - ops.image().psnr(psnr, reference, test); + ops.run(net.imagej.ops.image.quality.DefaultPSNR.class, psnr, reference, test); assertEquals(10.4319, psnr.getRealDouble(), 0.0001); } @@ -77,7 +77,7 @@ public void testPSNR() { @Test public void testRMSE() { final DoubleType rmse = new DoubleType(); - ops.image().rmse(rmse, reference, test); + ops.run(net.imagej.ops.image.quality.DefaultRMSE.class, rmse, reference, test); assertEquals(2.7080, rmse.getRealDouble(), 0.0001); } @@ -85,7 +85,7 @@ public void testRMSE() { @Test public void testMAE() { final DoubleType mae = new DoubleType(); - ops.image().mae(mae, reference, test); + ops.run(net.imagej.ops.image.quality.DefaultMAE.class, mae, reference, test); assertEquals(1.7777, mae.getRealDouble(), 0.0001); }