// Load Regions related to a provided SfM_Data View container virtual bool load( const SfM_Data & sfm_data, const std::string & feat_directory, std::unique_ptr<features::Regions>& region_type) { C_Progress_display my_progress_bar( sfm_data.GetViews().size(), std::cout, "\n- Regions Loading -\n"); // Read for each view the corresponding regions and store them for (Views::const_iterator iter = sfm_data.GetViews().begin(); iter != sfm_data.GetViews().end(); ++iter, ++my_progress_bar) { const std::string sImageName = stlplus::create_filespec(sfm_data.s_root_path, iter->second.get()->s_Img_path); const std::string basename = stlplus::basename_part(sImageName); const std::string featFile = stlplus::create_filespec(feat_directory, basename, ".feat"); const std::string descFile = stlplus::create_filespec(feat_directory, basename, ".desc"); regions_per_view[iter->second.get()->id_view] = std::unique_ptr<features::Regions>(region_type->EmptyClone()); if (!regions_per_view[iter->second.get()->id_view]->Load(featFile, descFile)) { std::cerr << "Invalid regions files for the view: " << sImageName << std::endl; return false; } } return true; }
void load_textures() { int nbCams = m_doc._vec_imageNames.size(); m_image_vector.resize(nbCams); std::cout << "**\Textures loading, Please wait...\n"; C_Progress_display my_progress_bar( nbCams ); for ( int i_cam=0; i_cam<nbCams; ++i_cam, ++my_progress_bar) { std::string sImageName = stlplus::create_filespec( stlplus::folder_append_separator(m_doc._sDirectory)+"images", m_doc._vec_imageNames[i_cam]); std::vector<unsigned char> img; int w,h,depth; if (ReadImage(sImageName.c_str(), &img, &w, &h, &depth)) { glEnable(GL_TEXTURE_2D); //std::cout << "Read image : " << sImageName << "\n" << std::endl; glDeleteTextures(1, &m_image_vector[i_cam].texture); // Create texture glGenTextures( 1, &m_image_vector[i_cam].texture); // select our current texture glBindTexture(GL_TEXTURE_2D, m_image_vector[i_cam].texture); m_image_vector[i_cam].width = w; m_image_vector[i_cam].height = h; glTexImage2D(GL_TEXTURE_2D, 0, (depth == 1) ? GL_LUMINANCE : GL_RGB, m_image_vector[i_cam].width, m_image_vector[i_cam].height, 0, (depth == 1) ? GL_LUMINANCE : GL_RGB, GL_UNSIGNED_BYTE, &img[0]); glBindTexture(GL_TEXTURE_2D, m_image_vector[i_cam].texture); } } std::cout << "**\Textures loading, Done" << std::endl; }
// Load features related to a provided SfM_Data View container virtual bool load( const SfM_Data & sfm_data, const std::string & feat_directory, std::unique_ptr<features::Image_describer>& image_describer) { C_Progress_display my_progress_bar( sfm_data.GetViews().size(), std::cout, "\n- Features Loading -\n" ); // Read for each view the corresponding features and store them as PointFeatures std::unique_ptr<features::Regions> regions; image_describer->Allocate(regions); for (Views::const_iterator iter = sfm_data.GetViews().begin(); iter != sfm_data.GetViews().end(); ++iter, ++my_progress_bar) { const std::string sImageName = stlplus::create_filespec(sfm_data.s_root_path, iter->second.get()->s_Img_path); const std::string basename = stlplus::basename_part(sImageName); const std::string featFile = stlplus::create_filespec(feat_directory, basename, ".feat"); if (!image_describer->LoadFeatures(regions.get(), featFile)) { std::cerr << "Invalid feature files for the view: " << sImageName << std::endl; return false; } // save loaded Features as PointFeature feats_per_view[iter->second.get()->id_view] = regions->GetRegionsPositions(); } return true; }
virtual bool load( const SfM_Data & sfm_data, const std::string & feat_directory, std::unique_ptr<features::Regions>& region_type) { C_Progress_display my_progress_bar( sfm_data.GetViews().size(), std::cout, "\n- Features Loading -\n" ); // Read for each view the corresponding features and store them as PointFeatures bool bContinue = true; #ifdef OPENMVG_USE_OPENMP #pragma omp parallel #endif for (Views::const_iterator iter = sfm_data.GetViews().begin(); iter != sfm_data.GetViews().end() && bContinue; ++iter) { #ifdef OPENMVG_USE_OPENMP #pragma omp single nowait #endif { const std::string sImageName = stlplus::create_filespec(sfm_data.s_root_path, iter->second.get()->s_Img_path); const std::string basename = stlplus::basename_part(sImageName); const std::string featFile = stlplus::create_filespec(feat_directory, basename, ".feat"); std::unique_ptr<features::Regions> regions(region_type->EmptyClone()); if (!regions->LoadFeatures(featFile)) { std::cerr << "Invalid feature files for the view: " << sImageName << std::endl; #ifdef OPENMVG_USE_OPENMP #pragma omp critical #endif bContinue = false; } #ifdef OPENMVG_USE_OPENMP #pragma omp critical #endif { // save loaded Features as PointFeature feats_per_view[iter->second.get()->id_view] = regions->GetRegionsPositions(); ++my_progress_bar; } } } return bContinue; }
/// 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]); } } } }
/// 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); }
void Match ( const sfm::SfM_Data & sfm_data, const sfm::Regions_Provider & regions_provider, const Pair_Set & pairs, float fDistRatio, PairWiseMatchesContainer & map_PutativesMatches // the pairwise photometric corresponding points ) { C_Progress_display my_progress_bar( pairs.size() ); // Collect used view indexes std::set<IndexT> used_index; // Sort pairs according the first index to minimize later memory swapping using Map_vectorT = std::map<IndexT, std::vector<IndexT>>; Map_vectorT map_Pairs; for (Pair_Set::const_iterator iter = pairs.begin(); iter != pairs.end(); ++iter) { map_Pairs[iter->first].push_back(iter->second); used_index.insert(iter->first); used_index.insert(iter->second); } using BaseMat = Eigen::Matrix<ScalarT, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; // Init the cascade hasher CascadeHasher cascade_hasher; if (!used_index.empty()) { const IndexT I = *used_index.begin(); std::shared_ptr<features::Regions> regionsI = regions_provider.get(I); const size_t dimension = regionsI.get()->DescriptorLength(); cascade_hasher.Init(dimension); } std::map<IndexT, HashedDescriptions> hashed_base_; // Compute the zero mean descriptor that will be used for hashing (one for all the image regions) Eigen::VectorXf zero_mean_descriptor; { Eigen::MatrixXf matForZeroMean; for (int i =0; i < used_index.size(); ++i) { std::set<IndexT>::const_iterator iter = used_index.begin(); std::advance(iter, i); const IndexT I = *iter; std::shared_ptr<features::Regions> regionsI = regions_provider.get(I); const ScalarT * tabI = reinterpret_cast<const ScalarT*>(regionsI.get()->DescriptorRawData()); const size_t dimension = regionsI.get()->DescriptorLength(); if (i==0) { matForZeroMean.resize(used_index.size(), dimension); matForZeroMean.fill(0.0f); } if (regionsI.get()->RegionCount() > 0) { Eigen::Map<BaseMat> mat_I( (ScalarT*)tabI, regionsI.get()->RegionCount(), dimension); matForZeroMean.row(i) = CascadeHasher::GetZeroMeanDescriptor(mat_I); } } zero_mean_descriptor = CascadeHasher::GetZeroMeanDescriptor(matForZeroMean); } // Index the input regions #ifdef OPENMVG_USE_OPENMP #pragma omp parallel for schedule(dynamic) #endif for (int i =0; i < used_index.size(); ++i) { std::set<IndexT>::const_iterator iter = used_index.begin(); std::advance(iter, i); const IndexT I = *iter; std::shared_ptr<features::Regions> regionsI = regions_provider.get(I); const ScalarT * tabI = reinterpret_cast<const ScalarT*>(regionsI.get()->DescriptorRawData()); const size_t dimension = regionsI.get()->DescriptorLength(); Eigen::Map<BaseMat> mat_I( (ScalarT*)tabI, regionsI.get()->RegionCount(), dimension); HashedDescriptions hashed_description = cascade_hasher.CreateHashedDescriptions(mat_I, zero_mean_descriptor); #ifdef OPENMVG_USE_OPENMP #pragma omp critical #endif { hashed_base_[I] = std::move(hashed_description); } } // Perform matching between all the pairs for (Map_vectorT::const_iterator iter = map_Pairs.begin(); iter != map_Pairs.end(); ++iter) { const IndexT I = iter->first; const std::vector<IndexT> & indexToCompare = iter->second; std::shared_ptr<features::Regions> regionsI = regions_provider.get(I); if (regionsI.get()->RegionCount() == 0) { my_progress_bar += indexToCompare.size(); continue; } const std::vector<features::PointFeature> pointFeaturesI = regionsI.get()->GetRegionsPositions(); const ScalarT * tabI = reinterpret_cast<const ScalarT*>(regionsI.get()->DescriptorRawData()); const size_t dimension = regionsI.get()->DescriptorLength(); Eigen::Map<BaseMat> mat_I( (ScalarT*)tabI, regionsI.get()->RegionCount(), dimension); #ifdef OPENMVG_USE_OPENMP #pragma omp parallel for schedule(dynamic) #endif for (int j = 0; j < (int)indexToCompare.size(); ++j) { size_t J = indexToCompare[j]; std::shared_ptr<features::Regions> regionsJ = regions_provider.get(J); if (regionsI.get()->Type_id() != regionsJ.get()->Type_id()) { #ifdef OPENMVG_USE_OPENMP #pragma omp critical #endif ++my_progress_bar; continue; } // Matrix representation of the query input data; const ScalarT * tabJ = reinterpret_cast<const ScalarT*>(regionsJ.get()->DescriptorRawData()); Eigen::Map<BaseMat> mat_J( (ScalarT*)tabJ, regionsJ.get()->RegionCount(), dimension); IndMatches pvec_indices; using ResultType = typename Accumulator<ScalarT>::Type; std::vector<ResultType> pvec_distances; pvec_distances.reserve(regionsJ.get()->RegionCount() * 2); pvec_indices.reserve(regionsJ.get()->RegionCount() * 2); // Match the query descriptors to the database cascade_hasher.Match_HashedDescriptions<BaseMat, ResultType>( hashed_base_[J], mat_J, hashed_base_[I], mat_I, &pvec_indices, &pvec_distances); std::vector<int> vec_nn_ratio_idx; // Filter the matches using a distance ratio test: // The probability that a match is correct is determined by taking // the ratio of distance from the closest neighbor to the distance // of the second closest. matching::NNdistanceRatio( pvec_distances.begin(), // distance start pvec_distances.end(), // distance end 2, // Number of neighbor in iterator sequence (minimum required 2) vec_nn_ratio_idx, // output (indices that respect the distance Ratio) Square(fDistRatio)); matching::IndMatches vec_putative_matches; vec_putative_matches.reserve(vec_nn_ratio_idx.size()); for (size_t k=0; k < vec_nn_ratio_idx.size(); ++k) { const size_t index = vec_nn_ratio_idx[k]; vec_putative_matches.emplace_back(pvec_indices[index*2].j_, pvec_indices[index*2].i_); } // Remove duplicates matching::IndMatch::getDeduplicated(vec_putative_matches); // Remove matches that have the same (X,Y) coordinates const std::vector<features::PointFeature> pointFeaturesJ = regionsJ.get()->GetRegionsPositions(); matching::IndMatchDecorator<float> matchDeduplicator(vec_putative_matches, pointFeaturesI, pointFeaturesJ); matchDeduplicator.getDeduplicated(vec_putative_matches); #ifdef OPENMVG_USE_OPENMP #pragma omp critical #endif { ++my_progress_bar; if (!vec_putative_matches.empty()) { map_PutativesMatches.insert( make_pair( make_pair(I,J), std::move(vec_putative_matches) )); } } } } }