| 389 | } |
| 390 | |
| 391 | void VocabTreePairGenerator::Query(const image_t image_id) { |
| 392 | Retrieval retrieval; |
| 393 | retrieval.image_id = image_id; |
| 394 | |
| 395 | // Each query must push exactly one result, because the consuming Next() pops |
| 396 | // exactly one result per query. If a query fails (e.g., due to corrupt |
| 397 | // features or an out-of-memory error during spatial verification), we still |
| 398 | // push an empty result and skip retrieval for this image. Otherwise, the |
| 399 | // consumer would block indefinitely waiting for a result that never arrives. |
| 400 | try { |
| 401 | auto keypoints = *cache_->GetKeypoints(image_id); |
| 402 | auto descriptors = *cache_->GetDescriptors(image_id); |
| 403 | if (options_.max_num_features > 0 && |
| 404 | descriptors.data.rows() > options_.max_num_features) { |
| 405 | ExtractTopScaleFeatures( |
| 406 | &keypoints, &descriptors, options_.max_num_features); |
| 407 | } |
| 408 | |
| 409 | visual_index_->Query(query_options_, |
| 410 | keypoints, |
| 411 | descriptors.ToFloat(), |
| 412 | &retrieval.image_scores); |
| 413 | } catch (const std::exception& error) { |
| 414 | LOG(ERROR) << "Failed to query image " << image_id |
| 415 | << " against vocabulary tree, skipping: " << error.what(); |
| 416 | retrieval.image_scores.clear(); |
| 417 | } |
| 418 | |
| 419 | THROW_CHECK(queue_.Push(std::move(retrieval))); |
| 420 | } |
| 421 | |
| 422 | SequentialPairGenerator::SequentialPairGenerator( |
| 423 | const SequentialPairingOptions& options, |
no test coverage detected