diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e5ac308..78c5f4af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,11 +26,7 @@ set(SRCS src/BowVector.cpp src/FBrief.cpp src/FORB.cpp src/FeatureVector.cpp src/QueryResults.cpp src/ScoringObject.cpp) -set(DEPENDENCY_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies) -set(DEPENDENCY_INSTALL_DIR ${DEPENDENCY_DIR}/install) - find_package(OpenCV REQUIRED) -include_directories(${OpenCV_INCLUDE_DIRS}) if(BUILD_DBoW2) set(LIB_SHARED "SHARED") @@ -38,14 +34,23 @@ if(BUILD_DBoW2) set(LIB_SHARED "STATIC") endif(WIN32) add_library(${PROJECT_NAME} ${LIB_SHARED} ${SRCS}) - target_include_directories(${PROJECT_NAME} PUBLIC include/DBoW2/ include/) - target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS}) - set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 11) + target_include_directories(${PROJECT_NAME} PUBLIC + $ + $ + $ + $) + target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCV_LIBRARIES}) + set_target_properties(${PROJECT_NAME} PROPERTIES + CXX_STANDARD 11 + POSITION_INDEPENDENT_CODE ON + DEBUG_POSTFIX _d + ) + add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) endif(BUILD_DBoW2) if(BUILD_Demo) add_executable(demo demo/demo.cpp) - target_link_libraries(demo ${PROJECT_NAME} ${OpenCV_LIBS}) + target_link_libraries(demo ${PROJECT_NAME} ${OpenCV_LIBRARIES}) set_target_properties(demo PROPERTIES CXX_STANDARD 11) file(COPY demo/images DESTINATION ${CMAKE_BINARY_DIR}/) endif(BUILD_Demo) @@ -53,13 +58,14 @@ endif(BUILD_Demo) configure_file(src/DBoW2.cmake.in "${PROJECT_BINARY_DIR}/DBoW2Config.cmake" @ONLY) -install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) +install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) if(BUILD_DBoW2) - install(DIRECTORY include/DBoW2 DESTINATION ${CMAKE_INSTALL_PREFIX}/include) + install(DIRECTORY include/DBoW2 DESTINATION ${CMAKE_INSTALL_PREFIX}/include/DBoW2) endif() -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/DBoW2Config.cmake" - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${PROJECT_NAME}) install(FILES "${PROJECT_BINARY_DIR}/DBoW2Config.cmake" DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cmake/DBoW2/) -install(DIRECTORY ${DEPENDENCY_INSTALL_DIR}/ DESTINATION ${CMAKE_INSTALL_PREFIX} OPTIONAL) - +install(EXPORT ${PROJECT_NAME}-targets DESTINATION lib/cmake/${PROJECT_NAME} + NAMESPACE ${PROJECT_NAME}::) diff --git a/include/DBoW2/TemplatedVocabulary.h b/include/DBoW2/TemplatedVocabulary.h index 6d8d6210..2ef32f7e 100644 --- a/include/DBoW2/TemplatedVocabulary.h +++ b/include/DBoW2/TemplatedVocabulary.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -30,9 +31,9 @@ namespace DBoW2 { template /// Generic Vocabulary class TemplatedVocabulary -{ +{ public: - + /** * Initiates an empty vocabulary * @param k branching factor @@ -227,13 +228,37 @@ class TemplatedVocabulary * @param filename */ void save(const std::string &filename) const; - + + /** + * Saves the vocabulary into a text file + * @param filename + */ + void saveToTextFile(const std::string &filename) const; + + /** + * Saves the vocabulary into a binary file + * @param filename + */ + void saveToBinaryFile(const std::string &filename) const; + /** * Loads the vocabulary from a file * @param filename */ void load(const std::string &filename); - + + /** + * Loads the vocabulary from a binary file + * @param filename + */ + void loadFromTextFile(const std::string &filename); + + /** + * Loads the vocabulary from a text file + * @param filename + */ + void loadFromBinaryFile(const std::string &filename); + /** * Saves the vocabulary to a file storage structure * @param fn node in file storage @@ -1343,6 +1368,61 @@ void TemplatedVocabulary::save(const std::string &filename) const // -------------------------------------------------------------------------- +template +void TemplatedVocabulary::saveToTextFile(const std::string &filename) const +{ + std::fstream f; + f.open(filename.c_str(), std::ios_base::out); + f << m_k << " " << m_L << " " << " " << m_scoring << " " << m_weighting << std::endl; + + for(size_t i=1; i +void TemplatedVocabulary::saveToBinaryFile(const std::string &filename) const +{ + std::ofstream vocabulary_bin(filename, std::ios::binary); + vocabulary_bin.write((char*)&m_k, sizeof(m_k)); + vocabulary_bin.write((char*)&m_L, sizeof(m_L)); + vocabulary_bin.write((char*)&m_weighting, sizeof(m_weighting)); + vocabulary_bin.write((char*)&m_scoring, sizeof(m_scoring)); + uint64_t vec_size = (uint64_t)m_nodes.size(); + vocabulary_bin.write((char*)&vec_size, sizeof(uint64_t)); + for (auto & node : m_nodes) + { + vocabulary_bin.write((char*)&node.id, sizeof(node.id)); + vocabulary_bin.write((char*)&node.weight, sizeof(node.weight)); + vocabulary_bin.write((char*)&node.parent, sizeof(node.parent)); + vocabulary_bin.write((char*)&node.word_id, sizeof(node.word_id)); + if (node.descriptor.total() > 0) + vocabulary_bin.write((char*)node.descriptor.ptr(), 32); + vec_size = (uint64_t)node.children.size(); + vocabulary_bin.write((char*)&vec_size, sizeof(uint64_t)); + if (vec_size > 0) + { + vocabulary_bin.write((char*)node.children.data(), sizeof(node.children[0]) * vec_size); + } + } + vocabulary_bin.close(); +} + +// -------------------------------------------------------------------------- + template void TemplatedVocabulary::load(const std::string &filename) { @@ -1354,6 +1434,141 @@ void TemplatedVocabulary::load(const std::string &filename) // -------------------------------------------------------------------------- +template +void TemplatedVocabulary::loadFromTextFile(const std::string &filename) +{ + std::ifstream f; + f.open(filename.c_str()); + if (!f.is_open()) + throw std::string("Could not open file ") + filename; + + m_words.clear(); + m_nodes.clear(); + + std::string s; + getline(f,s); + std::stringstream ss; + ss << s; + ss >> m_k; + ss >> m_L; + int n1, n2; + ss >> n1; + ss >> n2; + + if(m_k<0 || m_k>20 || m_L<1 || m_L>10 || n1<0 || n1>5 || n2<0 || n2>3) + { + throw std::string("Vocabulary loading failure: This is not a correct text file!") + filename; + } + + 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; + while(!f.eof()) + { + std::string snode; + std::getline(f,snode); + std::stringstream ssnode; + ssnode << snode; + + int nid = m_nodes.size(); + m_nodes.resize(m_nodes.size()+1); + m_nodes[nid].id = nid; + + int pid ; + ssnode >> pid; + m_nodes[nid].parent = pid; + m_nodes[pid].children.push_back(nid); + + int nIsLeaf; + ssnode >> nIsLeaf; + + std::stringstream ssd; + for(int iD=0;iD<32;iD++) // F::L + { + std::string sElement; + ssnode >> sElement; + ssd << sElement << " "; + } + F::fromString(m_nodes[nid].descriptor, ssd.str()); + + ssnode >> m_nodes[nid].weight; + + 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); + } + } +} + +// -------------------------------------------------------------------------- + +template +void TemplatedVocabulary::loadFromBinaryFile(const std::string & filename) +{ + std::ifstream vocabulary_bin(filename, std::ios::binary); + if (!vocabulary_bin.is_open()) + throw std::string("Could not open file ") + filename; + + vocabulary_bin.read((char*)&m_k, sizeof(m_k)); + vocabulary_bin.read((char*)&m_L, sizeof(m_L)); + vocabulary_bin.read((char*)&m_weighting, sizeof(m_weighting)); + vocabulary_bin.read((char*)&m_scoring, sizeof(m_scoring)); + createScoringObject(); + uint64_t vec_size = 0; + vocabulary_bin.read((char*)&vec_size, sizeof(uint64_t)); + m_nodes.resize(vec_size); + m_words.reserve(pow((double)m_k, (double)m_L + 1)); + + int nid = 0; + int wid = 0; + for (auto & node : m_nodes) + { + vocabulary_bin.read((char*)&node.id, sizeof(node.id)); + vocabulary_bin.read((char*)&node.weight, sizeof(node.weight)); + vocabulary_bin.read((char*)&node.parent, sizeof(node.parent)); + vocabulary_bin.read((char*)&node.word_id, sizeof(node.word_id)); + if (nid > 0) + { + node.descriptor.create(1, 32, CV_8UC1); + vocabulary_bin.read((char*)node.descriptor.ptr(), 32); + } + vec_size = 0; + vocabulary_bin.read((char*)&vec_size, sizeof(uint64_t)); + if (vec_size > 0) + { + node.children.resize(vec_size); + vocabulary_bin.read((char*)node.children.data(), sizeof(node.children[0]) * vec_size); + } + ++nid; + if (node.weight != 0) + { + m_words.resize(node.word_id + 1); + m_words[node.word_id] = &node; + } + } + vocabulary_bin.close(); +} + +// -------------------------------------------------------------------------- + template void TemplatedVocabulary::save(cv::FileStorage &f, const std::string &name) const diff --git a/src/DBoW2.cmake.in b/src/DBoW2.cmake.in index 2842f692..f052dde5 100644 --- a/src/DBoW2.cmake.in +++ b/src/DBoW2.cmake.in @@ -2,9 +2,15 @@ FIND_LIBRARY(DBoW2_LIBRARY DBoW2 PATHS "@CMAKE_INSTALL_PREFIX@/lib" ) FIND_PATH(DBoW2_INCLUDE_DIR DBoW2.h - PATHS "@CMAKE_INSTALL_PREFIX@/include/@PROJECT_NAME@" + PATHS "@CMAKE_INSTALL_PREFIX@/include/@PROJECT_NAME@" + PATH_SUFFIXES @PROJECT_NAME@ ) LIST(APPEND DBoW2_INCLUDE_DIR ${DBoW2_INCLUDE_DIR}/../) SET(DBoW2_LIBRARIES ${DBoW2_LIBRARY}) SET(DBoW2_LIBS ${DBoW2_LIBRARY}) SET(DBoW2_INCLUDE_DIRS ${DBoW2_INCLUDE_DIR}) + +#laod dbow targets +include(CMakeFindDependencyMacro) +find_dependency(OpenCV @OpenCV_VERSION@ EXACT) +include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake) \ No newline at end of file