private boolean processSlice( final RandomAccessibleInterval<FloatType> src, final RandomAccessibleInterval<FloatType> dx, final RandomAccessibleInterval<FloatType> dy) { // Gaussian filter. final ExtendedRandomAccessibleInterval<FloatType, RandomAccessibleInterval<FloatType>> extended = Views.extendMirrorSingle(src); try { Gauss3.gauss(new double[] {sigma, sigma}, extended, src, numThreads); } catch (final IncompatibleTypeException e) { errorMessage = BASE_ERROR_MSG + "Incompatible types: " + e.getMessage(); e.printStackTrace(); return false; } // Derivatives PartialDerivative.gradientCentralDifference(extended, dx, 0); PartialDerivative.gradientCentralDifference(extended, dy, 1); return true; }
@Override public boolean process() { /* 0. Instantiate tensor holder, and initialize cursors. */ long[] tensorDims = new long[input.numDimensions() + 1]; for (int i = 0; i < input.numDimensions(); i++) { tensorDims[i] = input.dimension(i); } tensorDims[input.numDimensions()] = 3; try { D = input.factory().imgFactory(new FloatType()).create(tensorDims, new FloatType()); } catch (IncompatibleTypeException e) { errorMessage = BASE_ERROR_MESSAGE + "Failed to create tensor holder:\n" + e.getMessage(); return false; } /* 1. Create a smoothed version of the input. */ Img<FloatType> smoothed = Gauss.toFloat(new double[] {sigma, sigma}, input); /* 2. Compute the gradient of the smoothed input, but only algon X & Y */ boolean[] doDimension = new boolean[input.numDimensions()]; doDimension[0] = true; doDimension[1] = true; Gradient<FloatType> gradientCalculator = new Gradient<FloatType>(smoothed, doDimension); gradientCalculator.process(); final Img<FloatType> gradient = gradientCalculator.getResult(); /* 3. Compute the structure tensor. */ final Img<FloatType> J = D.factory().create(D, new FloatType()); final int newDim = input.numDimensions(); final Vector<Chunk> chunks = SimpleMultiThreading.divideIntoChunks(input.size(), numThreads); Thread[] threads = SimpleMultiThreading.newThreads(numThreads); for (int i = 0; i < threads.length; i++) { final Chunk chunk = chunks.get(i); threads[i] = new Thread("" + BASE_ERROR_MESSAGE + "thread " + i) { @Override public void run() { float ux, uy; Cursor<T> cursor = input.localizingCursor(); RandomAccess<FloatType> grad_ra = gradient.randomAccess(); RandomAccess<FloatType> J_ra = J.randomAccess(); cursor.jumpFwd(chunk.getStartPosition()); for (long k = 0; k < chunk.getLoopSize(); k++) { cursor.fwd(); for (int i = 0; i < input.numDimensions(); i++) { grad_ra.setPosition(cursor.getLongPosition(i), i); J_ra.setPosition(cursor.getLongPosition(i), i); } grad_ra.setPosition(0, newDim); ux = grad_ra.get().get(); grad_ra.fwd(newDim); uy = grad_ra.get().get(); J_ra.setPosition(0, newDim); J_ra.get().set(ux * ux); J_ra.fwd(newDim); J_ra.get().set(ux * uy); J_ra.fwd(newDim); J_ra.get().set(uy * uy); } } }; } SimpleMultiThreading.startAndJoin(threads); /* 3.5 Smoooth the structure tensor. */ Gauss.inFloat(new double[] {rho, rho, 0}, J); /* 4. Construct Diffusion tensor. */ for (int i = 0; i < threads.length; i++) { final Chunk chunk = chunks.get(i); threads[i] = new Thread("" + BASE_ERROR_MESSAGE + "thread " + i) { @Override public void run() { Cursor<T> cursor = input.localizingCursor(); RandomAccess<FloatType> J_ra = J.randomAccess(); RandomAccess<FloatType> D_ra = D.randomAccess(); float Jxx, Jxy, Jyy; double tmp, v1x, v1y, v2x, v2y, mag, mu1, mu2, lambda1, lambda2, di; double newLambda1, newLambda2, Dxx, Dxy, Dyy; double scale; cursor.jumpFwd(chunk.getStartPosition()); for (long k = 0; k < chunk.getLoopSize(); k++) { cursor.fwd(); for (int j = 0; j < input.numDimensions(); j++) { D_ra.setPosition(cursor.getLongPosition(j), j); J_ra.setPosition(cursor.getLongPosition(j), j); } // Compute eigenvalues J_ra.setPosition(0, newDim); Jxx = J_ra.get().get(); J_ra.fwd(newDim); Jxy = J_ra.get().get(); J_ra.fwd(newDim); Jyy = J_ra.get().get(); tmp = Math.sqrt((Jxx - Jyy) * (Jxx - Jyy) + 4 * Jxy * Jxy); v2x = 2 * Jxy; v2y = Jyy - Jxx + tmp; mag = Math.sqrt(v2x * v2x + v2y * v2y); v2x /= mag; v2y /= mag; v1x = -v2y; v1y = v2x; mu1 = 0.5 * (Jxx + Jyy + tmp); mu2 = 0.5 * (Jxx + Jyy - tmp); // Large one in abs values must be the 2nd if (Math.abs(mu2) > Math.abs(mu1)) { lambda1 = mu1; lambda2 = mu2; } else { lambda1 = mu2; lambda2 = mu1; } di = lambda2 - lambda1; scale = Util.pow(di * di, m); newLambda1 = alpha + (1 - alpha) * Math.exp(-C / scale); newLambda2 = alpha; Dxx = newLambda1 * v1x * v1x + newLambda2 * v2x * v2x; Dxy = newLambda1 * v1x * v1y + newLambda2 * v2x * v2x; Dyy = newLambda1 * v1y * v1y + newLambda2 * v2y * v2y; D_ra.setPosition(0, 2); D_ra.get().setReal(Dxx); D_ra.fwd(2); D_ra.get().setReal(Dxy); D_ra.fwd(2); D_ra.get().setReal(Dyy); } } }; } SimpleMultiThreading.startAndJoin(threads); return true; }