44import net .imagej .Extents ;
55import net .imagej .Position ;
66import net .imagej .ops .Ops ;
7+ import net .imagej .ops .special .computer .Computers ;
8+ import net .imagej .ops .special .computer .UnaryComputerOp ;
79import net .imagej .ops .special .function .AbstractUnaryFunctionOp ;
8- import net .imglib2 .Cursor ;
9- import net .imglib2 .FinalInterval ;
10- import net .imglib2 .RandomAccess ;
10+ import net .imagej .ops .special .function .UnaryFunctionOp ;
11+ import net .imagej .ops .special .inplace .Inplaces ;
12+ import net .imagej .ops .special .inplace .UnaryInplaceOp ;
13+ import net .imglib2 .IterableInterval ;
1114import net .imglib2 .RandomAccessible ;
1215import net .imglib2 .RandomAccessibleInterval ;
13- import net .imglib2 .algorithm .neighborhood .Neighborhood ;
14- import net .imglib2 .algorithm .neighborhood .RectangleNeighborhood ;
15- import net .imglib2 .algorithm .neighborhood .RectangleNeighborhoodFactory ;
16- import net .imglib2 .algorithm .neighborhood .RectangleShape .NeighborhoodsAccessible ;
1716import net .imglib2 .type .numeric .IntegerType ;
1817import net .imglib2 .type .numeric .RealType ;
18+ import net .imglib2 .type .numeric .integer .ByteType ;
19+ import net .imglib2 .type .numeric .real .DoubleType ;
1920import net .imglib2 .util .Util ;
2021import net .imglib2 .view .Views ;
2122
@@ -32,109 +33,103 @@ public class DefaultSharpen<T extends RealType<T>> extends
3233 implements Ops .Filter .Sharpen
3334{
3435
35- final double [] kernel = { -1 , -1 , -1 , -1 , 12 , -1 , -1 , -1 , -1 };
36- double scale ;
36+ final double [][] kernel = { { -1 , -1 , -1 }, { -1 , 12 , -1 }, { -1 , -1 , -1 } };
3737
38+ RandomAccessibleInterval <ByteType > kernelRAI ;
39+
40+ /**
41+ * The sum of all of the kernel values
42+ */
43+ double scale = 4 ;
44+
45+ UnaryFunctionOp <double [][], RandomAccessibleInterval <T >> kernelCreator ;
46+ UnaryComputerOp <RandomAccessible <T >, RandomAccessibleInterval <DoubleType >> convolveOp ;
47+ UnaryInplaceOp <IterableInterval <DoubleType >, IterableInterval <DoubleType >> addConstOp ;
48+ UnaryInplaceOp <IterableInterval <DoubleType >, IterableInterval <DoubleType >> divConstOp ;
49+ UnaryComputerOp <DoubleType , T > clipTypesOp ;
50+ UnaryComputerOp <IterableInterval <DoubleType >, IterableInterval <T >> convertOp ;
51+
52+ @ SuppressWarnings ({ "unchecked" , "rawtypes" })
53+ @ Override
54+ public void initialize () {
55+ T inType = Util .getTypeFromInterval (in ());
56+
57+ // convolution kernel
58+ kernelRAI = ops ().create ().kernel (kernel , new ByteType ());
59+
60+ IterableInterval <DoubleType > dummyDoubleType = ops ().create ().img (in (), new DoubleType ());
61+
62+ convolveOp = (UnaryComputerOp ) Computers .unary (ops (),
63+ Ops .Filter .Convolve .class , RandomAccessibleInterval .class ,
64+ RandomAccessible .class , kernelRAI );
65+ addConstOp = (UnaryInplaceOp ) Inplaces .unary (ops (), Ops .Math .Add .class ,
66+ dummyDoubleType , new DoubleType (scale / 2 ));
67+ divConstOp = (UnaryInplaceOp ) Inplaces .unary (ops (), Ops .Math .Divide .class ,
68+ dummyDoubleType , new DoubleType (scale ));
69+ clipTypesOp = (UnaryComputerOp ) Computers .unary (ops (),
70+ Ops .Convert .Clip .class , new DoubleType (), inType );
71+ convertOp = Computers .unary (ops (),
72+ Ops .Convert .ImageType .class , Views .iterable (in ()), dummyDoubleType , clipTypesOp );
73+
74+ }
75+
76+ @ SuppressWarnings ("unchecked" )
3877 @ Override
3978 public RandomAccessibleInterval <T > calculate (
4079 final RandomAccessibleInterval <T > input )
4180 {
42- final RandomAccessibleInterval <T > output = ops ().copy ().rai (input );
81+ // intermediate image to hold the convolution data. Depending on the input
82+ // type we have to be able create an intermediate of wide enough type.
83+ final RandomAccessibleInterval <DoubleType > intermediate = ops ().create ().img (in (), new DoubleType ());
84+ // output image
85+ final RandomAccessibleInterval <T > output = (RandomAccessibleInterval <T >) ops ().create ().img (in ());
4386
87+ // compute the sharpening on 2D slices of the image
4488 final long [] planeDims = new long [input .numDimensions () - 2 ];
4589 for (int i = 0 ; i < planeDims .length ; i ++)
4690 planeDims [i ] = input .dimension (i + 2 );
4791 final Extents extents = new Extents (planeDims );
4892 final Position planePos = extents .createPosition ();
4993 if (planeDims .length == 0 ) {
50- computePlanar (planePos , input , output );
94+ computePlanar (planePos , input , intermediate );
5195 }
5296 else {
5397 while (planePos .hasNext ()) {
5498 planePos .fwd ();
55- computePlanar (planePos , input , output );
99+ computePlanar (planePos , input , intermediate );
56100 }
57101
58102 }
103+
104+ T inputType = Util .getTypeFromInterval (input );
105+ IterableInterval <DoubleType > iterableIntermediate = Views .iterable (
106+ intermediate );
107+
108+ // divide by the scale, if integerType input also add scale / 2.
109+ if (inputType instanceof IntegerType ) addConstOp .mutate (
110+ iterableIntermediate );
111+ divConstOp .mutate (iterableIntermediate );
112+
113+ //convert the result back to the input type.
114+ convertOp .compute (iterableIntermediate , Views .iterable (output ));
115+
59116 return output ;
60117 }
61118
62119 private void computePlanar (final Position planePos ,
63120 final RandomAccessibleInterval <T > input ,
64- final RandomAccessibleInterval <T > output )
121+ final RandomAccessibleInterval <DoubleType > intermediate )
65122 {
66- // TODO can we just set scale to 4?
67- scale = 0 ;
68- for (final double d : kernel )
69- scale += d ;
70-
71- final T type = Util .getTypeFromInterval (input );
72-
73- final long [] imageDims = new long [input .numDimensions ()];
74- input .dimensions (imageDims );
75-
76- // create all objects needed for NeighborhoodsAccessible
77- RandomAccessibleInterval <T > slicedInput = ops ().copy ().rai (input );
123+ // create 2D slice in the case of a (N>2)-dimensional image.
124+ RandomAccessible <T > slicedInput = Views .extendMirrorSingle (input );
125+ RandomAccessibleInterval <DoubleType > slicedIntermediate = intermediate ;
78126 for (int i = planePos .numDimensions () - 1 ; i >= 0 ; i --) {
79127 slicedInput = Views .hyperSlice (slicedInput , input .numDimensions () - 1 - i ,
80128 planePos .getLongPosition (i ));
129+ slicedIntermediate = Views .hyperSlice (slicedIntermediate , intermediate
130+ .numDimensions () - 1 - i , planePos .getLongPosition (i ));
81131 }
82132
83- final RandomAccessible <T > refactoredInput = Views .extendMirrorSingle (
84- slicedInput );
85- final RectangleNeighborhoodFactory <T > factory = RectangleNeighborhood
86- .factory ();
87- final FinalInterval neighborhoodSpan = new FinalInterval (new long [] { -1 ,
88- -1 }, new long [] { 1 , 1 });
89-
90- final NeighborhoodsAccessible <T > neighborhoods =
91- new NeighborhoodsAccessible <>(refactoredInput , neighborhoodSpan , factory );
92-
93- // create cursors and random accesses for loop.
94- final Cursor <T > cursor = Views .iterable (input ).localizingCursor ();
95- final RandomAccess <T > outputRA = output .randomAccess ();
96- for (int i = 0 ; i < planePos .numDimensions (); i ++) {
97- outputRA .setPosition (planePos .getLongPosition (i ), i + 2 );
98- }
99- final RandomAccess <Neighborhood <T >> neighborhoodsRA = neighborhoods
100- .randomAccess ();
101-
102- int algorithmIndex = 0 ;
103- double sum ;
104- final double [] n = new double [9 ];
105- while (cursor .hasNext ()) {
106- cursor .fwd ();
107- if (cursor .getLongPosition (0 ) == 14 && cursor .getLongPosition (1 ) == 0 )
108- System .out .println ("Hit 14" );
109- neighborhoodsRA .setPosition (cursor );
110- final Neighborhood <T > current = neighborhoodsRA .get ();
111- final Cursor <T > neighborhoodCursor = current .cursor ();
112-
113- algorithmIndex = 0 ;
114- sum = 0 ;
115- while (algorithmIndex < n .length ) {
116- neighborhoodCursor .fwd ();
117- n [algorithmIndex ++] = neighborhoodCursor .get ().getRealDouble ();
118- }
119-
120- for (int i = 0 ; i < kernel .length ; i ++) {
121- sum += kernel [i ] * n [i ];
122- }
123-
124- //find the value for the output
125- double value ;
126- if (type instanceof IntegerType ) {
127- value = (sum + scale / 2 ) / scale ;
128- }
129- else {
130- value = sum / scale ;
131- }
132-
133- outputRA .setPosition (cursor .getLongPosition (0 ), 0 );
134- outputRA .setPosition (cursor .getLongPosition (1 ), 1 );
135- if (value > type .getMaxValue ()) value = type .getMaxValue ();
136- if (value < type .getMinValue ()) value = type .getMinValue ();
137- outputRA .get ().setReal (value );
138- }
133+ convolveOp .compute (slicedInput , slicedIntermediate );
139134 }
140135}
0 commit comments