예제 #1
0
/// List the view indexes that have valid camera intrinsic and pose.
static std::set<IndexT> Get_Valid_Views
(
  const SfM_Data & sfm_data
)
{
  std::set<IndexT> valid_idx;
  for (Views::const_iterator it = sfm_data.getViews().begin();
    it != sfm_data.getViews().end(); ++it)
  {
    const View * v = it->second.get();
    const IndexT id_view = v->id_view;
    const IndexT id_intrinsic = v->id_intrinsic;
    const IndexT id_pose = v->id_pose;

    bool bDefined =
      id_intrinsic != UndefinedIndexT &&
      sfm_data.getIntrinsics().find(id_intrinsic) != sfm_data.getIntrinsics().end() &&
      id_pose != UndefinedIndexT &&
      sfm_data.getPoses().find(id_pose) != sfm_data.getPoses().end();

    if (bDefined)
    {
      valid_idx.insert(id_view);
    }
  }
  return valid_idx;
}
예제 #2
0
static bool eraseObservationsWithMissingPoses(SfM_Data & sfm_data, const IndexT min_points_per_landmark)
{
  IndexT removed_elements = 0;

  const Landmarks & landmarks = sfm_data.structure;
  std::set<IndexT> pose_Index;
  std::transform(sfm_data.poses.begin(), sfm_data.poses.end(),
    std::inserter(pose_Index, pose_Index.begin()), std::RetrieveKey());

  // For each landmark:
  //  - Check if we need to keep the observations & the track
  Landmarks::iterator itLandmarks = sfm_data.structure.begin();
  while (itLandmarks != sfm_data.structure.end())
  {
    Observations & obs = itLandmarks->second.obs;
    Observations::iterator itObs = obs.begin();
    while (itObs != obs.end())
    {
      const IndexT ViewId = itObs->first;
      const View * v = sfm_data.getViews().at(ViewId).get();
      if (pose_Index.count(v->id_pose) == 0)
      {
        itObs = obs.erase(itObs);
        ++removed_elements;
      }
      else
        ++itObs;
    }
    if (obs.empty() || obs.size() < min_points_per_landmark)
      itLandmarks = sfm_data.structure.erase(itLandmarks);
    else
      ++itLandmarks;
  }
  return removed_elements > 0;
}
예제 #3
0
///Check that each pose have a valid intrinsic and pose id in the existing View ids
bool ValidIds(const SfM_Data & sfm_data, ESfM_Data flags_part)
{
  const bool bCheck_Intrinsic = (flags_part & INTRINSICS) == INTRINSICS;
  const bool bCheck_Extrinsic = (flags_part & EXTRINSICS) == EXTRINSICS;

  std::set<IndexT> set_id_intrinsics;
  transform(sfm_data.getIntrinsics().begin(), sfm_data.getIntrinsics().end(),
    std::inserter(set_id_intrinsics, set_id_intrinsics.begin()), std::RetrieveKey());

  std::set<IndexT> set_id_extrinsics; //unique so can use a set
  transform(sfm_data.getPoses().begin(), sfm_data.getPoses().end(),
    std::inserter(set_id_extrinsics, set_id_extrinsics.begin()), std::RetrieveKey());

  // Collect existing id_intrinsic && id_extrinsic from views
  std::set<IndexT> reallyDefined_id_intrinsics;
  std::set<IndexT> reallyDefined_id_extrinsics;
  for (Views::const_iterator iter = sfm_data.getViews().begin();
    iter != sfm_data.getViews().end();
    ++iter)
  {
    // If a pose is defined, at least the intrinsic must be valid,
    // In order to generate a valid camera.
    const IndexT id_pose = iter->second.get()->id_pose;
    const IndexT id_intrinsic = iter->second.get()->id_intrinsic;

    if (set_id_extrinsics.count(id_pose))
      reallyDefined_id_extrinsics.insert(id_pose); //at least it exists

    if (set_id_intrinsics.count(id_intrinsic))
      reallyDefined_id_intrinsics.insert(id_intrinsic); //at least it exists
  }
  // Check if defined intrinsic & extrinsic are at least connected to views
  bool bRet = true;
  if (bCheck_Intrinsic)
    bRet &= set_id_intrinsics.size() == reallyDefined_id_intrinsics.size();

  if (bCheck_Extrinsic)
    bRet &= set_id_extrinsics.size() == reallyDefined_id_extrinsics.size();

  if (bRet == false)
    std::cout << "There is orphan intrinsics data or poses (do not depend on any view)" << std::endl;

  return bRet;
}
예제 #4
0
static bool eraseMissingPoses(SfM_Data & sfm_data, const IndexT min_points_per_pose)
{
  IndexT removed_elements = 0;
  const Landmarks & landmarks = sfm_data.structure;

  // Count the observation poses occurence
  Hash_Map<IndexT, IndexT> map_PoseId_Count;
  // Init with 0 count (in order to be able to remove non referenced elements)
  for (Poses::const_iterator itPoses = sfm_data.getPoses().begin();
    itPoses != sfm_data.getPoses().end(); ++itPoses)
  {
    map_PoseId_Count[itPoses->first] = 0;
  }

  // Count occurence of the poses in the Landmark observations
  for (Landmarks::const_iterator itLandmarks = landmarks.begin();
    itLandmarks != landmarks.end(); ++itLandmarks)
  {
    const Observations & obs = itLandmarks->second.obs;
    for (Observations::const_iterator itObs = obs.begin();
      itObs != obs.end(); ++itObs)
    {
      const IndexT ViewId = itObs->first;
      const View * v = sfm_data.getViews().at(ViewId).get();
      if (map_PoseId_Count.count(v->id_pose))
        map_PoseId_Count[v->id_pose] += 1;
      else
        map_PoseId_Count[v->id_pose] = 0;
    }
  }
  // If usage count is smaller than the threshold, remove the Pose
  for (Hash_Map<IndexT, IndexT>::const_iterator it = map_PoseId_Count.begin();
    it != map_PoseId_Count.end(); ++it)
  {
    if (it->second < min_points_per_pose)
    {
      sfm_data.poses.erase(it->first);
      ++removed_elements;
    }
  }
  return removed_elements > 0;
}
예제 #5
0
/// Compute the Root Mean Square Error of the residuals
double RMSE(const SfM_Data & sfm_data)
{
  // Compute residuals for each observation
  std::vector<double> vec;
  for(Landmarks::const_iterator iterTracks = sfm_data.getLandmarks().begin();
      iterTracks != sfm_data.getLandmarks().end();
      ++iterTracks)
  {
    const Observations & obs = iterTracks->second.obs;
    for(Observations::const_iterator itObs = obs.begin();
      itObs != obs.end(); ++itObs)
    {
      const View * view = sfm_data.getViews().find(itObs->first)->second.get();
      const Pose3 & pose = sfm_data.getPoses().find(view->id_pose)->second;
      const std::shared_ptr<IntrinsicBase> intrinsic = sfm_data.getIntrinsics().find(view->id_intrinsic)->second;
      const Vec2 residual = intrinsic->residual(pose, iterTracks->second.X, itObs->second.x);
      vec.push_back( residual(0) );
      vec.push_back( residual(1) );
    }
  }
  const Eigen::Map<Eigen::RowVectorXd> residuals(&vec[0], vec.size());
  const double RMSE = std::sqrt(residuals.squaredNorm() / vec.size());
  return RMSE;
}
예제 #6
0
  /// Use guided matching to find corresponding 2-view correspondences
  void match(
    const SfM_Data & sfm_data,
    const Pair_Set & pairs,
    const std::shared_ptr<Regions_Provider> & regions_provider)
  {
    C_Progress_display my_progress_bar( pairs.size(), std::cout,
      "Compute pairwise fundamental guided matching:\n" );
  #ifdef OPENMVG_USE_OPENMP
    #pragma omp parallel
  #endif // OPENMVG_USE_OPENMP
    for (Pair_Set::const_iterator it = pairs.begin(); it != pairs.end(); ++it)
    {
  #ifdef OPENMVG_USE_OPENMP
      #pragma omp single nowait
  #endif // OPENMVG_USE_OPENMP
      {
      // --
      // Perform GUIDED MATCHING
      // --
      // Use the computed model to check valid correspondences
      // - by considering geometric error and descriptor distance ratio.
      std::vector<IndMatch> vec_corresponding_indexes;

      const View * viewL = sfm_data.getViews().at(it->first).get();
      const Poses::const_iterator iterPoseL = sfm_data.getPoses().find(viewL->id_pose);
      const Intrinsics::const_iterator iterIntrinsicL = sfm_data.getIntrinsics().find(viewL->id_intrinsic);
      const View * viewR = sfm_data.getViews().at(it->second).get();
      const Poses::const_iterator iterPoseR = sfm_data.getPoses().find(viewR->id_pose);
      const Intrinsics::const_iterator iterIntrinsicR = sfm_data.getIntrinsics().find(viewR->id_intrinsic);

      Mat xL, xR;
      PointsToMat(iterIntrinsicL->second.get(), regions_provider->regions_per_view.at(it->first)->GetRegionsPositions(), xL);
      PointsToMat(iterIntrinsicR->second.get(), regions_provider->regions_per_view.at(it->second)->GetRegionsPositions(), xR);

      const Mat34 P_L = iterIntrinsicL->second.get()->get_projective_equivalent(iterPoseL->second);
      const Mat34 P_R = iterIntrinsicR->second.get()->get_projective_equivalent(iterPoseR->second);

      const Mat3 F_lr = F_from_P(P_L, P_R);
      const double thresholdF = 4.0;

#if defined(EXHAUSTIVE_MATCHING)
      // Guided matching considering geometric error and descriptor distance ratio
      geometry_aware::GuidedMatching
        <Mat3, openMVG::fundamental::kernel::EpipolarDistanceError,
        DescriptorT, L2_Vectorized<DescriptorT::bin_type> >(
        F_lr, xL, desc_provider.at(it->first), xR, desc_provider.at(it->second),
        Square(thresholdF), Square(0.8),
        vec_corresponding_indexes);
#else
      const Vec3 epipole2  = epipole_from_P(P_R, iterPoseL->second);

      const features::Regions * regions = regions_provider->regions_per_view.at(it->first).get();
      if (regions->IsScalar())
      {
        // L2 Metric (Handle descriptor internal type)
        if(regions->Type_id() == typeid(unsigned char).name())
        {
          geometry_aware::GuidedMatching_Fundamental_Fast<
          openMVG::fundamental::kernel::EpipolarDistanceError,
          L2_Vectorized<unsigned char> >
          ( F_lr,
            epipole2,
            regions_provider->regions_per_view.at(it->first).get(),
            iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(),
            regions_provider->regions_per_view.at(it->second).get(),
            Square(thresholdF), Square(0.8),
            vec_corresponding_indexes);
        }
        else
        if(regions->Type_id() == typeid(float).name())
        {
          geometry_aware::GuidedMatching_Fundamental_Fast<
          openMVG::fundamental::kernel::EpipolarDistanceError,
          L2_Vectorized<float> >
          ( F_lr,
            epipole2,
            regions_provider->regions_per_view.at(it->first).get(),
            iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(),
            regions_provider->regions_per_view.at(it->second).get(),
            Square(thresholdF), Square(0.8),
            vec_corresponding_indexes);
        }
        else
        if(regions->Type_id() == typeid(double).name())
        {
          geometry_aware::GuidedMatching_Fundamental_Fast<
          openMVG::fundamental::kernel::EpipolarDistanceError,
          L2_Vectorized<double> >
          ( F_lr,
            epipole2,
            regions_provider->regions_per_view.at(it->first).get(),
            iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(),
            regions_provider->regions_per_view.at(it->second).get(),
            Square(thresholdF), Square(0.8),
            vec_corresponding_indexes);
        }
      }
      else
      if (regions->IsBinary() && regions->Type_id() == typeid(unsigned char).name())
      {
        // Hamming metric
        geometry_aware::GuidedMatching_Fundamental_Fast<
        openMVG::fundamental::kernel::EpipolarDistanceError,
        Hamming<unsigned char> >
        ( F_lr,
          epipole2,
          regions_provider->regions_per_view.at(it->first).get(),
          iterIntrinsicR->second.get()->w(), iterIntrinsicR->second.get()->h(),
          regions_provider->regions_per_view.at(it->second).get(),
          Square(thresholdF), 0.8,
          vec_corresponding_indexes);
      }

#endif

  #ifdef OPENMVG_USE_OPENMP
      #pragma omp critical
  #endif // OPENMVG_USE_OPENMP
        {
          ++my_progress_bar;
          for (size_t i = 0; i < vec_corresponding_indexes.size(); ++i)
            putatives_matches[*it].push_back(vec_corresponding_indexes[i]);
        }
      }
    }
  }
