@Override @SuppressWarnings("unchecked") public O calculate(final I kernel, final Dimensions paddedDimensions) { Dimensions paddedFFTInputDimensions; // if an fftsize op has been set recompute padded size if (fftSizeOp != null) { long[][] sizes = fftSizeOp.calculate(paddedDimensions); paddedFFTInputDimensions = new FinalDimensions(sizes[0]); } else { paddedFFTInputDimensions = paddedDimensions; } // compute where to place the final Interval for the kernel so that the // coordinate in the center // of the kernel is shifted to position (0,0). final Interval kernelConvolutionInterval = paddingIntervalCentered.calculate(kernel, paddedFFTInputDimensions); final Interval kernelConvolutionIntervalOrigin = paddingIntervalOrigin.calculate(kernel, kernelConvolutionInterval); return (O) Views.interval( Views.extendPeriodic( Views.interval( Views.extendValue(kernel, Util.getTypeFromInterval(kernel).createVariable()), kernelConvolutionInterval)), kernelConvolutionIntervalOrigin); }
public boolean analyzePeak(final DifferenceOfGaussianPeak<T> peak) { final int numDimensions = laPlacian.numDimensions(); // the subpixel values final double[] subpixelLocation = new double[numDimensions]; // the current position for the quadratic fit final long[] currentPosition = new long[numDimensions]; peak.localize(currentPosition); // the cursor for the computation (one that cannot move out of Img) final RandomAccess<T> cursor; if (canMoveOutside) cursor = Views.extendPeriodic(laPlacian).randomAccess(); else cursor = laPlacian.randomAccess(); // the current hessian matrix and derivative vector Img<DoubleType> hessianMatrix = doubleArrayFactory.create( new int[] {cursor.numDimensions(), cursor.numDimensions()}, new DoubleType()); Img<DoubleType> derivativeVector = doubleArrayFactory.create(new int[] {cursor.numDimensions()}, new DoubleType()); // the inverse hessian matrix Matrix A, B, X; // the current value of the center T value = peak.value.createVariable(); boolean foundStableMaxima = true, pointsValid = false; int numMoves = 0; // fit n-dimensional quadratic function to the extremum and // if the extremum is shifted more than 0.5 in one or more // directions we test wheather it is better there // until we // - converge (find a stable extremum) // - move out of the Img // - achieved the maximal number of moves do { ++numMoves; // move the cursor to the current positon cursor.setPosition(currentPosition); // store the center value value.set(cursor.get()); // compute the n-dimensional hessian matrix [numDimensions][numDimensions] // containing all second derivatives, e.g. for 3d: // // xx xy xz // yx yy yz // zx zy zz hessianMatrix = getHessianMatrix(cursor, hessianMatrix); // compute the inverse of the hessian matrix A = invertMatrix(hessianMatrix); if (A == null) return handleFailure(peak, "Cannot invert hessian matrix"); // compute the n-dimensional derivative vector derivativeVector = getDerivativeVector(cursor, derivativeVector); B = getMatrix(derivativeVector); if (B == null) return handleFailure(peak, "Cannot compute derivative vector"); // compute the extremum of the n-dimensinal quadratic fit X = (A.uminus()).times(B); for (int d = 0; d < numDimensions; ++d) subpixelLocation[d] = X.get(d, 0); // test all dimensions for their change // if the absolute value of the subpixel location // is bigger than 0.5 we move into that direction foundStableMaxima = true; for (int d = 0; d < numDimensions; ++d) { // Normally, above an offset of 0.5 the base position // has to be changed, e.g. a subpixel location of 4.7 // would mean that the new base location is 5 with an offset of -0.3 // // If we allow an increasing maxima tolerance we will // not change the base position that easily. Sometimes // it simply jumps from left to right and back, because // it is 4.51 (i.e. goto 5), then 4.49 (i.e. goto 4) // Then we say, ok, lets keep the base position even if // the subpixel location is 0.6... final double threshold = allowMaximaTolerance ? 0.5 + numMoves * maximaTolerance : 0.5; if (Math.abs(subpixelLocation[d]) > threshold) { if (allowedToMoveInDim[d]) { // move to another base location currentPosition[d] += Math.signum(subpixelLocation[d]); foundStableMaxima = false; } else { // set it to the position that is maximally away when keeping the current base position // e.g. if (0.7) do 4 -> 4.5 (although it should be 4.7, i.e. a new base position of 5) // or if (-0.9) do 4 -> 3.5 (although it should be 3.1, i.e. a new base position of 3) subpixelLocation[d] = Math.signum(subpixelLocation[d]) * 0.5; } } } // check validity of the new location if there is a need to move pointsValid = true; if (!canMoveOutside) if (!foundStableMaxima) for (int d = 0; d < numDimensions; ++d) if (currentPosition[d] <= 0 || currentPosition[d] >= laPlacian.dimension(d) - 1) pointsValid = false; } while (numMoves <= maxNumMoves && !foundStableMaxima && pointsValid); if (!foundStableMaxima) return handleFailure(peak, "No stable extremum found."); if (!pointsValid) return handleFailure(peak, "Moved outside of the Img."); // compute the function value (intensity) of the fit double quadrFuncValue = 0; for (int d = 0; d < numDimensions; ++d) quadrFuncValue += X.get(d, 0) * B.get(d, 0); quadrFuncValue /= 2.0; // set the results if everything went well // subpixel location for (int d = 0; d < numDimensions; ++d) peak.setSubPixelLocationOffset((float) subpixelLocation[d], d); // pixel location peak.setPixelLocation(currentPosition); // quadratic fit value final T quadraticFit = peak.getImgValue().createVariable(); quadraticFit.setReal(quadrFuncValue); peak.setFitValue(quadraticFit); // normal value peak.setImgValue(value); return true; }