colmap调试学习(二)--feature_matching

这里主要将colmap中Feature Matching部分的vocab_tree_matcher对应源码

图像matcher分如下步骤:

函数主体在feature_matching.cc中Run()函数中。

复制代码
void Run() override {
    LOG_HEADING1("Feature matching & geometric verification");

    Timer run_timer;
    run_timer.Start();

    if (!matcher_.Setup()) {
      return;
    }

    std::unique_ptr<PairGenerator> pair_generator =
        THROW_CHECK_NOTNULL(pair_generator_factory_());

    while (!pair_generator->HasFinished()) {
      if (IsStopped()) {
        run_timer.PrintMinutes();
        return;
      }
      Timer timer;
      timer.Start();
      const std::vector<std::pair<image_t, image_t>> image_pairs =
          pair_generator->Next();
      matcher_.Match(image_pairs);
      LOG(INFO) << StringPrintf("in %.3fs", timer.ElapsedSeconds());
    }

在IndexImages()函数中处理加载的db库中的数据。主要是keypoints, descriptors,然后放入到visual_index_->Add()中。

复制代码
void VocabTreePairGenerator::IndexImages(
    const std::vector<image_t>& image_ids) {
  retrieval::VisualIndex::IndexOptions index_options;
  // We only assign each feature to a single visual word in the indexing phase.
  // During the query phase, we check for overlap in possibly multiple nearest
  // neighbor visual words. We could do it symmetrically but experiments showed
  // only marginal improvements that do not justify the memory/compute increase.
  index_options.num_neighbors = 1;
  index_options.num_checks = options_.num_checks;
  index_options.num_threads = options_.num_threads;

  for (size_t i = 0; i < image_ids.size(); ++i) {
    Timer timer;
    timer.Start();
    LOG(INFO) << StringPrintf(
        "Indexing image [%d/%d]", i + 1, image_ids.size());
    auto keypoints = *cache_->GetKeypoints(image_ids[i]);
    auto descriptors = *cache_->GetDescriptors(image_ids[i]);
    if (visual_index_ == nullptr) {
      visual_index_ = retrieval::VisualIndex::Read(
          options_.vocab_tree_path.empty()
              ? GetVocabTreeUriForFeatureType(descriptors.type)
              : options_.vocab_tree_path);
    }
    if (options_.max_num_features > 0 &&
        descriptors.data.rows() > options_.max_num_features) {
      ExtractTopScaleFeatures(
          &keypoints, &descriptors, options_.max_num_features);
    }
    visual_index_->Add(
        index_options, image_ids[i], keypoints, descriptors.ToFloat());
    LOG(INFO) << StringPrintf(" in %.3fs", timer.ElapsedSeconds());
  }

  // Compute the TF-IDF weights, etc.
  visual_index_->Prepare();
}

visual_index_->Add()函数的主体在visual_index.cc文件中。该函数的主要作用是将单张图像的特征描述添加到视觉索引中,建立图像特征与视觉单词的映射关系。这是词汇树图像检索系统的索引过程。主要注意其中word_ids.

复制代码
void Add(const IndexOptions& options,
           int image_id,
           const FeatureKeypoints& keypoints,
           const FeatureDescriptorsFloat& descriptors) override {
    THROW_CHECK_EQ(descriptors.data.cols(), kDescDim);
    THROW_CHECK_EQ(keypoints.size(), descriptors.data.rows());
    THROW_CHECK_EQ(descriptors.type, feature_type_)
        << "Feature type mismatch: index was built with "
        << FeatureExtractorTypeToString(feature_type_) << " but received "
        << FeatureExtractorTypeToString(descriptors.type);

    // If the image is already indexed, do nothing.
    if (IsImageIndexed(image_id)) {
      return;
    }

    image_ids_.insert(image_id);

    prepared_ = false;

    if (descriptors.data.rows() == 0) {
      return;
    }

    const WordIds word_ids = FindWordIds(descriptors.data,
                                         options.num_neighbors,
                                         options.num_checks,
                                         options.num_threads);

    for (Eigen::Index i = 0; i < descriptors.data.rows(); ++i) {
      const auto& descriptor = descriptors.data.row(i);

      typename InvertedIndexType::GeomType geometry;
      geometry.x = keypoints[i].x;
      geometry.y = keypoints[i].y;
      geometry.scale = keypoints[i].ComputeScale();
      geometry.orientation = keypoints[i].ComputeOrientation();

      for (int n = 0; n < options.num_neighbors; ++n) {
        const int word_id = word_ids(i, n);
        if (word_id != InvertedIndexType::kInvalidWordId) {
          inverted_index_.AddEntry(image_id, word_id, i, descriptor, geometry);
        }
      }
    }
  }

AddEntry()的源码如下。

复制代码
template <typename kDescType, int kDescDim, int kEmbeddingDim>
void InvertedIndex<kDescType, kDescDim, kEmbeddingDim>::AddEntry(
    const int image_id,
    const int64_t word_id,
    typename DescType::Index feature_idx,
    const DescType& descriptor,
    const GeomType& geometry) {
  THROW_CHECK_EQ(descriptor.size(), kDescDim);
  const ProjDescType proj_desc =
      proj_matrix_ * descriptor.transpose().template cast<float>();
  inverted_files_.at(word_id).AddEntry(
      image_id, feature_idx, proj_desc, geometry);
}

template <int kEmbeddingDim>
void InvertedFile<kEmbeddingDim>::AddEntry(const int image_id,
                                           typename DescType::Index feature_idx,
                                           const DescType& descriptor,
                                           const GeomType& geometry) {
  THROW_CHECK_GE(image_id, 0);
  THROW_CHECK_EQ(descriptor.size(), kEmbeddingDim);
  EntryType entry;
  entry.image_id = image_id;
  entry.feature_idx = feature_idx;
  entry.geometry = geometry;
  ConvertToBinaryDescriptor(descriptor, &entry.descriptor);
  entries_.push_back(entry);
  status_ &= ~kEntriesSorted;
}

最后都放入到entries_中。entries_可以理解为集成了描述子+key+id的结构体。

复制代码
 std::vector<EntryType> entries_;

template <int kEmbeddingDim>
class InvertedFile {
 public:
  using DescType = Eigen::VectorXf;
  using GeomType = FeatureGeometry;
  using EntryType = InvertedFileEntry<kEmbeddingDim>;

  enum Status : uint8_t {
    kUnusable = 0x00,
    kHasEmbedding = 0x01,
    kEntriesSorted = 0x02,
    kUsable = 0x03,
  };

template <int N>
struct InvertedFileEntry {
  void Read(std::istream* in);
  void Write(std::ostream* out) const;

  // The identifier of the image this entry is associated with.
  int image_id = -1;

  // The index of the feature within the image's keypoints list.
  int feature_idx = -1;

  // The geometry of the feature, used for spatial verification.
  FeatureGeometry geometry;

  // The binary signature in the Hamming embedding.
  std::bitset<N> descriptor;
};
相关推荐
Slow菜鸟13 小时前
AI学习篇(三) | AI效率工具指南(2026年)
人工智能·学习
qcwl6613 小时前
深入理解Linux进程与内存 学习笔记#4
笔记·学习
蒸蒸yyyyzwd13 小时前
后端学习笔记 day4
linux·笔记·学习
笨笨饿15 小时前
20_Git 仓库使用手册 - 初学者指南
c语言·开发语言·嵌入式硬件·mcu·学习
cqbelt16 小时前
Python 并发编程实战学习笔记
笔记·python·学习
智算菩萨16 小时前
【论文复现】Applied Intelligence 2025:Auto-PU正例无标签学习的自动化实现与GPT-5.4辅助编程实战
论文阅读·python·gpt·学习·自动化·复现
老神在在00116 小时前
【Selenium 自动化精讲】浏览器弹窗与登录界面的本质区别 & 实操指南
javascript·学习·selenium·测试工具·自动化
·醉挽清风·17 小时前
学习笔记—Linux—信号阻塞&信号捕捉
linux·笔记·学习
AnalogElectronic18 小时前
uniapp学习5,兼容微信小程序的俄罗斯方块游戏
学习·微信小程序·uni-app
知识分享小能手18 小时前
MongoDB入门学习教程,从入门到精通,MongoDB应用程序设计知识点梳理(9)
数据库·学习·mongodb