Skip to content

Commit 1bbbf2d

Browse files
committed
add hessian filter
1 parent ecc543a commit 1bbbf2d

File tree

4 files changed

+199
-0
lines changed

4 files changed

+199
-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
@@ -1012,6 +1012,31 @@ RandomAccessibleInterval<V> gauss(final RandomAccessibleInterval<T> in,
10121012
net.imagej.ops.filter.gauss.GaussRAISingleSigma.class, in, sigma);
10131013
return result;
10141014
}
1015+
1016+
// -- hessian --
1017+
1018+
@OpMethod(op = net.imagej.ops.filter.hessian.HessianRAI.class)
1019+
public <T extends RealType<T>> RandomAccessibleInterval<T> hessian(
1020+
final RandomAccessibleInterval<T> in)
1021+
{
1022+
@SuppressWarnings("unchecked")
1023+
final RandomAccessibleInterval<T> result =
1024+
(RandomAccessibleInterval<T>) ops().run(
1025+
net.imagej.ops.filter.hessian.HessianRAI.class, in);
1026+
return result;
1027+
}
1028+
1029+
@OpMethod(op = net.imagej.ops.filter.hessian.HessianRAI.class)
1030+
public <T extends RealType<T>> RandomAccessibleInterval<T> hessian(
1031+
final RandomAccessibleInterval<T> out,
1032+
final RandomAccessibleInterval<T> in)
1033+
{
1034+
@SuppressWarnings("unchecked")
1035+
final RandomAccessibleInterval<T> result =
1036+
(RandomAccessibleInterval<T>) ops().run(
1037+
net.imagej.ops.filter.hessian.HessianRAI.class, out, in);
1038+
return result;
1039+
}
10151040

