From 0e073978b9151e5f5e79ae315f9320f8260211d0 Mon Sep 17 00:00:00 2001 From: Vladyslav Usenko Date: Fri, 7 Jun 2019 12:42:18 +0000 Subject: [PATCH] Switched to HashBow instead of DBoW3 --- CMakeLists.txt | 5 +- data/tumvi_512_config.json | 3 +- doc/VioMapping.md | 6 +- include/basalt/hash_bow/hash_bow.h | 159 +++ include/basalt/utils/common_types.h | 11 +- include/basalt/utils/keypoints.h | 5 - include/basalt/utils/vio_config.h | 1 + include/basalt/vi_estimator/nfr_mapper.h | 18 +- scripts/eval_full/run_evaluations.sh | 2 +- src/mapper.cpp | 5 +- src/utils/keypoints.cpp | 10 +- src/utils/vio_config.cpp | 4 +- src/vi_estimator/nfr_mapper.cpp | 79 +- thirdparty/CMakeLists.txt | 1 - thirdparty/DBoW3/CMakeLists.txt | 15 - thirdparty/DBoW3/LICENSE.txt | 44 - thirdparty/DBoW3/README.txt | 7 - thirdparty/DBoW3/src/BowVector.cpp | 136 -- thirdparty/DBoW3/src/BowVector.h | 117 -- thirdparty/DBoW3/src/CMakeLists.txt | 20 - thirdparty/DBoW3/src/DBoW3.h | 68 - thirdparty/DBoW3/src/Database.cpp | 855 ------------ thirdparty/DBoW3/src/Database.h | 354 ----- thirdparty/DBoW3/src/DescManip.cpp | 239 ---- thirdparty/DBoW3/src/DescManip.h | 99 -- thirdparty/DBoW3/src/FeatureVector.cpp | 85 -- thirdparty/DBoW3/src/FeatureVector.h | 55 - thirdparty/DBoW3/src/QueryResults.cpp | 63 - thirdparty/DBoW3/src/QueryResults.h | 205 --- thirdparty/DBoW3/src/ScoringObject.cpp | 315 ----- thirdparty/DBoW3/src/ScoringObject.h | 95 -- thirdparty/DBoW3/src/Vocabulary.cpp | 1558 ---------------------- thirdparty/DBoW3/src/Vocabulary.h | 468 ------- thirdparty/DBoW3/src/exports.h | 51 - thirdparty/DBoW3/src/quicklz.c | 848 ------------ thirdparty/DBoW3/src/quicklz.h | 150 --- thirdparty/DBoW3/src/timers.h | 159 --- 37 files changed, 220 insertions(+), 6095 deletions(-) create mode 100644 include/basalt/hash_bow/hash_bow.h delete mode 100644 thirdparty/DBoW3/CMakeLists.txt delete mode 100644 thirdparty/DBoW3/LICENSE.txt delete mode 100644 thirdparty/DBoW3/README.txt delete mode 100644 thirdparty/DBoW3/src/BowVector.cpp delete mode 100644 thirdparty/DBoW3/src/BowVector.h delete mode 100644 thirdparty/DBoW3/src/CMakeLists.txt delete mode 100644 thirdparty/DBoW3/src/DBoW3.h delete mode 100644 thirdparty/DBoW3/src/Database.cpp delete mode 100644 thirdparty/DBoW3/src/Database.h delete mode 100644 thirdparty/DBoW3/src/DescManip.cpp delete mode 100644 thirdparty/DBoW3/src/DescManip.h delete mode 100644 thirdparty/DBoW3/src/FeatureVector.cpp delete mode 100644 thirdparty/DBoW3/src/FeatureVector.h delete mode 100644 thirdparty/DBoW3/src/QueryResults.cpp delete mode 100644 thirdparty/DBoW3/src/QueryResults.h delete mode 100644 thirdparty/DBoW3/src/ScoringObject.cpp delete mode 100644 thirdparty/DBoW3/src/ScoringObject.h delete mode 100644 thirdparty/DBoW3/src/Vocabulary.cpp delete mode 100644 thirdparty/DBoW3/src/Vocabulary.h delete mode 100644 thirdparty/DBoW3/src/exports.h delete mode 100644 thirdparty/DBoW3/src/quicklz.c delete mode 100644 thirdparty/DBoW3/src/quicklz.h delete mode 100644 thirdparty/DBoW3/src/timers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 11f4730..80d3c80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,6 @@ include_directories(thirdparty/basalt-headers/thirdparty/cereal/include) include_directories(thirdparty/basalt-headers/include) include_directories(thirdparty/CLI11/include) include_directories(thirdparty/fast/include) -include_directories(thirdparty/DBoW3/src/) include_directories(include) @@ -215,7 +214,7 @@ add_library(basalt SHARED src/utils/keypoints.cpp) -target_link_libraries(basalt PUBLIC ${TBB_LIBRARIES} ${STD_CXX_FS} ${OpenCV_LIBS} pangolin PRIVATE rosbag apriltag opengv DBoW3) +target_link_libraries(basalt PUBLIC ${TBB_LIBRARIES} ${STD_CXX_FS} ${OpenCV_LIBS} pangolin PRIVATE rosbag apriltag opengv) add_executable(basalt_calibrate src/calibrate.cpp) @@ -259,7 +258,7 @@ install(TARGETS basalt_calibrate basalt_calibrate_imu basalt_vio_sim basalt_mapp ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) file(GLOB CONFIG_FILES "${CMAKE_CURRENT_SOURCE_DIR}/data/*.json") -install(FILES ${CONFIG_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/data/basalt-data/orbvoc.dbow3 +install(FILES ${CONFIG_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/etc/basalt) diff --git a/data/tumvi_512_config.json b/data/tumvi_512_config.json index 5f189c4..a1219d1 100644 --- a/data/tumvi_512_config.json +++ b/data/tumvi_512_config.json @@ -25,6 +25,7 @@ "config.mapper_ransac_threshold": 5e-5, "config.mapper_min_track_length": 5, "config.mapper_max_hamming_distance": 70, - "config.mapper_second_best_test_ratio": 1.2 + "config.mapper_second_best_test_ratio": 1.2, + "config.mapper_bow_num_bits": 16 } } diff --git a/doc/VioMapping.md b/doc/VioMapping.md index ac905ae..3d99edd 100644 --- a/doc/VioMapping.md +++ b/doc/VioMapping.md @@ -47,9 +47,9 @@ For evaluation the button `align_svd` is used. It aligns the GT trajectory with ### Visual-inertial mapping To run the mapping tool execute the following command: ``` -basalt_mapper --cam-calib /usr/etc/basalt/euroc_ds_calib.json --marg-data euroc_marg_data --vocabulary /usr/etc/basalt/orbvoc.dbow3 +basalt_mapper --cam-calib /usr/etc/basalt/euroc_ds_calib.json --marg-data euroc_marg_data ``` -Here `--marg-data` is the folder with the results from VIO and `--vocabulary` is the path to DBoW3 vocabulary. +Here `--marg-data` is the folder with the results from VIO. This opens the GUI and extracts non-linear factors from the marginalization data. ![MH_05_MAPPING](/doc/img/MH_05_MAPPING.png) @@ -112,6 +112,6 @@ basalt_vio --dataset-path dataset-magistrale1_512_16/ --cam-calib /usr/etc/basal ### Visual-inertial mapping To run the mapping tool execute the following command: ``` -basalt_mapper --cam-calib /usr/etc/basalt/tumvi_512_ds_calib.json --marg-data tumvi_marg_data --vocabulary /usr/etc/basalt/orbvoc.dbow3 +basalt_mapper --cam-calib /usr/etc/basalt/tumvi_512_ds_calib.json --marg-data tumvi_marg_data ``` ![magistrale1_mapping](/doc/img/magistrale1_mapping.png) diff --git a/include/basalt/hash_bow/hash_bow.h b/include/basalt/hash_bow/hash_bow.h new file mode 100644 index 0000000..0c658d2 --- /dev/null +++ b/include/basalt/hash_bow/hash_bow.h @@ -0,0 +1,159 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include + +namespace basalt { + +template +class HashBow { + public: + HashBow(size_t num_bits) : num_bits(num_bits < 32 ? num_bits : 32) { + static_assert(N < 512, + "This implementation of HashBow only supports the descriptor " + "length below 512."); + } + + inline FeatureHash compute_hash(const std::bitset& descriptor) const { + FeatureHash res; + for (size_t i = 0; i < num_bits; ++i) { + res[i] = descriptor[word_bit_permutation[i]]; + } + return res; + } + + inline void compute_bow(const std::vector>& descriptors, + std::vector& hashes, + HashBowVector& bow_vector) const { + size_t descriptors_size = descriptors.size(); + hashes.resize(descriptors_size); + + bow_vector.clear(); + bow_vector.reserve(descriptors_size); + + for (size_t i = 0; i < descriptors_size; i++) { + hashes[i] = compute_hash(descriptors[i]); + + FeatureHash bow_word = hashes[i]; + bow_vector[bow_word] += 1.0; + } + + double sum_squared = 0; + for (const auto& kv : bow_vector) { + sum_squared += kv.second * kv.second; + } + + double norm = std::sqrt(sum_squared); + + for (auto& kv : bow_vector) { + kv.second /= norm; + } + } + + inline void add_to_database(const TimeCamId& tcid, + const HashBowVector& bow_vector) { + for (const auto& kv : bow_vector) { + std::pair p = std::make_pair(tcid, kv.second); + inverted_index.emplace(kv.first, p); + } + } + + inline void querry_database( + const HashBowVector& bow_vector, size_t num_results, + std::vector>& results, + const int64_t* max_t_ns = nullptr) const { + results.clear(); + + std::unordered_map> scores; + + for (const auto& kv : bow_vector) { + const auto range_it = inverted_index.equal_range(kv.first); + + for (auto it = range_it.first; it != range_it.second; ++it) { + // if there is a maximum query time select only the frames that have + // timestamp below max_t_ns + if (!max_t_ns || it->second.first.first < (*max_t_ns)) + scores[it->second.first] += kv.second * it->second.second; + } + } + + results.reserve(scores.size()); + + for (const auto& kv : scores) results.emplace_back(kv); + + std::sort(results.begin(), results.end(), + [](const auto& a, const auto& b) { return a.second > b.second; }); + + if (results.size() > num_results) results.resize(num_results); + } + + protected: + constexpr static const size_t random_bit_permutation[512] = { + 484, 458, 288, 170, 215, 424, 41, 38, 293, 96, 172, 428, 508, 52, 370, + 1, 182, 472, 89, 339, 273, 234, 98, 217, 73, 195, 307, 306, 113, 429, + 161, 443, 364, 439, 301, 247, 325, 24, 490, 366, 75, 7, 464, 232, 49, + 196, 144, 69, 470, 387, 3, 86, 361, 313, 396, 356, 94, 201, 291, 360, + 107, 251, 413, 393, 296, 124, 308, 146, 298, 160, 121, 302, 151, 345, 336, + 26, 63, 238, 79, 267, 262, 437, 433, 350, 53, 134, 194, 452, 114, 54, + 82, 214, 191, 242, 482, 37, 432, 311, 130, 460, 422, 221, 271, 192, 474, + 46, 289, 34, 20, 95, 463, 499, 159, 272, 481, 129, 448, 173, 323, 258, + 416, 229, 334, 510, 461, 263, 362, 346, 39, 500, 381, 401, 492, 299, 33, + 169, 241, 11, 254, 449, 199, 486, 400, 365, 70, 436, 108, 19, 233, 505, + 152, 6, 480, 468, 278, 426, 253, 471, 328, 327, 139, 29, 27, 488, 332, + 290, 412, 164, 259, 352, 222, 186, 32, 319, 410, 211, 405, 187, 213, 507, + 205, 395, 62, 178, 36, 140, 87, 491, 351, 450, 314, 77, 342, 132, 133, + 477, 103, 389, 206, 197, 324, 485, 425, 297, 231, 123, 447, 126, 9, 64, + 181, 40, 14, 5, 261, 431, 333, 223, 4, 138, 220, 76, 44, 300, 331, + 78, 193, 497, 403, 435, 275, 147, 66, 368, 141, 451, 225, 250, 61, 18, + 444, 208, 380, 109, 255, 337, 372, 212, 359, 457, 31, 398, 354, 219, 117, + 248, 392, 203, 88, 479, 509, 149, 120, 145, 51, 15, 367, 190, 163, 417, + 454, 329, 183, 390, 83, 404, 249, 81, 264, 445, 317, 179, 244, 473, 71, + 111, 118, 209, 171, 224, 459, 446, 104, 13, 377, 200, 414, 198, 420, 226, + 153, 384, 25, 441, 305, 338, 316, 483, 184, 402, 48, 131, 502, 252, 469, + 12, 167, 243, 373, 35, 127, 341, 455, 379, 210, 340, 128, 430, 57, 434, + 330, 415, 494, 142, 355, 282, 322, 65, 105, 421, 68, 409, 466, 245, 59, + 269, 112, 386, 257, 256, 93, 174, 16, 60, 143, 343, 115, 506, 276, 10, + 496, 489, 235, 47, 136, 22, 165, 204, 42, 465, 440, 498, 312, 504, 116, + 419, 185, 303, 218, 353, 283, 374, 2, 177, 137, 240, 102, 309, 292, 85, + 453, 388, 397, 438, 281, 279, 442, 110, 55, 101, 100, 150, 375, 406, 157, + 23, 0, 237, 376, 236, 216, 8, 154, 91, 456, 423, 176, 427, 284, 30, + 84, 349, 335, 56, 270, 227, 286, 168, 239, 122, 478, 162, 475, 166, 17, + 348, 285, 175, 155, 266, 382, 304, 268, 180, 295, 125, 371, 467, 277, 294, + 58, 347, 72, 280, 50, 287, 511, 80, 260, 326, 495, 45, 106, 399, 369, + 503, 357, 315, 418, 487, 99, 43, 320, 188, 407, 246, 501, 119, 158, 274, + 408, 230, 358, 90, 148, 363, 207, 344, 265, 462, 189, 310, 385, 67, 28, + 383, 378, 156, 394, 97, 476, 493, 321, 411, 228, 21, 391, 202, 92, 318, + 74, 135}; + + constexpr static std::array + compute_permutation() { + std::array res{}; + size_t j = 0; + for (size_t i = 0; i < 512 && j < FEATURE_HASH_MAX_SIZE; ++i) { + if (random_bit_permutation[i] < N) { + res[j] = random_bit_permutation[i]; + j++; + } + } + + return res; + } + + constexpr static const std::array + word_bit_permutation = compute_permutation(); + + size_t num_bits; + + tbb::concurrent_unordered_multimap, + std::hash> + inverted_index; +}; + +} // namespace basalt diff --git a/include/basalt/utils/common_types.h b/include/basalt/utils/common_types.h index 00526bf..e3d9a2e 100644 --- a/include/basalt/utils/common_types.h +++ b/include/basalt/utils/common_types.h @@ -48,6 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace basalt { +/// ids for 2D features detected in images +using FeatureId = int; + /// identifies a frame of multiple images (stereo pair) using FrameId = int64_t; @@ -61,8 +64,9 @@ inline std::ostream& operator<<(std::ostream& os, const TimeCamId& tcid) { return os; } -/// ids for 2D features detected in images -using FeatureId = int; +constexpr static const size_t FEATURE_HASH_MAX_SIZE = 32; +using FeatureHash = std::bitset; +using HashBowVector = std::unordered_map; /// keypoint positions and descriptors for an image struct KeypointsData { @@ -77,6 +81,9 @@ struct KeypointsData { std::vector> corner_descriptors; Eigen::vector corners_3d; + + std::vector hashes; + HashBowVector bow_vector; }; /// feature corners is a collection of { imageId => KeypointsData } diff --git a/include/basalt/utils/keypoints.h b/include/basalt/utils/keypoints.h index d37dd5a..1f3a360 100644 --- a/include/basalt/utils/keypoints.h +++ b/include/basalt/utils/keypoints.h @@ -65,11 +65,6 @@ void computeAngles(const basalt::Image& img_raw, void computeDescriptors(const basalt::Image& img_raw, KeypointsData& kd); -void matchFastHelper(const std::vector>& corner_descriptors_1, - const std::vector>& corner_descriptors_2, - std::map& matches, int threshold, - double test_dist); - void matchDescriptors(const std::vector>& corner_descriptors_1, const std::vector>& corner_descriptors_2, std::vector>& matches, int threshold, diff --git a/include/basalt/utils/vio_config.h b/include/basalt/utils/vio_config.h index abb8477..9d017ec 100644 --- a/include/basalt/utils/vio_config.h +++ b/include/basalt/utils/vio_config.h @@ -71,5 +71,6 @@ struct VioConfig { double mapper_min_track_length; double mapper_max_hamming_distance; double mapper_second_best_test_ratio; + int mapper_bow_num_bits; }; } // namespace basalt diff --git a/include/basalt/vi_estimator/nfr_mapper.h b/include/basalt/vi_estimator/nfr_mapper.h index d1710ab..f15be69 100644 --- a/include/basalt/vi_estimator/nfr_mapper.h +++ b/include/basalt/vi_estimator/nfr_mapper.h @@ -49,12 +49,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include - -#include - namespace basalt { +template +class HashBow; + class NfrMapper : public BundleAdjustmentBase { public: using Ptr = std::shared_ptr; @@ -164,8 +163,7 @@ class NfrMapper : public BundleAdjustmentBase { const Eigen::map* frame_poses; }; - NfrMapper(const basalt::Calibration& calib, const VioConfig& config, - const std::string& vocabulary = ""); + NfrMapper(const basalt::Calibration& calib, const VioConfig& config); void addMargData(basalt::MargData::Ptr& data); @@ -199,19 +197,13 @@ class NfrMapper : public BundleAdjustmentBase { std::unordered_map img_data; - tbb::concurrent_unordered_map< - TimeCamId, std::pair> - bow_data; - Corners feature_corners; Matches feature_matches; FeatureTracks feature_tracks; - DBoW3::Database bow_database; - - std::unordered_map bow_id_to_tcid; + std::shared_ptr> hash_bow_database; VioConfig config; }; diff --git a/scripts/eval_full/run_evaluations.sh b/scripts/eval_full/run_evaluations.sh index 996084d..ae04290 100755 --- a/scripts/eval_full/run_evaluations.sh +++ b/scripts/eval_full/run_evaluations.sh @@ -19,7 +19,7 @@ for d in ${DATASETS[$CI_NODE_INDEX-1]}; do --result-path $folder_name/vio_$d --marg-data eval_tmp_marg_data basalt_mapper --show-gui 0 --cam-calib /usr/etc/basalt/euroc_eucm_calib.json --marg-data eval_tmp_marg_data \ - --vocabulary /usr/etc/basalt/orbvoc.dbow3 --result-path $folder_name/mapper_$d + --result-path $folder_name/mapper_$d rm -rf eval_tmp_marg_data done diff --git a/src/mapper.cpp b/src/mapper.cpp index fa6ae57..11aa30f 100644 --- a/src/mapper.cpp +++ b/src/mapper.cpp @@ -140,7 +140,6 @@ Button align_btn("ui.aling_svd", &alignButton); pangolin::OpenGlRenderState camera; std::string marg_data_path; -std::string vocabulary; int main(int argc, char** argv) { bool show_gui = true; @@ -160,8 +159,6 @@ int main(int argc, char** argv) { app.add_option("--config-path", config_path, "Path to config file."); - app.add_option("--vocabulary", vocabulary, "Path to vocabulary.")->required(); - app.add_option("--result-path", result_path, "Path to config file."); try { @@ -537,7 +534,7 @@ void load_data(const std::string& calib_path, const std::string& cache_path) { } } - nrf_mapper.reset(new basalt::NfrMapper(calib, vio_config, vocabulary)); + nrf_mapper.reset(new basalt::NfrMapper(calib, vio_config)); basalt::MargDataLoader mdl; tbb::concurrent_bounded_queue marg_queue; diff --git a/src/utils/keypoints.cpp b/src/utils/keypoints.cpp index 9d7e768..2724233 100644 --- a/src/utils/keypoints.cpp +++ b/src/utils/keypoints.cpp @@ -33,6 +33,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include + #include #include @@ -305,7 +307,7 @@ void computeDescriptors(const basalt::Image& img_raw, void matchFastHelper(const std::vector>& corner_descriptors_1, const std::vector>& corner_descriptors_2, - std::map& matches, int threshold, + std::unordered_map& matches, int threshold, double test_dist) { matches.clear(); @@ -338,7 +340,7 @@ void matchDescriptors(const std::vector>& corner_descriptors_1, double dist_2_best) { matches.clear(); - std::map matches_1_2, matches_2_1; + std::unordered_map matches_1_2, matches_2_1; matchFastHelper(corner_descriptors_1, corner_descriptors_2, matches_1_2, threshold, dist_2_best); matchFastHelper(corner_descriptors_2, corner_descriptors_1, matches_2_1, @@ -397,8 +399,8 @@ void findInliersRansac(const KeypointsData& kd1, const KeypointsData& kd2, ransac.sac_model_->selectWithinDistance(nonlinear_transformation, ransac.threshold_, ransac.inliers_); - // Sanity check if the number of inliers decreased, but only warn if it is by - // 3 or more, since some small fluctuation is expected. + // Sanity check if the number of inliers decreased, but only warn if it is + // by 3 or more, since some small fluctuation is expected. if (ransac.inliers_.size() + 2 < num_inliers_ransac) { std::cout << "Warning: non-linear refinement reduced the relative pose " "ransac inlier count from " diff --git a/src/utils/vio_config.cpp b/src/utils/vio_config.cpp index d0ce423..d684e05 100644 --- a/src/utils/vio_config.cpp +++ b/src/utils/vio_config.cpp @@ -65,12 +65,13 @@ VioConfig::VioConfig() { mapper_obs_huber_thresh = 1.5; mapper_detection_num_points = 800; mapper_num_frames_to_match = 30; - mapper_frames_to_match_threshold = 0.3; + mapper_frames_to_match_threshold = 0.04; mapper_min_matches = 20; mapper_ransac_threshold = 5e-5; mapper_min_track_length = 5; mapper_max_hamming_distance = 70; mapper_second_best_test_ratio = 1.2; + mapper_bow_num_bits = 16; } void VioConfig::save(const std::string& filename) { @@ -126,5 +127,6 @@ void serialize(Archive& ar, basalt::VioConfig& config) { ar(CEREAL_NVP(config.mapper_min_track_length)); ar(CEREAL_NVP(config.mapper_max_hamming_distance)); ar(CEREAL_NVP(config.mapper_second_best_test_ratio)); + ar(CEREAL_NVP(config.mapper_bow_num_bits)); } } // namespace cereal diff --git a/src/vi_estimator/nfr_mapper.cpp b/src/vi_estimator/nfr_mapper.cpp index 863ce72..c84655a 100644 --- a/src/vi_estimator/nfr_mapper.cpp +++ b/src/vi_estimator/nfr_mapper.cpp @@ -39,21 +39,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include +#include namespace basalt { -NfrMapper::NfrMapper(const Calibration& calib, const VioConfig& config, - const std::string& vocabulary) +NfrMapper::NfrMapper(const Calibration& calib, const VioConfig& config) : config(config) { this->calib = calib; this->obs_std_dev = config.mapper_obs_std_dev; this->huber_thresh = config.mapper_obs_huber_thresh; - if (!vocabulary.empty()) { - DBoW3::Vocabulary voc(vocabulary); - bow_database.setVocabulary(voc); - } + hash_bow_database.reset(new HashBow<256>(config.mapper_bow_num_bits)); } void NfrMapper::addMargData(MargData::Ptr& data) { @@ -378,7 +374,7 @@ void NfrMapper::detect_keypoints() { if (kv->second.get()) { for (size_t i = 0; i < kv->second->img_data.size(); i++) { TimeCamId tcid(kv->first, i); - KeypointsData kd; + KeypointsData& kd = feature_corners[tcid]; if (!kv->second->img_data[i].img.get()) continue; @@ -394,18 +390,13 @@ void NfrMapper::detect_keypoints() { calib.intrinsics[tcid.second].unproject(kd.corners, kd.corners_3d, success); - feature_corners[tcid] = kd; + hash_bow_database->compute_bow(kd.corner_descriptors, kd.hashes, + kd.bow_vector); - auto& bow = bow_data[tcid]; + hash_bow_database->add_to_database(tcid, kd.bow_vector); - if (bow_database.usingDirectIndex()) { - bow_database.getVocabulary()->transform( - kd.corner_descriptors, bow.first, bow.second, - bow_database.getDirectIndexLevels()); - } else { - bow_database.getVocabulary()->transform(kd.corner_descriptors, - bow.first); - } + // std::cout << "bow " << kd.bow_vector.size() << " desc " + // << kd.corner_descriptors.size() << std::endl; } } } @@ -413,28 +404,13 @@ void NfrMapper::detect_keypoints() { auto t2 = std::chrono::high_resolution_clock::now(); - for (const auto& kv : bow_data) { - int bow_id; - if (bow_database.usingDirectIndex()) { - bow_id = bow_database.add(kv.second.first, kv.second.second); - } else { - bow_id = bow_database.add(kv.second.first); - } - bow_id_to_tcid[bow_id] = kv.first; - } - - auto t3 = std::chrono::high_resolution_clock::now(); - auto elapsed1 = std::chrono::duration_cast(t2 - t1); - auto elapsed2 = - std::chrono::duration_cast(t3 - t2); std::cout << "Processed " << feature_corners.size() << " frames." << std::endl; - std::cout << "Detection time: " << elapsed1.count() * 1e-6 - << "s. Adding to DB time: " << elapsed2.count() * 1e-6 << "s." + std::cout << "Detection time: " << elapsed1.count() * 1e-6 << "s." << std::endl; } @@ -502,33 +478,34 @@ void NfrMapper::match_all() { tbb::blocked_range keys_range(0, keys.size()); auto compute_pairs = [&](const tbb::blocked_range& r) { for (size_t i = r.begin(); i != r.end(); ++i) { - DBoW3::QueryResults q; + const TimeCamId& tcid = keys[i]; + const KeypointsData& kd = feature_corners.at(tcid); - auto it = bow_data.find(keys[i]); + std::vector> results; - if (it != bow_data.end()) { - bow_database.query(it->second.first, q, - config.mapper_num_frames_to_match); + hash_bow_database->querry_database(kd.bow_vector, + config.mapper_num_frames_to_match, + results, &tcid.first); - for (const auto& r : q) { - // Match only previous frames + // std::cout << "Closest frames for " << tcid << ": "; + for (const auto& otcid_score : results) { + // std::cout << otcid_score.first << "(" << otcid_score.second << ") "; + if (otcid_score.first.first != tcid.first && + otcid_score.second > config.mapper_frames_to_match_threshold) { + match_pair m; + m.i = i; + m.j = id_to_key_idx.at(otcid_score.first); + m.score = otcid_score.second; - size_t j = id_to_key_idx.at(bow_id_to_tcid.at(r.Id)); - if (r.Score > config.mapper_frames_to_match_threshold && - keys[i].first < keys[j].first) { - match_pair m; - m.i = i; - m.j = j; - m.score = r.Score; - - ids_to_match.emplace_back(m); - } + ids_to_match.emplace_back(m); } } + // std::cout << std::endl; } }; tbb::parallel_for(keys_range, compute_pairs); + // compute_pairs(keys_range); auto t2 = std::chrono::high_resolution_clock::now(); diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index f683830..3ab7e11 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.10) add_subdirectory(ros EXCLUDE_FROM_ALL) add_subdirectory(apriltag EXCLUDE_FROM_ALL) -add_subdirectory(DBoW3 EXCLUDE_FROM_ALL) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Enable BUILD_SHARED_LIBS") diff --git a/thirdparty/DBoW3/CMakeLists.txt b/thirdparty/DBoW3/CMakeLists.txt deleted file mode 100644 index c03b656..0000000 --- a/thirdparty/DBoW3/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -PROJECT(DBoW3) -set(PROJECT_VERSION "0.0.1") -string(REGEX MATCHALL "[0-9]" PROJECT_VERSION_PARTS "${PROJECT_VERSION}") -list(GET PROJECT_VERSION_PARTS 0 PROJECT_VERSION_MAJOR) -list(GET PROJECT_VERSION_PARTS 1 PROJECT_VERSION_MINOR) -list(GET PROJECT_VERSION_PARTS 2 PROJECT_VERSION_PATCH) -set(PROJECT_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") - -#------------------------------------------------ -# DIRS -#------------------------------------------------ -ADD_SUBDIRECTORY(src) -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) - diff --git a/thirdparty/DBoW3/LICENSE.txt b/thirdparty/DBoW3/LICENSE.txt deleted file mode 100644 index fa723d9..0000000 --- a/thirdparty/DBoW3/LICENSE.txt +++ /dev/null @@ -1,44 +0,0 @@ -DBoW3: bag-of-words library for C++ with generic descriptors - -Copyright (c) 2015 Dorian Galvez-Lopez (Universidad de Zaragoza) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of copyright holders nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -If you use it in an academic work, please cite: - - @ARTICLE{GalvezTRO12, - author={G\'alvez-L\'opez, Dorian and Tard\'os, J. D.}, - journal={IEEE Transactions on Robotics}, - title={Bags of Binary Words for Fast Place Recognition in Image Sequences}, - year={2012}, - month={October}, - volume={28}, - number={5}, - pages={1188--1197}, - doi={10.1109/TRO.2012.2197158}, - ISSN={1552-3098} - } - diff --git a/thirdparty/DBoW3/README.txt b/thirdparty/DBoW3/README.txt deleted file mode 100644 index aab0eae..0000000 --- a/thirdparty/DBoW3/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -You should have received this DBoW3 version along with ORB-SLAM2 (https://github.com/raulmur/ORB_SLAM2). -See the original DBoW3 library at: https://github.com/dorian3d/DBoW3 -All files included in this version are BSD, see LICENSE.txt - -We also use Random.h, Random.cpp, Timestamp.pp and Timestamp.h from DLib/DUtils. -See the original DLib library at: https://github.com/dorian3d/DLib -All files included in this version are BSD, see LICENSE.txt diff --git a/thirdparty/DBoW3/src/BowVector.cpp b/thirdparty/DBoW3/src/BowVector.cpp deleted file mode 100644 index 5af960b..0000000 --- a/thirdparty/DBoW3/src/BowVector.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * File: BowVector.cpp - * Date: March 2011 - * Author: Dorian Galvez-Lopez - * Description: bag of words vector - * License: see the LICENSE.txt file - * - */ - -#include -#include -#include -#include -#include - -#include "BowVector.h" - -namespace DBoW3 { - -// -------------------------------------------------------------------------- - -BowVector::BowVector(void) {} - -// -------------------------------------------------------------------------- - -BowVector::~BowVector(void) {} - -// -------------------------------------------------------------------------- - -void BowVector::addWeight(WordId id, WordValue v) { - BowVector::iterator vit = this->lower_bound(id); - - if (vit != this->end() && !(this->key_comp()(id, vit->first))) { - vit->second += v; - } else { - this->insert(vit, BowVector::value_type(id, v)); - } -} - -// -------------------------------------------------------------------------- - -void BowVector::addIfNotExist(WordId id, WordValue v) { - BowVector::iterator vit = this->lower_bound(id); - - if (vit == this->end() || (this->key_comp()(id, vit->first))) { - this->insert(vit, BowVector::value_type(id, v)); - } -} - -// -------------------------------------------------------------------------- - -void BowVector::normalize(LNorm norm_type) { - double norm = 0.0; - BowVector::iterator it; - - if (norm_type == DBoW3::L1) { - for (it = begin(); it != end(); ++it) norm += fabs(it->second); - } else { - for (it = begin(); it != end(); ++it) norm += it->second * it->second; - norm = sqrt(norm); - } - - if (norm > 0.0) { - for (it = begin(); it != end(); ++it) it->second /= norm; - } -} - -// -------------------------------------------------------------------------- - -std::ostream &operator<<(std::ostream &out, const BowVector &v) { - BowVector::const_iterator vit; - // std::vector::const_iterator iit; - unsigned int i = 0; - const size_t N = v.size(); - for (vit = v.begin(); vit != v.end(); ++vit, ++i) { - out << "<" << vit->first << ", " << vit->second << ">"; - - if (i < N - 1) out << ", "; - } - return out; -} - -// -------------------------------------------------------------------------- - -void BowVector::saveM(const std::string &filename, size_t W) const { - std::fstream f(filename.c_str(), std::ios::out); - - WordId last = 0; - BowVector::const_iterator bit; - for (bit = this->begin(); bit != this->end(); ++bit) { - for (; last < bit->first; ++last) { - f << "0 "; - } - f << bit->second << " "; - - last = bit->first + 1; - } - for (; last < (WordId)W; ++last) f << "0 "; - - f.close(); -} -// -------------------------------------------------------------------------- - -void BowVector::toStream(std::ostream &str) const { - uint32_t s = size(); - str.write((char *)&s, sizeof(s)); - for (auto d : *this) { - str.write((char *)&d.first, sizeof(d.first)); - str.write((char *)&d.second, sizeof(d.second)); - } -} -// -------------------------------------------------------------------------- - -void BowVector::fromStream(std::istream &str) { - clear(); - uint32_t s; - - str.read((char *)&s, sizeof(s)); - for (uint32_t i = 0; i < s; i++) { - WordId wid; - WordValue wv; - str.read((char *)&wid, sizeof(wid)); - str.read((char *)&wv, sizeof(wv)); - insert(std::make_pair(wid, wv)); - } -} - -uint64_t BowVector::getSignature() const { - uint64_t sig = 0; - for (auto ww : *this) sig += ww.first + 1e6 * ww.second; - return sig; -} - -// -------------------------------------------------------------------------- - -} // namespace DBoW3 diff --git a/thirdparty/DBoW3/src/BowVector.h b/thirdparty/DBoW3/src/BowVector.h deleted file mode 100644 index d8c17e0..0000000 --- a/thirdparty/DBoW3/src/BowVector.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * File: BowVector.h - * Date: March 2011 - * Author: Dorian Galvez-Lopez - * Description: bag of words vector - * License: see the LICENSE.txt file - * - */ - -#ifndef __D_T_BOW_VECTOR__ -#define __D_T_BOW_VECTOR__ - -#include -#include -#include "exports.h" -#if _WIN32 -#include -#endif -namespace DBoW3 { - -/// Id of words -typedef unsigned int WordId; - -/// Value of a word -typedef double WordValue; - -/// Id of nodes in the vocabulary tree -typedef unsigned int NodeId; - -/// L-norms for normalization -enum LNorm -{ - L1, - L2 -}; - -/// Weighting type -enum WeightingType -{ - TF_IDF, - TF, - IDF, - BINARY -}; - -/// Scoring type -enum ScoringType -{ - L1_NORM, - L2_NORM, - CHI_SQUARE, - KL, - BHATTACHARYYA, - DOT_PRODUCT -}; - -/// Vector of words to represent images -class DBOW_API BowVector: - public std::map -{ -public: - - /** - * Constructor - */ - BowVector(void); - - /** - * Destructor - */ - ~BowVector(void); - - /** - * Adds a value to a word value existing in the vector, or creates a new - * word with the given value - * @param id word id to look for - * @param v value to create the word with, or to add to existing word - */ - void addWeight(WordId id, WordValue v); - - /** - * Adds a word with a value to the vector only if this does not exist yet - * @param id word id to look for - * @param v value to give to the word if this does not exist - */ - void addIfNotExist(WordId id, WordValue v); - - /** - * L1-Normalizes the values in the vector - * @param norm_type norm used - */ - void normalize(LNorm norm_type); - - /** - * Prints the content of the bow vector - * @param out stream - * @param v - */ - friend std::ostream& operator<<(std::ostream &out, const BowVector &v); - - /** - * Saves the bow vector as a vector in a matlab file - * @param filename - * @param W number of words in the vocabulary - */ - void saveM(const std::string &filename, size_t W) const; - - //returns a unique number from the configuration - uint64_t getSignature()const; - //serialization - void toStream(std::ostream &str)const; - void fromStream(std::istream &str); -}; - -} // namespace DBoW3 - -#endif diff --git a/thirdparty/DBoW3/src/CMakeLists.txt b/thirdparty/DBoW3/src/CMakeLists.txt deleted file mode 100644 index 7d1019b..0000000 --- a/thirdparty/DBoW3/src/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -FILE(GLOB hdrs_base "*.h" ) -FILE(GLOB srcs_base "*.c*") - -FILE(GLOB hdrs ${hdrs_base} ) -FILE(GLOB srcs ${srcs_base} ) - - -ADD_LIBRARY(${PROJECT_NAME} ${srcs} ${hdrs}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ) - -SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES # create *nix style library versions + symbolic links - DEFINE_SYMBOL DBOW_DSO_EXPORTS - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_SOVERSION} - CLEAN_DIRECT_OUTPUT 1 # allow creating static and shared libs without conflicts - OUTPUT_NAME "${PROJECT_NAME}${PROJECT_DLLVERSION}" # avoid conflicts between library and binary target names -) - -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${REQUIRED_LIBRARIES} ${OpenCV_LIBS}) - diff --git a/thirdparty/DBoW3/src/DBoW3.h b/thirdparty/DBoW3/src/DBoW3.h deleted file mode 100644 index aabeadb..0000000 --- a/thirdparty/DBoW3/src/DBoW3.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * File: DBoW3.h - * Date: November 2011 - * Author: Dorian Galvez-Lopez - * Description: Generic include file for the DBoW3 classes and - * the specialized vocabularies and databases - * License: see the LICENSE.txt file - * - */ - -/*! \mainpage DBoW3 Library - * - * DBoW3 library for C++: - * Bag-of-word image database for image retrieval. - * - * Written by Rafael Muñoz Salinas, - * University of Cordoba (Spain) - * - * - * \section requirements Requirements - * This library requires the OpenCV libraries, - * as well as the boost::dynamic_bitset class. - * - * \section citation Citation - * If you use this software in academic works, please cite: -
-   @@ARTICLE{GalvezTRO12,
-    author={Galvez-Lopez, Dorian and Tardos, J. D.}, 
-    journal={IEEE Transactions on Robotics},
-    title={Bags of Binary Words for Fast Place Recognition in Image Sequences},
-    year={2012},
-    month={October},
-    volume={28},
-    number={5},
-    pages={1188--1197},
-    doi={10.1109/TRO.2012.2197158},
-    ISSN={1552-3098}
-  }
- 
- * - * \section license License - * This file is licensed under a Creative Commons - * Attribution-NonCommercial-ShareAlike 3.0 license. - * This file can be freely used and users can use, download and edit this file - * provided that credit is attributed to the original author. No users are - * permitted to use this file for commercial purposes unless explicit permission - * is given by the original author. Derivative works must be licensed using the - * same or similar license. - * Check http://creativecommons.org/licenses/by-nc-sa/3.0/ to obtain further - * details. - * - */ - -#ifndef __D_T_DBOW3__ -#define __D_T_DBOW3__ - -/// Includes all the data structures to manage vocabularies and image databases - -#include "Vocabulary.h" -#include "Database.h" -#include "BowVector.h" -#include "FeatureVector.h" -#include "QueryResults.h" - - - -#endif - diff --git a/thirdparty/DBoW3/src/Database.cpp b/thirdparty/DBoW3/src/Database.cpp deleted file mode 100644 index c31bd74..0000000 --- a/thirdparty/DBoW3/src/Database.cpp +++ /dev/null @@ -1,855 +0,0 @@ -#include "Database.h" - -#include - -namespace DBoW3 { - -// For query functions -static int MIN_COMMON_WORDS = 5; - -// -------------------------------------------------------------------------- - -Database::Database(bool use_di, int di_levels) - : m_voc(NULL), m_use_di(use_di), m_dilevels(di_levels), m_nentries(0) {} - -// -------------------------------------------------------------------------- - -Database::Database(const Vocabulary &voc, bool use_di, int di_levels) - : m_voc(NULL), m_use_di(use_di), m_dilevels(di_levels) { - setVocabulary(voc); - clear(); -} - -// -------------------------------------------------------------------------- - -Database::Database(const Database &db) : m_voc(NULL) { *this = db; } - -// -------------------------------------------------------------------------- - -Database::Database(const std::string &filename) : m_voc(NULL) { - load(filename); -} - -// -------------------------------------------------------------------------- - -Database::Database(const char *filename) : m_voc(NULL) { load(filename); } - -// -------------------------------------------------------------------------- - -Database::~Database(void) { delete m_voc; } - -// -------------------------------------------------------------------------- - -Database &Database::operator=(const Database &db) { - if (this != &db) { - m_dfile = db.m_dfile; - m_dilevels = db.m_dilevels; - m_ifile = db.m_ifile; - m_nentries = db.m_nentries; - m_use_di = db.m_use_di; - if (db.m_voc != 0) setVocabulary(*db.m_voc); - } - return *this; -} - -// -------------------------------------------------------------------------- - -EntryId Database::add(const cv::Mat &features, BowVector *bowvec, - FeatureVector *fvec) { - std::vector vf(features.rows); - for (int r = 0; r < features.rows; r++) vf[r] = features.rowRange(r, r + 1); - return add(vf, bowvec, fvec); -} - -EntryId Database::add(const std::vector &features, BowVector *bowvec, - FeatureVector *fvec) { - BowVector aux; - BowVector &v = (bowvec ? *bowvec : aux); - - if (m_use_di && fvec != NULL) { - m_voc->transform(features, v, *fvec, m_dilevels); // with features - return add(v, *fvec); - } else if (m_use_di) { - FeatureVector fv; - m_voc->transform(features, v, fv, m_dilevels); // with features - return add(v, fv); - } else if (fvec != NULL) { - m_voc->transform(features, v, *fvec, m_dilevels); // with features - return add(v); - } else { - m_voc->transform(features, v); // with features - return add(v); - } -} - -EntryId Database::add(const std::vector> &features, - BowVector *bowvec, FeatureVector *fvec) { - BowVector aux; - BowVector &v = (bowvec ? *bowvec : aux); - - if (m_use_di && fvec != NULL) { - m_voc->transform(features, v, *fvec, m_dilevels); // with features - return add(v, *fvec); - } else if (m_use_di) { - FeatureVector fv; - m_voc->transform(features, v, fv, m_dilevels); // with features - return add(v, fv); - } else if (fvec != NULL) { - m_voc->transform(features, v, *fvec, m_dilevels); // with features - return add(v); - } else { - m_voc->transform(features, v); // with features - return add(v); - } -} - -// --------------------------------------------------------------------------- - -EntryId Database::add(const BowVector &v, const FeatureVector &fv) { - EntryId entry_id = m_nentries++; - - BowVector::const_iterator vit; - // std::vector::const_iterator iit; - - if (m_use_di) { - // update direct file - if (entry_id == m_dfile.size()) { - m_dfile.push_back(fv); - } else { - m_dfile[entry_id] = fv; - } - } - - // update inverted file - for (vit = v.begin(); vit != v.end(); ++vit) { - const WordId &word_id = vit->first; - const WordValue &word_weight = vit->second; - - IFRow &ifrow = m_ifile[word_id]; - ifrow.push_back(IFPair(entry_id, word_weight)); - } - - return entry_id; -} - -// -------------------------------------------------------------------------- - -void Database::setVocabulary(const Vocabulary &voc) { - delete m_voc; - m_voc = new Vocabulary(voc); - clear(); -} - -// -------------------------------------------------------------------------- - -void Database::setVocabulary(const Vocabulary &voc, bool use_di, - int di_levels) { - m_use_di = use_di; - m_dilevels = di_levels; - delete m_voc; - m_voc = new Vocabulary(voc); - clear(); -} - -// -------------------------------------------------------------------------- - -void Database::clear() { - // resize vectors - m_ifile.resize(0); - m_ifile.resize(m_voc->size()); - m_dfile.resize(0); - m_nentries = 0; -} - -// -------------------------------------------------------------------------- - -void Database::allocate(int nd, int ni) { - // m_ifile already contains |words| items - if (ni > 0) { - for (auto rit = m_ifile.begin(); rit != m_ifile.end(); ++rit) { - int n = (int)rit->size(); - if (ni > n) { - rit->resize(ni); - rit->resize(n); - } - } - } - - if (m_use_di && (int)m_dfile.size() < nd) { - m_dfile.resize(nd); - } -} - -// -------------------------------------------------------------------------- - -void Database::query(const cv::Mat &features, QueryResults &ret, - int max_results, int max_id) const { - std::vector vf(features.rows); - for (int r = 0; r < features.rows; r++) vf[r] = features.rowRange(r, r + 1); - query(vf, ret, max_results, max_id); -} - -void Database::query(const std::vector &features, QueryResults &ret, - int max_results, int max_id) const { - BowVector vec; - m_voc->transform(features, vec); - query(vec, ret, max_results, max_id); -} - -void Database::query(const std::vector> &features, - QueryResults &ret, int max_results, int max_id) const { - BowVector vec; - m_voc->transform(features, vec); - query(vec, ret, max_results, max_id); -} - -// -------------------------------------------------------------------------- - -void Database::query(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const { - ret.resize(0); - - switch (m_voc->getScoringType()) { - case L1_NORM: - queryL1(vec, ret, max_results, max_id); - break; - - case L2_NORM: - queryL2(vec, ret, max_results, max_id); - break; - - case CHI_SQUARE: - queryChiSquare(vec, ret, max_results, max_id); - break; - - case KL: - queryKL(vec, ret, max_results, max_id); - break; - - case BHATTACHARYYA: - queryBhattacharyya(vec, ret, max_results, max_id); - break; - - case DOT_PRODUCT: - queryDotProduct(vec, ret, max_results, max_id); - break; - } -} - -// -------------------------------------------------------------------------- - -void Database::queryL1(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const { - BowVector::const_iterator vit; - - std::unordered_map pairs; - - for (vit = vec.begin(); vit != vec.end(); ++vit) { - const WordId word_id = vit->first; - const WordValue &qvalue = vit->second; - - const IFRow &row = m_ifile[word_id]; - - // IFRows are sorted in ascending entry_id order - - for (const auto &rit : row) { - const EntryId &entry_id = rit.entry_id; - const WordValue &dvalue = rit.word_weight; - - if ((int)entry_id < max_id || max_id == -1) { - double value = fabs(qvalue - dvalue) - fabs(qvalue) - fabs(dvalue); - - auto it = pairs.find(entry_id); - if (it != pairs.end()) { - it->second += value; - } else { - pairs.emplace(entry_id, value); - } - } - - } // for each inverted row - } // for each query word - - // move to vector - ret.reserve(pairs.size()); - for (const auto &pit : pairs) { - ret.push_back(Result(pit.first, pit.second)); - } - - // resulting "scores" are now in [-2 best .. 0 worst] - - // sort vector in ascending order of score - std::sort(ret.begin(), ret.end()); - // (ret is inverted now --the lower the better--) - - // cut vector - if (max_results > 0 && (int)ret.size() > max_results) ret.resize(max_results); - - // complete and scale score to [0 worst .. 1 best] - // ||v - w||_{L1} = 2 + Sum(|v_i - w_i| - |v_i| - |w_i|) - // for all i | v_i != 0 and w_i != 0 - // (Nister, 2006) - // scaled_||v - w||_{L1} = 1 - 0.5 * ||v - w||_{L1} - QueryResults::iterator qit; - for (qit = ret.begin(); qit != ret.end(); qit++) - qit->Score = -qit->Score / 2.0; -} - -// -------------------------------------------------------------------------- - -void Database::queryL2(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const { - BowVector::const_iterator vit; - - std::map pairs; - std::map::iterator pit; - - // map counters; - // map::iterator cit; - - for (vit = vec.begin(); vit != vec.end(); ++vit) { - const WordId word_id = vit->first; - const WordValue &qvalue = vit->second; - - const IFRow &row = m_ifile[word_id]; - - // IFRows are sorted in ascending entry_id order - - for (auto rit = row.begin(); rit != row.end(); ++rit) { - const EntryId entry_id = rit->entry_id; - const WordValue &dvalue = rit->word_weight; - - if ((int)entry_id < max_id || max_id == -1) { - double value = -qvalue * dvalue; // minus sign for sorting trick - - pit = pairs.lower_bound(entry_id); - // cit = counters.lower_bound(entry_id); - if (pit != pairs.end() && !(pairs.key_comp()(entry_id, pit->first))) { - pit->second += value; - // cit->second += 1; - } else { - pairs.insert(pit, - std::map::value_type(entry_id, value)); - - // counters.insert(cit, - // map::value_type(entry_id, 1)); - } - } - - } // for each inverted row - } // for each query word - - // move to vector - ret.reserve(pairs.size()); - // cit = counters.begin(); - for (pit = pairs.begin(); pit != pairs.end(); ++pit) //, ++cit) - { - ret.push_back(Result(pit->first, pit->second)); // / cit->second)); - } - - // resulting "scores" are now in [-1 best .. 0 worst] - - // sort vector in ascending order of score - std::sort(ret.begin(), ret.end()); - // (ret is inverted now --the lower the better--) - - // cut vector - if (max_results > 0 && (int)ret.size() > max_results) ret.resize(max_results); - - // complete and scale score to [0 worst .. 1 best] - // ||v - w||_{L2} = sqrt( 2 - 2 * Sum(v_i * w_i) - // for all i | v_i != 0 and w_i != 0 ) - // (Nister, 2006) - QueryResults::iterator qit; - for (qit = ret.begin(); qit != ret.end(); qit++) { - if (qit->Score <= -1.0) // rounding error - qit->Score = 1.0; - else - qit->Score = 1.0 - sqrt(1.0 + qit->Score); // [0..1] - // the + sign is ok, it is due to - sign in - // value = - qvalue * dvalue - } -} - -// -------------------------------------------------------------------------- - -void Database::queryChiSquare(const BowVector &vec, QueryResults &ret, - int max_results, int max_id) const { - BowVector::const_iterator vit; - - std::map> pairs; - std::map>::iterator pit; - - std::map> sums; // < sum vi, sum wi > - std::map>::iterator sit; - - // In the current implementation, we suppose vec is not normalized - - // map expected; - // map::iterator eit; - - for (vit = vec.begin(); vit != vec.end(); ++vit) { - const WordId word_id = vit->first; - const WordValue &qvalue = vit->second; - - const IFRow &row = m_ifile[word_id]; - - // IFRows are sorted in ascending entry_id order - - for (auto rit = row.begin(); rit != row.end(); ++rit) { - const EntryId entry_id = rit->entry_id; - const WordValue &dvalue = rit->word_weight; - - if ((int)entry_id < max_id || max_id == -1) { - // (v-w)^2/(v+w) - v - w = -4 vw/(v+w) - // we move the 4 out - double value = 0; - if (qvalue + dvalue != 0.0) // words may have weight zero - value = -qvalue * dvalue / (qvalue + dvalue); - - pit = pairs.lower_bound(entry_id); - sit = sums.lower_bound(entry_id); - // eit = expected.lower_bound(entry_id); - if (pit != pairs.end() && !(pairs.key_comp()(entry_id, pit->first))) { - pit->second.first += value; - pit->second.second += 1; - // eit->second += dvalue; - sit->second.first += qvalue; - sit->second.second += dvalue; - } else { - pairs.insert(pit, - std::map>::value_type( - entry_id, std::make_pair(value, 1))); - // expected.insert(eit, - // map::value_type(entry_id, dvalue)); - - sums.insert(sit, - std::map>::value_type( - entry_id, std::make_pair(qvalue, dvalue))); - } - } - - } // for each inverted row - } // for each query word - - // move to vector - ret.reserve(pairs.size()); - sit = sums.begin(); - for (pit = pairs.begin(); pit != pairs.end(); ++pit, ++sit) { - if (pit->second.second >= MIN_COMMON_WORDS) { - ret.push_back(Result(pit->first, pit->second.first)); - ret.back().nWords = pit->second.second; - ret.back().sumCommonVi = sit->second.first; - ret.back().sumCommonWi = sit->second.second; - ret.back().expectedChiScore = - 2 * sit->second.second / (1 + sit->second.second); - } - - // ret.push_back(Result(pit->first, pit->second)); - } - - // resulting "scores" are now in [-2 best .. 0 worst] - // we have to add +2 to the scores to obtain the chi square score - - // sort vector in ascending order of score - std::sort(ret.begin(), ret.end()); - // (ret is inverted now --the lower the better--) - - // cut vector - if (max_results > 0 && (int)ret.size() > max_results) ret.resize(max_results); - - // complete and scale score to [0 worst .. 1 best] - QueryResults::iterator qit; - for (qit = ret.begin(); qit != ret.end(); qit++) { - // this takes the 4 into account - qit->Score = -2. * qit->Score; // [0..1] - - qit->chiScore = qit->Score; - } -} - -// -------------------------------------------------------------------------- - -void Database::queryKL(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const { - BowVector::const_iterator vit; - - std::map pairs; - std::map::iterator pit; - - for (vit = vec.begin(); vit != vec.end(); ++vit) { - const WordId word_id = vit->first; - const WordValue &vi = vit->second; - - const IFRow &row = m_ifile[word_id]; - - // IFRows are sorted in ascending entry_id order - - for (auto rit = row.begin(); rit != row.end(); ++rit) { - const EntryId entry_id = rit->entry_id; - const WordValue &wi = rit->word_weight; - - if ((int)entry_id < max_id || max_id == -1) { - double value = 0; - if (vi != 0 && wi != 0) value = vi * log(vi / wi); - - pit = pairs.lower_bound(entry_id); - if (pit != pairs.end() && !(pairs.key_comp()(entry_id, pit->first))) { - pit->second += value; - } else { - pairs.insert(pit, - std::map::value_type(entry_id, value)); - } - } - - } // for each inverted row - } // for each query word - - // resulting "scores" are now in [-X worst .. 0 best .. X worst] - // but we cannot make sure which ones are better without calculating - // the complete score - - // complete scores and move to vector - ret.reserve(pairs.size()); - for (pit = pairs.begin(); pit != pairs.end(); ++pit) { - EntryId eid = pit->first; - double value = 0.0; - - for (vit = vec.begin(); vit != vec.end(); ++vit) { - const WordValue &vi = vit->second; - const IFRow &row = m_ifile[vit->first]; - - if (vi != 0) { - if (row.end() == find(row.begin(), row.end(), eid)) { - value += vi * (log(vi) - GeneralScoring::LOG_EPS); - } - } - } - - pit->second += value; - - // to vector - ret.push_back(Result(pit->first, pit->second)); - } - - // real scores are now in [0 best .. X worst] - - // sort vector in ascending order - // (scores are inverted now --the lower the better--) - std::sort(ret.begin(), ret.end()); - - // cut vector - if (max_results > 0 && (int)ret.size() > max_results) ret.resize(max_results); - - // cannot scale scores -} - -// -------------------------------------------------------------------------- - -void Database::queryBhattacharyya(const BowVector &vec, QueryResults &ret, - int max_results, int max_id) const { - BowVector::const_iterator vit; - - // map pairs; - // map::iterator pit; - - std::map> pairs; // > - std::map>::iterator pit; - - for (vit = vec.begin(); vit != vec.end(); ++vit) { - const WordId word_id = vit->first; - const WordValue &qvalue = vit->second; - - const IFRow &row = m_ifile[word_id]; - - // IFRows are sorted in ascending entry_id order - - for (auto rit = row.begin(); rit != row.end(); ++rit) { - const EntryId entry_id = rit->entry_id; - const WordValue &dvalue = rit->word_weight; - - if ((int)entry_id < max_id || max_id == -1) { - double value = sqrt(qvalue * dvalue); - - pit = pairs.lower_bound(entry_id); - if (pit != pairs.end() && !(pairs.key_comp()(entry_id, pit->first))) { - pit->second.first += value; - pit->second.second += 1; - } else { - pairs.insert(pit, - std::map>::value_type( - entry_id, std::make_pair(value, 1))); - } - } - - } // for each inverted row - } // for each query word - - // move to vector - ret.reserve(pairs.size()); - for (pit = pairs.begin(); pit != pairs.end(); ++pit) { - if (pit->second.second >= MIN_COMMON_WORDS) { - ret.push_back(Result(pit->first, pit->second.first)); - ret.back().nWords = pit->second.second; - ret.back().bhatScore = pit->second.first; - } - } - - // scores are already in [0..1] - - // sort vector in descending order - std::sort(ret.begin(), ret.end(), Result::gt); - - // cut vector - if (max_results > 0 && (int)ret.size() > max_results) ret.resize(max_results); -} - -// --------------------------------------------------------------------------- - -void Database::queryDotProduct(const BowVector &vec, QueryResults &ret, - int max_results, int max_id) const { - BowVector::const_iterator vit; - - std::map pairs; - std::map::iterator pit; - - for (vit = vec.begin(); vit != vec.end(); ++vit) { - const WordId word_id = vit->first; - const WordValue &qvalue = vit->second; - - const IFRow &row = m_ifile[word_id]; - - // IFRows are sorted in ascending entry_id order - - for (auto rit = row.begin(); rit != row.end(); ++rit) { - const EntryId entry_id = rit->entry_id; - const WordValue &dvalue = rit->word_weight; - - if ((int)entry_id < max_id || max_id == -1) { - double value; - if (this->m_voc->getWeightingType() == BINARY) - value = 1; - else - value = qvalue * dvalue; - - pit = pairs.lower_bound(entry_id); - if (pit != pairs.end() && !(pairs.key_comp()(entry_id, pit->first))) { - pit->second += value; - } else { - pairs.insert(pit, - std::map::value_type(entry_id, value)); - } - } - - } // for each inverted row - } // for each query word - - // move to vector - ret.reserve(pairs.size()); - for (pit = pairs.begin(); pit != pairs.end(); ++pit) { - ret.push_back(Result(pit->first, pit->second)); - } - - // scores are the greater the better - - // sort vector in descending order - std::sort(ret.begin(), ret.end(), Result::gt); - - // cut vector - if (max_results > 0 && (int)ret.size() > max_results) ret.resize(max_results); - - // these scores cannot be scaled -} - -// --------------------------------------------------------------------------- - -const FeatureVector &Database::retrieveFeatures(EntryId id) const { - assert(id < size()); - return m_dfile[id]; -} - -// -------------------------------------------------------------------------- - -void Database::save(const std::string &filename) const { - cv::FileStorage fs(filename.c_str(), cv::FileStorage::WRITE); - if (!fs.isOpened()) throw std::string("Could not open file ") + filename; - - save(fs); -} - -// -------------------------------------------------------------------------- - -void Database::save(cv::FileStorage &fs, const std::string &name) const { - // Format YAML: - // vocabulary { ... see TemplatedVocabulary::save } - // database - // { - // nEntries: - // usingDI: - // diLevels: - // invertedIndex - // [ - // [ - // { - // imageId: - // weight: - // } - // ] - // ] - // directIndex - // [ - // [ - // { - // nodeId: - // features: [ ] - // } - // ] - // ] - - // invertedIndex[i] is for the i-th word - // directIndex[i] is for the i-th entry - // directIndex may be empty if not using direct index - // - // imageId's and nodeId's must be stored in ascending order - // (according to the construction of the indexes) - - m_voc->save(fs); - - fs << name << "{"; - - fs << "nEntries" << m_nentries; - fs << "usingDI" << (m_use_di ? 1 : 0); - fs << "diLevels" << m_dilevels; - - fs << "invertedIndex" - << "["; - - for (auto iit = m_ifile.begin(); iit != m_ifile.end(); ++iit) { - fs << "["; // word of IF - for (auto irit = iit->begin(); irit != iit->end(); ++irit) { - fs << "{:" - << "imageId" << (int)irit->entry_id << "weight" << irit->word_weight - << "}"; - } - fs << "]"; // word of IF - } - - fs << "]"; // invertedIndex - - fs << "directIndex" - << "["; - - for (auto dit = m_dfile.begin(); dit != m_dfile.end(); ++dit) { - fs << "["; // entry of DF - - for (auto drit = dit->begin(); drit != dit->end(); ++drit) { - NodeId nid = drit->first; - const std::vector &features = drit->second; - - // save info of last_nid - fs << "{"; - fs << "nodeId" << (int)nid; - // msvc++ 2010 with opencv 2.3.1 does not allow FileStorage::operator<< - // with vectors of unsigned int - fs << "features" - << "[" << *(const std::vector *)(&features) << "]"; - fs << "}"; - } - - fs << "]"; // entry of DF - } - - fs << "]"; // directIndex - - fs << "}"; // database -} - -// -------------------------------------------------------------------------- - -void Database::load(const std::string &filename) { - cv::FileStorage fs(filename.c_str(), cv::FileStorage::READ); - if (!fs.isOpened()) throw std::string("Could not open file ") + filename; - - load(fs); -} - -// -------------------------------------------------------------------------- - -void Database::load(const cv::FileStorage &fs, const std::string &name) { - // load voc first - // subclasses must instantiate m_voc before calling this ::load - if (!m_voc) m_voc = new Vocabulary; - - m_voc->load(fs); - - // load database now - clear(); // resizes inverted file - - cv::FileNode fdb = fs[name]; - - m_nentries = (int)fdb["nEntries"]; - m_use_di = (int)fdb["usingDI"] != 0; - m_dilevels = (int)fdb["diLevels"]; - - cv::FileNode fn = fdb["invertedIndex"]; - for (WordId wid = 0; wid < fn.size(); ++wid) { - cv::FileNode fw = fn[wid]; - - for (unsigned int i = 0; i < fw.size(); ++i) { - EntryId eid = (int)fw[i]["imageId"]; - WordValue v = fw[i]["weight"]; - - m_ifile[wid].push_back(IFPair(eid, v)); - } - } - - if (m_use_di) { - fn = fdb["directIndex"]; - - m_dfile.resize(fn.size()); - assert(m_nentries == (int)fn.size()); - - FeatureVector::iterator dit; - for (EntryId eid = 0; eid < fn.size(); ++eid) { - cv::FileNode fe = fn[eid]; - - m_dfile[eid].clear(); - for (unsigned int i = 0; i < fe.size(); ++i) { - NodeId nid = (int)fe[i]["nodeId"]; - - dit = m_dfile[eid].insert(m_dfile[eid].end(), - make_pair(nid, std::vector())); - - // this failed to compile with some opencv versions (2.3.1) - // fe[i]["features"] >> dit->second; - - // this was ok until OpenCV 2.4.1 - // std::vector aux; - // fe[i]["features"] >> aux; // OpenCV < 2.4.1 - // dit->second.resize(aux.size()); - // std::copy(aux.begin(), aux.end(), dit->second.begin()); - - cv::FileNode ff = fe[i]["features"][0]; - dit->second.reserve(ff.size()); - - cv::FileNodeIterator ffit; - for (ffit = ff.begin(); ffit != ff.end(); ++ffit) { - dit->second.push_back((int)*ffit); - } - } - } // for each entry - } // if use_id -} - -std::ostream &operator<<(std::ostream &os, const Database &db) { - os << "Database: Entries = " << db.size() << ", " - "Using direct index = " - << (db.usingDirectIndex() ? "yes" : "no"); - - if (db.usingDirectIndex()) - os << ", Direct index levels = " << db.getDirectIndexLevels(); - - os << ". " << *db.getVocabulary(); - return os; -} -} // namespace DBoW3 diff --git a/thirdparty/DBoW3/src/Database.h b/thirdparty/DBoW3/src/Database.h deleted file mode 100644 index 2397404..0000000 --- a/thirdparty/DBoW3/src/Database.h +++ /dev/null @@ -1,354 +0,0 @@ -/** - * File: Database.h - * Date: March 2011 - * Modified By Rafael Muñoz in 2016 - * Author: Dorian Galvez-Lopez - * Description: database of images - * License: see the LICENSE.txt file - * - */ - -#ifndef __D_T_DATABASE__ -#define __D_T_DATABASE__ - -#include -#include -#include -#include -#include -#include -#include - -#include "BowVector.h" -#include "FeatureVector.h" -#include "QueryResults.h" -#include "ScoringObject.h" -#include "Vocabulary.h" -#include "exports.h" - -namespace DBoW3 { - -/// Database -class DBOW_API Database { - public: - /** - * Creates an empty database without vocabulary - * @param use_di a direct index is used to store feature indexes - * @param di_levels levels to go up the vocabulary tree to select the - * node id to store in the direct index when adding images - */ - explicit Database(bool use_di = true, int di_levels = 0); - - /** - * Creates a database with the given vocabulary - * @param T class inherited from Vocabulary - * @param voc vocabulary - * @param use_di a direct index is used to store feature indexes - * @param di_levels levels to go up the vocabulary tree to select the - * node id to store in the direct index when adding images - */ - - explicit Database(const Vocabulary &voc, bool use_di = true, - int di_levels = 0); - - /** - * Copy constructor. Copies the vocabulary too - * @param db object to copy - */ - Database(const Database &db); - - /** - * Creates the database from a file - * @param filename - */ - Database(const std::string &filename); - - /** - * Creates the database from a file - * @param filename - */ - Database(const char *filename); - - /** - * Destructor - */ - virtual ~Database(void); - - /** - * Copies the given database and its vocabulary - * @param db database to copy - */ - Database &operator=(const Database &db); - - /** - * Sets the vocabulary to use and clears the content of the database. - * @param T class inherited from Vocabulary - * @param voc vocabulary to copy - */ - void setVocabulary(const Vocabulary &voc); - - /** - * Sets the vocabulary to use and the direct index parameters, and clears - * the content of the database - * @param T class inherited from Vocabulary - * @param voc vocabulary to copy - * @param use_di a direct index is used to store feature indexes - * @param di_levels levels to go up the vocabulary tree to select the - * node id to store in the direct index when adding images - */ - - void setVocabulary(const Vocabulary &voc, bool use_di, int di_levels = 0); - - /** - * Returns a pointer to the vocabulary used - * @return vocabulary - */ - inline const Vocabulary *getVocabulary() const { return m_voc; } - - /** - * Allocates some memory for the direct and inverted indexes - * @param nd number of expected image entries in the database - * @param ni number of expected words per image - * @note Use 0 to ignore a parameter - */ - void allocate(int nd = 0, int ni = 0); - - /** - * Adds an entry to the database and returns its index - * @param features features of the new entry - * @param bowvec if given, the bow vector of these features is returned - * @param fvec if given, the vector of nodes and feature indexes is returned - * @return id of new entry - */ - EntryId add(const std::vector> &features, - BowVector *bowvec = NULL, FeatureVector *fvec = NULL); - - /** - * Adds an entry to the database and returns its index - * @param features features of the new entry - * @param bowvec if given, the bow vector of these features is returned - * @param fvec if given, the vector of nodes and feature indexes is returned - * @return id of new entry - */ - EntryId add(const std::vector &features, BowVector *bowvec = NULL, - FeatureVector *fvec = NULL); - /** - * Adds an entry to the database and returns its index - * @param features features of the new entry, one per row - * @param bowvec if given, the bow vector of these features is returned - * @param fvec if given, the vector of nodes and feature indexes is returned - * @return id of new entry - */ - EntryId add(const cv::Mat &features, BowVector *bowvec = NULL, - FeatureVector *fvec = NULL); - - /** - * Adss an entry to the database and returns its index - * @param vec bow vector - * @param fec feature vector to add the entry. Only necessary if using the - * direct index - * @return id of new entry - */ - EntryId add(const BowVector &vec, const FeatureVector &fec = FeatureVector()); - - /** - * Empties the database - */ - inline void clear(); - - /** - * Returns the number of entries in the database - * @return number of entries in the database - */ - unsigned int size() const { return m_nentries; } - - /** - * Checks if the direct index is being used - * @return true iff using direct index - */ - bool usingDirectIndex() const { return m_use_di; } - - /** - * Returns the di levels when using direct index - * @return di levels - */ - int getDirectIndexLevels() const { return m_dilevels; } - - /** - * Queries the database with some features - * @param features query features - * @param ret (out) query results - * @param max_results number of results to return. <= 0 means all - * @param max_id only entries with id <= max_id are returned in ret. - * < 0 means all - */ - void query(const std::vector &features, QueryResults &ret, - int max_results = 1, int max_id = -1) const; - - void query(const std::vector> &features, QueryResults &ret, - int max_results = 1, int max_id = -1) const; - - /** - * Queries the database with some features - * @param features query features,one per row - * @param ret (out) query results - * @param max_results number of results to return. <= 0 means all - * @param max_id only entries with id <= max_id are returned in ret. - * < 0 means all - */ - void query(const cv::Mat &features, QueryResults &ret, int max_results = 1, - int max_id = -1) const; - - /** - * Queries the database with a vector - * @param vec bow vector already normalized - * @param ret results - * @param max_results number of results to return. <= 0 means all - * @param max_id only entries with id <= max_id are returned in ret. - * < 0 means all - */ - void query(const BowVector &vec, QueryResults &ret, int max_results = 1, - int max_id = -1) const; - - /** - * Returns the a feature vector associated with a database entry - * @param id entry id (must be < size()) - * @return const reference to map of nodes and their associated features in - * the given entry - */ - const FeatureVector &retrieveFeatures(EntryId id) const; - - /** - * Stores the database in a file - * @param filename - */ - void save(const std::string &filename) const; - - /** - * Loads the database from a file - * @param filename - */ - void load(const std::string &filename); - - /** - * Stores the database in the given file storage structure - * @param fs - * @param name node name - */ - virtual void save(cv::FileStorage &fs, - const std::string &name = "database") const; - - /** - * Loads the database from the given file storage structure - * @param fs - * @param name node name - */ - virtual void load(const cv::FileStorage &fs, - const std::string &name = "database"); - - // -------------------------------------------------------------------------- - - /** - * Writes printable information of the database - * @param os stream to write to - * @param db - */ - DBOW_API friend std::ostream &operator<<(std::ostream &os, - const Database &db); - - protected: - /// Query with L1 scoring - void queryL1(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const; - - /// Query with L2 scoring - void queryL2(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const; - - /// Query with Chi square scoring - void queryChiSquare(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const; - - /// Query with Bhattacharyya scoring - void queryBhattacharyya(const BowVector &vec, QueryResults &ret, - int max_results, int max_id) const; - - /// Query with KL divergence scoring - void queryKL(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const; - - /// Query with dot product scoring - void queryDotProduct(const BowVector &vec, QueryResults &ret, int max_results, - int max_id) const; - - protected: - /* Inverted file declaration */ - - /// Item of IFRow - struct IFPair { - /// Entry id - EntryId entry_id; - - /// Word weight in this entry - WordValue word_weight; - - /** - * Creates an empty pair - */ - IFPair() {} - - /** - * Creates an inverted file pair - * @param eid entry id - * @param wv word weight - */ - IFPair(EntryId eid, WordValue wv) : entry_id(eid), word_weight(wv) {} - - /** - * Compares the entry ids - * @param eid - * @return true iff this entry id is the same as eid - */ - inline bool operator==(EntryId eid) const { return entry_id == eid; } - }; - - /// Row of InvertedFile - typedef std::vector IFRow; - // IFRows are sorted in ascending entry_id order - - /// Inverted index - typedef std::vector InvertedFile; - // InvertedFile[word_id] --> inverted file of that word - - /* Direct file declaration */ - - /// Direct index - typedef std::vector DirectFile; - // DirectFile[entry_id] --> [ directentry, ... ] - - protected: - /// Associated vocabulary - Vocabulary *m_voc; - - /// Flag to use direct index - bool m_use_di; - - /// Levels to go up the vocabulary tree to select nodes to store - /// in the direct index - int m_dilevels; - - /// Inverted file (must have size() == |words|) - InvertedFile m_ifile; - - /// Direct file (resized for allocation) - DirectFile m_dfile; - - /// Number of valid entries in m_dfile - int m_nentries; -}; - -// -------------------------------------------------------------------------- - -} // namespace DBoW3 - -#endif diff --git a/thirdparty/DBoW3/src/DescManip.cpp b/thirdparty/DBoW3/src/DescManip.cpp deleted file mode 100644 index aa0553d..0000000 --- a/thirdparty/DBoW3/src/DescManip.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/** - * File: DescManip.cpp - * Date: June 2012 - * Author: Dorian Galvez-Lopez - * Description: functions for ORB descriptors - * License: see the LICENSE.txt file - * - */ - -#include -#include -#include -#include -#include -#include - -#include "DescManip.h" - -using namespace std; - -namespace DBoW3 { - -// -------------------------------------------------------------------------- - -void DescManip::meanValue(const std::vector &descriptors, - cv::Mat &mean) { - if (descriptors.empty()) return; - - if (descriptors.size() == 1) { - mean = descriptors[0].clone(); - return; - } - // binary descriptor - if (descriptors[0].type() == CV_8U) { - // determine number of bytes of the binary descriptor - int L = getDescSizeBytes(descriptors[0]); - vector sum(L * 8, 0); - - for (size_t i = 0; i < descriptors.size(); ++i) { - const cv::Mat &d = descriptors[i]; - const unsigned char *p = d.ptr(); - - for (int j = 0; j < d.cols; ++j, ++p) { - if (*p & (1 << 7)) ++sum[j * 8]; - if (*p & (1 << 6)) ++sum[j * 8 + 1]; - if (*p & (1 << 5)) ++sum[j * 8 + 2]; - if (*p & (1 << 4)) ++sum[j * 8 + 3]; - if (*p & (1 << 3)) ++sum[j * 8 + 4]; - if (*p & (1 << 2)) ++sum[j * 8 + 5]; - if (*p & (1 << 1)) ++sum[j * 8 + 6]; - if (*p & (1)) ++sum[j * 8 + 7]; - } - } - - mean = cv::Mat::zeros(1, L, CV_8U); - unsigned char *p = mean.ptr(); - - const int N2 = (int)descriptors.size() / 2 + descriptors.size() % 2; - for (size_t i = 0; i < sum.size(); ++i) { - if (sum[i] >= N2) { - // set bit - *p |= 1 << (7 - (i % 8)); - } - - if (i % 8 == 7) ++p; - } - } - // non binary descriptor - else { - assert(descriptors[0].type() == CV_32F); // ensure it is float - - mean.create(1, descriptors[0].cols, descriptors[0].type()); - mean.setTo(cv::Scalar::all(0)); - float inv_s = 1. / double(descriptors.size()); - for (size_t i = 0; i < descriptors.size(); i++) - mean += descriptors[i] * inv_s; - } -} - -// -------------------------------------------------------------------------- -// static inline uint32_t distance_8uc1(const cv::Mat &a, const cv::Mat &b); - -double DescManip::distance(const cv::Mat &a, const cv::Mat &b) { - // binary descriptor - if (a.type() == CV_8U) { - // Bit count function got from: - // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan - // This implementation assumes that a.cols (CV_8U) % sizeof(uint64_t) == 0 - - const uint64_t *pa, *pb; - pa = a.ptr(); // a & b are actually CV_8U - pb = b.ptr(); - - uint64_t v, ret = 0; - for (size_t i = 0; i < a.cols / sizeof(uint64_t); ++i, ++pa, ++pb) { - v = *pa ^ *pb; - v = v - ((v >> 1) & (uint64_t) ~(uint64_t)0 / 3); - v = (v & (uint64_t) ~(uint64_t)0 / 15 * 3) + - ((v >> 2) & (uint64_t) ~(uint64_t)0 / 15 * 3); - v = (v + (v >> 4)) & (uint64_t) ~(uint64_t)0 / 255 * 15; - ret += (uint64_t)(v * ((uint64_t) ~(uint64_t)0 / 255)) >> - (sizeof(uint64_t) - 1) * CHAR_BIT; - } - - return ret; - } else { - double sqd = 0.; - assert(a.type() == CV_32F); - assert(a.rows == 1); - const float *a_ptr = a.ptr(0); - const float *b_ptr = b.ptr(0); - for (int i = 0; i < a.cols; i++) - sqd += (a_ptr[i] - b_ptr[i]) * (a_ptr[i] - b_ptr[i]); - return sqd; - } -} - -// -------------------------------------------------------------------------- - -std::string DescManip::toString(const cv::Mat &a) { - stringstream ss; - // introduce a magic value to distinguish from DBoW3 - ss << "dbw3 "; - // save size and type - - ss << a.type() << " " << a.cols << " "; - - if (a.type() == CV_8U) { - const unsigned char *p = a.ptr(); - for (int i = 0; i < a.cols; ++i, ++p) ss << (int)*p << " "; - } else { - const float *p = a.ptr(); - for (int i = 0; i < a.cols; ++i, ++p) ss << *p << " "; - } - - return ss.str(); -} - -// -------------------------------------------------------------------------- - -void DescManip::fromString(cv::Mat &a, const std::string &s) { - // check if the dbow3 is present - string ss_aux; - ss_aux.reserve(10); - for (size_t i = 0; i < 10 && i < s.size(); i++) ss_aux.push_back(s[i]); - if (ss_aux.find("dbw3") == std::string::npos) { // is DBoW3 - // READ UNTIL END - stringstream ss(s); - int val; - vector data; - data.reserve(100); - while (ss >> val) data.push_back(val); - // copy to a - a.create(1, data.size(), CV_8UC1); - memcpy(a.ptr(0), &data[0], data.size()); - } else { - int type, cols; - stringstream ss(s); - ss >> type >> cols; - a.create(1, cols, type); - if (type == CV_8UC1) { - unsigned char *p = a.ptr(); - int n; - for (int i = 0; i < a.cols; ++i, ++p) - if (ss >> n) *p = (unsigned char)n; - } else { - float *p = a.ptr(); - for (int i = 0; i < a.cols; ++i, ++p) - if (!(ss >> *p)) - cerr << "Error reading. Unexpected EOF. DescManip::fromString" - << endl; - } - } -} - -// -------------------------------------------------------------------------- - -void DescManip::toMat32F(const std::vector &descriptors, - cv::Mat &mat) { - if (descriptors.empty()) { - mat.release(); - return; - } - - if (descriptors[0].type() == CV_8UC1) { - const size_t N = descriptors.size(); - int L = getDescSizeBytes(descriptors[0]); - mat.create(N, L * 8, CV_32F); - float *p = mat.ptr(); - - for (size_t i = 0; i < N; ++i) { - const int C = descriptors[i].cols; - const unsigned char *desc = descriptors[i].ptr(); - - for (int j = 0; j < C; ++j, p += 8) { - p[0] = (desc[j] & (1 << 7) ? 1 : 0); - p[1] = (desc[j] & (1 << 6) ? 1 : 0); - p[2] = (desc[j] & (1 << 5) ? 1 : 0); - p[3] = (desc[j] & (1 << 4) ? 1 : 0); - p[4] = (desc[j] & (1 << 3) ? 1 : 0); - p[5] = (desc[j] & (1 << 2) ? 1 : 0); - p[6] = (desc[j] & (1 << 1) ? 1 : 0); - p[7] = desc[j] & (1); - } - } - } else { - assert(descriptors[0].type() == CV_32F); - const int N = descriptors.size(); - int L = descriptors[0].cols; - mat.create(N, L, CV_32F); - for (int i = 0; i < N; ++i) - memcpy(mat.ptr(i), descriptors[i].ptr(0), - sizeof(float) * L); - } -} - -void DescManip::toStream(const cv::Mat &m, std::ostream &str) { - assert(m.rows == 1 || m.isContinuous()); - int type = m.type(); - int cols = m.cols; - int rows = m.rows; - str.write((char *)&cols, sizeof(cols)); - str.write((char *)&rows, sizeof(rows)); - str.write((char *)&type, sizeof(type)); - str.write((char *)m.ptr(0), m.elemSize() * m.cols); -} - -void DescManip::fromStream(cv::Mat &m, std::istream &str) { - int type, cols, rows; - str.read((char *)&cols, sizeof(cols)); - str.read((char *)&rows, sizeof(rows)); - str.read((char *)&type, sizeof(type)); - m.create(rows, cols, type); - str.read((char *)m.ptr(0), m.elemSize() * m.cols); -} - -// -------------------------------------------------------------------------- - -} // namespace DBoW3 diff --git a/thirdparty/DBoW3/src/DescManip.h b/thirdparty/DBoW3/src/DescManip.h deleted file mode 100644 index 8281176..0000000 --- a/thirdparty/DBoW3/src/DescManip.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * File: FClass.h - * Date: November 2011 - * Author: Dorian Galvez-Lopez - * Description: generic FClass to instantiate templated classes - * License: see the LICENSE.txt file - * - */ - -#ifndef __D_T_DESCMANIP__ -#define __D_T_DESCMANIP__ - -#include -#include -#include -#include "exports.h" - -namespace DBoW3 { - -/// Class to manipulate descriptors (calculating means, differences and IO -/// routines) -class DBOW_API DescManip { - public: - /** - * Calculates the mean value of a set of descriptors - * @param descriptors - * @param mean mean descriptor - */ - static void meanValue(const std::vector &descriptors, cv::Mat &mean); - - /** - * Calculates the distance between two descriptors - * @param a - * @param b - * @return distance - */ - static double distance(const cv::Mat &a, const cv::Mat &b); - static inline uint32_t distance_8uc1(const cv::Mat &a, const cv::Mat &b); - - /** - * Returns a string version of the descriptor - * @param a descriptor - * @return string version - */ - static std::string toString(const cv::Mat &a); - - /** - * Returns a descriptor from a string - * @param a descriptor - * @param s string version - */ - static void fromString(cv::Mat &a, const std::string &s); - - /** - * Returns a mat with the descriptors in float format - * @param descriptors - * @param mat (out) NxL 32F matrix - */ - static void toMat32F(const std::vector &descriptors, cv::Mat &mat); - - /**io routines*/ - static void toStream(const cv::Mat &m, std::ostream &str); - static void fromStream(cv::Mat &m, std::istream &str); - - public: - /**Returns the number of bytes of the descriptor - * used for binary descriptors only*/ - static size_t getDescSizeBytes(const cv::Mat &d) { - return d.cols * d.elemSize(); - } -}; - -uint32_t DescManip::distance_8uc1(const cv::Mat &a, const cv::Mat &b) { - // binary descriptor - - // Bit count function got from: - // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan - // This implementation assumes that a.cols (CV_8U) % sizeof(uint64_t) == 0 - - const uint64_t *pa, *pb; - pa = a.ptr(); // a & b are actually CV_8U - pb = b.ptr(); - - uint64_t v, ret = 0; - size_t n = a.cols / sizeof(uint64_t); - for (size_t i = 0; i < n; ++i, ++pa, ++pb) { - v = *pa ^ *pb; - v = v - ((v >> 1) & (uint64_t) ~(uint64_t)0 / 3); - v = (v & (uint64_t) ~(uint64_t)0 / 15 * 3) + - ((v >> 2) & (uint64_t) ~(uint64_t)0 / 15 * 3); - v = (v + (v >> 4)) & (uint64_t) ~(uint64_t)0 / 255 * 15; - ret += (uint64_t)(v * ((uint64_t) ~(uint64_t)0 / 255)) >> - (sizeof(uint64_t) - 1) * CHAR_BIT; - } - return ret; -} -} // namespace DBoW3 - -#endif diff --git a/thirdparty/DBoW3/src/FeatureVector.cpp b/thirdparty/DBoW3/src/FeatureVector.cpp deleted file mode 100644 index 880eab1..0000000 --- a/thirdparty/DBoW3/src/FeatureVector.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * File: FeatureVector.cpp - * Date: November 2011 - * Author: Dorian Galvez-Lopez - * Description: feature vector - * License: see the LICENSE.txt file - * - */ - -#include "FeatureVector.h" -#include -#include -#include - -namespace DBoW3 { - -// --------------------------------------------------------------------------- - -FeatureVector::FeatureVector(void) -{ -} - -// --------------------------------------------------------------------------- - -FeatureVector::~FeatureVector(void) -{ -} - -// --------------------------------------------------------------------------- - -void FeatureVector::addFeature(NodeId id, unsigned int i_feature) -{ - FeatureVector::iterator vit = this->lower_bound(id); - - if(vit != this->end() && vit->first == id) - { - vit->second.push_back(i_feature); - } - else - { - vit = this->insert(vit, FeatureVector::value_type(id, - std::vector() )); - vit->second.push_back(i_feature); - } -} - -// --------------------------------------------------------------------------- - -std::ostream& operator<<(std::ostream &out, - const FeatureVector &v) -{ - if(!v.empty()) - { - FeatureVector::const_iterator vit = v.begin(); - - const std::vector* f = &vit->second; - - out << "<" << vit->first << ": ["; - if(!f->empty()) out << (*f)[0]; - for(unsigned int i = 1; i < f->size(); ++i) - { - out << ", " << (*f)[i]; - } - out << "]>"; - - for(++vit; vit != v.end(); ++vit) - { - f = &vit->second; - - out << ", <" << vit->first << ": ["; - if(!f->empty()) out << (*f)[0]; - for(unsigned int i = 1; i < f->size(); ++i) - { - out << ", " << (*f)[i]; - } - out << "]>"; - } - } - - return out; -} - -// --------------------------------------------------------------------------- - -} // namespace DBoW3 diff --git a/thirdparty/DBoW3/src/FeatureVector.h b/thirdparty/DBoW3/src/FeatureVector.h deleted file mode 100644 index f06bc1e..0000000 --- a/thirdparty/DBoW3/src/FeatureVector.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * File: FeatureVector.h - * Date: November 2011 - * Author: Dorian Galvez-Lopez - * Description: feature vector - * License: see the LICENSE.txt file - * - */ - -#ifndef __D_T_FEATURE_VECTOR__ -#define __D_T_FEATURE_VECTOR__ - -#include "BowVector.h" -#include -#include -#include "exports.h" -namespace DBoW3 { - -/// Vector of nodes with indexes of local features -class DBOW_API FeatureVector: - public std::map > -{ -public: - - /** - * Constructor - */ - FeatureVector(void); - - /** - * Destructor - */ - ~FeatureVector(void); - - /** - * Adds a feature to an existing node, or adds a new node with an initial - * feature - * @param id node id to add or to modify - * @param i_feature index of feature to add to the given node - */ - void addFeature(NodeId id, unsigned int i_feature); - - /** - * Sends a string versions of the feature vector through the stream - * @param out stream - * @param v feature vector - */ - friend std::ostream& operator<<(std::ostream &out, const FeatureVector &v); - -}; - -} // namespace DBoW3 - -#endif - diff --git a/thirdparty/DBoW3/src/QueryResults.cpp b/thirdparty/DBoW3/src/QueryResults.cpp deleted file mode 100644 index 7062400..0000000 --- a/thirdparty/DBoW3/src/QueryResults.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * File: QueryResults.cpp - * Date: March, November 2011 - * Author: Dorian Galvez-Lopez - * Description: structure to store results of database queries - * License: see the LICENSE.txt file - * - */ - -#include -#include -#include "QueryResults.h" - -using namespace std; - -namespace DBoW3 -{ - -// --------------------------------------------------------------------------- - -ostream & operator<<(ostream& os, const Result& ret ) -{ - os << ""; - return os; -} - -// --------------------------------------------------------------------------- - -ostream & operator<<(ostream& os, const QueryResults& ret ) -{ - if(ret.size() == 1) - os << "1 result:" << endl; - else - os << ret.size() << " results:" << endl; - - QueryResults::const_iterator rit; - for(rit = ret.begin(); rit != ret.end(); ++rit) - { - os << *rit; - if(rit + 1 != ret.end()) os << endl; - } - return os; -} - -// --------------------------------------------------------------------------- - -void QueryResults::saveM(const std::string &filename) const -{ - fstream f(filename.c_str(), ios::out); - - QueryResults::const_iterator qit; - for(qit = begin(); qit != end(); ++qit) - { - f << qit->Id << " " << qit->Score << endl; - } - - f.close(); -} - -// --------------------------------------------------------------------------- - -} // namespace DBoW3 - diff --git a/thirdparty/DBoW3/src/QueryResults.h b/thirdparty/DBoW3/src/QueryResults.h deleted file mode 100644 index bebbd1e..0000000 --- a/thirdparty/DBoW3/src/QueryResults.h +++ /dev/null @@ -1,205 +0,0 @@ -/** - * File: QueryResults.h - * Date: March, November 2011 - * Author: Dorian Galvez-Lopez - * Description: structure to store results of database queries - * License: see the LICENSE.txt file - * - */ - -#ifndef __D_T_QUERY_RESULTS__ -#define __D_T_QUERY_RESULTS__ - -#include -#include "exports.h" -namespace DBoW3 { - -/// Id of entries of the database -typedef unsigned int EntryId; - -/// Single result of a query -class DBOW_API Result -{ -public: - - /// Entry id - EntryId Id; - - /// Score obtained - double Score; - - /// debug - int nWords; // words in common - // !!! this is filled only by Bhatt score! - // (and for BCMatching, BCThresholding then) - - double bhatScore, chiScore; - /// debug - - // only done by ChiSq and BCThresholding - double sumCommonVi; - double sumCommonWi; - double expectedChiScore; - /// debug - - /** - * Empty constructors - */ - inline Result(){} - - /** - * Creates a result with the given data - * @param _id entry id - * @param _score score - */ - inline Result(EntryId _id, double _score): Id(_id), Score(_score){} - - /** - * Compares the scores of two results - * @return true iff this.score < r.score - */ - inline bool operator<(const Result &r) const - { - return this->Score < r.Score; - } - - /** - * Compares the scores of two results - * @return true iff this.score > r.score - */ - inline bool operator>(const Result &r) const - { - return this->Score > r.Score; - } - - /** - * Compares the entry id of the result - * @return true iff this.id == id - */ - inline bool operator==(EntryId id) const - { - return this->Id == id; - } - - /** - * Compares the score of this entry with a given one - * @param s score to compare with - * @return true iff this score < s - */ - inline bool operator<(double s) const - { - return this->Score < s; - } - - /** - * Compares the score of this entry with a given one - * @param s score to compare with - * @return true iff this score > s - */ - inline bool operator>(double s) const - { - return this->Score > s; - } - - /** - * Compares the score of two results - * @param a - * @param b - * @return true iff a.Score > b.Score - */ - static inline bool gt(const Result &a, const Result &b) - { - return a.Score > b.Score; - } - - /** - * Compares the scores of two results - * @return true iff a.Score > b.Score - */ - inline static bool ge(const Result &a, const Result &b) - { - return a.Score > b.Score; - } - - /** - * Returns true iff a.Score >= b.Score - * @param a - * @param b - * @return true iff a.Score >= b.Score - */ - static inline bool geq(const Result &a, const Result &b) - { - return a.Score >= b.Score; - } - - /** - * Returns true iff a.Score >= s - * @param a - * @param s - * @return true iff a.Score >= s - */ - static inline bool geqv(const Result &a, double s) - { - return a.Score >= s; - } - - - /** - * Returns true iff a.Id < b.Id - * @param a - * @param b - * @return true iff a.Id < b.Id - */ - static inline bool ltId(const Result &a, const Result &b) - { - return a.Id < b.Id; - } - - /** - * Prints a string version of the result - * @param os ostream - * @param ret Result to print - */ - friend std::ostream & operator<<(std::ostream& os, const Result& ret ); -}; - -/// Multiple results from a query -class QueryResults: public std::vector -{ -public: - - /** - * Multiplies all the scores in the vector by factor - * @param factor - */ - inline void scaleScores(double factor); - - /** - * Prints a string version of the results - * @param os ostream - * @param ret QueryResults to print - */ - DBOW_API friend std::ostream & operator<<(std::ostream& os, const QueryResults& ret ); - - /** - * Saves a matlab file with the results - * @param filename - */ - void saveM(const std::string &filename) const; - -}; - -// -------------------------------------------------------------------------- - -inline void QueryResults::scaleScores(double factor) -{ - for(QueryResults::iterator qit = begin(); qit != end(); ++qit) - qit->Score *= factor; -} - -// -------------------------------------------------------------------------- - -} // namespace TemplatedBoW - -#endif - diff --git a/thirdparty/DBoW3/src/ScoringObject.cpp b/thirdparty/DBoW3/src/ScoringObject.cpp deleted file mode 100644 index 7cf0812..0000000 --- a/thirdparty/DBoW3/src/ScoringObject.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/** - * File: ScoringObject.cpp - * Date: November 2011 - * Author: Dorian Galvez-Lopez - * Description: functions to compute bow scores - * License: see the LICENSE.txt file - * - */ - -#include -#include "Vocabulary.h" -#include "BowVector.h" - -using namespace DBoW3; - -// If you change the type of WordValue, make sure you change also the -// epsilon value (this is needed by the KL method) -const double GeneralScoring::LOG_EPS = log(DBL_EPSILON); // FLT_EPSILON - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -double L1Scoring::score(const BowVector &v1, const BowVector &v2) const -{ - BowVector::const_iterator v1_it, v2_it; - const BowVector::const_iterator v1_end = v1.end(); - const BowVector::const_iterator v2_end = v2.end(); - - v1_it = v1.begin(); - v2_it = v2.begin(); - - double score = 0; - - while(v1_it != v1_end && v2_it != v2_end) - { - const WordValue& vi = v1_it->second; - const WordValue& wi = v2_it->second; - - if(v1_it->first == v2_it->first) - { - score += fabs(vi - wi) - fabs(vi) - fabs(wi); - - // move v1 and v2 forward - ++v1_it; - ++v2_it; - } - else if(v1_it->first < v2_it->first) - { - // move v1 forward - v1_it = v1.lower_bound(v2_it->first); - // v1_it = (first element >= v2_it.id) - } - else - { - // move v2 forward - v2_it = v2.lower_bound(v1_it->first); - // v2_it = (first element >= v1_it.id) - } - } - - // ||v - w||_{L1} = 2 + Sum(|v_i - w_i| - |v_i| - |w_i|) - // for all i | v_i != 0 and w_i != 0 - // (Nister, 2006) - // scaled_||v - w||_{L1} = 1 - 0.5 * ||v - w||_{L1} - score = -score/2.0; - - return score; // [0..1] -} - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -double L2Scoring::score(const BowVector &v1, const BowVector &v2) const -{ - BowVector::const_iterator v1_it, v2_it; - const BowVector::const_iterator v1_end = v1.end(); - const BowVector::const_iterator v2_end = v2.end(); - - v1_it = v1.begin(); - v2_it = v2.begin(); - - double score = 0; - - while(v1_it != v1_end && v2_it != v2_end) - { - const WordValue& vi = v1_it->second; - const WordValue& wi = v2_it->second; - - if(v1_it->first == v2_it->first) - { - score += vi * wi; - - // move v1 and v2 forward - ++v1_it; - ++v2_it; - } - else if(v1_it->first < v2_it->first) - { - // move v1 forward - v1_it = v1.lower_bound(v2_it->first); - // v1_it = (first element >= v2_it.id) - } - else - { - // move v2 forward - v2_it = v2.lower_bound(v1_it->first); - // v2_it = (first element >= v1_it.id) - } - } - - // ||v - w||_{L2} = sqrt( 2 - 2 * Sum(v_i * w_i) ) - // for all i | v_i != 0 and w_i != 0 ) - // (Nister, 2006) - if(score >= 1) // rounding errors - score = 1.0; - else - score = 1.0 - sqrt(1.0 - score); // [0..1] - - return score; -} - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -double ChiSquareScoring::score(const BowVector &v1, const BowVector &v2) - const -{ - BowVector::const_iterator v1_it, v2_it; - const BowVector::const_iterator v1_end = v1.end(); - const BowVector::const_iterator v2_end = v2.end(); - - v1_it = v1.begin(); - v2_it = v2.begin(); - - double score = 0; - - // all the items are taken into account - - while(v1_it != v1_end && v2_it != v2_end) - { - const WordValue& vi = v1_it->second; - const WordValue& wi = v2_it->second; - - if(v1_it->first == v2_it->first) - { - // (v-w)^2/(v+w) - v - w = -4 vw/(v+w) - // we move the -4 out - if(vi + wi != 0.0) score += vi * wi / (vi + wi); - - // move v1 and v2 forward - ++v1_it; - ++v2_it; - } - else if(v1_it->first < v2_it->first) - { - // move v1 forward - v1_it = v1.lower_bound(v2_it->first); - } - else - { - // move v2 forward - v2_it = v2.lower_bound(v1_it->first); - } - } - - // this takes the -4 into account - score = 2. * score; // [0..1] - - return score; -} - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -double KLScoring::score(const BowVector &v1, const BowVector &v2) const -{ - BowVector::const_iterator v1_it, v2_it; - const BowVector::const_iterator v1_end = v1.end(); - const BowVector::const_iterator v2_end = v2.end(); - - v1_it = v1.begin(); - v2_it = v2.begin(); - - double score = 0; - - // all the items or v are taken into account - - while(v1_it != v1_end && v2_it != v2_end) - { - const WordValue& vi = v1_it->second; - const WordValue& wi = v2_it->second; - - if(v1_it->first == v2_it->first) - { - if(vi != 0 && wi != 0) score += vi * log(vi/wi); - - // move v1 and v2 forward - ++v1_it; - ++v2_it; - } - else if(v1_it->first < v2_it->first) - { - // move v1 forward - score += vi * (log(vi) - LOG_EPS); - ++v1_it; - } - else - { - // move v2_it forward, do not add any score - v2_it = v2.lower_bound(v1_it->first); - // v2_it = (first element >= v1_it.id) - } - } - - // sum rest of items of v - for(; v1_it != v1_end; ++v1_it) - if(v1_it->second != 0) - score += v1_it->second * (log(v1_it->second) - LOG_EPS); - - return score; // cannot be scaled -} - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -double BhattacharyyaScoring::score(const BowVector &v1, - const BowVector &v2) const -{ - BowVector::const_iterator v1_it, v2_it; - const BowVector::const_iterator v1_end = v1.end(); - const BowVector::const_iterator v2_end = v2.end(); - - v1_it = v1.begin(); - v2_it = v2.begin(); - - double score = 0; - - while(v1_it != v1_end && v2_it != v2_end) - { - const WordValue& vi = v1_it->second; - const WordValue& wi = v2_it->second; - - if(v1_it->first == v2_it->first) - { - score += sqrt(vi * wi); - - // move v1 and v2 forward - ++v1_it; - ++v2_it; - } - else if(v1_it->first < v2_it->first) - { - // move v1 forward - v1_it = v1.lower_bound(v2_it->first); - // v1_it = (first element >= v2_it.id) - } - else - { - // move v2 forward - v2_it = v2.lower_bound(v1_it->first); - // v2_it = (first element >= v1_it.id) - } - } - - return score; // already scaled -} - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -double DotProductScoring::score(const BowVector &v1, - const BowVector &v2) const -{ - BowVector::const_iterator v1_it, v2_it; - const BowVector::const_iterator v1_end = v1.end(); - const BowVector::const_iterator v2_end = v2.end(); - - v1_it = v1.begin(); - v2_it = v2.begin(); - - double score = 0; - - while(v1_it != v1_end && v2_it != v2_end) - { - const WordValue& vi = v1_it->second; - const WordValue& wi = v2_it->second; - - if(v1_it->first == v2_it->first) - { - score += vi * wi; - - // move v1 and v2 forward - ++v1_it; - ++v2_it; - } - else if(v1_it->first < v2_it->first) - { - // move v1 forward - v1_it = v1.lower_bound(v2_it->first); - // v1_it = (first element >= v2_it.id) - } - else - { - // move v2 forward - v2_it = v2.lower_bound(v1_it->first); - // v2_it = (first element >= v1_it.id) - } - } - - return score; // cannot scale -} - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - diff --git a/thirdparty/DBoW3/src/ScoringObject.h b/thirdparty/DBoW3/src/ScoringObject.h deleted file mode 100644 index 8d6c64e..0000000 --- a/thirdparty/DBoW3/src/ScoringObject.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * File: ScoringObject.h - * Date: November 2011 - * Author: Dorian Galvez-Lopez - * Description: functions to compute bow scores - * License: see the LICENSE.txt file - * - */ - -#ifndef __D_T_SCORING_OBJECT__ -#define __D_T_SCORING_OBJECT__ - -#include "BowVector.h" -#include "exports.h" -namespace DBoW3 { - -/// Base class of scoring functions -class DBOW_API GeneralScoring -{ -public: - /** - * Computes the score between two vectors. Vectors must be sorted and - * normalized if necessary - * @param v (in/out) - * @param w (in/out) - * @return score - */ - virtual double score(const BowVector &v, const BowVector &w) const = 0; - - /** - * Returns whether a vector must be normalized before scoring according - * to the scoring scheme - * @param norm norm to use - * @return true iff must normalize - */ - virtual bool mustNormalize(LNorm &norm) const = 0; - - /// Log of epsilon - static const double LOG_EPS; - // If you change the type of WordValue, make sure you change also the - // epsilon value (this is needed by the KL method) - - virtual ~GeneralScoring() {} //!< Required for virtual base classes -}; - -/** - * Macro for defining Scoring classes - * @param NAME name of class - * @param MUSTNORMALIZE if vectors must be normalized to compute the score - * @param NORM type of norm to use when MUSTNORMALIZE - */ -#define __SCORING_CLASS(NAME, MUSTNORMALIZE, NORM) \ - NAME: public GeneralScoring \ - { public: \ - /** \ - * Computes score between two vectors \ - * @param v \ - * @param w \ - * @return score between v and w \ - */ \ - virtual double score(const BowVector &v, const BowVector &w) const; \ - \ - /** \ - * Says if a vector must be normalized according to the scoring function \ - * @param norm (out) if true, norm to use - * @return true iff vectors must be normalized \ - */ \ - virtual inline bool mustNormalize(LNorm &norm) const \ - { norm = NORM; return MUSTNORMALIZE; } \ - } - -/// L1 Scoring object -class __SCORING_CLASS(L1Scoring, true, L1); - -/// L2 Scoring object -class __SCORING_CLASS(L2Scoring, true, L2); - -/// Chi square Scoring object -class __SCORING_CLASS(ChiSquareScoring, true, L1); - -/// KL divergence Scoring object -class __SCORING_CLASS(KLScoring, true, L1); - -/// Bhattacharyya Scoring object -class __SCORING_CLASS(BhattacharyyaScoring, true, L1); - -/// Dot product Scoring object -class __SCORING_CLASS(DotProductScoring, false, L1); - -#undef __SCORING_CLASS - -} // namespace DBoW3 - -#endif - diff --git a/thirdparty/DBoW3/src/Vocabulary.cpp b/thirdparty/DBoW3/src/Vocabulary.cpp deleted file mode 100644 index 47d64f5..0000000 --- a/thirdparty/DBoW3/src/Vocabulary.cpp +++ /dev/null @@ -1,1558 +0,0 @@ -#include "Vocabulary.h" -#include -#include -#include "DescManip.h" -#include "quicklz.h" -#include "timers.h" - -namespace DBoW3 { -// -------------------------------------------------------------------------- - -Vocabulary::Vocabulary(int k, int L, WeightingType weighting, - ScoringType scoring) - : m_k(k), - m_L(L), - m_weighting(weighting), - m_scoring(scoring), - m_scoring_object(NULL) { - createScoringObject(); -} - -// -------------------------------------------------------------------------- - -Vocabulary::Vocabulary(const std::string &filename) : m_scoring_object(NULL) { - load(filename); -} - -// -------------------------------------------------------------------------- - -Vocabulary::Vocabulary(const char *filename) : m_scoring_object(NULL) { - load(filename); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::createScoringObject() { - delete m_scoring_object; - m_scoring_object = NULL; - - switch (m_scoring) { - case L1_NORM: - m_scoring_object = new L1Scoring; - break; - - case L2_NORM: - m_scoring_object = new L2Scoring; - break; - - case CHI_SQUARE: - m_scoring_object = new ChiSquareScoring; - break; - - case KL: - m_scoring_object = new KLScoring; - break; - - case BHATTACHARYYA: - m_scoring_object = new BhattacharyyaScoring; - break; - - case DOT_PRODUCT: - m_scoring_object = new DotProductScoring; - break; - } -} - -// -------------------------------------------------------------------------- - -void Vocabulary::setScoringType(ScoringType type) { - m_scoring = type; - createScoringObject(); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::setWeightingType(WeightingType type) { - this->m_weighting = type; -} - -// -------------------------------------------------------------------------- - -Vocabulary::Vocabulary(const Vocabulary &voc) : m_scoring_object(NULL) { - *this = voc; -} - -// -------------------------------------------------------------------------- - -Vocabulary::~Vocabulary() { delete m_scoring_object; } - -// -------------------------------------------------------------------------- - -Vocabulary &Vocabulary::operator=(const Vocabulary &voc) { - this->m_k = voc.m_k; - this->m_L = voc.m_L; - this->m_scoring = voc.m_scoring; - this->m_weighting = voc.m_weighting; - - this->createScoringObject(); - - this->m_nodes.clear(); - this->m_words.clear(); - - this->m_nodes = voc.m_nodes; - this->createWords(); - - return *this; -} - -void Vocabulary::create(const std::vector &training_features) { - std::vector> vtf(training_features.size()); - for (size_t i = 0; i < training_features.size(); i++) { - vtf[i].resize(training_features[i].rows); - for (int r = 0; r < training_features[i].rows; r++) - vtf[i][r] = training_features[i].rowRange(r, r + 1); - } - create(vtf); -} - -void Vocabulary::create( - const std::vector> &training_features) { - m_nodes.clear(); - m_words.clear(); - - // expected_nodes = Sum_{i=0..L} ( k^i ) - int expected_nodes = - (int)((pow((double)m_k, (double)m_L + 1) - 1) / (m_k - 1)); - - m_nodes.reserve(expected_nodes); // avoid allocations when creating the tree - - std::vector features; - getFeatures(training_features, features); - - // create root - m_nodes.push_back(Node(0)); // root - - // create the tree - HKmeansStep(0, features, 1); - - // create the words - createWords(); - - // and set the weight of each node of the tree - setNodeWeights(training_features); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::create( - const std::vector> &training_features, int k, int L) { - m_k = k; - m_L = L; - - create(training_features); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::create( - const std::vector> &training_features, int k, int L, - WeightingType weighting, ScoringType scoring) { - m_k = k; - m_L = L; - m_weighting = weighting; - m_scoring = scoring; - createScoringObject(); - - create(training_features); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::getFeatures( - const std::vector> &training_features, - std::vector &features) const { - features.resize(0); - for (size_t i = 0; i < training_features.size(); i++) - for (size_t j = 0; j < training_features[i].size(); j++) - features.push_back(training_features[i][j]); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::HKmeansStep(NodeId parent_id, - const std::vector &descriptors, - int current_level) { - if (descriptors.empty()) return; - - // features associated to each cluster - std::vector clusters; - std::vector> groups; // groups[i] = [j1, j2, ...] - // j1, j2, ... indices of descriptors associated to cluster i - - clusters.reserve(m_k); - groups.reserve(m_k); - - if ((int)descriptors.size() <= m_k) { - // trivial case: one cluster per feature - groups.resize(descriptors.size()); - - for (unsigned int i = 0; i < descriptors.size(); i++) { - groups[i].push_back(i); - clusters.push_back(descriptors[i]); - } - } else { - // select clusters and groups with kmeans - - bool first_time = true; - bool goon = true; - - // to check if clusters move after iterations - std::vector last_association, current_association; - - while (goon) { - // 1. Calculate clusters - - if (first_time) { - // random sample - initiateClusters(descriptors, clusters); - } else { - // calculate cluster centres - - for (unsigned int c = 0; c < clusters.size(); ++c) { - std::vector cluster_descriptors; - cluster_descriptors.reserve(groups[c].size()); - std::vector::const_iterator vit; - for (vit = groups[c].begin(); vit != groups[c].end(); ++vit) { - cluster_descriptors.push_back(descriptors[*vit]); - } - - DescManip::meanValue(cluster_descriptors, clusters[c]); - } - - } // if(!first_time) - - // 2. Associate features with clusters - - // calculate distances to cluster centers - groups.clear(); - groups.resize(clusters.size(), std::vector()); - current_association.resize(descriptors.size()); - - // assoc.clear(); - - // unsigned int d = 0; - for (auto fit = descriptors.begin(); fit != descriptors.end(); - ++fit) //, ++d) - { - double best_dist = DescManip::distance((*fit), clusters[0]); - unsigned int icluster = 0; - - for (unsigned int c = 1; c < clusters.size(); ++c) { - double dist = DescManip::distance((*fit), clusters[c]); - if (dist < best_dist) { - best_dist = dist; - icluster = c; - } - } - - // assoc.ref(icluster, d) = 1; - - groups[icluster].push_back(fit - descriptors.begin()); - current_association[fit - descriptors.begin()] = icluster; - } - - // kmeans++ ensures all the clusters has any feature associated with them - - // 3. check convergence - if (first_time) { - first_time = false; - } else { - // goon = !eqUChar(last_assoc, assoc); - - goon = false; - for (unsigned int i = 0; i < current_association.size(); i++) { - if (current_association[i] != last_association[i]) { - goon = true; - break; - } - } - } - - if (goon) { - // copy last feature-cluster association - last_association = current_association; - // last_assoc = assoc.clone(); - } - - } // while(goon) - - } // if must run kmeans - - // create nodes - for (unsigned int i = 0; i < clusters.size(); ++i) { - NodeId id = m_nodes.size(); - m_nodes.push_back(Node(id)); - m_nodes.back().descriptor = clusters[i]; - m_nodes.back().parent = parent_id; - m_nodes[parent_id].children.push_back(id); - } - - // go on with the next level - if (current_level < m_L) { - // iterate again with the resulting clusters - const std::vector &children_ids = m_nodes[parent_id].children; - for (unsigned int i = 0; i < clusters.size(); ++i) { - NodeId id = children_ids[i]; - - std::vector child_features; - child_features.reserve(groups[i].size()); - - std::vector::const_iterator vit; - for (vit = groups[i].begin(); vit != groups[i].end(); ++vit) { - child_features.push_back(descriptors[*vit]); - } - - if (child_features.size() > 1) { - HKmeansStep(id, child_features, current_level + 1); - } - } - } -} - -// -------------------------------------------------------------------------- - -void Vocabulary::initiateClusters(const std::vector &descriptors, - std::vector &clusters) const { - initiateClustersKMpp(descriptors, clusters); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::initiateClustersKMpp(const std::vector &pfeatures, - std::vector &clusters) const { - // Implements kmeans++ seeding algorithm - // Algorithm: - // 1. Choose one center uniformly at random from among the data points. - // 2. For each data point x, compute D(x), the distance between x and the - // nearest - // center that has already been chosen. - // 3. Add one new data point as a center. Each point x is chosen with - // probability - // proportional to D(x)^2. - // 4. Repeat Steps 2 and 3 until k centers have been chosen. - // 5. Now that the initial centers have been chosen, proceed using standard - // k-means - // clustering. - - // DUtils::Random::SeedRandOnce(); - - clusters.resize(0); - clusters.reserve(m_k); - std::vector min_dists(pfeatures.size(), - std::numeric_limits::max()); - - // 1. - - int ifeature = - rand() % - pfeatures.size(); // DUtils::Random::RandomInt(0, pfeatures.size()-1); - - // create first cluster - clusters.push_back(pfeatures[ifeature]); - - // compute the initial distances - std::vector::iterator dit; - dit = min_dists.begin(); - for (auto fit = pfeatures.begin(); fit != pfeatures.end(); ++fit, ++dit) { - *dit = DescManip::distance((*fit), clusters.back()); - } - - while ((int)clusters.size() < m_k) { - // 2. - dit = min_dists.begin(); - for (auto fit = pfeatures.begin(); fit != pfeatures.end(); ++fit, ++dit) { - if (*dit > 0) { - double dist = DescManip::distance((*fit), clusters.back()); - if (dist < *dit) *dit = dist; - } - } - - // 3. - double dist_sum = std::accumulate(min_dists.begin(), min_dists.end(), 0.0); - - if (dist_sum > 0) { - double cut_d; - do { - cut_d = (double(rand()) / double(RAND_MAX)) * dist_sum; - } while (cut_d == 0.0); - - double d_up_now = 0; - for (dit = min_dists.begin(); dit != min_dists.end(); ++dit) { - d_up_now += *dit; - if (d_up_now >= cut_d) break; - } - - if (dit == min_dists.end()) - ifeature = pfeatures.size() - 1; - else - ifeature = dit - min_dists.begin(); - - clusters.push_back(pfeatures[ifeature]); - } // if dist_sum > 0 - else - break; - - } // while(used_clusters < m_k) -} - -// -------------------------------------------------------------------------- - -void Vocabulary::createWords() { - m_words.resize(0); - - if (!m_nodes.empty()) { - m_words.reserve((int)pow((double)m_k, (double)m_L)); - - auto nit = m_nodes.begin(); // ignore root - for (++nit; nit != m_nodes.end(); ++nit) { - if (nit->isLeaf()) { - nit->word_id = m_words.size(); - m_words.push_back(&(*nit)); - } - } - } -} - -// -------------------------------------------------------------------------- - -void Vocabulary::setNodeWeights( - const std::vector> &training_features) { - const unsigned int NWords = m_words.size(); - const unsigned int NDocs = training_features.size(); - - if (m_weighting == TF || m_weighting == BINARY) { - // idf part must be 1 always - for (unsigned int i = 0; i < NWords; i++) m_words[i]->weight = 1; - } else if (m_weighting == IDF || m_weighting == TF_IDF) { - // IDF and TF-IDF: we calculte the idf path now - - // Note: this actually calculates the idf part of the tf-idf score. - // The complete tf-idf score is calculated in ::transform - - std::vector Ni(NWords, 0); - std::vector counted(NWords, false); - - for (auto mit = training_features.begin(); mit != training_features.end(); - ++mit) { - fill(counted.begin(), counted.end(), false); - - for (auto fit = mit->begin(); fit < mit->end(); ++fit) { - WordId word_id; - transform(*fit, word_id); - - if (!counted[word_id]) { - Ni[word_id]++; - counted[word_id] = true; - } - } - } - - // set ln(N/Ni) - for (unsigned int i = 0; i < NWords; i++) { - if (Ni[i] > 0) { - m_words[i]->weight = log((double)NDocs / (double)Ni[i]); - } // else // This cannot occur if using kmeans++ - } - } -} - -// -------------------------------------------------------------------------- - -// -------------------------------------------------------------------------- - -float Vocabulary::getEffectiveLevels() const { - long sum = 0; - for (auto wit = m_words.begin(); wit != m_words.end(); ++wit) { - const Node *p = *wit; - - for (; p->id != 0; sum++) p = &m_nodes[p->parent]; - } - - return (float)((double)sum / (double)m_words.size()); -} - -// -------------------------------------------------------------------------- - -cv::Mat Vocabulary::getWord(WordId wid) const { - return m_words[wid]->descriptor; -} - -// -------------------------------------------------------------------------- - -WordValue Vocabulary::getWordWeight(WordId wid) const { - return m_words[wid]->weight; -} - -// -------------------------------------------------------------------------- - -WordId Vocabulary::transform(const cv::Mat &feature) const { - if (empty()) { - return 0; - } - - WordId wid; - transform(feature, wid); - return wid; -} - -// -------------------------------------------------------------------------- - -void Vocabulary::transform(const cv::Mat &features, BowVector &v) const { - // std::vector vf(features.rows); - // for(int r=0;rmustNormalize(norm); - - if (m_weighting == TF || m_weighting == TF_IDF) { - for (int r = 0; r < features.rows; r++) { - WordId id; - WordValue w; - // w is the idf value if TF_IDF, 1 if TF - transform(features.row(r), id, w); - // not stopped - if (w > 0) v.addWeight(id, w); - } - - if (!v.empty() && !must) { - // unnecessary when normalizing - const double nd = v.size(); - for (BowVector::iterator vit = v.begin(); vit != v.end(); vit++) - vit->second /= nd; - } - - } else // IDF || BINARY - { - for (int r = 0; r < features.rows; r++) { - WordId id; - WordValue w; - // w is idf if IDF, or 1 if BINARY - - transform(features.row(r), id, w); - - // not stopped - if (w > 0) v.addIfNotExist(id, w); - - } // if add_features - } // if m_weighting == ... - - if (must) v.normalize(norm); -} - -void Vocabulary::transform(const std::vector &features, - BowVector &v) const { - v.clear(); - - if (empty()) { - return; - } - - // normalize - LNorm norm; - bool must = m_scoring_object->mustNormalize(norm); - - if (m_weighting == TF || m_weighting == TF_IDF) { - for (auto fit = features.begin(); fit < features.end(); ++fit) { - WordId id; - WordValue w; - // w is the idf value if TF_IDF, 1 if TF - - transform(*fit, id, w); - - // not stopped - if (w > 0) v.addWeight(id, w); - } - - if (!v.empty() && !must) { - // unnecessary when normalizing - const double nd = v.size(); - for (BowVector::iterator vit = v.begin(); vit != v.end(); vit++) - vit->second /= nd; - } - - } else // IDF || BINARY - { - for (auto fit = features.begin(); fit < features.end(); ++fit) { - WordId id; - WordValue w; - // w is idf if IDF, or 1 if BINARY - - transform(*fit, id, w); - - // not stopped - if (w > 0) v.addIfNotExist(id, w); - - } // if add_features - } // if m_weighting == ... - - if (must) v.normalize(norm); -} - -void Vocabulary::transform(const std::vector> &features, - BowVector &v) const { - v.clear(); - - if (empty()) { - return; - } - - // normalize - LNorm norm; - bool must = m_scoring_object->mustNormalize(norm); - - if (m_weighting == TF || m_weighting == TF_IDF) { - for (auto fit = features.begin(); fit < features.end(); ++fit) { - WordId id; - WordValue w; - // w is the idf value if TF_IDF, 1 if TF - - transform(*fit, id, w); - - // not stopped - if (w > 0) v.addWeight(id, w); - } - - if (!v.empty() && !must) { - // unnecessary when normalizing - const double nd = v.size(); - for (BowVector::iterator vit = v.begin(); vit != v.end(); vit++) - vit->second /= nd; - } - - } else // IDF || BINARY - { - for (auto fit = features.begin(); fit < features.end(); ++fit) { - WordId id; - WordValue w; - // w is idf if IDF, or 1 if BINARY - - transform(*fit, id, w); - - // not stopped - if (w > 0) v.addIfNotExist(id, w); - - } // if add_features - } // if m_weighting == ... - - if (must) v.normalize(norm); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::transform(const std::vector> &features, - BowVector &v, FeatureVector &fv, - int levelsup) const { - v.clear(); - fv.clear(); - - if (empty()) // safe for subclasses - { - return; - } - - // normalize - LNorm norm; - bool must = m_scoring_object->mustNormalize(norm); - - if (m_weighting == TF || m_weighting == TF_IDF) { - unsigned int i_feature = 0; - for (auto fit = features.begin(); fit < features.end(); - ++fit, ++i_feature) { - WordId id; - NodeId nid; - WordValue w; - // w is the idf value if TF_IDF, 1 if TF - - transform(*fit, id, w, &nid, levelsup); - - if (w > 0) // not stopped - { - v.addWeight(id, w); - fv.addFeature(nid, i_feature); - } - } - - if (!v.empty() && !must) { - // unnecessary when normalizing - const double nd = v.size(); - for (BowVector::iterator vit = v.begin(); vit != v.end(); vit++) - vit->second /= nd; - } - - } else // IDF || BINARY - { - unsigned int i_feature = 0; - for (auto fit = features.begin(); fit < features.end(); - ++fit, ++i_feature) { - WordId id; - NodeId nid; - WordValue w; - // w is idf if IDF, or 1 if BINARY - - transform(*fit, id, w, &nid, levelsup); - - if (w > 0) // not stopped - { - v.addIfNotExist(id, w); - fv.addFeature(nid, i_feature); - } - } - } // if m_weighting == ... - - if (must) v.normalize(norm); -} - -void Vocabulary::transform(const std::vector &features, BowVector &v, - FeatureVector &fv, int levelsup) const { - v.clear(); - fv.clear(); - - if (empty()) // safe for subclasses - { - return; - } - - // normalize - LNorm norm; - bool must = m_scoring_object->mustNormalize(norm); - - if (m_weighting == TF || m_weighting == TF_IDF) { - unsigned int i_feature = 0; - for (auto fit = features.begin(); fit < features.end(); - ++fit, ++i_feature) { - WordId id; - NodeId nid; - WordValue w; - // w is the idf value if TF_IDF, 1 if TF - - transform(*fit, id, w, &nid, levelsup); - - if (w > 0) // not stopped - { - v.addWeight(id, w); - fv.addFeature(nid, i_feature); - } - } - - if (!v.empty() && !must) { - // unnecessary when normalizing - const double nd = v.size(); - for (BowVector::iterator vit = v.begin(); vit != v.end(); vit++) - vit->second /= nd; - } - - } else // IDF || BINARY - { - unsigned int i_feature = 0; - for (auto fit = features.begin(); fit < features.end(); - ++fit, ++i_feature) { - WordId id; - NodeId nid; - WordValue w; - // w is idf if IDF, or 1 if BINARY - - transform(*fit, id, w, &nid, levelsup); - - if (w > 0) // not stopped - { - v.addIfNotExist(id, w); - fv.addFeature(nid, i_feature); - } - } - } // if m_weighting == ... - - if (must) v.normalize(norm); -} - -// -------------------------------------------------------------------------- - -// -------------------------------------------------------------------------- - -void Vocabulary::transform(const cv::Mat &feature, WordId &id) const { - WordValue weight; - transform(feature, id, weight); -} - -// -------------------------------------------------------------------------- - -void Vocabulary::transform(const std::bitset<256> &feature, WordId &word_id, - WordValue &weight, NodeId *nid, int levelsup) const { - // propagate the feature down the tree - - // level at which the node must be stored in nid, if given - const int nid_level = m_L - levelsup; - if (nid_level <= 0 && nid != NULL) *nid = 0; // root - - NodeId final_id = 0; // root - int current_level = 0; - - do { - ++current_level; - auto const &nodes = m_nodes[final_id].children; - double best_d = std::numeric_limits::max(); - // DescManip::distance(feature, m_nodes[final_id].descriptor); - - for (const auto &id : nodes) { - if (m_nodes[id].descriptor.type() != CV_8U || - m_nodes[id].descriptor.cols != sizeof(std::bitset<256>)) { - std::cerr << "Wrong descriptor type" << std::endl; - std::abort(); - } - - std::bitset<256> *desc = (std::bitset<256> *)m_nodes[id].descriptor.data; - - double d = ((*desc) & feature).count(); - - if (d < best_d) { - best_d = d; - final_id = id; - } - } - - if (nid != NULL && current_level == nid_level) *nid = final_id; - - } while (!m_nodes[final_id].isLeaf()); - - // turn node id into word id - word_id = m_nodes[final_id].word_id; - weight = m_nodes[final_id].weight; -} - -void Vocabulary::transform(const cv::Mat &feature, WordId &word_id, - WordValue &weight, NodeId *nid, int levelsup) const { - // propagate the feature down the tree - - // level at which the node must be stored in nid, if given - const int nid_level = m_L - levelsup; - if (nid_level <= 0 && nid != NULL) *nid = 0; // root - - NodeId final_id = 0; // root - int current_level = 0; - - do { - ++current_level; - auto const &nodes = m_nodes[final_id].children; - double best_d = std::numeric_limits::max(); - // DescManip::distance(feature, m_nodes[final_id].descriptor); - - for (const auto &id : nodes) { - double d = DescManip::distance(feature, m_nodes[id].descriptor); - if (d < best_d) { - best_d = d; - final_id = id; - } - } - - if (nid != NULL && current_level == nid_level) *nid = final_id; - - } while (!m_nodes[final_id].isLeaf()); - - // turn node id into word id - word_id = m_nodes[final_id].word_id; - weight = m_nodes[final_id].weight; -} - -void Vocabulary::transform(const cv::Mat &feature, WordId &word_id, - WordValue &weight) const { - // propagate the feature down the tree - - // level at which the node must be stored in nid, if given - - NodeId final_id = 0; // root - // maximum speed by computing here distance and avoid calling to - // DescManip::distance - - // binary descriptor - // int ntimes=0; - if (feature.type() == CV_8U) { - do { - auto const &nodes = m_nodes[final_id].children; - uint64_t best_d = std::numeric_limits::max(); - int idx = 0; //, bestidx = 0; - for (const auto &id : nodes) { - // compute distance - // std::cout<(); - // for(int i=0;i(0); - // const float *b_ptr=b.ptr(0); - // for(int i = 0; i < a.cols; i ++) - // sqd += (a_ptr[i ] - b_ptr[i ])*(a_ptr[i ] - b_ptr[i ]); - // return sqd; - // } - - // do - // { - // auto const &nodes = m_nodes[final_id].children; - // double best_d = std::numeric_limits::max(); - - // for(const auto &id:nodes) - // { - // double d = DescManip::distance(feature, m_nodes[id].descriptor); - // if(d < best_d) - // { - // best_d = d; - // final_id = id; - // } - // } - // } while( !m_nodes[final_id].isLeaf() ); - - // turn node id into word id - word_id = m_nodes[final_id].word_id; - weight = m_nodes[final_id].weight; -} - -void Vocabulary::transform(const std::bitset<256> &feature, WordId &word_id, - WordValue &weight) const { - // propagate the feature down the tree - - // level at which the node must be stored in nid, if given - - NodeId final_id = 0; // root - // maximum speed by computing here distance and avoid calling to - // DescManip::distance - - // binary descriptor - // int ntimes=0; - if (1) { - do { - auto const &nodes = m_nodes[final_id].children; - uint64_t best_d = std::numeric_limits::max(); - int idx = 0; //, bestidx = 0; - for (const auto &id : nodes) { - // compute distance - // std::cout<)) { - std::cerr << "Wrong descriptor type" << std::endl; - std::abort(); - } - - std::bitset<256> *desc = - (std::bitset<256> *)m_nodes[id].descriptor.data; - - uint64_t dist = ((*desc) & feature).count(); - - if (dist < best_d) { - best_d = dist; - final_id = id; - // bestidx = idx; - } - idx++; - } - // std::cout<(); - // for(int i=0;i(0); - // const float *b_ptr=b.ptr(0); - // for(int i = 0; i < a.cols; i ++) - // sqd += (a_ptr[i ] - b_ptr[i ])*(a_ptr[i ] - b_ptr[i ]); - // return sqd; - // } - - // do - // { - // auto const &nodes = m_nodes[final_id].children; - // double best_d = std::numeric_limits::max(); - - // for(const auto &id:nodes) - // { - // double d = DescManip::distance(feature, m_nodes[id].descriptor); - // if(d < best_d) - // { - // best_d = d; - // final_id = id; - // } - // } - // } while( !m_nodes[final_id].isLeaf() ); - - // turn node id into word id - word_id = m_nodes[final_id].word_id; - weight = m_nodes[final_id].weight; -} - -// -------------------------------------------------------------------------- - -NodeId Vocabulary::getParentNode(WordId wid, int levelsup) const { - NodeId ret = m_words[wid]->id; // node id - while (levelsup > 0 && ret != 0) // ret == 0 --> root - { - --levelsup; - ret = m_nodes[ret].parent; - } - return ret; -} - -// -------------------------------------------------------------------------- - -void Vocabulary::getWordsFromNode(NodeId nid, - std::vector &words) const { - words.clear(); - - if (m_nodes[nid].isLeaf()) { - words.push_back(m_nodes[nid].word_id); - } else { - words.reserve(m_k); // ^1, ^2, ... - - std::vector parents; - parents.push_back(nid); - - while (!parents.empty()) { - NodeId parentid = parents.back(); - parents.pop_back(); - - const std::vector &child_ids = m_nodes[parentid].children; - std::vector::const_iterator cit; - - for (cit = child_ids.begin(); cit != child_ids.end(); ++cit) { - const Node &child_node = m_nodes[*cit]; - - if (child_node.isLeaf()) - words.push_back(child_node.word_id); - else - parents.push_back(*cit); - - } // for each child - } // while !parents.empty - } -} - -// -------------------------------------------------------------------------- - -int Vocabulary::stopWords(double minWeight) { - int c = 0; - for (auto wit = m_words.begin(); wit != m_words.end(); ++wit) { - if ((*wit)->weight < minWeight) { - ++c; - (*wit)->weight = 0; - } - } - return c; -} - -// -------------------------------------------------------------------------- - -void Vocabulary::save(const std::string &filename, - bool binary_compressed) const { - if (filename.find(".yml") == std::string::npos) { - std::ofstream file_out(filename, std::ios::binary); - if (!file_out) - throw std::runtime_error("Vocabulary::saveBinary Could not open file :" + - filename + " for writing"); - toStream(file_out, binary_compressed); - } else { - cv::FileStorage fs(filename.c_str(), cv::FileStorage::WRITE); - if (!fs.isOpened()) throw std::string("Could not open file ") + filename; - save(fs); - } -} - -// -------------------------------------------------------------------------- - -void Vocabulary::load(const std::string &filename) { - // check first if it is a binary file - std::ifstream ifile(filename, std::ios::binary); - if (!ifile) - throw std::runtime_error("Vocabulary::load Could not open file :" + - filename + " for reading"); - uint64_t sig; // magic number describing the file - ifile.read((char *)&sig, sizeof(sig)); - if (sig == 88877711233) { // it is a binary file. read from it - ifile.seekg(0, std::ios::beg); - fromStream(ifile); - - } else { - if (filename.find(".txt") != std::string::npos) { - // read from a text file (used in ORBSLAM2) - load_fromtxt(filename); - } else { - cv::FileStorage fs(filename.c_str(), cv::FileStorage::READ); - if (!fs.isOpened()) throw std::string("Could not open file ") + filename; - this->load(fs); - } - } -} - -void Vocabulary::save(cv::FileStorage &f, const std::string &name) const { - f << name << "{"; - - f << "k" << m_k; - f << "L" << m_L; - f << "scoringType" << m_scoring; - f << "weightingType" << m_weighting; - - // tree - f << "nodes" - << "["; - std::vector parents, children; - std::vector::const_iterator pit; - - parents.push_back(0); // root - - while (!parents.empty()) { - NodeId pid = parents.back(); - parents.pop_back(); - - const Node &parent = m_nodes[pid]; - children = parent.children; - - for (pit = children.begin(); pit != children.end(); pit++) { - const Node &child = m_nodes[*pit]; - std::cout << m_nodes[*pit].id << " "; - - // save node data - f << "{:"; - f << "nodeId" << (int)child.id; - f << "parentId" << (int)pid; - f << "weight" << (double)child.weight; - f << "descriptor" << DescManip::toString(child.descriptor); - f << "}"; - - // add to parent list - if (!child.isLeaf()) { - parents.push_back(*pit); - } - } - } - std::cout << "\n"; - - f << "]"; // nodes - - // words - f << "words" - << "["; - - for (auto wit = m_words.begin(); wit != m_words.end(); wit++) { - WordId id = wit - m_words.begin(); - f << "{:"; - f << "wordId" << (int)id; - f << "nodeId" << (int)(*wit)->id; - f << "}"; - } - - f << "]"; // words - - f << "}"; -} - -void Vocabulary::toStream(std::ostream &out_str, bool compressed) const { - uint64_t sig = 88877711233; // magic number describing the file - out_str.write((char *)&sig, sizeof(sig)); - out_str.write((char *)&compressed, sizeof(compressed)); - uint32_t nnodes = m_nodes.size(); - out_str.write((char *)&nnodes, sizeof(nnodes)); - if (nnodes == 0) return; - // save everything to a stream - std::stringstream aux_stream; - aux_stream.write((char *)&m_k, sizeof(m_k)); - aux_stream.write((char *)&m_L, sizeof(m_L)); - aux_stream.write((char *)&m_scoring, sizeof(m_scoring)); - aux_stream.write((char *)&m_weighting, sizeof(m_weighting)); - // nodes - std::vector parents = {0}; // root - - while (!parents.empty()) { - NodeId pid = parents.back(); - parents.pop_back(); - - const Node &parent = m_nodes[pid]; - - for (auto pit : parent.children) { - const Node &child = m_nodes[pit]; - aux_stream.write((char *)&child.id, sizeof(child.id)); - aux_stream.write((char *)&pid, sizeof(pid)); - aux_stream.write((char *)&child.weight, sizeof(child.weight)); - DescManip::toStream(child.descriptor, aux_stream); - // add to parent list - if (!child.isLeaf()) parents.push_back(pit); - } - } - // words - // save size - uint32_t m_words_size = m_words.size(); - aux_stream.write((char *)&m_words_size, sizeof(m_words_size)); - for (auto wit = m_words.begin(); wit != m_words.end(); wit++) { - WordId id = wit - m_words.begin(); - aux_stream.write((char *)&id, sizeof(id)); - aux_stream.write((char *)&(*wit)->id, sizeof((*wit)->id)); - } - - // now, decide if compress or not - if (compressed) { - qlz_state_compress state_compress; - memset(&state_compress, 0, sizeof(qlz_state_compress)); - // Create output buffer - int chunkSize = 10000; - std::vector compressed(chunkSize + size_t(400), 0); - std::vector input(chunkSize, 0); - int64_t total_size = static_cast(aux_stream.tellp()); - uint64_t total_compress_size = 0; - // calculate how many chunks will be written - uint32_t nChunks = total_size / chunkSize; - if (total_size % chunkSize != 0) nChunks++; - out_str.write((char *)&nChunks, sizeof(nChunks)); - // start compressing the chunks - while (total_size != 0) { - int readSize = chunkSize; - if (total_size < chunkSize) readSize = total_size; - aux_stream.read(&input[0], readSize); - uint64_t compressed_size = - qlz_compress(&input[0], &compressed[0], readSize, &state_compress); - total_size -= readSize; - out_str.write(&compressed[0], compressed_size); - total_compress_size += compressed_size; - } - } else { - out_str << aux_stream.rdbuf(); - } -} - -void Vocabulary::load_fromtxt(const std::string &filename) { - std::ifstream ifile(filename); - if (!ifile) - throw std::runtime_error( - "Vocabulary:: load_fromtxt Could not open file for reading:" + - filename); - int n1, n2; - { - std::string str; - getline(ifile, str); - std::stringstream ss(str); - ss >> m_k >> m_L >> n1 >> n2; - } - if (m_k < 0 || m_k > 20 || m_L < 1 || m_L > 10 || n1 < 0 || n1 > 5 || - n2 < 0 || n2 > 3) - throw std::runtime_error( - "Vocabulary loading failure: This is not a correct text file!"); - - m_scoring = (ScoringType)n1; - m_weighting = (WeightingType)n2; - createScoringObject(); - // nodes - int expected_nodes = - (int)((pow((double)m_k, (double)m_L + 1) - 1) / (m_k - 1)); - m_nodes.reserve(expected_nodes); - - m_words.reserve(pow((double)m_k, (double)m_L + 1)); - - m_nodes.resize(1); - m_nodes[0].id = 0; - - int counter = 0; - while (!ifile.eof()) { - std::string snode; - getline(ifile, snode); - if (counter++ % 100 == 0) std::cerr << "."; - // std::cout<> pid; - m_nodes[nid].parent = pid; - m_nodes[pid].children.push_back(nid); - - int nIsLeaf; - ssnode >> nIsLeaf; - - // read until the end and add to data - std::vector data; - data.reserve(100); - float d; - while (ssnode >> d) data.push_back(d); - // the weight is the last - m_nodes[nid].weight = data.back(); - data.pop_back(); // remove - // the rest, to the descriptor - m_nodes[nid].descriptor.create(1, data.size(), CV_8UC1); - auto ptr = m_nodes[nid].descriptor.ptr(0); - for (auto d : data) *ptr++ = d; - - if (nIsLeaf > 0) { - int wid = m_words.size(); - m_words.resize(wid + 1); - - m_nodes[nid].word_id = wid; - m_words[wid] = &m_nodes[nid]; - } else { - m_nodes[nid].children.reserve(m_k); - } - } -} -void Vocabulary::fromStream(std::istream &str) { - m_words.clear(); - m_nodes.clear(); - uint64_t sig = 0; // magic number describing the file - str.read((char *)&sig, sizeof(sig)); - if (sig != 88877711233) - throw std::runtime_error( - "Vocabulary::fromStream is not of appropriate type"); - bool compressed; - str.read((char *)&compressed, sizeof(compressed)); - uint32_t nnodes; - str.read((char *)&nnodes, sizeof(nnodes)); - if (nnodes == 0) return; - std::stringstream decompressed_stream; - std::istream *_used_str = 0; - if (compressed) { - qlz_state_decompress state_decompress; - memset(&state_decompress, 0, sizeof(qlz_state_decompress)); - int chunkSize = 10000; - std::vector decompressed(chunkSize); - std::vector input(chunkSize + 400); - // read how many chunks are there - uint32_t nChunks; - str.read((char *)&nChunks, sizeof(nChunks)); - for (uint32_t i = 0; i < nChunks; i++) { - str.read(&input[0], 9); - int c = qlz_size_compressed(&input[0]); - str.read(&input[9], c - 9); - size_t d = qlz_decompress(&input[0], &decompressed[0], &state_decompress); - decompressed_stream.write(&decompressed[0], d); - } - _used_str = &decompressed_stream; - } else { - _used_str = &str; - } - - _used_str->read((char *)&m_k, sizeof(m_k)); - _used_str->read((char *)&m_L, sizeof(m_L)); - _used_str->read((char *)&m_scoring, sizeof(m_scoring)); - _used_str->read((char *)&m_weighting, sizeof(m_weighting)); - - createScoringObject(); - m_nodes.resize(nnodes); - m_nodes[0].id = 0; - - for (size_t i = 1; i < m_nodes.size(); ++i) { - NodeId nid; - _used_str->read((char *)&nid, sizeof(NodeId)); - Node &child = m_nodes[nid]; - child.id = nid; - _used_str->read((char *)&child.parent, sizeof(child.parent)); - _used_str->read((char *)&child.weight, sizeof(child.weight)); - DescManip::fromStream(child.descriptor, *_used_str); - m_nodes[child.parent].children.push_back(child.id); - } - // // words - uint32_t m_words_size; - _used_str->read((char *)&m_words_size, sizeof(m_words_size)); - m_words.resize(m_words_size); - for (unsigned int i = 0; i < m_words.size(); ++i) { - WordId wid; - NodeId nid; - _used_str->read((char *)&wid, sizeof(wid)); - _used_str->read((char *)&nid, sizeof(nid)); - m_nodes[nid].word_id = wid; - m_words[wid] = &m_nodes[nid]; - } -} -// -------------------------------------------------------------------------- - -void Vocabulary::load(const cv::FileStorage &fs, const std::string &name) { - m_words.clear(); - m_nodes.clear(); - - cv::FileNode fvoc = fs[name]; - - m_k = (int)fvoc["k"]; - m_L = (int)fvoc["L"]; - m_scoring = (ScoringType)((int)fvoc["scoringType"]); - m_weighting = (WeightingType)((int)fvoc["weightingType"]); - - createScoringObject(); - - // nodes - cv::FileNode fn = fvoc["nodes"]; - - m_nodes.resize(fn.size() + 1); // +1 to include root - m_nodes[0].id = 0; - - for (unsigned int i = 0; i < fn.size(); ++i) { - NodeId nid = (int)fn[i]["nodeId"]; - NodeId pid = (int)fn[i]["parentId"]; - WordValue weight = (WordValue)fn[i]["weight"]; - std::string d = (std::string)fn[i]["descriptor"]; - - m_nodes[nid].id = nid; - m_nodes[nid].parent = pid; - m_nodes[nid].weight = weight; - m_nodes[pid].children.push_back(nid); - - DescManip::fromString(m_nodes[nid].descriptor, d); - } - - // words - fn = fvoc["words"]; - - m_words.resize(fn.size()); - - for (unsigned int i = 0; i < fn.size(); ++i) { - NodeId wid = (int)fn[i]["wordId"]; - NodeId nid = (int)fn[i]["nodeId"]; - - m_nodes[nid].word_id = wid; - m_words[wid] = &m_nodes[nid]; - } -} - -// -------------------------------------------------------------------------- - -/** - * Writes printable information of the vocabulary - * @param os stream to write to - * @param voc - */ - -std::ostream &operator<<(std::ostream &os, const Vocabulary &voc) { - os << "Vocabulary: k = " << voc.getBranchingFactor() - << ", L = " << voc.getDepthLevels() << ", Weighting = "; - - switch (voc.getWeightingType()) { - case TF_IDF: - os << "tf-idf"; - break; - case TF: - os << "tf"; - break; - case IDF: - os << "idf"; - break; - case BINARY: - os << "binary"; - break; - } - - os << ", Scoring = "; - switch (voc.getScoringType()) { - case L1_NORM: - os << "L1-norm"; - break; - case L2_NORM: - os << "L2-norm"; - break; - case CHI_SQUARE: - os << "Chi square distance"; - break; - case KL: - os << "KL-divergence"; - break; - case BHATTACHARYYA: - os << "Bhattacharyya coefficient"; - break; - case DOT_PRODUCT: - os << "Dot product"; - break; - } - - os << ", Number of words = " << voc.size(); - - return os; -} -/** - * @brief Vocabulary::clear - */ -void Vocabulary::clear() { - delete m_scoring_object; - m_scoring_object = 0; - m_nodes.clear(); - m_words.clear(); -} -int Vocabulary::getDescritorSize() const { - if (m_words.size() == 0) - return -1; - else - return m_words[0]->descriptor.cols; -} -int Vocabulary::getDescritorType() const { - if (m_words.size() == 0) - return -1; - else - return m_words[0]->descriptor.type(); -} -} diff --git a/thirdparty/DBoW3/src/Vocabulary.h b/thirdparty/DBoW3/src/Vocabulary.h deleted file mode 100644 index d2966f5..0000000 --- a/thirdparty/DBoW3/src/Vocabulary.h +++ /dev/null @@ -1,468 +0,0 @@ -/** - * File: Vocabulary.h - * Date: February 2011 - * Author: Dorian Galvez-Lopez - * Description: templated vocabulary - * License: see the LICENSE.txt file - * - */ - -#ifndef __D_T__VOCABULARY__ -#define __D_T__VOCABULARY__ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "BowVector.h" -#include "FeatureVector.h" -#include "ScoringObject.h" -#include "exports.h" -namespace DBoW3 { -/// Vocabulary -class DBOW_API Vocabulary { - friend class FastSearch; - - public: - /** - * Initiates an empty vocabulary - * @param k branching factor - * @param L depth levels - * @param weighting weighting type - * @param scoring scoring type - */ - Vocabulary(int k = 10, int L = 5, WeightingType weighting = TF_IDF, - ScoringType scoring = L1_NORM); - - /** - * Creates the vocabulary by loading a file - * @param filename - */ - Vocabulary(const std::string &filename); - - /** - * Creates the vocabulary by loading a file - * @param filename - */ - Vocabulary(const char *filename); - - /** - * Copy constructor - * @param voc - */ - Vocabulary(const Vocabulary &voc); - - /** - * Destructor - */ - virtual ~Vocabulary(); - - /** - * Assigns the given vocabulary to this by copying its data and removing - * all the data contained by this vocabulary before - * @param voc - * @return reference to this vocabulary - */ - Vocabulary &operator=(const Vocabulary &voc); - - /** - * Creates a vocabulary from the training features with the already - * defined parameters - * @param training_features - */ - virtual void create( - const std::vector> &training_features); - /** - * Creates a vocabulary from the training features with the already - * defined parameters - * @param training_features. Each row of a matrix is a feature - */ - virtual void create(const std::vector &training_features); - - /** - * Creates a vocabulary from the training features, setting the branching - * factor and the depth levels of the tree - * @param training_features - * @param k branching factor - * @param L depth levels - */ - virtual void create( - const std::vector> &training_features, int k, int L); - - /** - * Creates a vocabulary from the training features, setting the branching - * factor nad the depth levels of the tree, and the weighting and scoring - * schemes - */ - virtual void create( - const std::vector> &training_features, int k, int L, - WeightingType weighting, ScoringType scoring); - - /** - * Returns the number of words in the vocabulary - * @return number of words - */ - virtual inline unsigned int size() const { - return (unsigned int)m_words.size(); - } - - /** - * Returns whether the vocabulary is empty (i.e. it has not been trained) - * @return true iff the vocabulary is empty - */ - virtual inline bool empty() const { return m_words.empty(); } - - /** Clears the vocabulary object - */ - void clear(); - /** - * Transforms a set of descriptores into a bow vector - * @param features - * @param v (out) bow vector of weighted words - */ - virtual void transform(const std::vector &features, - BowVector &v) const; - - virtual void transform(const std::vector> &features, - BowVector &v) const; - - /** - * Transforms a set of descriptores into a bow vector - * @param features, one per row - * @param v (out) bow vector of weighted words - */ - virtual void transform(const cv::Mat &features, BowVector &v) const; - /** - * Transform a set of descriptors into a bow vector and a feature vector - * @param features - * @param v (out) bow vector - * @param fv (out) feature vector of nodes and feature indexes - * @param levelsup levels to go up the vocabulary tree to get the node index - */ - virtual void transform(const std::vector &features, BowVector &v, - FeatureVector &fv, int levelsup) const; - - /** - * Transforms a single feature into a word (without weight) - * @param feature - * @return word id - */ - virtual WordId transform(const cv::Mat &feature) const; - - void transform(const std::vector> &features, BowVector &v, - FeatureVector &fv, int levelsup) const; - - /** - * Returns the score of two vectors - * @param a vector - * @param b vector - * @return score between vectors - * @note the vectors must be already sorted and normalized if necessary - */ - double score(const BowVector &a, const BowVector &b) const { - return m_scoring_object->score(a, b); - } - - /** - * Returns the id of the node that is "levelsup" levels from the word given - * @param wid word id - * @param levelsup 0..L - * @return node id. if levelsup is 0, returns the node id associated to the - * word id - */ - virtual NodeId getParentNode(WordId wid, int levelsup) const; - - /** - * Returns the ids of all the words that are under the given node id, - * by traversing any of the branches that goes down from the node - * @param nid starting node id - * @param words ids of words - */ - void getWordsFromNode(NodeId nid, std::vector &words) const; - - /** - * Returns the branching factor of the tree (k) - * @return k - */ - inline int getBranchingFactor() const { return m_k; } - - /** - * Returns the depth levels of the tree (L) - * @return L - */ - inline int getDepthLevels() const { return m_L; } - - /** - * Returns the real depth levels of the tree on average - * @return average of depth levels of leaves - */ - float getEffectiveLevels() const; - - /** - * Returns the descriptor of a word - * @param wid word id - * @return descriptor - */ - virtual inline cv::Mat getWord(WordId wid) const; - - /** - * Returns the weight of a word - * @param wid word id - * @return weight - */ - virtual inline WordValue getWordWeight(WordId wid) const; - - /** - * Returns the weighting method - * @return weighting method - */ - inline WeightingType getWeightingType() const { return m_weighting; } - - /** - * Returns the scoring method - * @return scoring method - */ - inline ScoringType getScoringType() const { return m_scoring; } - - /** - * Changes the weighting method - * @param type new weighting type - */ - inline void setWeightingType(WeightingType type); - - /** - * Changes the scoring method - * @param type new scoring type - */ - void setScoringType(ScoringType type); - - /** - * Saves the vocabulary into a file. If filename extension contains .yml, - * opencv YALM format is used. Otherwise, binary format is employed - * @param filename - */ - void save(const std::string &filename, bool binary_compressed = true) const; - - /** - * Loads the vocabulary from a file created with save - * @param filename. - */ - void load(const std::string &filename); - - /** - * Saves the vocabulary to a file storage structure - * @param fn node in file storage - */ - virtual void save(cv::FileStorage &fs, - const std::string &name = "vocabulary") const; - - /** - * Loads the vocabulary from a file storage node - * @param fn first node - * @param subname name of the child node of fn where the tree is stored. - * If not given, the fn node is used instead - */ - virtual void load(const cv::FileStorage &fs, - const std::string &name = "vocabulary"); - - /** - * Stops those words whose weight is below minWeight. - * Words are stopped by setting their weight to 0. There are not returned - * later when transforming image features into vectors. - * Note that when using IDF or TF_IDF, the weight is the idf part, which - * is equivalent to -log(f), where f is the frequency of the word - * (f = Ni/N, Ni: number of training images where the word is present, - * N: number of training images). - * Note that the old weight is forgotten, and subsequent calls to this - * function with a lower minWeight have no effect. - * @return number of words stopped now - */ - virtual int stopWords(double minWeight); - - /** Returns the size of the descriptor employed. If the Vocabulary is empty, - * returns -1 - */ - int getDescritorSize() const; - /** Returns the type of the descriptor employed normally(8U_C1, 32F_C1) - */ - int getDescritorType() const; - // io to-from a stream - void toStream(std::ostream &str, bool compressed = true) const; - void fromStream(std::istream &str); - - protected: - /// reference to descriptor - typedef const cv::Mat pDescriptor; - - /// Tree node - struct Node { - /// Node id - NodeId id; - /// Weight if the node is a word - WordValue weight; - /// Children - std::vector children; - /// Parent node (undefined in case of root) - NodeId parent; - /// Node descriptor - cv::Mat descriptor; - - /// Word id if the node is a word - WordId word_id; - - /** - * Empty constructor - */ - Node() : id(0), weight(0), parent(0), word_id(0) {} - - /** - * Constructor - * @param _id node id - */ - Node(NodeId _id) : id(_id), weight(0), parent(0), word_id(0) {} - - /** - * Returns whether the node is a leaf node - * @return true iff the node is a leaf - */ - inline bool isLeaf() const { return children.empty(); } - }; - - protected: - /** - * Creates an instance of the scoring object accoring to m_scoring - */ - void createScoringObject(); - - /** - * Returns a set of pointers to descriptores - * @param training_features all the features - * @param features (out) pointers to the training features - */ - void getFeatures(const std::vector> &training_features, - std::vector &features) const; - - /** - * Returns the word id associated to a feature - * @param feature - * @param id (out) word id - * @param weight (out) word weight - * @param nid (out) if given, id of the node "levelsup" levels up - * @param levelsup - */ - virtual void transform(const cv::Mat &feature, WordId &id, WordValue &weight, - NodeId *nid, int levelsup = 0) const; - /** - * Returns the word id associated to a feature - * @param feature - * @param id (out) word id - * @param weight (out) word weight - * @param nid (out) if given, id of the node "levelsup" levels up - * @param levelsup - */ - virtual void transform(const cv::Mat &feature, WordId &id, - WordValue &weight) const; - - void transform(const std::bitset<256> &feature, WordId &word_id, - WordValue &weight) const; - - virtual void transform(const std::bitset<256> &feature, WordId &word_id, - WordValue &weight, NodeId *nid, int levelsup) const; - - /** - * Returns the word id associated to a feature - * @param feature - * @param id (out) word id - */ - virtual void transform(const cv::Mat &feature, WordId &id) const; - - /** - * Creates a level in the tree, under the parent, by running kmeans with - * a descriptor set, and recursively creates the subsequent levels too - * @param parent_id id of parent node - * @param descriptors descriptors to run the kmeans on - * @param current_level current level in the tree - */ - void HKmeansStep(NodeId parent_id, const std::vector &descriptors, - int current_level); - - /** - * Creates k clusters from the given descriptors with some seeding algorithm. - * @note In this class, kmeans++ is used, but this function should be - * overriden by inherited classes. - */ - virtual void initiateClusters(const std::vector &descriptors, - std::vector &clusters) const; - - /** - * Creates k clusters from the given descriptor sets by running the - * initial step of kmeans++ - * @param descriptors - * @param clusters resulting clusters - */ - void initiateClustersKMpp(const std::vector &descriptors, - std::vector &clusters) const; - - /** - * Create the words of the vocabulary once the tree has been built - */ - void createWords(); - - /** - * Sets the weights of the nodes of tree according to the given features. - * Before calling this function, the nodes and the words must be already - * created (by calling HKmeansStep and createWords) - * @param features - */ - void setNodeWeights(const std::vector> &features); - - /** - * Writes printable information of the vocabulary - * @param os stream to write to - * @param voc - */ - DBOW_API friend std::ostream &operator<<(std::ostream &os, - const Vocabulary &voc); - - /**Loads from ORBSLAM txt files - */ - void load_fromtxt(const std::string &filename); - - protected: - /// Branching factor - int m_k; - - /// Depth levels - int m_L; - - /// Weighting method - WeightingType m_weighting; - - /// Scoring method - ScoringType m_scoring; - - /// Object for computing scores - GeneralScoring *m_scoring_object; - - /// Tree nodes - std::vector m_nodes; - - /// Words of the vocabulary (tree leaves) - /// this condition holds: m_words[wid]->word_id == wid - std::vector m_words; - - public: - // for debug (REMOVE) - inline Node *getNodeWord(uint32_t idx) { return m_words[idx]; } -}; - -} // namespace DBoW3 - -#endif diff --git a/thirdparty/DBoW3/src/exports.h b/thirdparty/DBoW3/src/exports.h deleted file mode 100644 index c324953..0000000 --- a/thirdparty/DBoW3/src/exports.h +++ /dev/null @@ -1,51 +0,0 @@ -/***************************** -Copyright 2014 Rafael Muñoz Salinas. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other materials - provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the -authors and should not be interpreted as representing official policies, either expressed -or implied, of Rafael Muñoz Salinas. -********************************/ - - - -#ifndef __DBOW_CORE_TYPES_H__ -#define __DBOW_CORE_TYPES_H__ - -#if !defined _CRT_SECURE_NO_DEPRECATE && _MSC_VER > 1300 -#define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio 2005 warnings */ -#endif - -#if (defined WIN32 || defined _WIN32 || defined WINCE) && defined DBOW_DSO_EXPORTS - #define DBOW_API __declspec(dllexport) - #pragma warning ( disable : 4251 ) //disable warning to templates with dll linkage. - #pragma warning ( disable : 4290 ) //disable warning due to exception specifications. - #pragma warning ( disable : 4996 ) //disable warning regarding unsafe vsprintf. - #pragma warning ( disable : 4244 ) //disable warning convesions with lost of data. - -#else - #define DBOW_API -#endif - - -#define DBOW_VERSION "3.0.0" -#endif diff --git a/thirdparty/DBoW3/src/quicklz.c b/thirdparty/DBoW3/src/quicklz.c deleted file mode 100644 index 3742129..0000000 --- a/thirdparty/DBoW3/src/quicklz.c +++ /dev/null @@ -1,848 +0,0 @@ -// Fast data compression library -// Copyright (C) 2006-2011 Lasse Mikkel Reinhold -// lar@quicklz.com -// -// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything -// released into public must be open source) or under a commercial license if such -// has been acquired (see http://www.quicklz.com/order.html). The commercial license -// does not cover derived or ported versions created by third parties under GPL. - -// 1.5.0 final - -#include "quicklz.h" - -#if QLZ_VERSION_MAJOR != 1 || QLZ_VERSION_MINOR != 5 || QLZ_VERSION_REVISION != 0 - #error quicklz.c and quicklz.h have different versions -#endif - -#if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64)) - #define X86X64 -#endif - -#define MINOFFSET 2 -#define UNCONDITIONAL_MATCHLEN 6 -#define UNCOMPRESSED_END 4 -#define CWORD_LEN 4 - -#if QLZ_COMPRESSION_LEVEL == 1 && defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 - #define OFFSET_BASE source - #define CAST (ui32)(size_t) -#else - #define OFFSET_BASE 0 - #define CAST -#endif - -int qlz_get_setting(int setting) -{ - switch (setting) - { - case 0: return QLZ_COMPRESSION_LEVEL; - case 1: return sizeof(qlz_state_compress); - case 2: return sizeof(qlz_state_decompress); - case 3: return QLZ_STREAMING_BUFFER; -#ifdef QLZ_MEMORY_SAFE - case 6: return 1; -#else - case 6: return 0; -#endif - case 7: return QLZ_VERSION_MAJOR; - case 8: return QLZ_VERSION_MINOR; - case 9: return QLZ_VERSION_REVISION; - } - return -1; -} - -#if QLZ_COMPRESSION_LEVEL == 1 -static int same(const unsigned char *src, size_t n) -{ - while(n > 0 && *(src + n) == *src) - n--; - return n == 0 ? 1 : 0; -} -#endif - -static void reset_table_compress(qlz_state_compress *state) -{ - int i; - for(i = 0; i < QLZ_HASH_VALUES; i++) - { -#if QLZ_COMPRESSION_LEVEL == 1 - state->hash[i].offset = 0; -#else - state->hash_counter[i] = 0; -#endif - } -} - -static void reset_table_decompress(qlz_state_decompress *state) -{ - int i; - (void)state; - (void)i; -#if QLZ_COMPRESSION_LEVEL == 2 - for(i = 0; i < QLZ_HASH_VALUES; i++) - { - state->hash_counter[i] = 0; - } -#endif -} - -static __inline ui32 hash_func(ui32 i) -{ -#if QLZ_COMPRESSION_LEVEL == 2 - return ((i >> 9) ^ (i >> 13) ^ i) & (QLZ_HASH_VALUES - 1); -#else - return ((i >> 12) ^ i) & (QLZ_HASH_VALUES - 1); -#endif -} - -static __inline ui32 fast_read(void const *src, ui32 bytes) -{ -#ifndef X86X64 - unsigned char *p = (unsigned char*)src; - switch (bytes) - { - case 4: - return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24); - case 3: - return(*p | *(p + 1) << 8 | *(p + 2) << 16); - case 2: - return(*p | *(p + 1) << 8); - case 1: - return(*p); - } - return 0; -#else - if (bytes >= 1 && bytes <= 4) - return *((ui32*)src); - else - return 0; -#endif -} - -static __inline ui32 hashat(const unsigned char *src) -{ - ui32 fetch, hash; - fetch = fast_read(src, 3); - hash = hash_func(fetch); - return hash; -} - -static __inline void fast_write(ui32 f, void *dst, size_t bytes) -{ -#ifndef X86X64 - unsigned char *p = (unsigned char*)dst; - - switch (bytes) - { - case 4: - *p = (unsigned char)f; - *(p + 1) = (unsigned char)(f >> 8); - *(p + 2) = (unsigned char)(f >> 16); - *(p + 3) = (unsigned char)(f >> 24); - return; - case 3: - *p = (unsigned char)f; - *(p + 1) = (unsigned char)(f >> 8); - *(p + 2) = (unsigned char)(f >> 16); - return; - case 2: - *p = (unsigned char)f; - *(p + 1) = (unsigned char)(f >> 8); - return; - case 1: - *p = (unsigned char)f; - return; - } -#else - switch (bytes) - { - case 4: - *((ui32*)dst) = f; - return; - case 3: - *((ui32*)dst) = f; - return; - case 2: - *((ui16 *)dst) = (ui16)f; - return; - case 1: - *((unsigned char*)dst) = (unsigned char)f; - return; - } -#endif -} - - -size_t qlz_size_decompressed(const char *source) -{ - ui32 n, r; - n = (((*source) & 2) == 2) ? 4 : 1; - r = fast_read(source + 1 + n, n); - r = r & (0xffffffff >> ((4 - n)*8)); - return r; -} - -size_t qlz_size_compressed(const char *source) -{ - ui32 n, r; - n = (((*source) & 2) == 2) ? 4 : 1; - r = fast_read(source + 1, n); - r = r & (0xffffffff >> ((4 - n)*8)); - return r; -} - -size_t qlz_size_header(const char *source) -{ - size_t n = 2*((((*source) & 2) == 2) ? 4 : 1) + 1; - return n; -} - - -static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, ui32 n) -{ - // Caution if modifying memcpy_up! Overlap of dst and src must be special handled. -#ifndef X86X64 - unsigned char *end = dst + n; - while(dst < end) - { - *dst = *src; - dst++; - src++; - } -#else - ui32 f = 0; - do - { - *(ui32 *)(dst + f) = *(ui32 *)(src + f); - f += MINOFFSET + 1; - } - while (f < n); -#endif -} - -static __inline void update_hash(qlz_state_decompress *state, const unsigned char *s) -{ -#if QLZ_COMPRESSION_LEVEL == 1 - ui32 hash; - hash = hashat(s); - state->hash[hash].offset = s; - state->hash_counter[hash] = 1; -#elif QLZ_COMPRESSION_LEVEL == 2 - ui32 hash; - unsigned char c; - hash = hashat(s); - c = state->hash_counter[hash]; - state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = s; - c++; - state->hash_counter[hash] = c; -#endif - (void)state; - (void)s; -} - -#if QLZ_COMPRESSION_LEVEL <= 2 -static void update_hash_upto(qlz_state_decompress *state, unsigned char **lh, const unsigned char *max) -{ - while(*lh < max) - { - (*lh)++; - update_hash(state, *lh); - } -} -#endif - -static size_t qlz_compress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_compress *state) -{ - const unsigned char *last_byte = source + size - 1; - const unsigned char *src = source; - unsigned char *cword_ptr = destination; - unsigned char *dst = destination + CWORD_LEN; - ui32 cword_val = 1U << 31; - const unsigned char *last_matchstart = last_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; - ui32 fetch = 0; - unsigned int lits = 0; - - (void) lits; - - if(src <= last_matchstart) - fetch = fast_read(src, 3); - - while(src <= last_matchstart) - { - if ((cword_val & 1) == 1) - { - // store uncompressed if compression ratio is too low - if (src > source + (size >> 1) && dst - destination > src - source - ((src - source) >> 5)) - return 0; - - fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); - - cword_ptr = dst; - dst += CWORD_LEN; - cword_val = 1U << 31; - fetch = fast_read(src, 3); - } -#if QLZ_COMPRESSION_LEVEL == 1 - { - const unsigned char *o; - ui32 hash, cached; - - hash = hash_func(fetch); - cached = fetch ^ state->hash[hash].cache; - state->hash[hash].cache = fetch; - - o = state->hash[hash].offset + OFFSET_BASE; - state->hash[hash].offset = CAST(src - OFFSET_BASE); - -#ifdef X86X64 - if ((cached & 0xffffff) == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) - { - if(cached != 0) - { -#else - if (cached == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) - { - if (*(o + 3) != *(src + 3)) - { -#endif - hash <<= 4; - cword_val = (cword_val >> 1) | (1U << 31); - fast_write((3 - 2) | hash, dst, 2); - src += 3; - dst += 2; - } - else - { - const unsigned char *old_src = src; - size_t matchlen; - hash <<= 4; - - cword_val = (cword_val >> 1) | (1U << 31); - src += 4; - - if(*(o + (src - old_src)) == *src) - { - src++; - if(*(o + (src - old_src)) == *src) - { - size_t q = last_byte - UNCOMPRESSED_END - (src - 5) + 1; - size_t remaining = q > 255 ? 255 : q; - src++; - while(*(o + (src - old_src)) == *src && (size_t)(src - old_src) < remaining) - src++; - } - } - - matchlen = src - old_src; - if (matchlen < 18) - { - fast_write((ui32)(matchlen - 2) | hash, dst, 2); - dst += 2; - } - else - { - fast_write((ui32)(matchlen << 16) | hash, dst, 3); - dst += 3; - } - } - fetch = fast_read(src, 3); - lits = 0; - } - else - { - lits++; - *dst = *src; - src++; - dst++; - cword_val = (cword_val >> 1); -#ifdef X86X64 - fetch = fast_read(src, 3); -#else - fetch = (fetch >> 8 & 0xffff) | (*(src + 2) << 16); -#endif - } - } -#elif QLZ_COMPRESSION_LEVEL >= 2 - { - const unsigned char *o, *offset2; - ui32 hash, matchlen, k, m, best_k = 0; - unsigned char c; - size_t remaining = (last_byte - UNCOMPRESSED_END - src + 1) > 255 ? 255 : (last_byte - UNCOMPRESSED_END - src + 1); - (void)best_k; - - - //hash = hashat(src); - fetch = fast_read(src, 3); - hash = hash_func(fetch); - - c = state->hash_counter[hash]; - - offset2 = state->hash[hash].offset[0]; - if(offset2 < src - MINOFFSET && c > 0 && ((fast_read(offset2, 3) ^ fetch) & 0xffffff) == 0) - { - matchlen = 3; - if(*(offset2 + matchlen) == *(src + matchlen)) - { - matchlen = 4; - while(*(offset2 + matchlen) == *(src + matchlen) && matchlen < remaining) - matchlen++; - } - } - else - matchlen = 0; - for(k = 1; k < QLZ_POINTERS && c > k; k++) - { - o = state->hash[hash].offset[k]; -#if QLZ_COMPRESSION_LEVEL == 3 - if(((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) -#elif QLZ_COMPRESSION_LEVEL == 2 - if(*(src + matchlen) == *(o + matchlen) && ((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) -#endif - { - m = 3; - while(*(o + m) == *(src + m) && m < remaining) - m++; -#if QLZ_COMPRESSION_LEVEL == 3 - if ((m > matchlen) || (m == matchlen && o > offset2)) -#elif QLZ_COMPRESSION_LEVEL == 2 - if (m > matchlen) -#endif - { - offset2 = o; - matchlen = m; - best_k = k; - } - } - } - o = offset2; - state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; - c++; - state->hash_counter[hash] = c; - -#if QLZ_COMPRESSION_LEVEL == 3 - if(matchlen > 2 && src - o < 131071) - { - ui32 u; - size_t offset = src - o; - - for(u = 1; u < matchlen; u++) - { - hash = hashat(src + u); - c = state->hash_counter[hash]++; - state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src + u; - } - - cword_val = (cword_val >> 1) | (1U << 31); - src += matchlen; - - if(matchlen == 3 && offset <= 63) - { - *dst = (unsigned char)(offset << 2); - dst++; - } - else if (matchlen == 3 && offset <= 16383) - { - ui32 f = (ui32)((offset << 2) | 1); - fast_write(f, dst, 2); - dst += 2; - } - else if (matchlen <= 18 && offset <= 1023) - { - ui32 f = ((matchlen - 3) << 2) | ((ui32)offset << 6) | 2; - fast_write(f, dst, 2); - dst += 2; - } - - else if(matchlen <= 33) - { - ui32 f = ((matchlen - 2) << 2) | ((ui32)offset << 7) | 3; - fast_write(f, dst, 3); - dst += 3; - } - else - { - ui32 f = ((matchlen - 3) << 7) | ((ui32)offset << 15) | 3; - fast_write(f, dst, 4); - dst += 4; - } - } - else - { - *dst = *src; - src++; - dst++; - cword_val = (cword_val >> 1); - } -#elif QLZ_COMPRESSION_LEVEL == 2 - - if(matchlen > 2) - { - cword_val = (cword_val >> 1) | (1U << 31); - src += matchlen; - - if (matchlen < 10) - { - ui32 f = best_k | ((matchlen - 2) << 2) | (hash << 5); - fast_write(f, dst, 2); - dst += 2; - } - else - { - ui32 f = best_k | (matchlen << 16) | (hash << 5); - fast_write(f, dst, 3); - dst += 3; - } - } - else - { - *dst = *src; - src++; - dst++; - cword_val = (cword_val >> 1); - } -#endif - } -#endif - } - while (src <= last_byte) - { - if ((cword_val & 1) == 1) - { - fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); - cword_ptr = dst; - dst += CWORD_LEN; - cword_val = 1U << 31; - } -#if QLZ_COMPRESSION_LEVEL < 3 - if (src <= last_byte - 3) - { -#if QLZ_COMPRESSION_LEVEL == 1 - ui32 hash, fetch; - fetch = fast_read(src, 3); - hash = hash_func(fetch); - state->hash[hash].offset = CAST(src - OFFSET_BASE); - state->hash[hash].cache = fetch; -#elif QLZ_COMPRESSION_LEVEL == 2 - ui32 hash; - unsigned char c; - hash = hashat(src); - c = state->hash_counter[hash]; - state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; - c++; - state->hash_counter[hash] = c; -#endif - } -#endif - *dst = *src; - src++; - dst++; - cword_val = (cword_val >> 1); - } - - while((cword_val & 1) != 1) - cword_val = (cword_val >> 1); - - fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); - - // min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument - return dst - destination < 9 ? 9 : dst - destination; -} - -static size_t qlz_decompress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_decompress *state, const unsigned char *history) -{ - const unsigned char *src = source + qlz_size_header((const char *)source); - unsigned char *dst = destination; - const unsigned char *last_destination_byte = destination + size - 1; - ui32 cword_val = 1; - const unsigned char *last_matchstart = last_destination_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; - unsigned char *last_hashed = destination - 1; - const unsigned char *last_source_byte = source + qlz_size_compressed((const char *)source) - 1; - static const ui32 bitlut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; - - (void) last_source_byte; - (void) last_hashed; - (void) state; - (void) history; - - for(;;) - { - ui32 fetch; - - if (cword_val == 1) - { -#ifdef QLZ_MEMORY_SAFE - if(src + CWORD_LEN - 1 > last_source_byte) - return 0; -#endif - cword_val = fast_read(src, CWORD_LEN); - src += CWORD_LEN; - } - -#ifdef QLZ_MEMORY_SAFE - if(src + 4 - 1 > last_source_byte) - return 0; -#endif - - fetch = fast_read(src, 4); - - if ((cword_val & 1) == 1) - { - ui32 matchlen; - const unsigned char *offset2; - -#if QLZ_COMPRESSION_LEVEL == 1 - ui32 hash; - cword_val = cword_val >> 1; - hash = (fetch >> 4) & 0xfff; - offset2 = (const unsigned char *)(size_t)state->hash[hash].offset; - - if((fetch & 0xf) != 0) - { - matchlen = (fetch & 0xf) + 2; - src += 2; - } - else - { - matchlen = *(src + 2); - src += 3; - } - -#elif QLZ_COMPRESSION_LEVEL == 2 - ui32 hash; - unsigned char c; - cword_val = cword_val >> 1; - hash = (fetch >> 5) & 0x7ff; - c = (unsigned char)(fetch & 0x3); - offset2 = state->hash[hash].offset[c]; - - if((fetch & (28)) != 0) - { - matchlen = ((fetch >> 2) & 0x7) + 2; - src += 2; - } - else - { - matchlen = *(src + 2); - src += 3; - } - -#elif QLZ_COMPRESSION_LEVEL == 3 - ui32 offset; - cword_val = cword_val >> 1; - if ((fetch & 3) == 0) - { - offset = (fetch & 0xff) >> 2; - matchlen = 3; - src++; - } - else if ((fetch & 2) == 0) - { - offset = (fetch & 0xffff) >> 2; - matchlen = 3; - src += 2; - } - else if ((fetch & 1) == 0) - { - offset = (fetch & 0xffff) >> 6; - matchlen = ((fetch >> 2) & 15) + 3; - src += 2; - } - else if ((fetch & 127) != 3) - { - offset = (fetch >> 7) & 0x1ffff; - matchlen = ((fetch >> 2) & 0x1f) + 2; - src += 3; - } - else - { - offset = (fetch >> 15); - matchlen = ((fetch >> 7) & 255) + 3; - src += 4; - } - - offset2 = dst - offset; -#endif - -#ifdef QLZ_MEMORY_SAFE - if(offset2 < history || offset2 > dst - MINOFFSET - 1) - return 0; - - if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1)) - return 0; -#endif - - memcpy_up(dst, offset2, matchlen); - dst += matchlen; - -#if QLZ_COMPRESSION_LEVEL <= 2 - update_hash_upto(state, &last_hashed, dst - matchlen); - last_hashed = dst - 1; -#endif - } - else - { - if (dst < last_matchstart) - { - unsigned int n = bitlut[cword_val & 0xf]; -#ifdef X86X64 - *(ui32 *)dst = *(ui32 *)src; -#else - memcpy_up(dst, src, 4); -#endif - cword_val = cword_val >> n; - dst += n; - src += n; -#if QLZ_COMPRESSION_LEVEL <= 2 - update_hash_upto(state, &last_hashed, dst - 3); -#endif - } - else - { - while(dst <= last_destination_byte) - { - if (cword_val == 1) - { - src += CWORD_LEN; - cword_val = 1U << 31; - } -#ifdef QLZ_MEMORY_SAFE - if(src >= last_source_byte + 1) - return 0; -#endif - *dst = *src; - dst++; - src++; - cword_val = cword_val >> 1; - } - -#if QLZ_COMPRESSION_LEVEL <= 2 - update_hash_upto(state, &last_hashed, last_destination_byte - 3); // todo, use constant -#endif - return size; - } - - } - } -} - -size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state) -{ - size_t r; - ui32 compressed; - size_t base; - - if(size == 0 || size > 0xffffffff - 400) - return 0; - - if(size < 216) - base = 3; - else - base = 9; - -#if QLZ_STREAMING_BUFFER > 0 - if (state->stream_counter + size - 1 >= QLZ_STREAMING_BUFFER) -#endif - { - reset_table_compress(state); - r = base + qlz_compress_core((const unsigned char *)source, (unsigned char*)destination + base, size, state); -#if QLZ_STREAMING_BUFFER > 0 - reset_table_compress(state); -#endif - if(r == base) - { - memcpy(destination + base, source, size); - r = size + base; - compressed = 0; - } - else - { - compressed = 1; - } - state->stream_counter = 0; - } -#if QLZ_STREAMING_BUFFER > 0 - else - { - unsigned char *src = state->stream_buffer + state->stream_counter; - - memcpy(src, source, size); - r = base + qlz_compress_core(src, (unsigned char*)destination + base, size, state); - - if(r == base) - { - memcpy(destination + base, src, size); - r = size + base; - compressed = 0; - reset_table_compress(state); - } - else - { - compressed = 1; - } - state->stream_counter += size; - } -#endif - if(base == 3) - { - *destination = (unsigned char)(0 | compressed); - *(destination + 1) = (unsigned char)r; - *(destination + 2) = (unsigned char)size; - } - else - { - *destination = (unsigned char)(2 | compressed); - fast_write((ui32)r, destination + 1, 4); - fast_write((ui32)size, destination + 5, 4); - } - - *destination |= (QLZ_COMPRESSION_LEVEL << 2); - *destination |= (1 << 6); - *destination |= ((QLZ_STREAMING_BUFFER == 0 ? 0 : (QLZ_STREAMING_BUFFER == 100000 ? 1 : (QLZ_STREAMING_BUFFER == 1000000 ? 2 : 3))) << 4); - -// 76543210 -// 01SSLLHC - - return r; -} - -size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state) -{ - size_t dsiz = qlz_size_decompressed(source); - -#if QLZ_STREAMING_BUFFER > 0 - if (state->stream_counter + qlz_size_decompressed(source) - 1 >= QLZ_STREAMING_BUFFER) -#endif - { - if((*source & 1) == 1) - { - reset_table_decompress(state); - dsiz = qlz_decompress_core((const unsigned char *)source, (unsigned char *)destination, dsiz, state, (const unsigned char *)destination); - } - else - { - memcpy(destination, source + qlz_size_header(source), dsiz); - } - state->stream_counter = 0; - reset_table_decompress(state); - } -#if QLZ_STREAMING_BUFFER > 0 - else - { - unsigned char *dst = state->stream_buffer + state->stream_counter; - if((*source & 1) == 1) - { - dsiz = qlz_decompress_core((const unsigned char *)source, dst, dsiz, state, (const unsigned char *)state->stream_buffer); - } - else - { - memcpy(dst, source + qlz_size_header(source), dsiz); - reset_table_decompress(state); - } - memcpy(destination, dst, dsiz); - state->stream_counter += dsiz; - } -#endif - return dsiz; -} - diff --git a/thirdparty/DBoW3/src/quicklz.h b/thirdparty/DBoW3/src/quicklz.h deleted file mode 100644 index 6a710f1..0000000 --- a/thirdparty/DBoW3/src/quicklz.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef QLZ_HEADER -#define QLZ_HEADER - -// Fast data compression library -// Copyright (C) 2006-2011 Lasse Mikkel Reinhold -// lar@quicklz.com -// -// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything -// released into public must be open source) or under a commercial license if such -// has been acquired (see http://www.quicklz.com/order.html). The commercial license -// does not cover derived or ported versions created by third parties under GPL. - -// You can edit following user settings. Data must be decompressed with the same -// setting of QLZ_COMPRESSION_LEVEL and QLZ_STREAMING_BUFFER as it was compressed -// (see manual). If QLZ_STREAMING_BUFFER > 0, scratch buffers must be initially -// zeroed out (see manual). First #ifndef makes it possible to define settings from -// the outside like the compiler command line. - -// 1.5.0 final - -#ifndef QLZ_COMPRESSION_LEVEL - - // 1 gives fastest compression speed. 3 gives fastest decompression speed and best - // compression ratio. - #define QLZ_COMPRESSION_LEVEL 1 - //#define QLZ_COMPRESSION_LEVEL 2 - //#define QLZ_COMPRESSION_LEVEL 3 - - // If > 0, zero out both states prior to first call to qlz_compress() or qlz_decompress() - // and decompress packets in the same order as they were compressed - #define QLZ_STREAMING_BUFFER 0 - //#define QLZ_STREAMING_BUFFER 100000 - //#define QLZ_STREAMING_BUFFER 1000000 - - // Guarantees that decompression of corrupted data cannot crash. Decreases decompression - // speed 10-20%. Compression speed not affected. - //#define QLZ_MEMORY_SAFE -#endif - -#define QLZ_VERSION_MAJOR 1 -#define QLZ_VERSION_MINOR 5 -#define QLZ_VERSION_REVISION 0 - -// Using size_t, memset() and memcpy() -#include - -// Verify compression level -#if QLZ_COMPRESSION_LEVEL != 1 && QLZ_COMPRESSION_LEVEL != 2 && QLZ_COMPRESSION_LEVEL != 3 -#error QLZ_COMPRESSION_LEVEL must be 1, 2 or 3 -#endif - -typedef unsigned int ui32; -typedef unsigned short int ui16; - -// Decrease QLZ_POINTERS for level 3 to increase compression speed. Do not touch any other values! -#if QLZ_COMPRESSION_LEVEL == 1 -#define QLZ_POINTERS 1 -#define QLZ_HASH_VALUES 4096 -#elif QLZ_COMPRESSION_LEVEL == 2 -#define QLZ_POINTERS 4 -#define QLZ_HASH_VALUES 2048 -#elif QLZ_COMPRESSION_LEVEL == 3 -#define QLZ_POINTERS 16 -#define QLZ_HASH_VALUES 4096 -#endif - -// Detect if pointer size is 64-bit. It's not fatal if some 64-bit target is not detected because this is only for adding an optional 64-bit optimization. -#if defined _LP64 || defined __LP64__ || defined __64BIT__ || _ADDR64 || defined _WIN64 || defined __arch64__ || __WORDSIZE == 64 || (defined __sparc && defined __sparcv9) || defined __x86_64 || defined __amd64 || defined __x86_64__ || defined _M_X64 || defined _M_IA64 || defined __ia64 || defined __IA64__ - #define QLZ_PTR_64 -#endif - -// hash entry -typedef struct -{ -#if QLZ_COMPRESSION_LEVEL == 1 - ui32 cache; -#if defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 - unsigned int offset; -#else - const unsigned char *offset; -#endif -#else - const unsigned char *offset[QLZ_POINTERS]; -#endif - -} qlz_hash_compress; - -typedef struct -{ -#if QLZ_COMPRESSION_LEVEL == 1 - const unsigned char *offset; -#else - const unsigned char *offset[QLZ_POINTERS]; -#endif -} qlz_hash_decompress; - - -// states -typedef struct -{ - #if QLZ_STREAMING_BUFFER > 0 - unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; - #endif - size_t stream_counter; - qlz_hash_compress hash[QLZ_HASH_VALUES]; - unsigned char hash_counter[QLZ_HASH_VALUES]; -} qlz_state_compress; - - -#if QLZ_COMPRESSION_LEVEL == 1 || QLZ_COMPRESSION_LEVEL == 2 - typedef struct - { -#if QLZ_STREAMING_BUFFER > 0 - unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; -#endif - qlz_hash_decompress hash[QLZ_HASH_VALUES]; - unsigned char hash_counter[QLZ_HASH_VALUES]; - size_t stream_counter; - } qlz_state_decompress; -#elif QLZ_COMPRESSION_LEVEL == 3 - typedef struct - { -#if QLZ_STREAMING_BUFFER > 0 - unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; -#endif -#if QLZ_COMPRESSION_LEVEL <= 2 - qlz_hash_decompress hash[QLZ_HASH_VALUES]; -#endif - size_t stream_counter; - } qlz_state_decompress; -#endif - - -#if defined (__cplusplus) -extern "C" { -#endif - -// Public functions of QuickLZ -size_t qlz_size_decompressed(const char *source); -size_t qlz_size_compressed(const char *source); -size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state); -size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state); -int qlz_get_setting(int setting); - -#if defined (__cplusplus) -} -#endif - -#endif - diff --git a/thirdparty/DBoW3/src/timers.h b/thirdparty/DBoW3/src/timers.h deleted file mode 100644 index 98fd0fc..0000000 --- a/thirdparty/DBoW3/src/timers.h +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef DBoW3_TIMERS_H -#define DBoW3_TIMERS_H - -#include -#include -#include -#include -namespace DBoW3 { - -// timer -struct ScopeTimer { - std::chrono::high_resolution_clock::time_point begin, end; - - std::string name; - bool use; - enum SCALE { NSEC, MSEC, SEC }; - SCALE sc; - ScopeTimer(std::string name_, bool use_ = true, SCALE _sc = MSEC) { - name = name_; - use = use_; - sc = _sc; - begin = std::chrono::high_resolution_clock::now(); - } - ~ScopeTimer() { - if (use) { - end = std::chrono::high_resolution_clock::now(); - double fact = 1; - std::string str; - switch (sc) { - case NSEC: - fact = 1; - str = "ns"; - break; - case MSEC: - fact = 1e6; - str = "ms"; - break; - case SEC: - fact = 1e9; - str = "s"; - break; - }; - - std::cout << "Time (" << name << ")= " - << double(std::chrono::duration_cast( - end - begin) - .count()) / - fact - << str << std::endl; - ; - } - } -}; - -struct ScopedTimerEvents { - enum SCALE { NSEC, MSEC, SEC }; - SCALE sc; - std::vector vtimes; - std::vector names; - std::string _name; - - ScopedTimerEvents(std::string name = "", bool start = true, - SCALE _sc = MSEC) { - if (start) add("start"); - sc = _sc; - _name = name; - } - - void add(std::string name) { - vtimes.push_back(std::chrono::high_resolution_clock::now()); - names.push_back(name); - } - void addspaces(std::vector &str) { - // get max size - size_t m = -1; - for (auto &s : str) m = std::max(s.size(), m); - for (auto &s : str) { - while (s.size() < m) s.push_back(' '); - } - } - - ~ScopedTimerEvents() { - double fact = 1; - std::string str; - switch (sc) { - case NSEC: - fact = 1; - str = "ns"; - break; - case MSEC: - fact = 1e6; - str = "ms"; - break; - case SEC: - fact = 1e9; - str = "s"; - break; - }; - - add("total"); - addspaces(names); - for (size_t i = 1; i < vtimes.size(); i++) { - std::cout << "Time(" << _name << ")-" << names[i] << " " - << double(std::chrono::duration_cast( - vtimes[i] - vtimes[i - 1]) - .count()) / - fact - << str << " " - << double(std::chrono::duration_cast( - vtimes[i] - vtimes[0]) - .count()) / - fact - << str << std::endl; - } - } -}; - -struct Timer { - enum SCALE { NSEC, MSEC, SEC }; - - std::chrono::high_resolution_clock::time_point _s; - double sum = 0, n = 0; - std::string _name; - Timer() {} - - Timer(std::string name) : _name(name) {} - void setName(std::string name) { _name = name; } - void start() { _s = std::chrono::high_resolution_clock::now(); } - void end() { - auto e = std::chrono::high_resolution_clock::now(); - sum += double( - std::chrono::duration_cast(e - _s).count()); - n++; - } - - void print(SCALE sc = MSEC) { - double fact = 1; - std::string str; - switch (sc) { - case NSEC: - fact = 1; - str = "ns"; - break; - case MSEC: - fact = 1e6; - str = "ms"; - break; - case SEC: - fact = 1e9; - str = "s"; - break; - }; - std::cout << "Time(" << _name << ")= " << (sum / n) / fact << str - << std::endl; - } -}; -} - -#endif