<commit_before>
// Copyright (c) 2014, 2015 <NAME>.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#pragma once

#include "openMVG/multiview/solver_homography_kernel.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansac.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansacKernelAdaptator.hpp"
#include "openMVG/robust_estimation/guided_matching.hpp"

#include "openMVG/matching/indMatch.hpp"
#include "openMVG/matching/indMatchDecoratorXY.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/features/RegionsPerView.hpp"
#include "openMVG/matching_image_collection/GeometricFilterMatrix.hpp"

namespace openMVG {
namespace matching_image_collection {

//-- A contrario homography matrix estimation template functor used for filter pair of putative correspondences
struct GeometricFilter_HMatrix_AC : public GeometricFilterMatrix
{
  GeometricFilter_HMatrix_AC(
    double dPrecision = std::numeric_limits<double>::infinity(),
    size_t iteration = 1024)
    : GeometricFilterMatrix(dPrecision, std::numeric_limits<double>::infinity(), iteration)
    , m_H(Mat3::Identity())
  {}

  /**
   * @brief Given two sets of image points, it estimates the homography matrix
   * relating them using a robust method (like A Contrario Ransac).
   */
  template<typename Regions_or_Features_ProviderT>
  EstimationStatus geometricEstimation(
    const sfm::SfM_Data * sfmData,
    const Regions_or_Features_ProviderT& regionsPerView,
    const Pair pairIndex,
    const matching::MatchesPerDescType & putativeMatchesPerType,
    matching::MatchesPerDescType & out_geometricInliersPerType)
  {
    using namespace openMVG;
    using namespace openMVG::robust;
    out_geometricInliersPerType.clear();

    // Get back corresponding view index
    const IndexT iIndex = pairIndex.first;
    const IndexT jIndex = pairIndex.second;

    const std::vector<features::EImageDescriberType> descTypes = regionsPerView.getCommonDescTypes(pairIndex);
    if(descTypes.empty())
      return EstimationStatus(false, false);

    // Retrieve all 2D features as undistorted positions into flat arrays
    Mat xI, xJ;
    MatchesPairToMat(pairIndex, putativeMatchesPerType, sfmData, regionsPerView, descTypes, xI, xJ);

    // Define the AContrario adapted Homography matrix solver
    typedef ACKernelAdaptor<
        openMVG::homography::kernel::FourPointSolver,
        openMVG::homography::kernel::AsymmetricError,
        UnnormalizerI,
        Mat3>
        KernelType;

    KernelType kernel(
      xI, sfmData->GetViews().at(iIndex)->ui_width, sfmData->GetViews().at(iIndex)->ui_height,
      xJ, sfmData->GetViews().at(jIndex)->ui_width, sfmData->GetViews().at(jIndex)->ui_height,
      false); // configure as point to point error model.

    // Robustly estimate the Homography matrix with A Contrario ransac
    const double upper_bound_precision = Square(m_dPrecision);

    std::vector<size_t> inliers;
    const std::pair<double,double> ACRansacOut = ACRANSAC(kernel, inliers, m_stIteration, &m_H, upper_bound_precision);

    if (inliers.empty())
      return EstimationStatus(false, false);

    m_dPrecision_robust = ACRansacOut.first;

    // Fill geometricInliersPerType with inliers from putativeMatchesPerType
    copyInlierMatches(
          inliers,
          putativeMatchesPerType,
          descTypes,
          out_geometricInliersPerType);

    // Check if resection has strong support
    const bool hasStrongSupport = robust::hasStrongSupport(out_geometricInliersPerType, KernelType::MINIMUM_SAMPLES);

    return EstimationStatus(true, hasStrongSupport);
  }

