From 61119d02a0fa3daa89b6458081960694f4ec23ee Mon Sep 17 00:00:00 2001 From: Stefan Helfrich Date: Thu, 11 Jan 2018 11:13:50 +0100 Subject: [PATCH] Add (P)SNR, RMSE, and MAE implementations Adds various metrics for comparing reference images with (noisy) test images. --- .../net/imagej/ops/image/ImageNamespace.java | 80 +++++++++++++- .../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, 559 insertions(+), 2 deletions(-) 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 190ccdcdda..29a1fd477a 100644 --- a/src/main/java/net/imagej/ops/image/ImageNamespace.java +++ b/src/main/java/net/imagej/ops/image/ImageNamespace.java @@ -42,7 +42,11 @@ import net.imglib2.type.Type; import net.imglib2.type.numeric.IntegerType; import net.imglib2.type.numeric.RealType; +<<<<<<< feeb13e88b0439bc34b78168a232e062dc5be692 import net.imglib2.type.numeric.integer.IntType; +======= +import net.imglib2.type.numeric.real.DoubleType; +>>>>>>> Add (P)SNR, RMSE, and MAE implementations import org.scijava.plugin.Plugin; @@ -469,6 +473,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. */ @@ -609,8 +687,6 @@ public , T extends RealType> ImgLabeling result = (ImgLabeling) ops().run( net.imagej.ops.image.watershed.WatershedSeeded.class, out, in, seeds, eightConnectivity, drawWatersheds, mask); - return result; - } // -- Named methods -- 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..a7161cca3d --- /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 - 2017 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) + { + Cursor cursor = input1.cursor(); + Cursor cursor2 = input2.cursor(); + + double denominatorSum = 0d; + while (cursor.hasNext()) { + double r = cursor.next().getRealDouble(); + double t = cursor2.next().getRealDouble(); + 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(IterableInterval input1, + 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..2ed6501f1f --- /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 - 2017 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) + { + Cursor cursor = input1.cursor(); + Cursor cursor2 = input2.cursor(); + double max = opService.stats().max(input1).getRealDouble(); + max *= max; + + double denominatorSum = 0d; + while (cursor.hasNext()) { + double r = cursor.next().getRealDouble(); + double t = cursor2.next().getRealDouble(); + denominatorSum += Math.pow(r - t, 2); + } + + denominatorSum *= 1d / Intervals.numElements(input1); + 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(IterableInterval input1, + 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..f42f27923c --- /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 - 2017 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) + { + Cursor cursor = input1.cursor(); + Cursor cursor2 = input2.cursor(); + + double denominatorSum = 0d; + while (cursor.hasNext()) { + double r = cursor.next().getRealDouble(); + double t = cursor2.next().getRealDouble(); + denominatorSum += Math.pow(r - t, 2); + } + + denominatorSum *= 1d / Intervals.numElements(input1); + + 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(IterableInterval input1, + 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..1df1207fa1 --- /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 - 2017 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) + { + Cursor cursor = input1.cursor(); + Cursor cursor2 = input2.cursor(); + double numeratorSum = 0; + double denominatorSum = 0; + while (cursor.hasNext()) { + double r = cursor.next().getRealDouble(); + numeratorSum += Math.pow(r, 2); + + double t = cursor2.next().getRealDouble(); + denominatorSum += Math.pow(r - t, 2); + } + + 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(IterableInterval input1, + 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 e85b24d02c..096d04b84c 100644 --- a/src/main/templates/net/imagej/ops/Ops.list +++ b/src/main/templates/net/imagej/ops/Ops.list @@ -198,7 +198,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..958b080c6b --- /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 - 2017 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() { + DoubleType snr = new DoubleType(); + ops.image().snr(snr, reference, test); + + assertEquals(7.0937, snr.getRealDouble(), 0.0001); + } + + @Test + public void testPSNR() { + DoubleType psnr = new DoubleType(); + ops.image().psnr(psnr, reference, test); + + assertEquals(10.4319, psnr.getRealDouble(), 0.0001); + } + + @Test + public void testRMSE() { + DoubleType rmse = new DoubleType(); + ops.image().rmse(rmse, reference, test); + + assertEquals(2.7080, rmse.getRealDouble(), 0.0001); + } + + @Test + public void testMAE() { + DoubleType mae = new DoubleType(); + ops.image().mae(mae, reference, test); + + assertEquals(1.7777, mae.getRealDouble(), 0.0001); + } + +}