diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d587440..16ad62f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,6 +39,7 @@ set (LIBDART_OPENMVG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src) find_package(JPEG REQUIRED) find_package(TIFF REQUIRED) +find_package(OpenCV REQUIRED) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extlib/cwalk) @@ -59,6 +60,7 @@ set(SKIP_INSTALL_ALL OFF CACHE BOOL "" FORCE) # we only want lib add_definitions(${PNG_DEFINITIONS}) add_library(${LIBDART_OPENMVG} SHARED + "mvg_override/describer/akaze.hpp" "frame.cxx" "streamingview.cxx" "image.cxx" @@ -67,6 +69,8 @@ add_library(${LIBDART_OPENMVG} SHARED set(CEREAL_INCLUDE_DIR ${OpenMVG_DIR}/../../../include/openMVG_dependencies/cereal/include/cereal/) +dump_cmake_variables("^opencv") + target_include_directories( ${LIBDART_OPENMVG} PRIVATE @@ -74,6 +78,7 @@ target_include_directories( ${PNG_INCLUDE_DIRS} ${ARCHIMEDES_INCLUDE_DIRS} ${CEREAL_INCLUDE_DIR} + ${OpenCV_INCLUDE_DIRS} ) target_link_libraries( @@ -82,6 +87,7 @@ target_link_libraries( jpeg tiff png + ${OpenCV_LIBS} OpenMVG::openMVG_image OpenMVG::openMVG_numeric OpenMVG::openMVG_features diff --git a/src/frame.cxx b/src/frame.cxx index 40a7273..2df768d 100644 --- a/src/frame.cxx +++ b/src/frame.cxx @@ -72,16 +72,18 @@ Frame *new_frame_from_handle(FILE *stream, int w, int h, int depth) return f; } -void clean_frame(Frame *f) { +void clean_frame(Frame *f) +{ fclose(f->stream); free(f); } #ifdef __cplusplus -DartOpenMvg::Frame::Frame(const DartOpenMvg::Frame &frame) { +DartOpenMvg::Frame::Frame(const DartOpenMvg::Frame &frame) +{ cFrame = frame.cFrame; - mRegions = std::unique_ptr(frame.mRegions.get()); + // mRegions = std::unique_ptr(frame.mRegions.get()); } openMVG::image::Image DartOpenMvg::imageFromFrame(const CFrame *frame) @@ -107,20 +109,15 @@ DartOpenMvg::Frames::Frames(openMVG::sfm::Bundle_Adjustment_Ceres::BA_Ceres_opti mAdjustment = openMVG::sfm::Bundle_Adjustment_Ceres(options); } -void DartOpenMvg::Frames::add_frame(FILE *handle, int w, int h, int depth) { +void DartOpenMvg::Frames::add_frame(FILE *handle, int w, int h, int depth) +{ CFrame *f = new_frame_from_handle(handle, w, h, depth); mFrames.push_back( - Frame(f) - ); + Frame(f)); } void DartOpenMvg::Frames::computeMatches() { -#ifdef OPENMVG_USE_OPENMP - OPENMVG_LOG_INFO << "Using the OPENMP thread interface"; - const bool b_multithreaded_pair_search = (eMatcherType_ == CASCADE_HASHING_L2); - // -> set to true for CASCADE_HASHING_L2, since OpenMP instructions are not used in this matcher -#endif // Match the pairs as a sequence // Within openMvg::matching_image_collection::Matcher @@ -129,16 +126,17 @@ void DartOpenMvg::Frames::computeMatches() for (size_t i = 0; i < mFrames.size() - 1; ++i) { const Frame &frame1 = mFrames[i]; - const Frame &frame2 = mFrames[i+1]; - auto *regions1 = frame1.mRegions.get(); - auto *regions2 = frame2.mRegions.get(); - if (!regions1) { + const Frame &frame2 = mFrames[i + 1]; + auto regions1 = frame1.mRegions.get(); + auto regions2 = frame2.mRegions.get(); + if (!regions1) + { std::string msg = std::string("Did you remember to calculate regions for frame ") + std::to_string(i) + "?"; throw std::out_of_range(msg); } - regions1->Load(); - std::cerr << "Loading " << std::to_string(regions1->RegionCount()) << " regions" << endl; + // regions1->Load(); + std::cerr << "Loading " << std::to_string(regions1->RegionCount()) << " regions" << std::endl; auto is_binary = regions1->IsBinary(); @@ -147,10 +145,6 @@ void DartOpenMvg::Frames::computeMatches() openMVG::matching::RegionMatcherFactory(openMVG::matching::EMatcherType::HNSW_L2, *regions1); if (!matcher) continue; - -#ifdef OPENMVG_USE_OPENMP -#pragma omp parallel for schedule(dynamic) if (b_multithreaded_pair_search) -#endif openMVG::matching::IndMatches vec_putative_matches; matcher->MatchDistanceRatio(0.5, *regions2, vec_putative_matches); if (vec_putative_matches.empty()) @@ -186,12 +180,17 @@ void DartOpenMvg::Frame::calculateFeatures() { using namespace openMVG::image; using namespace openMVG::features; - auto desc = SIFT_Anatomy_Image_describer(SIFT_Anatomy_Image_describer::Params()); - auto image = imageFromFrame(cFrame); - mRegions = desc.Describe(image); + MvgOverride::AKAZE_OCV_Image_describer desc; + auto im = imageFromFrame(cFrame); + mRegions = std::make_shared(std::move(desc.Describe(im))); + + if (!mRegions.get()) { + throw std::range_error("Could not set regions member."); + } } -void DartOpenMvg::Frames::resection() { +void DartOpenMvg::Frames::resection() +{ // openMVG::tracks::TracksUtilsMap::GetFeatIndexPerViewAndTrackId( // mTracks; // ) diff --git a/src/frame.h b/src/frame.h index 1eb3cb5..5e7ba7c 100644 --- a/src/frame.h +++ b/src/frame.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include "./base.hpp" +#include "./mvg_override/describer/akaze.hpp" #ifndef __FRAME_H #define __FRAME_H diff --git a/src/mvg_override/describer/akaze.hpp b/src/mvg_override/describer/akaze.hpp new file mode 100644 index 0000000..a13f9a1 --- /dev/null +++ b/src/mvg_override/describer/akaze.hpp @@ -0,0 +1,152 @@ +// This file is part of OpenMVG, an Open Multiple View Geometry C++ library. + +// Copyright (c) 2012, 2013 Pierre MOULON. + +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// The headers are special and must be included first. +#include + +#include "openMVG/image/image_io.hpp" +#include "openMVG/features/regions_factory_io.hpp" +#include "openMVG/sfm/sfm.hpp" +#include "openMVG/system/timer.hpp" + +/// OpenCV Includes +#include +#include + +#include +#include + +#ifndef __MVG_OVERRIDE_DESCRIBER_AKAZE_H +#define __MVG_OVERRIDE_DESCRIBER_AKAZE_H + + +namespace MvgOverride +{ + + using namespace openMVG; + using namespace openMVG::image; + using namespace openMVG::features; + using namespace openMVG::sfm; + + enum eGeometricModel + { + FUNDAMENTAL_MATRIX = 0, + ESSENTIAL_MATRIX = 1, + HOMOGRAPHY_MATRIX = 2 + }; + + enum ePairMode + { + PAIR_EXHAUSTIVE = 0, + PAIR_CONTIGUOUS = 1, + PAIR_FROM_FILE = 2 + }; + + /// + //- Create an Image_describer interface that use an OpenCV feature extraction method + // i.e. with the AKAZE detector+descriptor + //--/!\ If you use a new Regions type you define and register it in + // "openMVG/features/regions_factory.hpp" file. + /// + // Reuse the existing AKAZE floating point Keypoint. + typedef features::AKAZE_Float_Regions AKAZE_OpenCV_Regions; + // Define the Interface + class AKAZE_OCV_Image_describer : public Image_describer + { + public: + using Regions_type = AKAZE_OpenCV_Regions; + + cv::Ptr extractor; + + AKAZE_OCV_Image_describer() : Image_describer() + { + extractor = cv::AKAZE::create(cv::AKAZE::DESCRIPTOR_KAZE); + } + + bool Set_configuration_preset(EDESCRIBER_PRESET preset) override + { + return false; + } + /** + @brief Detect regions on the image and compute their attributes (description) + @param image Image. + @param mask 8-bit gray image for keypoint filtering (optional). + Non-zero values depict the region of interest. + @return regions The detected regions and attributes (the caller must delete the allocated data) + */ + std::unique_ptr Describe( + const Image &image, + const Image *mask = nullptr) override + { + return Describe_AKAZE_OCV(image, mask); + } + + /** + @brief Detect regions on the image and compute their attributes (description) + @param image Image. + @param mask 8-bit gray image for keypoint filtering (optional). + Non-zero values depict the region of interest. + @return regions The detected regions and attributes (the caller must delete the allocated data) + */ + std::unique_ptr Describe_AKAZE_OCV( + const Image &image, + const Image *mask = nullptr) + { + auto regions = std::unique_ptr(new Regions_type); + + cv::Mat img; + cv::eigen2cv(image.GetMat(), img); + + cv::Mat m_mask; + if (mask != nullptr) + { + cv::eigen2cv(mask->GetMat(), m_mask); + } + + std::vector vec_keypoints; + cv::Mat m_desc; + + extractor->detectAndCompute(img, m_mask, vec_keypoints, m_desc); + + if (!vec_keypoints.empty()) + { + // reserve some memory for faster keypoint saving + regions->Features().reserve(vec_keypoints.size()); + regions->Descriptors().reserve(vec_keypoints.size()); + + using DescriptorT = Descriptor; + DescriptorT descriptor; + int cpt = 0; + for (auto i_keypoint = vec_keypoints.begin(); i_keypoint != vec_keypoints.end(); ++i_keypoint, ++cpt) + { + const SIOPointFeature feat((*i_keypoint).pt.x, (*i_keypoint).pt.y, (*i_keypoint).size, (*i_keypoint).angle); + regions->Features().push_back(feat); + + memcpy(descriptor.data(), + m_desc.ptr(cpt), + DescriptorT::static_size * sizeof(DescriptorT::bin_type)); + regions->Descriptors().push_back(descriptor); + } + } + return regions; + }; + + /// Allocate Regions type depending of the Image_describer + std::unique_ptr Allocate() const override + { + return std::unique_ptr(new Regions_type); + } + + template + void serialize(Archive &ar) + { + } + }; +} + +#endif // __MVG_OVERRIDE_DESCRIBER_AKAZE_H