Skip to content

Commit 6b72824

Browse files
committed
Add (P)SNR, RMSE, and MAE implementations
Adds various metrics for comparing reference images with (noisy) test images.
1 parent 8095565 commit 6b72824

File tree

7 files changed

+556
-0
lines changed

7 files changed

+556
-0
lines changed

src/main/java/net/imagej/ops/image/ImageNamespace.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import net.imglib2.type.BooleanType;
4141
import net.imglib2.type.Type;
4242
import net.imglib2.type.numeric.RealType;
43+
import net.imglib2.type.numeric.real.DoubleType;
4344

4445
import org.scijava.plugin.Plugin;
4546

@@ -421,6 +422,80 @@ <T extends RealType<T>> IterableInterval<T> normalize(
421422
return result;
422423
}
423424

425+
// -- quality --
426+
427+
@OpMethod(op = net.imagej.ops.image.quality.DefaultMAE.class)
428+
public <T extends RealType<T>> DoubleType mae(final DoubleType out,
429+
final IterableInterval<T> reference, final IterableInterval<T> test)
430+
{
431+
final DoubleType result = (DoubleType) ops().run(
432+
net.imagej.ops.image.quality.DefaultMAE.class, out, reference, test);
433+
return result;
434+
}
435+
436+
@OpMethod(op = net.imagej.ops.image.quality.DefaultMAE.class)
437+
public <T extends RealType<T>> DoubleType mae(
438+
final IterableInterval<T> reference, final IterableInterval<T> test)
439+
{
440+
final DoubleType result = (DoubleType) ops().run(
441+
net.imagej.ops.image.quality.DefaultMAE.class, reference, test);
442+
return result;
443+
}
444+
445+
@OpMethod(op = net.imagej.ops.image.quality.DefaultPSNR.class)
446+
public <T extends RealType<T>> DoubleType psnr(final DoubleType out,
447+
final IterableInterval<T> reference, final IterableInterval<T> test)
448+
{
449+
final DoubleType result = (DoubleType) ops().run(
450+
net.imagej.ops.image.quality.DefaultPSNR.class, out, reference, test);
451+
return result;
452+
}
453+
454+
@OpMethod(op = net.imagej.ops.image.quality.DefaultPSNR.class)
455+
public <T extends RealType<T>> DoubleType psnr(
456+
final IterableInterval<T> reference, final IterableInterval<T> test)
457+
{
458+
final DoubleType result = (DoubleType) ops().run(
459+
net.imagej.ops.image.quality.DefaultPSNR.class, reference, test);
460+
return result;
461+
}
462+
463+
@OpMethod(op = net.imagej.ops.image.quality.DefaultRMSE.class)
464+
public <T extends RealType<T>> DoubleType rmse(final DoubleType out,
465+
final IterableInterval<T> reference, final IterableInterval<T> test)
466+
{
467+
final DoubleType result = (DoubleType) ops().run(
468+
net.imagej.ops.image.quality.DefaultRMSE.class, out, reference, test);
469+
return result;
470+
}
471+
472+
@OpMethod(op = net.imagej.ops.image.quality.DefaultRMSE.class)
473+
public <T extends RealType<T>> DoubleType rmse(
474+
final IterableInterval<T> reference, final IterableInterval<T> test)
475+
{
476+
final DoubleType result = (DoubleType) ops().run(
477+
net.imagej.ops.image.quality.DefaultRMSE.class, reference, test);
478+
return result;
479+
}
480+
481+
@OpMethod(op = net.imagej.ops.image.quality.DefaultSNR.class)
482+
public <T extends RealType<T>> DoubleType snr(final DoubleType out,
483+
final IterableInterval<T> reference, final IterableInterval<T> test)
484+
{
485+
final DoubleType result = (DoubleType) ops().run(
486+
net.imagej.ops.image.quality.DefaultSNR.class, out, reference, test);
487+
return result;
488+
}
489+
490+
@OpMethod(op = net.imagej.ops.image.quality.DefaultSNR.class)
491+
public <T extends RealType<T>> DoubleType snr(
492+
final IterableInterval<T> reference, final IterableInterval<T> test)
493+
{
494+
final DoubleType result = (DoubleType) ops().run(
495+
net.imagej.ops.image.quality.DefaultSNR.class, reference, test);
496+
return result;
497+
}
498+
424499
// -- Named methods --
425500

