Skip to content

Commit f623fd7

Browse files
gselzerctrueden
authored andcommitted
Port filter namespace
1 parent 4c84d5d commit f623fd7

32 files changed

Lines changed: 3595 additions & 0 deletions
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/* #%L
2+
* ImageJ software for multidimensional image processing and analysis.
3+
* %%
4+
* Copyright (C) 2014 - 2018 ImageJ developers.
5+
* %%
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice,
10+
* this list of conditions and the following disclaimer.
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
19+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25+
* POSSIBILITY OF SUCH DAMAGE.
26+
* #L%
27+
*/
28+
29+
package net.imagej.ops.filter.derivative;
30+
31+
import java.util.function.Function;
32+
33+
import net.imglib2.FinalInterval;
34+
import net.imglib2.Interval;
35+
import net.imglib2.RandomAccessible;
36+
import net.imglib2.RandomAccessibleInterval;
37+
import net.imglib2.img.Img;
38+
import net.imglib2.type.numeric.RealType;
39+
import net.imglib2.type.numeric.real.DoubleType;
40+
import net.imglib2.util.Util;
41+
import net.imglib2.view.Views;
42+
43+
import org.scijava.ops.OpDependency;
44+
import org.scijava.ops.core.Op;
45+
import org.scijava.ops.core.computer.BiComputer;
46+
import org.scijava.ops.core.computer.Computer;
47+
import org.scijava.param.Parameter;
48+
import org.scijava.plugin.Plugin;
49+
import org.scijava.struct.ItemIO;
50+
51+
/**
52+
* Calculates the derivative (with sobel kernel) of an image in a given
53+
* dimension.
54+
*
55+
* @author Eike Heinz, University of Konstanz
56+
*
57+
* @param <T>
58+
* type of input
59+
*/
60+
@Plugin(type = Op.class, name = "filter.partialDerivative")
61+
@Parameter(key = "input")
62+
@Parameter(key = "dimension")
63+
@Parameter(key = "output", type = ItemIO.BOTH)
64+
public class PartialDerivativeRAI<T extends RealType<T>>
65+
implements BiComputer<RandomAccessibleInterval<T>, Integer, RandomAccessibleInterval<T>> {
66+
67+
@OpDependency(name = "create.img")
68+
private Function<RandomAccessibleInterval<T>, Img<T>> createRAI;
69+
70+
@OpDependency(name = "create.img")
71+
private Function<long[], Img<DoubleType>> createImg;
72+
73+
@OpDependency(name = "math.add")
74+
private BiComputer<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> addOp;
75+
76+
@OpDependency(name = "filter.convolve")
77+
private BiComputer<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> convolveOp;
78+
79+
private Computer<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> kernelBConvolveOp;
80+
81+
private Computer<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>>[] kernelAConvolveOps;
82+
83+
@OpDependency(name = "create.kernelSobel")
84+
private Function<T, RandomAccessibleInterval<T>> sobelKernelCreator;
85+
86+
// TODO: is there any way to speed this up?
87+
public void setupConvolves(RandomAccessibleInterval<T> input, Integer dimension) {
88+
RandomAccessibleInterval<T> kernel = sobelKernelCreator.apply(Util.getTypeFromInterval(input));
89+
90+
RandomAccessibleInterval<T> kernelA = Views.hyperSlice(Views.hyperSlice(kernel, 3, 0), 2, 0);
91+
92+
RandomAccessibleInterval<T> kernelB = Views.hyperSlice(Views.hyperSlice(kernel, 3, 0), 2, 1);
93+
94+
// add dimensions to kernel to rotate properly
95+
if (input.numDimensions() > 2) {
96+
RandomAccessible<T> expandedKernelA = Views.addDimension(kernelA);
97+
RandomAccessible<T> expandedKernelB = Views.addDimension(kernelB);
98+
for (int i = 0; i < input.numDimensions() - 3; i++) {
99+
expandedKernelA = Views.addDimension(expandedKernelA);
100+
expandedKernelB = Views.addDimension(expandedKernelB);
101+
}
102+
long[] dims = new long[input.numDimensions()];
103+
for (int j = 0; j < input.numDimensions(); j++) {
104+
dims[j] = 1;
105+
}
106+
dims[0] = 3;
107+
Interval kernelInterval = new FinalInterval(dims);
108+
kernelA = Views.interval(expandedKernelA, kernelInterval);
109+
kernelB = Views.interval(expandedKernelB, kernelInterval);
110+
}
111+
112+
long[] dims = new long[input.numDimensions()];
113+
if (dimension == 0) {
114+
// HACK needs to be final so that the compiler can encapsulate it.
115+
final RandomAccessibleInterval<T> finalKernelB = kernelB;
116+
// FIXME hack
117+
kernelBConvolveOp = (in, out) -> convolveOp.compute(in, finalKernelB, out);
118+
} else {
119+
// rotate kernel B to dimension
120+
for (int j = 0; j < input.numDimensions(); j++) {
121+
if (j == dimension) {
122+
dims[j] = 3;
123+
} else {
124+
dims[j] = 1;
125+
}
126+
}
127+
128+
Img<DoubleType> kernelInterval = createImg.apply(dims);
129+
130+
RandomAccessibleInterval<T> rotatedKernelB = kernelB;
131+
for (int i = 0; i < dimension; i++) {
132+
rotatedKernelB = Views.rotate(rotatedKernelB, i, i + 1);
133+
}
134+
135+
// HACK needs to be final so that the compiler can encapsulate it.
136+
final RandomAccessibleInterval<T> finalRotatedKernelB = Views.interval(rotatedKernelB, kernelInterval);
137+
kernelBConvolveOp = (in, out) -> convolveOp.compute(in, finalRotatedKernelB, out);
138+
}
139+
140+
dims = null;
141+
142+
// rotate kernel A to all other dimensions
143+
kernelAConvolveOps = new Computer[input.numDimensions()];
144+
if (dimension != 0) {
145+
// HACK needs to be final so that the compiler can encapsulate it.
146+
final RandomAccessibleInterval<T> finalKernelA = kernelA;
147+
kernelAConvolveOps[0] = (in, out) -> convolveOp.compute(in, finalKernelA, out);
148+
}
149+
RandomAccessibleInterval<T> rotatedKernelA = kernelA;
150+
for (int i = 1; i < input.numDimensions(); i++) {
151+
if (i != dimension) {
152+
dims = new long[input.numDimensions()];
153+
for (int j = 0; j < input.numDimensions(); j++) {
154+
if (i == j) {
155+
dims[j] = 3;
156+
} else {
157+
dims[j] = 1;
158+
}
159+
}
160+
Img<DoubleType> kernelInterval = createImg.apply(dims);
161+
for (int j = 0; j < i; j++) {
162+
rotatedKernelA = Views.rotate(rotatedKernelA, j, j + 1);
163+
}
164+
165+
// HACK needs to be final so that the compiler can encapsulate it.
166+
final RandomAccessibleInterval<T> finalRotatedKernelA = rotatedKernelA;
167+
kernelAConvolveOps[i] = (in, out) -> convolveOp.compute(in,
168+
Views.interval(finalRotatedKernelA, kernelInterval), out);
169+
rotatedKernelA = kernelA;
170+
}
171+
}
172+
173+
}
174+
175+
@Override
176+
public void compute(RandomAccessibleInterval<T> input, final Integer dimension,
177+
RandomAccessibleInterval<T> output) {
178+
setupConvolves(input, dimension);
179+
RandomAccessibleInterval<T> in = input;
180+
for (int i = input.numDimensions() - 1; i >= 0; i--) {
181+
RandomAccessibleInterval<T> derivative = createRAI.apply(input);
182+
if (dimension == i) {
183+
kernelBConvolveOp.compute(Views.interval(Views.extendMirrorDouble(in), input), derivative);
184+
} else {
185+
kernelAConvolveOps[i].compute(Views.interval(Views.extendMirrorDouble(in), input), derivative);
186+
}
187+
in = derivative;
188+
}
189+
addOp.compute(output, in, output);
190+
}
191+
192+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* #%L
2+
* ImageJ software for multidimensional image processing and analysis.
3+
* %%
4+
* Copyright (C) 2014 - 2018 ImageJ developers.
5+
* %%
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice,
10+
* this list of conditions and the following disclaimer.
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
19+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25+
* POSSIBILITY OF SUCH DAMAGE.
26+
* #L%
27+
*/
28+
29+
package net.imagej.ops.filter.derivative;
30+
31+
import java.util.ArrayList;
32+
import java.util.List;
33+
import java.util.function.Function;
34+
35+
import net.imglib2.RandomAccessibleInterval;
36+
import net.imglib2.type.numeric.RealType;
37+
import net.imglib2.view.Views;
38+
import net.imglib2.view.composite.CompositeIntervalView;
39+
import net.imglib2.view.composite.RealComposite;
40+
41+
import org.scijava.ops.OpDependency;
42+
import org.scijava.ops.core.Op;
43+
import org.scijava.ops.core.computer.BiComputer;
44+
import org.scijava.param.Parameter;
45+
import org.scijava.plugin.Plugin;
46+
import org.scijava.struct.ItemIO;
47+
48+
/**
49+
* Convenience op for partial derivatives. Calculates all partial derivatives
50+
* using a separated sobel kernel and returns a {@link CompositeIntervalView}.
51+
*
52+
* @author Eike Heinz, University of Konstanz
53+
*
54+
* @param <T>
55+
* type of input
56+
*/
57+
58+
@Plugin(type = Op.class, name = "filter.partialDerivative")
59+
@Parameter(key = "input")
60+
@Parameter(key = "outputComposite", type = ItemIO.OUTPUT)
61+
public class PartialDerivativesRAI<T extends RealType<T>>
62+
implements Function<RandomAccessibleInterval<T>, CompositeIntervalView<T, RealComposite<T>>> {
63+
64+
@OpDependency(name = "filter.partialDerivative")
65+
private BiComputer<RandomAccessibleInterval<T>, Integer, RandomAccessibleInterval<T>> derivativeFunction;
66+
67+
@OpDependency(name = "create.img")
68+
private Function<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> imgCreator;
69+
70+
@Override
71+
public CompositeIntervalView<T, RealComposite<T>> apply(RandomAccessibleInterval<T> input) {
72+
List<RandomAccessibleInterval<T>> derivatives = new ArrayList<>();
73+
for (int i = 0; i < input.numDimensions(); i++) {
74+
RandomAccessibleInterval<T> derivative = imgCreator.apply(input);
75+
derivativeFunction.compute(input, i, derivative);
76+
derivatives.add(derivative);
77+
}
78+
79+
RandomAccessibleInterval<T> stacked = Views.stack(derivatives);
80+
return Views.collapseReal(stacked);
81+
}
82+
}

0 commit comments

Comments
 (0)