public static final LocalFeaturesMatches getMatchesFloatsLF(
      ALocalFeaturesGroup<FloatsLF> g1, ALocalFeaturesGroup<FloatsLF> g2, double sqMaxDist) {
    LocalFeaturesMatches matches = new LocalFeaturesMatches();
    if (g2.size() == 0) return null;
    int nMatches = 0;
    for (FloatsLF curr : g1.lfArr) {
      FloatsLF match = get(curr, g2, sqMaxDist);
      if (match != null) matches.add(new LocalFeatureMatch(curr, match));
    }

    return matches;
  }
  public static final LocalFeaturesMatches getMatchesRootSIFT(
      ALocalFeaturesGroup<RootSIFT> g1, ALocalFeaturesGroup<RootSIFT> g2, int sqMaxDist) {
    LocalFeaturesMatches matches = new LocalFeaturesMatches();
    if (g2.size() == 0) return null;
    int nMatches = 0;
    for (RootSIFT curr : g1.lfArr) {
      RootSIFT match = get(curr, g2, sqMaxDist);
      if (match != null) matches.add(new LocalFeatureMatch(curr, match));
    }

    return matches;
  }
  public final ArrayList<TransformationHypothesis> getTrHypothesis(
      LocalFeaturesMatches matches, int qN) {

    Hashtable<Long, LocalFeaturesMatches> ht = this.getLoweHoughTransforms_HT(matches);

    if (ht == null || ht.size() == 0) return null;
    LocalFeaturesMatches[] ordered = LoweHoughTransform.orderHT(ht);

    if (ordered[0].size() < minHoughMatches || ordered[0].size() / (double) qN < minPercMatches)
      return null;

    totNRANSAC++;

    return matches.getRANSAC(
        ht, cycles, nHoughMaxForRANSAC, errorPerc, tr, minXYDist, true, rejectUnConsistent);
  }
  public final double distance(F g1, F g2, LocalFeaturesMatches matches) {

    distCount++;

    if (matches == null || matches.size() == 0) return 1.0;

    if (matches.size() / (double) g1.size() < minPercMatches) {
      updateStats(0, matches.size(), 0);
      return 1.0;
    }

    if (nHoughMatches) {
      Hashtable<Long, LocalFeaturesMatches> ht = this.getLoweHoughTransforms_HT(matches);
      if (ht == null || ht.size() == 0) {
        updateStats(0, matches.size(), 0);
        return 1.0;
      }
      LocalFeaturesMatches[] ordered = LoweHoughTransform.orderHT(ht);
      updateStats(0, matches.size(), 0);
      return 1.0 - this.getPercentage(ordered[0].size(), g1.size(), g2.size());
    } else if (onlyNMatches) {
      updateStats(0, matches.size(), 0);
      return 1.0 - this.getPercentage(matches.size(), g1.size(), g2.size());
    }

    double res = 0;

    if (matches.size() / (double) g1.size() < minPercMatches) {
      updateStats(0, matches.size(), 0);
      return 1.0;
    }

    ArrayList<TransformationHypothesis> trArr = getTrHypothesis(matches, g1.size());

    if (trArr == null || trArr.size() == 0) {
      res = 0.0;
      updateStats(0, 0, matches.size());
    } else {

      res = this.getPercentage(trArr.get(0).getMatches().size(), g1.size(), g2.size());

      updateStats(matches.size(), trArr.get(0).getMatches().size(), 0);
    }
    if (res > 1.0) res = 1.0;

    return 1.0 - res;
  }
 public final Hashtable<Long, LocalFeaturesMatches> getLoweHoughTransforms_HT(
     LocalFeaturesMatches matches) {
   if (matches.size() < minMatches) return null;
   return LoweHoughTransform.getLoweHoughTransforms_HT(
       matches.getMatches(), false, RANSAC_minMaxSR);
 }