  /**
   * @brief Export point feature based vector to a matrix [(x,y)'T, (x,y)'T].
   * Use the camera intrinsics in order to get undistorted pixel coordinates
   */
  template<typename MatT >
  static void fillMatricesWithUndistortFeatures(
    const cameras::IntrinsicBase * cam,
    const features::PointFeatures & vec_feats,
    MatT & m)
  {
    using Scalar = typename MatT::Scalar; // Output matrix type

    const bool hasValidIntrinsics = cam && cam->isValid();
    size_t i = 0;

    if (hasValidIntrinsics)
    {
      for( features::PointFeatures::const_iterator iter = vec_feats.begin();
        iter != vec_feats.end(); ++iter, ++i)
      {
          m.col(i) = cam->get_ud_pixel(Vec2(iter->x(), iter->y()));
      }
    }
    else
    {
      for( features::PointFeatures::const_iterator iter = vec_feats.begin();
        iter != vec_feats.end(); ++iter, ++i)
      {
          m.col(i) = iter->coords().cast<Scalar>();
        }
    }
  }

  template<typename MatT >
  static void createMatricesWithUndistortFeatures(
    const cameras::IntrinsicBase * cam,
    const features::MapRegionsPerDesc & regionsPerDesc,
    MatT & m)
  {
    size_t nbRegions = 0;
    for(const auto regions: regionsPerDesc)
    {
      nbRegions += regions.second->RegionCount();
    }
    m.resize(2, nbRegions);

    size_t y = 0;
    for(const auto regions: regionsPerDesc)
    {
      fillMatricesWithUndistortFeatures(
            cam,
            regions.second,
            m.block(0, y, 2, regions.second->RegionCount()));
      y += regions.second->RegionCount();
    }
  }

