Skip to content

Commit 0294253

Browse files
authored
Merge pull request #293 from scijava/scijava-ops-image/projection-improvements
Projection op improvments
2 parents 4c5b75f + cad5161 commit 0294253

4 files changed

Lines changed: 186 additions & 205 deletions

File tree

scijava-ops-image/src/main/java/org/scijava/ops/image/transform/project/project/DefaultProjectParallel.java renamed to scijava-ops-image/src/main/java/org/scijava/ops/image/transform/project/project/ProjectParallelComputer.java

Lines changed: 35 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,47 @@
2929

3030
package org.scijava.ops.image.transform.project.project;
3131

32-
import java.util.Iterator;
3332

34-
import net.imglib2.RandomAccess;
33+
import net.imglib2.FinalInterval;
3534
import net.imglib2.RandomAccessibleInterval;
3635
import net.imglib2.loops.LoopBuilder;
3736
import net.imglib2.util.Intervals;
3837

38+
import net.imglib2.view.Views;
3939
import org.scijava.function.Computers;
4040

4141
/**
42-
* @param <T>
43-
* @param <V>
44-
* @implNote op name='transform.project', priority='99.'
42+
* <b>Projection</b> is the act of creating 1-dimensional slices of an n-dimensional image,
43+
* reducing that slice down to a single value, and combining those images back into a (n-1)-dimensional array
44+
* <p>
45+
* Note that this Op cannot be adapted because the output is necessarily of different dimensionality than the input.
46+
* </p>
47+
*
48+
* @param <T> the type of input image elements
49+
* @param <V> the type of output image elements
50+
* @implNote op name='transform.project', priority='99.', hints="adaptation.FORBIDDEN"
51+
* @see ProjectParallelFunction for an Op that creates its own output
4552
*/
46-
public class DefaultProjectParallel<T, V> implements
47-
Computers.Arity3<RandomAccessibleInterval<T>, Computers.Arity1<Iterable<T>, V>, Integer, RandomAccessibleInterval<V>>
53+
public class ProjectParallelComputer<T, V> implements
54+
Computers.Arity3<
55+
RandomAccessibleInterval<T>,
56+
Computers.Arity1<? super RandomAccessibleInterval<T>, V>,
57+
Integer,
58+
RandomAccessibleInterval<V>
59+
>
4860
{
49-
5061
/**
51-
* TODO
62+
* Projects {@code op} along 1-dimensional slices (along dimension {@code dim}) of {@code input}
5263
*
53-
* @param input
54-
* @param op
55-
* @param dim
56-
* @param output
64+
* @param input the input {@code n}-dimensional dataset
65+
* @param op the Op to project over {@code dim}
66+
* @param dim the dimension along {@code input} to project
67+
* @param output the output {@code n-1}-dimensional dataset
5768
*/
5869
@Override
5970
public void compute(final RandomAccessibleInterval<T> input,
60-
Computers.Arity1<Iterable<T>, V> op, Integer dim,
61-
final RandomAccessibleInterval<V> output)
62-
{
71+
Computers.Arity1<? super RandomAccessibleInterval<T>, V> op, Integer dim,
72+
final RandomAccessibleInterval<V> output) {
6373
// TODO this first check is too simple, but for now ok
6474
if (input.numDimensions() != output.numDimensions() + 1) //
6575
throw new IllegalArgumentException(
@@ -70,61 +80,18 @@ public void compute(final RandomAccessibleInterval<T> input,
7080

7181
LoopBuilder.setImages(output, Intervals.positions(output)).multiThreaded()
7282
.forEachChunk(chunk -> {
73-
var chunkRA = input.randomAccess();
83+
var min = new long[input.numDimensions()];
84+
var max = new long[input.numDimensions()];
85+
min[dim] = input.min(dim);
86+
max[dim] = input.max(dim);
7487
chunk.forEachPixel((pixel, position) -> {
75-
for (var d = 0; d < input.numDimensions(); d++) {
76-
if (d != dim) {
77-
chunkRA.setPosition(position.getIntPosition(d - (d > dim ? 1
78-
: 0)), d);
79-
}
88+
for (var d = 0; d < position.numDimensions(); d++) {
89+
min[d >= dim ? d+1 : d] = position.getLongPosition(d);
90+
max[d >= dim ? d+1 : d] = position.getLongPosition(d);
8091
}
81-
82-
op.compute(new DimensionIterable(input.dimension(dim), dim, chunkRA),
83-
pixel);
84-
92+
op.compute(Views.interval(input, new FinalInterval(min, max)), pixel);
8593
});
86-
87-
return null;
94+
return chunk;
8895
});
8996
}
90-
91-
final class DimensionIterable implements Iterable<T> {
92-
93-
private final long size;
94-
private final int dim;
95-
private final RandomAccess<T> access;
96-
97-
public DimensionIterable(final long size, final int dim,
98-
final RandomAccess<T> access)
99-
{
100-
this.size = size;
101-
this.dim = dim;
102-
this.access = access;
103-
}
104-
105-
@Override
106-
public Iterator<T> iterator() {
107-
return new Iterator<T>() {
108-
109-
int k = -1;
110-
111-
@Override
112-
public boolean hasNext() {
113-
return k < size - 1;
114-
}
115-
116-
@Override
117-
public T next() {
118-
k++;
119-
access.setPosition(k, dim);
120-
return access.get();
121-
}
122-
123-
@Override
124-
public void remove() {
125-
throw new UnsupportedOperationException("Not supported");
126-
}
127-
};
128-
}
129-
}
13097
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.scijava.ops.image.transform.project.project;
2+
3+
import net.imglib2.FinalDimensions;
4+
import net.imglib2.RandomAccessibleInterval;
5+
import org.scijava.function.Computers;
6+
import org.scijava.function.Functions;
7+
import org.scijava.function.Producer;
8+
import org.scijava.ops.spi.OpDependency;
9+
10+
import java.util.function.BiFunction;
11+
12+
/**
13+
* Wraps {@link ProjectParallelComputer}, but creates a new output image in the process.
14+
* @param <T> the type of input image elements
15+
* @param <V> the type of output image elements
16+
* @author Gabriel Selzer
17+
* @implNote op name='transform.project', priority='99.'
18+
*/
19+
public class ProjectParallelFunction<T, V> implements
20+
Functions.Arity3<RandomAccessibleInterval<T>, Computers.Arity1<? super RandomAccessibleInterval<T>, V>, Integer, RandomAccessibleInterval<V>>
21+
{
22+
@OpDependency(name="transform.project")
23+
Computers.Arity3<RandomAccessibleInterval<T>, Computers.Arity1<? super RandomAccessibleInterval<T>, V>, Integer, RandomAccessibleInterval<V>> projector;
24+
25+
@OpDependency(name="transform.translateView")
26+
BiFunction<RandomAccessibleInterval<V>, long[], RandomAccessibleInterval<V>> translator;
27+
28+
@OpDependency(name="create.type")
29+
Producer<V> typeCreator;
30+
31+
@OpDependency(name="create.img")
32+
BiFunction<FinalDimensions, V, RandomAccessibleInterval<V>> creator;
33+
34+
35+
/**
36+
* Projects {@code op} along 1-dimensional slices (along dimension {@code dim}) of {@code input}
37+
*
38+
* @param input the input {@code n}-dimensional dataset
39+
* @param op the Op to project over {@code dim}
40+
* @param dim the dimension along {@code input} to project
41+
* @return a {@code n-1}-dimensional dataset
42+
*/
43+
@Override
44+
public RandomAccessibleInterval<V> apply(RandomAccessibleInterval<T> input, Computers.Arity1<? super RandomAccessibleInterval<T>, V> op, Integer dim) {
45+
var dims = new long[input.numDimensions() - 1];
46+
var min = new long[input.numDimensions() - 1];
47+
for(int i = 0; i < input.numDimensions() - 1; i++) {
48+
dims[i] = input.dimension(i >= dim ? i+1 : i);
49+
min[i] = input.min(i >= dim ? i+1 : i);
50+
}
51+
// Get an arbitrary instance of the output type
52+
var outImg = creator.apply(new FinalDimensions(dims), typeCreator.create());
53+
// translate by the minimum of the input img
54+
var translated = translator.apply(outImg, min);
55+
56+
projector.compute(input, op, dim, translated);
57+
return translated;
58+
}
59+
}

scijava-ops-image/src/main/java/org/scijava/ops/image/transform/project/project/ProjectRAIToIterableInterval.java

Lines changed: 0 additions & 122 deletions
This file was deleted.

0 commit comments

Comments
 (0)