55 const std::string& database_path,
const int max_num_images) {
56 Database database(database_path);
57 DatabaseTransaction database_transaction(&database);
59 const std::vector<Image> images = database.ReadAllImages();
63 std::vector<size_t> image_idxs;
64 size_t num_descriptors = 0;
65 if (max_num_images < 0) {
67 image_idxs.resize(images.size());
68 std::iota(image_idxs.begin(), image_idxs.end(), 0);
69 num_descriptors = database.NumDescriptors();
72 CHECK_LE(max_num_images, images.size());
73 RandomSampler random_sampler(max_num_images);
74 random_sampler.Initialize(images.size());
75 image_idxs = random_sampler.Sample();
76 for (
const auto image_idx : image_idxs) {
77 const auto&
image = images.at(image_idx);
78 num_descriptors += database.NumDescriptorsForImage(
image.ImageId());
84 size_t descriptor_row = 0;
85 for (
const auto image_idx : image_idxs) {
86 const auto&
image = images.at(image_idx);
88 database.ReadDescriptors(
image.ImageId());
89 descriptors.block(descriptor_row, 0, image_descriptors.rows(), 128) =
91 descriptor_row += image_descriptors.rows();
94 CHECK_EQ(descriptor_row, num_descriptors);
99 std::vector<Image> ReadVocabTreeRetrievalImageList(
const std::string&
path,
100 Database* database) {
101 std::vector<Image> images;
103 images.reserve(database->NumImages());
104 for (
const auto&
image : database->ReadAllImages()) {
105 images.push_back(
image);
108 DatabaseTransaction database_transaction(database);
111 images.reserve(image_names.size());
112 for (
const auto& image_name : image_names) {
113 const auto image = database->ReadImageWithName(image_name);
115 images.push_back(
image);
126 int max_num_images = -1;
136 options.
Parse(argc, argv);
140 std::cout <<
"Loading descriptors..." <<
std::endl;
142 LoadRandomDatabaseDescriptors(*options.
database_path, max_num_images);
143 std::cout <<
" => Loaded a total of " <<
descriptors.rows() <<
" descriptors"
146 std::cout <<
"Building index for visual words..." <<
std::endl;
148 std::cout <<
" => Quantized descriptor space using "
151 std::cout <<
"Saving index to file..." <<
std::endl;
152 visual_index.
Write(vocab_tree_path);
159 std::string database_image_list_path;
160 std::string query_image_list_path;
161 std::string output_index_path;
163 int max_num_features = -1;
169 &database_image_list_path);
178 options.
Parse(argc, argv);
181 std::string resolved_vocab_tree_path =
184 visual_index.
Read(resolved_vocab_tree_path);
188 const auto database_images =
189 ReadVocabTreeRetrievalImageList(database_image_list_path, &database);
190 const auto query_images =
191 (!query_image_list_path.empty() || output_index_path.empty())
192 ? ReadVocabTreeRetrievalImageList(query_image_list_path, &database)
193 : std::vector<Image>();
199 for (
size_t i = 0; i < database_images.size(); ++i) {
203 std::cout <<
StringPrintf(
"Indexing image [%d/%d]", i + 1,
204 database_images.size())
207 if (visual_index.
ImageIndexed(database_images[i].ImageId())) {
212 auto keypoints = database.
ReadKeypoints(database_images[i].ImageId());
214 if (max_num_features > 0 &&
descriptors.rows() > max_num_features) {
219 database_images[i].ImageId(), keypoints,
descriptors);
229 if (!output_index_path.empty()) {
230 visual_index.
Write(output_index_path);
233 if (query_images.empty()) {
241 std::unordered_map<image_t, const Image*> image_id_to_image;
242 image_id_to_image.reserve(database_images.size());
243 for (
const auto&
image : database_images) {
244 image_id_to_image.emplace(
image.ImageId(), &
image);
247 for (
size_t i = 0; i < query_images.size(); ++i) {
251 std::cout <<
StringPrintf(
"Querying for image %s [%d/%d]",
252 query_images[i].Name().c_str(), i + 1,
256 auto keypoints = database.
ReadKeypoints(query_images[i].ImageId());
258 if (max_num_features > 0 &&
descriptors.rows() > max_num_features) {
262 std::vector<retrieval::ImageScore> image_scores;
266 for (
const auto& image_score : image_scores) {
267 const auto&
image = *image_id_to_image.at(image_score.image_id);
268 std::cout <<
StringPrintf(
" image_id=%d, image_name=%s, score=%f",
269 image_score.image_id,
image.Name().c_str(),
std::shared_ptr< core::Tensor > image
FeatureDescriptors ReadDescriptors(const image_t image_id) const
FeatureKeypoints ReadKeypoints(const image_t image_id) const
void AddRequiredOption(const std::string &name, T *option, const std::string &help_text="")
void AddDefaultOption(const std::string &name, T *option, const std::string &help_text="")
std::shared_ptr< std::string > database_path
void AddDatabaseOptions()
void Parse(const int argc, char **argv)
double ElapsedSeconds() const
bool ImageIndexed(const int image_id) const
void Read(const std::string &path)
void Add(const IndexOptions &options, const int image_id, const GeomType &geometries, const DescType &descriptors)
void Build(const BuildOptions &options, const DescType &descriptors)
void Query(const QueryOptions &options, const DescType &descriptors, std::vector< ImageScore > *image_scores) const
size_t NumVisualWords() const
void Write(const std::string &path)
QTextStream & endl(QTextStream &stream)
static const std::string path
static const std::string kDefaultVocabTreeUri
void ExtractTopScaleFeatures(FeatureKeypoints *keypoints, FeatureDescriptors *descriptors, const size_t num_features)
int RunVocabTreeRetriever(int argc, char **argv)
Eigen::Matrix< uint8_t, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > FeatureDescriptors
int RunVocabTreeBuilder(int argc, char **argv)
std::vector< std::string > ReadTextFileLines(const std::string &path)
std::string StringPrintf(const char *format,...)
const image_t kInvalidImageId
std::filesystem::path MaybeDownloadAndCacheFile(const std::string &uri)
int num_images_after_verification