예제 #7
0
  /// Filter inconsistent correspondences by using 3-view correspondences on view triplets
  void filter(
    const SfM_Data & sfm_data,
    const Pair_Set & pairs,
    const std::shared_ptr<Regions_Provider> & regions_provider)
  {
    // Compute triplets
    // Triangulate triplet tracks
    //  - keep valid one

    typedef std::vector< graphUtils::Triplet > Triplets;
    const Triplets triplets = graphUtils::tripletListing(pairs);

    C_Progress_display my_progress_bar( triplets.size(), std::cout,
      "Per triplet tracks validation (discard spurious correspondences):\n" );
  #ifdef OPENMVG_USE_OPENMP
      #pragma omp parallel
  #endif // OPENMVG_USE_OPENMP
    for( Triplets::const_iterator it = triplets.begin(); it != triplets.end(); ++it)
    {
  #ifdef OPENMVG_USE_OPENMP
      #pragma omp single nowait
  #endif // OPENMVG_USE_OPENMP
      {
        #ifdef OPENMVG_USE_OPENMP
          #pragma omp critical
        #endif // OPENMVG_USE_OPENMP
        {++my_progress_bar;}

        const graphUtils::Triplet & triplet = *it;
        const IndexT I = triplet.i, J = triplet.j , K = triplet.k;

        openMVG::tracks::STLMAPTracks map_tracksCommon;
        openMVG::tracks::TracksBuilder tracksBuilder;
        {
          PairWiseMatches map_matchesIJK;
          if(putatives_matches.find(std::make_pair(I,J)) != putatives_matches.end())
            map_matchesIJK.insert(*putatives_matches.find(std::make_pair(I,J)));

          if(putatives_matches.find(std::make_pair(I,K)) != putatives_matches.end())
            map_matchesIJK.insert(*putatives_matches.find(std::make_pair(I,K)));

          if(putatives_matches.find(std::make_pair(J,K)) != putatives_matches.end())
            map_matchesIJK.insert(*putatives_matches.find(std::make_pair(J,K)));

          if (map_matchesIJK.size() >= 2) {
            tracksBuilder.Build(map_matchesIJK);
            tracksBuilder.Filter(3);
            tracksBuilder.ExportToSTL(map_tracksCommon);
          }

          // Triangulate the tracks
          for (tracks::STLMAPTracks::const_iterator iterTracks = map_tracksCommon.begin();
            iterTracks != map_tracksCommon.end(); ++iterTracks) {
            {
              const tracks::submapTrack & subTrack = iterTracks->second;
              Triangulation trianObj;
              for (tracks::submapTrack::const_iterator iter = subTrack.begin(); iter != subTrack.end(); ++iter) {
                const size_t imaIndex = iter->first;
                const size_t featIndex = iter->second;
                const View * view = sfm_data.getViews().at(imaIndex).get();
                const IntrinsicBase * cam = sfm_data.getIntrinsics().at(view->id_intrinsic).get();
                const Pose3 & pose = sfm_data.poses.at(view->id_pose);
                const Vec2 pt = regions_provider->regions_per_view.at(imaIndex)->GetRegionPosition(featIndex);
                trianObj.add(cam->get_projective_equivalent(pose), cam->get_ud_pixel(pt));
              }
              const Vec3 Xs = trianObj.compute();
              if (trianObj.minDepth() > 0 && trianObj.error() < 4.0)
              // TODO: Add an angular check ?
              {
                #ifdef OPENMVG_USE_OPENMP
                  #pragma omp critical
                #endif // OPENMVG_USE_OPENMP
                {
                  openMVG::tracks::submapTrack::const_iterator iterI, iterJ, iterK;
                  iterI = iterJ = iterK = subTrack.begin();
                  std::advance(iterJ,1);
                  std::advance(iterK,2);

                  triplets_matches[std::make_pair(I,J)].push_back(IndMatch(iterI->second, iterJ->second));
                  triplets_matches[std::make_pair(J,K)].push_back(IndMatch(iterJ->second, iterK->second));
                  triplets_matches[std::make_pair(I,K)].push_back(IndMatch(iterI->second, iterK->second));
                }
              }
            }
          }
        }
      }
    }
    // Clear putatives matches since they are no longer required
    matching::PairWiseMatches().swap(putatives_matches);
  }
