Skip to content

Commit 172e8c4

Browse files
committed
add sobel filter using partial derivative
1 parent eb809cf commit 172e8c4

File tree

4 files changed

+228
-0
lines changed

4 files changed

+228
-0
lines changed

src/main/java/net/imagej/ops/filter/FilterNamespace.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,31 @@ public <T extends RealType<T>> IterableInterval<T> sigma(
12361236
return result;
12371237
}
12381238

1239+
// -- Sobel
1240+
1241+
@OpMethod(op = net.imagej.ops.filter.sobel.SobelRAI.class)
1242+
public <T extends RealType<T>> RandomAccessibleInterval<T> sobel(
1243+
final RandomAccessibleInterval<T> in)
1244+
{
1245+
@SuppressWarnings("unchecked")
1246+
final RandomAccessibleInterval<T> result =
1247+
(RandomAccessibleInterval<T>) ops().run(
1248+
net.imagej.ops.filter.sobel.SobelRAI.class, in);
1249+
return result;
1250+
}
1251+
1252+
@OpMethod(op = net.imagej.ops.filter.sobel.SobelRAI.class)
1253+
public <T extends RealType<T>> RandomAccessibleInterval<T> sobel(
1254+
final RandomAccessibleInterval<T> out,
1255+
final RandomAccessibleInterval<T> in)
1256+
{
1257+
@SuppressWarnings("unchecked")
1258+
final RandomAccessibleInterval<T> result =
1259+
(RandomAccessibleInterval<T>) ops().run(
1260+
net.imagej.ops.filter.sobel.SobelRAI.class, out, in);
1261+
return result;
1262+
}
1263+
12391264
/** Executes the "variance" filter operation on the given arguments. */
12401265
@OpMethod(op = net.imagej.ops.filter.variance.DefaultVarianceFilter.class)
12411266
public <T extends RealType<T>> IterableInterval<T> variance(
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/* #%L
2+
* ImageJ software for multidimensional image processing and analysis.
3+
* %%
4+
* Copyright (C) 2014 - 2016 Board of Regents of the University of
5+
* Wisconsin-Madison, University of Konstanz and Brian Northan.
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.filter.sobel;
31+
32+
import net.imagej.ops.Ops;
33+
import net.imagej.ops.Ops.Math.Sqr;
34+
import net.imagej.ops.Ops.Math.Sqrt;
35+
import net.imagej.ops.special.chain.RAIs;
36+
import net.imagej.ops.special.computer.BinaryComputerOp;
37+
import net.imagej.ops.special.computer.UnaryComputerOp;
38+
import net.imagej.ops.special.function.UnaryFunctionOp;
39+
import net.imagej.ops.special.hybrid.AbstractUnaryHybridCF;
40+
import net.imglib2.RandomAccessibleInterval;
41+
import net.imglib2.type.numeric.RealType;
42+
43+
import org.scijava.plugin.Plugin;
44+
45+
/**
46+
* Sobel filter implementation using separated sobel kernel.
47+
*
48+
* @author Eike Heinz, University of Konstanz
49+
*
50+
* @param <T>
51+
* type of input
52+
*/
53+
54+
@Plugin(type = Ops.Filter.Sobel.class)
55+
public class SobelRAI<T extends RealType<T>>
56+
extends AbstractUnaryHybridCF<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> implements Ops.Filter.Sobel {
57+
58+
private UnaryFunctionOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> createRAI;
59+
60+
private UnaryComputerOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> squareMapOp;
61+
62+
private UnaryComputerOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> sqrtMapOp;
63+
64+
private BinaryComputerOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> addOp;
65+
66+
private UnaryComputerOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>>[] derivativeComputers;
67+
68+
@SuppressWarnings("unchecked")
69+
@Override
70+
public void initialize() {
71+
createRAI = RAIs.function(ops(), Ops.Create.Img.class, in());
72+
73+
Sqr squareOp = ops().op(Ops.Math.Sqr.class, RealType.class, RealType.class);
74+
squareMapOp = RAIs.computer(ops(), Ops.Map.class, in(), squareOp);
75+
Sqrt sqrtOp = ops().op(Ops.Math.Sqrt.class, RealType.class, RealType.class);
76+
sqrtMapOp = RAIs.computer(ops(), Ops.Map.class, in(), sqrtOp);
77+
addOp = RAIs.binaryComputer(ops(), Ops.Math.Add.class, in(), in());
78+
79+
derivativeComputers = new UnaryComputerOp[in().numDimensions()];
80+
for (int i = 0; i < in().numDimensions(); i++) {
81+
derivativeComputers[i] = RAIs.computer(ops(), Ops.Filter.PartialDerivative.class, in(), i);
82+
}
83+
84+
}
85+
86+
@Override
87+
public void compute(RandomAccessibleInterval<T> input, RandomAccessibleInterval<T> output) {
88+
89+
for (int i = 0; i < derivativeComputers.length; i++) {
90+
RandomAccessibleInterval<T> derivative = createRAI.calculate(input);
91+
derivativeComputers[i].compute(input, derivative);
92+
squareMapOp.compute(derivative, derivative);
93+
addOp.compute(output, derivative, output);
94+
}
95+
sqrtMapOp.compute(output, output);
96+
}
97+
98+
@Override
99+
public RandomAccessibleInterval<T> createOutput(RandomAccessibleInterval<T> input) {
100+
return createRAI.calculate(input);
101+
}
102+
}

src/main/templates/net/imagej/ops/Ops.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ namespaces = ```
106106
[name: "paddingIntervalCentered", iface: "PaddingIntervalCentered"],
107107
[name: "paddingIntervalOrigin", iface: "PaddingIntervalOrigin"],
108108
[name: "sigma", iface: "Sigma", aliases: ["sigmaFilter", "filterSigma"]],
109+
[name: "sobel", iface: "Sobel"],
109110
[name: "variance", iface: "Variance", aliases: ["varianceFilter", "filterVariance", "var", "varFilter", "filterVar"]],
110111
]],
111112
[name: "geom", iface: "Geometric", ops: [
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* #%L
2+
* ImageJ software for multidimensional image processing and analysis.
3+
* %%
4+
* Copyright (C) 2014 - 2016 Board of Regents of the University of
5+
* Wisconsin-Madison, University of Konstanz and Brian Northan.
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.filter.sobel;
31+
32+
import static org.junit.Assert.assertEquals;
33+
34+
import net.imagej.ops.AbstractOpTest;
35+
import net.imglib2.Cursor;
36+
import net.imglib2.RandomAccess;
37+
import net.imglib2.RandomAccessibleInterval;
38+
import net.imglib2.img.Img;
39+
import net.imglib2.type.numeric.real.FloatType;
40+
import net.imglib2.util.Util;
41+
42+
import org.junit.Test;
43+
44+
/**
45+
* Test for sobel op using separated kernel.
46+
*
47+
* @author Eike Heinz, University of Konstanz
48+
*
49+
*/
50+
51+
public class SobelFilterTest extends AbstractOpTest {
52+
53+
@Test
54+
public void test() {
55+
56+
Img<FloatType> img = generateFloatArrayTestImg(false, new long[] { 20, 20 });
57+
58+
Cursor<FloatType> cursorImg = img.cursor();
59+
int counterX = 0;
60+
int counterY = 0;
61+
while (cursorImg.hasNext()) {
62+
if (counterX > 8 && counterX < 12 || counterY > 8 && counterY < 12) {
63+
cursorImg.next().setOne();
64+
} else {
65+
cursorImg.next().setZero();
66+
}
67+
counterX++;
68+
if (counterX % 20 == 0) {
69+
counterY++;
70+
}
71+
if (counterX == 20) {
72+
counterX = 0;
73+
}
74+
if (counterY == 20) {
75+
counterY = 0;
76+
}
77+
}
78+
RandomAccessibleInterval<FloatType> out = ops.filter().sobel(img);
79+
80+
RandomAccess<FloatType> outRA = out.randomAccess();
81+
outRA.setPosition(new int[] { 0, 8 });
82+
FloatType type = Util.getTypeFromInterval(out).createVariable();
83+
type.set(4.0f);
84+
assertEquals(type, outRA.get());
85+
type.setZero();
86+
outRA.setPosition(new int[] { 0, 10 });
87+
assertEquals(type, outRA.get());
88+
outRA.setPosition(new int[] { 10, 8 });
89+
assertEquals(type, outRA.get());
90+
outRA.setPosition(new int[] { 10, 10 });
91+
assertEquals(type, outRA.get());
92+
93+
outRA.setPosition(new int[] { 10, 12 });
94+
type.set(0.0f);
95+
assertEquals(type, outRA.get());
96+
outRA.setPosition(new int[] { 12, 10 });
97+
assertEquals(type, outRA.get());
98+
}
99+
100+
}

0 commit comments

Comments
 (0)