10161041
// -- ifft --
10171042

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
2+
package net.imagej.ops.filter.hessian;
3+
4+
import net.imagej.ops.Ops;
5+
import net.imagej.ops.Ops.Filter.Hessian;
6+
import net.imagej.ops.special.chain.RAIs;
7+
import net.imagej.ops.special.computer.UnaryComputerOp;
8+
import net.imagej.ops.special.function.Functions;
9+
import net.imagej.ops.special.function.UnaryFunctionOp;
10+
import net.imagej.ops.special.hybrid.AbstractUnaryHybridCF;
11+
import net.imglib2.Dimensions;
12+
import net.imglib2.FinalDimensions;
13+
import net.imglib2.RandomAccessibleInterval;
14+
import net.imglib2.type.numeric.RealType;
15+
import net.imglib2.util.Util;
16+
import net.imglib2.view.IntervalView;
17+
import net.imglib2.view.Views;
18+
19+
import org.scijava.plugin.Plugin;
20+
21+
/**
22+
* Hessian filter using the sobel filter with separated kernel.
23+
*
24+
* @author Eike Heinz
25+
*
26+
* @param <T> type of input
27+
*/
28+
29+
@Plugin(type = Ops.Filter.Hessian.class, name = Ops.Filter.Hessian.NAME)
30+
public class HessianRAI<T extends RealType<T>>
31+
extends AbstractUnaryHybridCF<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> implements Hessian {
32+
33+
private UnaryComputerOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>>[] derivativeComputers;
34+
35+
@SuppressWarnings("rawtypes")
36+
private UnaryFunctionOp<Dimensions, RandomAccessibleInterval> createRAIFromDim;
37+
38+
private UnaryFunctionOp<RandomAccessibleInterval<T>, RandomAccessibleInterval<T>> createRAIFromRAI;
39+
40+
@SuppressWarnings("unchecked")
41+
@Override
42+
public void initialize() {
43+
createRAIFromDim = Functions.unary(ops(), Ops.Create.Img.class, RandomAccessibleInterval.class,
44+
Dimensions.class, Util.getTypeFromInterval(in()).createVariable());
45+
createRAIFromRAI = RAIs.function(ops(), Ops.Create.Img.class, in());
46+
47+
derivativeComputers = new UnaryComputerOp[in().numDimensions()];
48+
for (int i = 0; i < in().numDimensions(); i++) {
49+
derivativeComputers[i] = RAIs.computer(ops(), Ops.Filter.DirectionalDerivative.class, in(), i);
50+
}
51+
}
52+
53+
@Override
54+
public void compute1(RandomAccessibleInterval<T> input, RandomAccessibleInterval<T> output) {
55+
int iteration = 0;
56+
57+
for (int i = 0; i < input.numDimensions(); i++) {
58+
RandomAccessibleInterval<T> derivative = createRAIFromRAI.compute1(input);
59+
derivativeComputers[i].compute1(input, derivative);
60+
for (int j = 0; j < input.numDimensions(); j++) {
61+
IntervalView<T> out = Views.hyperSlice(Views.hyperSlice(output, 3, 0), 2, iteration);
62+
derivativeComputers[j].compute1(derivative, out);
63+
iteration++;
64+
}
65+
}
66+
}
67+
68+
@SuppressWarnings("unchecked")
69+
@Override
70+
public RandomAccessibleInterval<T> createOutput(RandomAccessibleInterval<T> input) {
71+
long[] dims = new long[input.numDimensions() + 2];
72+
for (int i = 0; i < dims.length - 1; i++) {
73+
dims[i] = input.dimension(i);
74+
}
75+
dims[dims.length - 1] = input.numDimensions() * input.numDimensions();
76+
Dimensions dim = FinalDimensions.wrap(dims);
77+
return createRAIFromDim.compute1(dim);
78+
}
79+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ namespaces = ```
9494
[name: "fft", iface: "FFT"],
9595
[name: "fftSize", iface: "FFTSize"],
9696
[name: "gauss", iface: "Gauss", aliases: ["smooth"]],
97+
[name: "hessian", iface: "Hessian"],
9798
[name: "ifft", iface: "IFFT"],
9899
[name: "max", iface: "Max", aliases: ["maxFilter", "filterMax"]],
99100
[name: "mean", iface: "Mean", aliases: ["meanFilter", "filterMean"]],
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package net.imagej.ops.filter.hessian;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import net.imagej.ops.AbstractOpTest;
6+
import net.imglib2.Cursor;
7+
import net.imglib2.RandomAccess;
8+
import net.imglib2.RandomAccessibleInterval;
9+
import net.imglib2.img.Img;
10+
import net.imglib2.type.numeric.real.DoubleType;
11+
import net.imglib2.type.numeric.real.FloatType;
12+
import net.imglib2.util.Util;
13+
import net.imglib2.view.IntervalView;
14+
import net.imglib2.view.Views;
15+
16+
import org.junit.Test;
17+
18+
public class HessianFilterTest extends AbstractOpTest {
19+
20+
@Test
21+
public void test() {
22+
Img<FloatType> img = generateFloatArrayTestImg(false, new long[] { 50, 50 });
23+
24+
Cursor<FloatType> cursorImg = img.cursor();
25+
int counterX = 0;
26+
int counterY = 0;
27+
while (cursorImg.hasNext()) {
28+
if (counterX > 20 && counterX < 30 || counterY > 20 && counterY < 30) {
29+
cursorImg.next().setOne();
30+
} else {
31+
cursorImg.next().setZero();
32+
}
33+
counterX++;
34+
if (counterX % 50 == 0) {
35+
counterY++;
36+
}
37+
if (counterX == 50) {
38+
counterX = 0;
39+
}
40+
if (counterY == 50) {
41+
counterY = 0;
42+
}
43+
}
44+
45+
RandomAccessibleInterval<FloatType> out = ops.filter().hessian(img);
46+
47+
IntervalView<FloatType> xx = Views.hyperSlice(Views.hyperSlice(out, 3, 0), 2, 0);
48+
IntervalView<FloatType> xy = Views.hyperSlice(Views.hyperSlice(out, 3, 0), 2, 1);
49+
IntervalView<FloatType> yx = Views.hyperSlice(Views.hyperSlice(out, 3, 0), 2, 2);
50+
IntervalView<FloatType> yy = Views.hyperSlice(Views.hyperSlice(out, 3, 0), 2, 3);
51+
52+
Cursor<FloatType> xyCursor = xy.cursor();
53+
Cursor<FloatType> yxCursor = yx.cursor();
54+
while (xyCursor.hasNext()) {
55+
xyCursor.fwd();
56+
yxCursor.fwd();
57+
assertEquals(xyCursor.get(), yxCursor.get());
58+
}
59+
// two numbers represent a coordinate: 20|0 ; 21|0 ...
60+
int[] positions = new int[] { 20, 0, 21, 0, 19, 31, 19, 30 };
61+
float[] valuesXX = new float[] { 16.0f, -16.0f, 15.0f, 11.0f };
62+
float[] valuesXY = new float[] { 0.0f, 0.0f, 1.0f, 3.0f };
63+
float[] valuesYY = new float[] { 0.0f, 0.0f, 15.0f, 15.0f };
64+
65+
RandomAccess<FloatType> xxRA = xx.randomAccess();
66+
RandomAccess<FloatType> xyRA = xy.randomAccess();
67+
RandomAccess<FloatType> yyRA = yy.randomAccess();
68+
69+
FloatType type = Util.getTypeFromInterval(out).createVariable();
70+
int i = 0;
71+
int j = 0;
72+
while (i < positions.length - 1) {
73+
int[] pos = new int[2];
74+
pos[0] = positions[i];
75+
pos[1] = positions[i + 1];
76+
77+
xxRA.setPosition(pos);
78+
type.set(valuesXX[j]);
79+
assertEquals(type, xxRA.get());
80+
81+
xyRA.setPosition(pos);
82+
type.set(valuesXY[j]);
83+
assertEquals(type, xyRA.get());
84+
85+
yyRA.setPosition(pos);
86+
type.set(valuesYY[j]);
87+
assertEquals(type, yyRA.get());
88+
89+
i += 2;
90+
j++;
91+
}
92+
}
93+
94+
}

0 commit comments

Comments
 (0)