/// Find the color of the SfM_Data Landmarks/structure
void ColorizeTracks(
  const SfM_Data & sfm_data,
  std::vector<Vec3> & vec_3dPoints,
  std::vector<Vec3> & vec_tracksColor)
{
  // Colorize each track
  //  Start with the most representative image
  //    and iterate to provide a color to each 3D point

  {
    C_Progress_display my_progress_bar(sfm_data.getLandmarks().size(),
                                       std::cout,
                                       "\nCompute scene structure color\n");

    vec_tracksColor.resize(sfm_data.getLandmarks().size());
    vec_3dPoints.resize(sfm_data.getLandmarks().size());

    //Build a list of contiguous index for the trackIds
    std::map<IndexT, IndexT> trackIds_to_contiguousIndexes;
    IndexT cpt = 0;
    for (Landmarks::const_iterator it = sfm_data.getLandmarks().begin();
      it != sfm_data.getLandmarks().end(); ++it, ++cpt)
    {
      trackIds_to_contiguousIndexes[it->first] = cpt;
      vec_3dPoints[cpt] = it->second.X;
    }

    // The track list that will be colored (point removed during the process)
    std::set<IndexT> remainingTrackToColor;
    std::transform(sfm_data.getLandmarks().begin(), sfm_data.getLandmarks().end(),
      std::inserter(remainingTrackToColor, remainingTrackToColor.begin()),
      RetrieveKey() );

    while( !remainingTrackToColor.empty() )
    {
      // Find the most representative image (for the remaining 3D points)
      //  a. Count the number of observation per view for each 3Dpoint Index
      //  b. Sort to find the most representative view index

      std::map<IndexT, IndexT> map_IndexCardinal; // ViewId, Cardinal
      for (std::set<IndexT>::const_iterator
        iterT = remainingTrackToColor.begin();
        iterT != remainingTrackToColor.end();
        ++iterT)
      {
        const size_t trackId = *iterT;
        const Observations & obs = sfm_data.getLandmarks().at(trackId).obs;
        for( Observations::const_iterator iterObs = obs.begin();
          iterObs != obs.end(); ++iterObs)
        {
          const size_t viewId = iterObs->first;
          if (map_IndexCardinal.find(viewId) == map_IndexCardinal.end())
            map_IndexCardinal[viewId] = 1;
          else
            ++map_IndexCardinal[viewId];
        }
      }

      // Find the View index that is the most represented
      std::vector<IndexT> vec_cardinal;
      std::transform(map_IndexCardinal.begin(),
        map_IndexCardinal.end(),
        std::back_inserter(vec_cardinal),
        RetrieveValue());
      using namespace indexed_sort;
      std::vector< sort_index_packet_descend< IndexT, IndexT> > packet_vec(vec_cardinal.size());
      sort_index_helper(packet_vec, &vec_cardinal[0], 1);

      // First image index with the most of occurence
      std::map<IndexT, IndexT>::const_iterator iterTT = map_IndexCardinal.begin();
      std::advance(iterTT, packet_vec[0].index);
      const size_t view_index = iterTT->first;
      const View * view = sfm_data.getViews().at(view_index).get();
      const std::string sView_filename = stlplus::create_filespec(sfm_data.s_root_path,
        view->s_Img_path);
      Image<RGBColor> image;
      ReadImage(sView_filename.c_str(), &image);

      // Iterate through the remaining track to color
      // - look if the current view is present to color the track
      std::set<IndexT> set_toRemove;
      for (std::set<IndexT>::const_iterator
        iterT = remainingTrackToColor.begin();
        iterT != remainingTrackToColor.end();
        ++iterT)
      {
        const size_t trackId = *iterT;
        const Observations & obs = sfm_data.getLandmarks().at(trackId).obs;
        Observations::const_iterator it = obs.find(view_index);

        if (it != obs.end())
        {
          // Color the track
          const Vec2 & pt = it->second.x;
          const RGBColor color = image(pt.y(), pt.x());

          vec_tracksColor[ trackIds_to_contiguousIndexes[trackId] ] = Vec3(color.r(), color.g(), color.b());
          set_toRemove.insert(trackId);
          ++my_progress_bar;
        }
      }
      // Remove colored track
      for (std::set<IndexT>::const_iterator iter = set_toRemove.begin();
        iter != set_toRemove.end(); ++iter)
      {
        remainingTrackToColor.erase(*iter);
      }
    }
  }
}