use of net.imglib2.RandomAccessible in project imagej-ops by imagej.
the class AbstractThin method compute.
@Override
public void compute(final RandomAccessibleInterval<BitType> input, final RandomAccessibleInterval<BitType> output) {
// Create a new image as a buffer to store the thinning image in each
// iteration.
// This image and output are swapped each iteration since we need to work on
// the image
// without changing it.
final Img<BitType> buffer = ops().create().img(input, new BitType());
final IterableInterval<BitType> it1 = Views.iterable(buffer);
final IterableInterval<BitType> it2 = Views.iterable(output);
// Extend the buffer in order to be able to iterate care-free later.
final RandomAccessible<BitType> ra1 = Views.extendBorder(buffer);
final RandomAccessible<BitType> ra2 = Views.extendBorder(output);
// Used only in first iteration.
RandomAccessible<BitType> currRa = Views.extendBorder(input);
// Create cursors.
final Cursor<BitType> firstCursor = it1.localizingCursor();
Cursor<BitType> currentCursor = Views.iterable(input).localizingCursor();
final Cursor<BitType> secondCursor = it2.localizingCursor();
// Create pointers to the current and next cursor and set them to Buffer and
// output respectively.
Cursor<BitType> nextCursor;
nextCursor = secondCursor;
// The main loop.
boolean changes = true;
int i = 0;
// Until no more changes, do:
while (changes) {
changes = false;
// defined by the strategies).
for (int j = 0; j < m_strategy.getIterationsPerCycle(); ++j) {
// For each pixel in the image.
while (currentCursor.hasNext()) {
// Move both cursors
currentCursor.fwd();
nextCursor.fwd();
// Get the position of the current cursor.
final long[] coordinates = new long[currentCursor.numDimensions()];
currentCursor.localize(coordinates);
// Copy the value of the image currently operated upon.
final boolean curr = currentCursor.get().get();
nextCursor.get().set(curr);
// Only foreground pixels may be thinned
if (curr) {
// Ask the strategy whether to flip the foreground pixel or not.
final boolean flip = m_strategy.removePixel(coordinates, currRa, j);
// If yes - change and keep track of the change.
if (flip) {
nextCursor.get().set(false);
changes = true;
}
}
}
// One step of the cycle is finished, notify the strategy.
m_strategy.afterCycle();
// Reset the cursors to the beginning and assign pointers for the next
// iteration.
currentCursor.reset();
nextCursor.reset();
// Keep track of the most recent image. Needed for output.
if (currRa == ra2) {
currRa = ra1;
currentCursor = firstCursor;
nextCursor = secondCursor;
} else {
currRa = ra2;
currentCursor = secondCursor;
nextCursor = firstCursor;
}
// Keep track of iterations.
++i;
}
}
// ra2. Copy it to output.
if (i % 2 == 0) {
// Ra1 points to img1, ra2 points to output.
copy(buffer, output);
}
}
use of net.imglib2.RandomAccessible in project imagej-ops by imagej.
the class HistogramOfOrientedGradients2D method compute.
@SuppressWarnings("unchecked")
@Override
public void compute(RandomAccessibleInterval<T> in, RandomAccessibleInterval<T> out) {
final RandomAccessible<FloatType> convertedIn = Converters.convert(Views.extendMirrorDouble(in), converterToFloat, new FloatType());
// compute partial derivative for each dimension
RandomAccessibleInterval<FloatType> derivative0 = createImgOp.calculate();
RandomAccessibleInterval<FloatType> derivative1 = createImgOp.calculate();
// case of grayscale image
if (in.numDimensions() == 2) {
PartialDerivative.gradientCentralDifference(convertedIn, derivative0, 0);
PartialDerivative.gradientCentralDifference(convertedIn, derivative1, 1);
} else // case of color image
{
List<RandomAccessibleInterval<FloatType>> listDerivs0 = new ArrayList<>();
List<RandomAccessibleInterval<FloatType>> listDerivs1 = new ArrayList<>();
for (int i = 0; i < in.dimension(2); i++) {
final RandomAccessibleInterval<FloatType> deriv0 = createImgOp.calculate();
final RandomAccessibleInterval<FloatType> deriv1 = createImgOp.calculate();
PartialDerivative.gradientCentralDifference(Views.interval(convertedIn, new long[] { 0, 0, i }, new long[] { in.max(0), in.max(1), i }), deriv0, 0);
PartialDerivative.gradientCentralDifference(Views.interval(convertedIn, new long[] { 0, 0, i }, new long[] { in.max(0), in.max(1), i }), deriv1, 1);
listDerivs0.add(deriv0);
listDerivs1.add(deriv1);
}
derivative0 = Converters.convert(Views.collapse(Views.stack(listDerivs0)), converterGetMax, new FloatType());
derivative1 = Converters.convert(Views.collapse(Views.stack(listDerivs1)), converterGetMax, new FloatType());
}
final RandomAccessibleInterval<FloatType> finalderivative0 = derivative0;
final RandomAccessibleInterval<FloatType> finalderivative1 = derivative1;
// compute angles and magnitudes
final RandomAccessibleInterval<FloatType> angles = createImgOp.calculate();
final RandomAccessibleInterval<FloatType> magnitudes = createImgOp.calculate();
final CursorBasedChunk chunkable = new CursorBasedChunk() {
@Override
public void execute(int startIndex, int stepSize, int numSteps) {
final Cursor<FloatType> cursorAngles = Views.flatIterable(angles).localizingCursor();
final Cursor<FloatType> cursorMagnitudes = Views.flatIterable(magnitudes).localizingCursor();
final Cursor<FloatType> cursorDerivative0 = Views.flatIterable(finalderivative0).localizingCursor();
final Cursor<FloatType> cursorDerivative1 = Views.flatIterable(finalderivative1).localizingCursor();
setToStart(cursorAngles, startIndex);
setToStart(cursorMagnitudes, startIndex);
setToStart(cursorDerivative0, startIndex);
setToStart(cursorDerivative1, startIndex);
for (int i = 0; i < numSteps; i++) {
final float x = cursorDerivative0.get().getRealFloat();
final float y = cursorDerivative1.get().getRealFloat();
cursorAngles.get().setReal(getAngle(x, y));
cursorMagnitudes.get().setReal(getMagnitude(x, y));
cursorAngles.jumpFwd(stepSize);
cursorMagnitudes.jumpFwd(stepSize);
cursorDerivative0.jumpFwd(stepSize);
cursorDerivative1.jumpFwd(stepSize);
}
}
};
ops().thread().chunker(chunkable, Views.flatIterable(magnitudes).size());
// stores each Thread to execute
final List<Callable<Void>> listCallables = new ArrayList<>();
// compute descriptor (default 3x3, i.e. 9 channels: one channel for
// each bin)
final RectangleShape shape = new RectangleShape(spanOfNeighborhood, false);
final NeighborhoodsAccessible<FloatType> neighborHood = shape.neighborhoodsRandomAccessible(angles);
for (int i = 0; i < in.dimension(0); i++) {
listCallables.add(new ComputeDescriptor(Views.interval(convertedIn, in), i, angles.randomAccess(), magnitudes.randomAccess(), (RandomAccess<FloatType>) out.randomAccess(), neighborHood.randomAccess()));
}
try {
es.invokeAll(listCallables);
} catch (final InterruptedException e) {
throw new RuntimeException(e);
}
listCallables.clear();
}
use of net.imglib2.RandomAccessible in project imagej-ops by imagej.
the class PartialDerivativeRAI method initialize.
@SuppressWarnings("unchecked")
@Override
public void initialize() {
RandomAccessibleInterval<T> kernel = ops().create().kernelSobel(Util.getTypeFromInterval(in()));
RandomAccessibleInterval<T> kernelA = Views.hyperSlice(Views.hyperSlice(kernel, 3, 0), 2, 0);
RandomAccessibleInterval<T> kernelB = Views.hyperSlice(Views.hyperSlice(kernel, 3, 0), 2, 1);
// add dimensions to kernel to rotate properly
if (in().numDimensions() > 2) {
RandomAccessible<T> expandedKernelA = Views.addDimension(kernelA);
RandomAccessible<T> expandedKernelB = Views.addDimension(kernelB);
for (int i = 0; i < in().numDimensions() - 3; i++) {
expandedKernelA = Views.addDimension(expandedKernelA);
expandedKernelB = Views.addDimension(expandedKernelB);
}
long[] dims = new long[in().numDimensions()];
for (int j = 0; j < in().numDimensions(); j++) {
dims[j] = 1;
}
dims[0] = 3;
Interval kernelInterval = new FinalInterval(dims);
kernelA = Views.interval(expandedKernelA, kernelInterval);
kernelB = Views.interval(expandedKernelB, kernelInterval);
}
long[] dims = new long[in().numDimensions()];
if (dimension == 0) {
// FIXME hack
kernelBConvolveOp = RAIs.computer(ops(), Ops.Filter.Convolve.class, in(), new Object[] { kernelB });
} else {
// rotate kernel B to dimension
for (int j = 0; j < in().numDimensions(); j++) {
if (j == dimension) {
dims[j] = 3;
} else {
dims[j] = 1;
}
}
Img<DoubleType> kernelInterval = ops().create().img(dims);
RandomAccessibleInterval<T> rotatedKernelB = kernelB;
for (int i = 0; i < dimension; i++) {
rotatedKernelB = Views.rotate(rotatedKernelB, i, i + 1);
}
rotatedKernelB = Views.interval(rotatedKernelB, kernelInterval);
kernelBConvolveOp = RAIs.computer(ops(), Ops.Filter.Convolve.class, in(), new Object[] { rotatedKernelB });
}
dims = null;
// rotate kernel A to all other dimensions
kernelAConvolveOps = new UnaryComputerOp[in().numDimensions()];
if (dimension != 0) {
kernelAConvolveOps[0] = RAIs.computer(ops(), Ops.Filter.Convolve.class, in(), new Object[] { kernelA });
}
RandomAccessibleInterval<T> rotatedKernelA = kernelA;
for (int i = 1; i < in().numDimensions(); i++) {
if (i != dimension) {
dims = new long[in().numDimensions()];
for (int j = 0; j < in().numDimensions(); j++) {
if (i == j) {
dims[j] = 3;
} else {
dims[j] = 1;
}
}
Img<DoubleType> kernelInterval = ops().create().img(dims);
for (int j = 0; j < i; j++) {
rotatedKernelA = Views.rotate(rotatedKernelA, j, j + 1);
}
kernelAConvolveOps[i] = RAIs.computer(ops(), Ops.Filter.Convolve.class, in(), new Object[] { Views.interval(rotatedKernelA, kernelInterval) });
rotatedKernelA = kernelA;
}
}
addOp = RAIs.binaryComputer(ops(), Ops.Math.Add.class, in(), in());
createRAI = RAIs.function(ops(), Ops.Create.Img.class, in());
}
use of net.imglib2.RandomAccessible in project imagej-ops by imagej.
the class ConvolveNaiveC method compute.
@Override
public void compute(final RandomAccessible<I> input, final RandomAccessibleInterval<O> output) {
// TODO: try a decomposition of the kernel into n 1-dim kernels
final long[] min = new long[input.numDimensions()];
final long[] max = new long[input.numDimensions()];
for (int d = 0; d < kernel.numDimensions(); d++) {
min[d] = -kernel.dimension(d);
max[d] = kernel.dimension(d) + output.dimension(d);
}
final RandomAccess<I> inRA = input.randomAccess(new FinalInterval(min, max));
final Cursor<K> kernelC = Views.iterable(kernel).localizingCursor();
final Cursor<O> outC = Views.iterable(output).localizingCursor();
final long[] pos = new long[input.numDimensions()];
final long[] kernelRadius = new long[kernel.numDimensions()];
for (int i = 0; i < kernelRadius.length; i++) {
kernelRadius[i] = kernel.dimension(i) / 2;
}
float val;
while (outC.hasNext()) {
// image
outC.fwd();
outC.localize(pos);
// kernel inlined version of the method convolve
val = 0;
inRA.setPosition(pos);
kernelC.reset();
while (kernelC.hasNext()) {
kernelC.fwd();
for (int i = 0; i < kernelRadius.length; i++) {
// dimension can have zero extension e.g. vertical 1d kernel
if (kernelRadius[i] > 0) {
inRA.setPosition(pos[i] + kernelC.getLongPosition(i) - kernelRadius[i], i);
}
}
val += inRA.get().getRealDouble() * kernelC.get().getRealDouble();
}
outC.get().setReal(val);
}
}
use of net.imglib2.RandomAccessible in project imagej-ops by imagej.
the class HyperSliceViewTest method defaultHyperSliceTest.
@Test
public void defaultHyperSliceTest() {
final Img<DoubleType> img = new ArrayImgFactory<DoubleType>().create(new int[] { 10, 10, 10 }, new DoubleType());
final MixedTransformView<DoubleType> il2 = Views.hyperSlice((RandomAccessible<DoubleType>) img, 1, 8);
final MixedTransformView<DoubleType> opr = ops.transform().hyperSliceView(deinterval(img), 1, 8);
for (int i = 0; i < il2.getTransformToSource().getMatrix().length; i++) {
for (int j = 0; j < il2.getTransformToSource().getMatrix()[i].length; j++) {
assertEquals(il2.getTransformToSource().getMatrix()[i][j], opr.getTransformToSource().getMatrix()[i][j], 1e-10);
}
}
}
Aggregations