AbstractStructureTensorIPD selDifferentiationScaleFast(
      FImage img, AbstractStructureTensorIPD ipd, float si, Pixel c) {
    AbstractStructureTensorIPD best = ipd.clone();
    float s = 0.75f;
    float sigma;
    FImage L;
    L = img.clone();
    float sd = s * si;

    // Smooth previous smoothed image L
    sigma = sd;

    L.processInplace(new FGaussianConvolve(sigma, 3));

    // X and Y derivatives
    best.setDetectionScale(sd);
    best.setIntegrationScale(si);
    best.setImageBlurred(true);

    best.findInterestPoints(L);

    //		M = calcSecondMomentMatrix(best, c.x, c.y);

    //		EigenValueVectorPair meig = MatrixUtils.symmetricEig2x2(M);
    //		Matrix eval = meig.getD();
    //		double eval1 = Math.abs(eval.get(0, 0));
    //		double eval2 = Math.abs(eval.get(1, 1));

    return best;
  }
  /*
   * Selects diffrentiation scale
   */
  AbstractStructureTensorIPD selDifferentiationScale(
      FImage img, AbstractStructureTensorIPD ipdToUse, float si, Pixel c) {
    AbstractStructureTensorIPD best = null;
    float s = 0.5f;
    float sigma_prev = 0, sigma;

    FImage L;

    double qMax = 0;

    L = img.clone();

    AbstractStructureTensorIPD ipd = ipdToUse.clone();

    while (s <= 0.751) {
      Matrix M;
      float sd = s * si;

      // Smooth previous smoothed image L
      sigma = (float) Math.sqrt(Math.pow(sd, 2) - Math.pow(sigma_prev, 2));

      L.processInplace(new FGaussianConvolve(sigma, 3));
      sigma_prev = sd;

      // X and Y derivatives
      ipd.setDetectionScale(sd);
      ipd.setIntegrationScale(si);
      ipd.setImageBlurred(true);

      ipd.findInterestPoints(L);
      //			FImage Lx = L.process(new FConvolution(DX_KERNEL.multiply(sd)));
      //			FImage Ly = L.process(new FConvolution(DY_KERNEL.multiply(sd)));
      //
      //			FGaussianConvolve gauss = new FGaussianConvolve(si, 3);
      //
      //			FImage Lxm2 = Lx.multiply(Lx);
      //			dx2 = Lxm2.process(gauss);
      //
      //			FImage Lym2 = Ly.multiply(Ly);
      //			dy2 = Lym2.process(gauss);
      //
      //			FImage Lxmy = Lx.multiply(Ly);
      //			dxy = Lxmy.process(gauss);

      M = calcSecondMomentMatrix(ipd, c.x, c.y);

      // calc eigenvalues
      //			EigenvalueDecomposition meig = M.eig();
      EigenValueVectorPair meig = MatrixUtils.symmetricEig2x2(M);
      Matrix eval = meig.getValues();
      double eval1 = Math.abs(eval.get(0, 0));
      double eval2 = Math.abs(eval.get(1, 1));
      double q = Math.min(eval1, eval2) / Math.max(eval1, eval2);

      if (q >= qMax) {
        qMax = q;
        best = ipd.clone();
      }

      s += 0.05;
    }
    return best;
  }