  template<typename MatT >
  static void createMatricesWithUndistortFeatures(
    const cameras::IntrinsicBase * cam,
    const features::PointFeatures & vec_feats,
    MatT & m)
  {
    size_t nbRegions = vec_feats.size();
    m.resize(2, nbRegions);

    fillMatricesWithUndistortFeatures(
          cam,
          vec_feats,
          m);<commit_msg>[image_collection] missing reference &<commit_after>
// Copyright (c) 2014, 2015 <NAME>.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#pragma once

#include "openMVG/multiview/solver_homography_kernel.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansac.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansacKernelAdaptator.hpp"
#include "openMVG/robust_estimation/guided_matching.hpp"

#include "openMVG/matching/indMatch.hpp"
#include "openMVG/matching/indMatchDecoratorXY.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/features/RegionsPerView.hpp"
#include "openMVG/matching_image_collection/GeometricFilterMatrix.hpp"

namespace openMVG {
namespace matching_image_collection {

//-- A contrario homography matrix estimation template functor used for filter pair of putative correspondences
struct GeometricFilter_HMatrix_AC : public GeometricFilterMatrix
{
  GeometricFilter_HMatrix_AC(
    double dPrecision = std::numeric_limits<double>::infinity(),
    size_t iteration = 1024)
    : GeometricFilterMatrix(dPrecision, std::numeric_limits<double>::infinity(), iteration)
    , m_H(Mat3::Identity())
  {}

  /**
   * @brief Given two sets of image points, it estimates the homography matrix
   * relating them using a robust method (like A Contrario Ransac).
   */
  template<typename Regions_or_Features_ProviderT>
  EstimationStatus geometricEstimation(
    const sfm::SfM_Data * sfmData,
    const Regions_or_Features_ProviderT& regionsPerView,
    const Pair pairIndex,
    const matching::MatchesPerDescType & putativeMatchesPerType,
    matching::MatchesPerDescType & out_geometricInliersPerType)
  {
    using namespace openMVG;
    using namespace openMVG::robust;
    out_geometricInliersPerType.clear();

    // Get back corresponding view index
    const IndexT iIndex = pairIndex.first;
    const IndexT jIndex = pairIndex.second;

    const std::vector<features::EImageDescriberType> descTypes = regionsPerView.getCommonDescTypes(pairIndex);
    if(descTypes.empty())
      return EstimationStatus(false, false);

    // Retrieve all 2D features as undistorted positions into flat arrays
    Mat xI, xJ;
    MatchesPairToMat(pairIndex, putativeMatchesPerType, sfmData, regionsPerView, descTypes, xI, xJ);

    // Define the AContrario adapted Homography matrix solver
    typedef ACKernelAdaptor<
        openMVG::homography::kernel::FourPointSolver,
        openMVG::homography::kernel::AsymmetricError,
        UnnormalizerI,
        Mat3>
        KernelType;

    KernelType kernel(
      xI, sfmData->GetViews().at(iIndex)->ui_width, sfmData->GetViews().at(iIndex)->ui_height,
      xJ, sfmData->GetViews().at(jIndex)->ui_width, sfmData->GetViews().at(jIndex)->ui_height,
      false); // configure as point to point error model.

    // Robustly estimate the Homography matrix with A Contrario ransac
    const double upper_bound_precision = Square(m_dPrecision);

    std::vector<size_t> inliers;
    const std::pair<double,double> ACRansacOut = ACRANSAC(kernel, inliers, m_stIteration, &m_H, upper_bound_precision);

    if (inliers.empty())
      return EstimationStatus(false, false);

    m_dPrecision_robust = ACRansacOut.first;

    // Fill geometricInliersPerType with inliers from putativeMatchesPerType
    copyInlierMatches(
          inliers,
          putativeMatchesPerType,
          descTypes,
          out_geometricInliersPerType);

    // Check if resection has strong support
    const bool hasStrongSupport = robust::hasStrongSupport(out_geometricInliersPerType, KernelType::MINIMUM_SAMPLES);

    return EstimationStatus(true, hasStrongSupport);
  }

  /**
   * @brief Export point feature based vector to a matrix [(x,y)'T, (x,y)'T].
   * Use the camera intrinsics in order to get undistorted pixel coordinates
   */
  template<typename MatT >
  static void fillMatricesWithUndistortFeatures(
    const cameras::IntrinsicBase * cam,
    const features::PointFeatures & vec_feats,
    MatT & m)
  {
    using Scalar = typename MatT::Scalar; // Output matrix type

    const bool hasValidIntrinsics = cam && cam->isValid();
    size_t i = 0;

    if (hasValidIntrinsics)
    {
      for( features::PointFeatures::const_iterator iter = vec_feats.begin();
        iter != vec_feats.end(); ++iter, ++i)
      {
          m.col(i) = cam->get_ud_pixel(Vec2(iter->x(), iter->y()));
      }
    }
    else
    {
      for( features::PointFeatures::const_iterator iter = vec_feats.begin();
        iter != vec_feats.end(); ++iter, ++i)
      {
          m.col(i) = iter->coords().cast<Scalar>();
        }
    }
  }

  template<typename MatT >
  static void createMatricesWithUndistortFeatures(
    const cameras::IntrinsicBase * cam,
    const features::MapRegionsPerDesc & regionsPerDesc,
    MatT & m)
  {
    size_t nbRegions = 0;
    for(const auto &regions: regionsPerDesc)
    {
      nbRegions += regions.second->RegionCount();
    }
    m.resize(2, nbRegions);

    size_t y = 0;
    for(const auto &regions: regionsPerDesc)
    {
      fillMatricesWithUndistortFeatures(
            cam,
            regions.second,
            m.block(0, y, 2, regions.second->RegionCount()));
      y += regions.second->RegionCount();
    }
  }

  template<typename MatT >
  static void createMatricesWithUndistortFeatures(
    const cameras::IntrinsicBase * cam,
    const features::PointFeatures & vec_feats,
    MatT & m)
  {
    size_t nbRegions = vec_feats.size();
    m.resize(2, nbRegions);

    fillMatricesWithUndistortFeatures(
          cam,
          vec_feats,
          m);
{'fraction_non_alphanumeric': 0.10093834955713409, 'fraction_numerical': 0.004735595895816891, 'mean_word_length': 3.708505367464905, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2975870', 'n_tokens_mistral': 3734, 'n_tokens_neox': 3516, 'n_words': 806}