426501
@Override
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2014 - 2017 ImageJ developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
30+
package net.imagej.ops.image.quality;
31+
32+
import net.imagej.ops.Contingent;
33+
import net.imagej.ops.Ops;
34+
import net.imagej.ops.map.Maps;
35+
import net.imagej.ops.special.hybrid.AbstractBinaryHybridCF;
36+
import net.imglib2.Cursor;
37+
import net.imglib2.IterableInterval;
38+
import net.imglib2.type.numeric.RealType;
39+
import net.imglib2.type.numeric.real.DoubleType;
40+
import net.imglib2.util.Intervals;
41+
42+
import org.scijava.plugin.Plugin;
43+
44+
/**
45+
* Computes the mean absolute error (MAE) between a reference image and a
46+
* (noisy) test image.
47+
* <p>
48+
* Computations are based on the definitions of Gonzalez (R.C. Gonzalez and R.E.
49+
* Woods, "Digital Image Processing," Prentice Hall 2008).
50+
* </p>
51+
*
52+
* @author Stefan Helfrich (University of Konstanz)
53+
* @param <I> type of input elements
54+
*/
55+
@Plugin(type = Ops.Image.MAE.class)
56+
public class DefaultMAE<I extends RealType<I>> extends
57+
AbstractBinaryHybridCF<IterableInterval<I>, IterableInterval<I>, DoubleType>
58+
implements Ops.Image.MAE, Contingent
59+
{
60+
61+
@Override
62+
public void compute(final IterableInterval<I> input1,
63+
final IterableInterval<I> input2, final DoubleType output)
64+
{
65+
Cursor<I> cursor = input1.cursor();
66+
Cursor<I> cursor2 = input2.cursor();
67+
68+
double denominatorSum = 0d;
69+
while (cursor.hasNext()) {
70+
double r = cursor.next().getRealDouble();
71+
double t = cursor2.next().getRealDouble();
72+
double abs = Math.abs(r - t);
73+
denominatorSum += abs;
74+
}
75+
76+
denominatorSum *= 1d / Intervals.numElements(input1);
77+
output.setReal(denominatorSum);
78+
}
79+
80+
@Override
81+
public boolean conforms() {
82+
return Intervals.equalDimensions(in1(), in2()) && //
83+
Maps.compatible(in1(), in2());
84+
}
85+
86+
@Override
87+
public DoubleType createOutput(IterableInterval<I> input1,
88+
IterableInterval<I> input2)
89+
{
90+
return new DoubleType();
91+
}
92+
93+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2014 - 2017 ImageJ developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
30+
package net.imagej.ops.image.quality;
31+
32+
import net.imagej.ops.Contingent;
33+
import net.imagej.ops.OpService;
34+
import net.imagej.ops.Ops;
35+
import net.imagej.ops.map.Maps;
36+
import net.imagej.ops.special.hybrid.AbstractBinaryHybridCF;
37+
import net.imglib2.Cursor;
38+
import net.imglib2.IterableInterval;
39+
import net.imglib2.type.numeric.RealType;
40+
import net.imglib2.type.numeric.real.DoubleType;
41+
import net.imglib2.util.Intervals;
42+
43+
import org.scijava.plugin.Parameter;
44+
import org.scijava.plugin.Plugin;
45+
46+
/**
47+
* Computes peak signal-to-noise ratio (PSNR) between a reference image and a
48+
* (noisy) test image. The resulting PSNR is expressed in decibel.
49+
* <p>
50+
* Computations are based on the definitions of Gonzalez (R.C. Gonzalez and R.E.
51+
* Woods, "Digital Image Processing," Prentice Hall 2008).
52+
* </p>
53+
*
54+
* @author Stefan Helfrich (University of Konstanz)
55+
* @param <I> type of input elements
56+
*/
57+
@Plugin(type = Ops.Image.PSNR.class)
58+
public class DefaultPSNR<I extends RealType<I>> extends
59+
AbstractBinaryHybridCF<IterableInterval<I>, IterableInterval<I>, DoubleType>
60+
implements Ops.Image.PSNR, Contingent
61+
{
62+
63+
@Parameter
64+
private OpService opService;
65+
66+
@Override
67+
public void compute(final IterableInterval<I> input1,
68+
final IterableInterval<I> input2, final DoubleType output)
69+
{
70+
Cursor<I> cursor = input1.cursor();
71+
Cursor<I> cursor2 = input2.cursor();
72+
double max = opService.stats().max(input1).getRealDouble();
73+
max *= max;
74+
75+
double denominatorSum = 0d;
76+
while (cursor.hasNext()) {
77+
double r = cursor.next().getRealDouble();
78+
double t = cursor2.next().getRealDouble();
79+
denominatorSum += Math.pow(r - t, 2);
80+
}
81+
82+
denominatorSum *= 1d / Intervals.numElements(input1);
83+
double psnr = 10 * Math.log10(max/denominatorSum);
84+
85+
output.setReal(psnr);
86+
}
87+
88+
@Override
89+
public boolean conforms() {
90+
return Intervals.equalDimensions(in1(), in2()) && //
91+
Maps.compatible(in1(), in2());
92+
}
93+
94+
@Override
95+
public DoubleType createOutput(IterableInterval<I> input1,
96+
IterableInterval<I> input2)
97+
{
98+
return new DoubleType();
99+
}
100+
101+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2014 - 2017 ImageJ developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
30+
package net.imagej.ops.image.quality;
31+
32+
import net.imagej.ops.Contingent;
33+
import net.imagej.ops.Ops;
34+
import net.imagej.ops.map.Maps;
35+
import net.imagej.ops.special.hybrid.AbstractBinaryHybridCF;
36+
import net.imglib2.Cursor;
37+
import net.imglib2.IterableInterval;
38+
import net.imglib2.type.numeric.RealType;
39+
import net.imglib2.type.numeric.real.DoubleType;
40+
import net.imglib2.util.Intervals;
41+
42+
import org.scijava.plugin.Plugin;
43+
44+
/**
45+
* Computes the root mean square error (RMSE) between a reference image and a
46+
* (noisy) test image.
47+
* <p>
48+
* Computations are based on the definitions of Gonzalez (R.C. Gonzalez and R.E.
49+
* Woods, "Digital Image Processing," Prentice Hall 2008).
50+
* </p>
51+
*
52+
* @author Stefan Helfrich (University of Konstanz)
53+
* @param <I> type of input elements
54+
*/
55+
@Plugin(type = Ops.Image.RMSE.class)
56+
public class DefaultRMSE<I extends RealType<I>> extends
57+
AbstractBinaryHybridCF<IterableInterval<I>, IterableInterval<I>, DoubleType>
58+
implements Ops.Image.RMSE, Contingent
59+
{
60+
61+
@Override
62+
public void compute(final IterableInterval<I> input1,
63+
final IterableInterval<I> input2, final DoubleType output)
64+
{
65+
Cursor<I> cursor = input1.cursor();
66+
Cursor<I> cursor2 = input2.cursor();
67+
68+
double denominatorSum = 0d;
69+
while (cursor.hasNext()) {
70+
double r = cursor.next().getRealDouble();
71+
double t = cursor2.next().getRealDouble();
72+
denominatorSum += Math.pow(r - t, 2);
73+
}
74+
75+
denominatorSum *= 1d / Intervals.numElements(input1);
76+
77+
double rmse = Math.sqrt(denominatorSum);
78+
79+
output.setReal(rmse);
80+
}
81+
82+
@Override
83+
public boolean conforms() {
84+
return Intervals.equalDimensions(in1(), in2()) && //
85+
Maps.compatible(in1(), in2());
86+
}
87+
88+
@Override
89+
public DoubleType createOutput(IterableInterval<I> input1,
90+
IterableInterval<I> input2)
91+
{
92+
return new DoubleType();
93+
}
94+
95+
}

0 commit comments

Comments
 (0)