@Override public void map() { for (int d = 2; d < position.length; ++d) min[d] = max[d] = position[d]; min[0] = target.min(0); min[1] = target.min(1); max[0] = target.max(0); max[1] = target.max(1); final FinalInterval sourceInterval = new FinalInterval(min, max); final long cr = -target.dimension(0); final RandomAccess<B> targetRandomAccess = target.randomAccess(target); final RandomAccess<A> sourceRandomAccess = source.randomAccess(sourceInterval); for (sourceRandomAccess.setPosition(min), targetRandomAccess.setPosition(min[0], 0), targetRandomAccess.setPosition(min[1], 1); targetRandomAccess.getLongPosition(1) <= max[1]; sourceRandomAccess.move(cr, 0), targetRandomAccess.move(cr, 0), sourceRandomAccess.fwd(1), targetRandomAccess.fwd(1)) { for (; targetRandomAccess.getLongPosition(0) <= max[0]; sourceRandomAccess.fwd(0), targetRandomAccess.fwd(0)) converter.convert(sourceRandomAccess.get(), targetRandomAccess.get()); } }
@Override public void fwd() { if (--s[0] >= 0) source.fwd(0); else { int d = 1; for (; d < n; ++d) { if (--s[d] >= 0) { source.fwd(d); break; } } for (; d > 0; --d) { final int e = d - 1; final double rd = r[d]; final long pd = s[d] - ri[d]; final double rad = Math.sqrt(rd * rd - pd * pd); final long radi = (long) rad; r[e] = rad; ri[e] = radi; s[e] = 2 * radi; source.setPosition(position[e] - radi, e); } } }
@Override public void fwd() { int d; for (d = 0; d < numDimensions; ++d) { if (--s[d] >= 0) { randomAccess.fwd(d); break; } else { s[d] = r[d] = 0; randomAccess.setPosition(center[d], d); } } if (d > 0) { final int e = d - 1; final long rd = r[d]; final long pd = rd - s[d]; final long rad = (long) (Math.sqrt(rd * rd - pd * pd)); s[e] = 2 * rad; r[e] = rad; randomAccess.setPosition(center[e] - rad, e); } }
protected void integrateLineDim0( final Converter<R, T> converter, final RandomAccess<R> cursorIn, final RandomAccess<T> cursorOut, final T sum, final T tmpVar, final long size) { // compute the first pixel converter.convert(cursorIn.get(), sum); cursorOut.get().set(sum); for (long i = 2; i < size; ++i) { cursorIn.fwd(0); cursorOut.fwd(0); converter.convert(cursorIn.get(), tmpVar); sum.add(tmpVar); cursorOut.get().set(sum); } }
public void fwd() { m_count++; if (m_count % m_breaks[0] == 0) { // we checked this already, so just do it m_ra.setPosition(0, 0); m_ra.fwd(1); // skip the last dim, is handled by previous // dims for (int i = 1; i < m_breaks.length - 1; i++) { if (m_count % m_breaks[i] == 0) { m_ra.setPosition(0, i); m_ra.fwd(i + 1); } } } else { m_ra.fwd(0); } }
protected void integrateLine( final int d, final RandomAccess<T> cursor, final T sum, final long size) { // init sum on first pixel that is not zero sum.set(cursor.get()); for (long i = 2; i < size; ++i) { cursor.fwd(d); sum.add(cursor.get()); cursor.get().set(sum); } }
/** * Computes the n-dimensional 1st derivative vector in 3x3x3...x3 environment for a certain {@link * Img} location defined by the position of the {@link LocalizableByDimCursor}. * * @param cursor - the position for which to compute the Hessian Matrix * @param derivativeVector - the derivative, which is essentially a one-dimensional {@link * DoubleType} {@link Img} of size [numDimensions] */ public static final <T extends RealType<T>> void computeDerivativeVector( final RandomAccess<T> cursor, final Img<DoubleType> derivativeVector) { // instantiate a cursor to traverse over the derivative vector we want to compute, the position // defines the current dimension final Cursor<DoubleType> derivativeCursor = derivativeVector.localizingCursor(); while (derivativeCursor.hasNext()) { derivativeCursor.fwd(); final int dim = derivativeCursor.getIntPosition(0); // we compute the derivative for dimension A like this // // | a0 | a1 | a2 | // ^ // | // Original position of Img cursor // // d(a) = (a2 - a0)/2 // we divide by 2 because it is a jump over two pixels cursor.fwd(dim); final double a2 = cursor.get().getRealDouble(); cursor.bck(dim); cursor.bck(dim); final double a0 = cursor.get().getRealDouble(); // back to the original position cursor.fwd(dim); derivativeCursor.get().setReal((a2 - a0) / 2); } }
/** Compute the inverse Hessian matrix from the the steepest descent images. */ public static <T extends RealType<T>> double[][] computeInverseHessian( final RandomAccessibleInterval<T> descent) { final int n = descent.numDimensions() - 1; final int numParameters = (int) descent.dimension(n); final long[] dim = new long[n + 1]; descent.dimensions(dim); dim[n] = 1; final LocalizingIntervalIterator pos = new LocalizingIntervalIterator(dim); final RandomAccess<T> r = descent.randomAccess(); final double[] deriv = new double[numParameters]; final double[][] H = new double[numParameters][numParameters]; while (pos.hasNext()) { pos.fwd(); r.setPosition(pos); for (int p = 0; p < numParameters; ++p) { deriv[p] = r.get().getRealDouble(); r.fwd(n); } for (int i = 0; i < numParameters; ++i) for (int j = 0; j < numParameters; ++j) H[i][j] += deriv[i] * deriv[j]; } return new Matrix(H).inverse().getArray(); }
// change the return type to Img<FloatType> and adjust the code accordingly public <T extends RealType<T>> Img<T> gradient(Img<T> img) { // create a new ImgLib2 image of same dimensions, but FloatType // to to that, create a new PlanarImgFactory and instantiate a new // Img<FloatType> /** * ImgFactory<T> imgFactory = img.factory(); Img<T> gradientImg = imgFactory.create( img, * img.firstElement() ); */ // create a localizing cursor on the GradientImg, it will iterate all pixels // and is able to efficiently return its position at each pixel, at each // pixel we will compute the gradient /** Cursor<T> cursor = gradientImg.localizingCursor(); */ // We extend the input image by a mirroring out of bounds strategy so // that we can access pixels outside of the image RandomAccessible<T> view = Views.extendMirrorSingle(img); // instantiate a RandomAccess on the extended view, it will be used to // compute the gradient locally at each pixel location RandomAccess<T> randomAccess = view.randomAccess(); // iterate over all pixels while (cursor.hasNext()) { // move the cursor to the next pixel cursor.fwd(); // compute gradient in each dimension double gradient = 0; for (int d = 0; d < img.numDimensions(); ++d) { // set the randomaccess to the location of the cursor randomAccess.setPosition(cursor); // move one pixel back in dimension d randomAccess.bck(d); // get the value double v1 = randomAccess.get().getRealDouble(); // move twice forward in dimension d, i.e. // one pixel above the location of the cursor randomAccess.fwd(d); randomAccess.fwd(d); // get the value double v2 = randomAccess.get().getRealDouble(); // add the square of the magnitude of the gradient gradient += ((v2 - v1) * (v2 - v1)) / 4; } // the square root of all quadratic sums yields // the magnitude of the gradient at this location, // set the pixel value of the gradient image // change the value to float, otherwise it will not be // compatible cursor.get().setReal(Math.sqrt(gradient)); } return gradientImg; }
protected void convolve( final RandomAccess<T> inputIterator, final Cursor<T> outputIterator, final int dim, final float[] kernel, final long startPos, final long loopSize) { // move to the starting position of the current thread outputIterator.jumpFwd(startPos); final int filterSize = kernel.length; final int filterSizeMinus1 = filterSize - 1; final int filterSizeHalf = filterSize / 2; final int filterSizeHalfMinus1 = filterSizeHalf - 1; final int numDimensions = inputIterator.numDimensions(); final int iteratorPosition = filterSizeHalf; final int[] to = new int[numDimensions]; final T sum = inputIterator.get().createVariable(); final T tmp = inputIterator.get().createVariable(); // do as many pixels as wanted by this thread for (long j = 0; j < loopSize; ++j) { outputIterator.fwd(); // set the sum to zero sum.setZero(); // // we move filtersize/2 of the convolved pixel in the input container // // get the current positon in the output container outputIterator.localize(to); // position in the input container is filtersize/2 to the left to[dim] -= iteratorPosition; // set the input cursor to this very position inputIterator.setPosition(to); // System.out.println( "out: " + outputIterator ); // System.out.println( "iteratorPosition: " + iteratorPosition ); // System.out.println( "in: " + inputIterator ); // System.exit ( 0 ); // iterate over the kernel length across the input container for (int f = -filterSizeHalf; f <= filterSizeHalfMinus1; ++f) { // get value from the input container tmp.set(inputIterator.get()); // multiply the kernel tmp.mul(kernel[f + filterSizeHalf]); // add up the sum sum.add(tmp); // move the cursor forward for the next iteration inputIterator.fwd(dim); } // // for the last pixel we do not move forward // // get value from the input container tmp.set(inputIterator.get()); // multiply the kernel tmp.mul(kernel[filterSizeMinus1]); // add up the sum sum.add(tmp); outputIterator.get().set(sum); } }
@Override public boolean process() { final int numDimensions = img.numDimensions(); final long integralSize[] = new long[numDimensions]; // the size of the first dimension is changed for (int d = 0; d < numDimensions; ++d) integralSize[d] = img.dimension(d) + 1; final Img<T> integral = imgFactory.create(integralSize, type); // not enough RAM or disc space if (integral == null) return false; this.integral = integral; if (numDimensions > 1) { final long[] fakeSize = new long[numDimensions - 1]; // the size of dimension 0 final long size = integralSize[0]; for (int d = 1; d < numDimensions; ++d) fakeSize[d - 1] = integralSize[d]; final long imageSize = getNumPixels(fakeSize); final AtomicInteger ai = new AtomicInteger(0); final Thread[] threads = SimpleMultiThreading.newThreads(); final Vector<Chunk> threadChunks = SimpleMultiThreading.divideIntoChunks(imageSize, threads.length); for (int ithread = 0; ithread < threads.length; ++ithread) threads[ithread] = new Thread( new Runnable() { @Override public void run() { // Thread ID final int myNumber = ai.getAndIncrement(); // get chunk of pixels to process final Chunk myChunk = threadChunks.get(myNumber); final long loopSize = myChunk.getLoopSize(); final LocalizingZeroMinIntervalIterator cursorDim = new LocalizingZeroMinIntervalIterator(fakeSize); // location for the input location final long[] tmpIn = new long[numDimensions]; // location for the integral location final long[] tmpOut = new long[numDimensions]; final long[] tmp = new long[numDimensions - 1]; final RandomAccess<R> cursorIn = img.randomAccess(); final RandomAccess<T> cursorOut = integral.randomAccess(); final T tmpVar = integral.firstElement().createVariable(); final T sum = integral.firstElement().createVariable(); cursorDim.jumpFwd(myChunk.getStartPosition()); // iterate over all dimensions except the one we are computing the integral in, // which is dim=0 here main: for (long j = 0; j < loopSize; ++j) { cursorDim.fwd(); // get all dimensions except the one we are currently doing the integral on cursorDim.localize(tmp); tmpIn[0] = 0; tmpOut[0] = 1; for (int d = 1; d < numDimensions; ++d) { tmpIn[d] = tmp[d - 1] - 1; tmpOut[d] = tmp[d - 1]; // all entries of position 0 are 0 if (tmpOut[d] == 0) continue main; } // set the cursor to the beginning of the correct line cursorIn.setPosition(tmpIn); // set the cursor in the integral image to the right position cursorOut.setPosition(tmpOut); // integrate over the line integrateLineDim0(converter, cursorIn, cursorOut, sum, tmpVar, size); } } }); SimpleMultiThreading.startAndJoin(threads); } else { final T tmpVar = integral.firstElement().createVariable(); final T sum = integral.firstElement().createVariable(); // the size of dimension 0 final long size = integralSize[0]; final RandomAccess<R> cursorIn = img.randomAccess(); final RandomAccess<T> cursorOut = integral.randomAccess(); cursorIn.setPosition(0, 0); cursorOut.setPosition(1, 0); // compute the first pixel converter.convert(cursorIn.get(), sum); cursorOut.get().set(sum); for (long i = 2; i < size; ++i) { cursorIn.fwd(0); cursorOut.fwd(0); converter.convert(cursorIn.get(), tmpVar); sum.add(tmpVar); cursorOut.get().set(sum); } return true; } for (int d = 1; d < numDimensions; ++d) { final int dim = d; final long[] fakeSize = new long[numDimensions - 1]; // the size of dimension d final long size = integralSize[d]; // get all dimensions except the one we are currently doing the integral on int countDim = 0; for (int e = 0; e < numDimensions; ++e) if (e != d) fakeSize[countDim++] = integralSize[e]; final long imageSize = getNumPixels(fakeSize); final AtomicInteger ai = new AtomicInteger(0); final Thread[] threads = SimpleMultiThreading.newThreads(); final Vector<Chunk> threadChunks = SimpleMultiThreading.divideIntoChunks(imageSize, threads.length); for (int ithread = 0; ithread < threads.length; ++ithread) threads[ithread] = new Thread( new Runnable() { @Override public void run() { // Thread ID final int myNumber = ai.getAndIncrement(); // get chunk of pixels to process final Chunk myChunk = threadChunks.get(myNumber); final long loopSize = myChunk.getLoopSize(); final LocalizingZeroMinIntervalIterator cursorDim = new LocalizingZeroMinIntervalIterator(fakeSize); // local instances final long[] tmp2 = new long[numDimensions - 1]; final long[] tmp = new long[numDimensions]; final RandomAccess<T> cursor = integral.randomAccess(); final T sum = integral.firstElement().createVariable(); cursorDim.jumpFwd(myChunk.getStartPosition()); for (long j = 0; j < loopSize; ++j) { cursorDim.fwd(); // get all dimensions except the one we are currently doing the integral on cursorDim.localize(tmp2); tmp[dim] = 1; int countDim = 0; for (int e = 0; e < numDimensions; ++e) if (e != dim) tmp[e] = tmp2[countDim++]; // update the cursor in the input image to the current dimension position cursor.setPosition(tmp); // sum up line integrateLine(dim, cursor, sum, size); } } }); SimpleMultiThreading.startAndJoin(threads); } return true; }
/** * Computes the n-dimensional Hessian Matrix in 3x3x3...x3 environment for a certain {@link Img} * location defined by the position of the {@link LocalizableByDimCursor}. * * @param cursor - the position for which to compute the Hessian Matrix * @param hessianMatrix - the hessian matrix, which is essentially a two-dimensional {@link * DoubleType} {@link Img} of size [numDimensions][numDimensions] */ public static final <T extends RealType<T>> void computeHessianMatrix( final RandomAccess<T> cursor, final Img<DoubleType> hessianMatrix) { // we need this for all diagonal elements final double temp = 2.0 * cursor.get().getRealDouble(); // instantiate a cursor to traverse over the hessian matrix we want to compute, the position // defines the current dimensions final Cursor<DoubleType> hessianCursor = hessianMatrix.localizingCursor(); // another cursor to fill the redundant lower area of the matrix final RandomAccess<DoubleType> hessianCursorLowerHalf = hessianMatrix.randomAccess(); while (hessianCursor.hasNext()) { hessianCursor.fwd(); final int dimA = hessianCursor.getIntPosition(0); final int dimB = hessianCursor.getIntPosition(1); if (dimA == dimB) { // diagonal elements h(aa) for dimension a // computed from the row a in the input Img // // | a0 | a1 | a2 | // ^ // | // Original position of Img cursor // // h(aa) = (a2-a1) - (a1-a0) // = a2 - 2*a1 + a0 cursor.fwd(dimA); final double a2 = cursor.get().getRealDouble(); cursor.bck(dimA); cursor.bck(dimA); final double a0 = cursor.get().getRealDouble(); // back to the original position cursor.fwd(dimA); hessianCursor.get().set(a2 - temp + a0); } else if (dimB > dimA) // we compute all elements above the diagonal (see below for explanation) { // other elements h(ab) are computed as a combination // of dimA (dimension a) and dimB (dimension b), i.e. we always operate in a // two-dimensional plane // ______________________ // | a0b0 | a1b0 | a2b0 | // | a0b1 | a1b1 | a2b1 | // | a0b2 | a1b2 | a2b2 | // ---------------------- // where a1b1 is the original position of the cursor // // h(ab) = ( (a2b2-a0b2)/2 - (a2b0 - a0b0)/2 )/2 // // we divide by 2 because these are always jumps over two pixels // we only have to do that if dimB > dimA, // because h(ab) = h(ba) cursor.fwd(dimB); cursor.fwd(dimA); final double a2b2 = cursor.get().getRealDouble(); cursor.bck(dimA); cursor.bck(dimA); final double a0b2 = cursor.get().getRealDouble(); cursor.bck(dimB); cursor.bck(dimB); final double a0b0 = cursor.get().getRealDouble(); cursor.fwd(dimA); cursor.fwd(dimA); final double a2b0 = cursor.get().getRealDouble(); // back to the original position cursor.bck(dimA); cursor.fwd(dimB); hessianCursor.get().set(((a2b2 - a0b2) / 2 - (a2b0 - a0b0) / 2) / 2); // update the corresponding element below the diagonal hessianCursorLowerHalf.setPosition(dimB, 0); hessianCursorLowerHalf.setPosition(dimA, 1); hessianCursorLowerHalf.get().set(hessianCursor.get()); } } }