@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;
  }