From 7d225729ecad45c74cdd44540e98d8371d42958f Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 22 Mar 2024 09:07:04 -0700 Subject: [PATCH] start developing unit tests for frames. --- src/CMakeLists.txt | 32 ++++++++++++++ src/extlib/openMVG | 2 +- src/frame.cxx | 95 ++++++++++++++++++++++++++++++---------- src/frame.h | 48 ++++++++++++++------ src/tests/test_frame.cxx | 85 +++++++++++++++++++++++++++++++++++ src/tests/test_image.cxx | 36 +-------------- src/util.h | 6 +++ util.cpp | 29 ++++++++++++ 8 files changed, 260 insertions(+), 73 deletions(-) create mode 100644 src/tests/test_frame.cxx create mode 100644 src/util.h create mode 100644 util.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b39c846..7e7a92a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -102,6 +102,11 @@ add_executable( ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_image.cxx ) +add_executable( + test_frame + ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_image.cxx +) + target_link_libraries( test_image cunit @@ -116,6 +121,20 @@ target_link_libraries( OpenMVG::openMVG_exif ) +target_link_libraries( + test_frame + cunit + cwalk + ${LIBDART_OPENMVG} + png + OpenMVG::openMVG_image + OpenMVG::openMVG_numeric + OpenMVG::openMVG_features + OpenMVG::openMVG_sfm + OpenMVG::openMVG_features + OpenMVG::openMVG_exif +) + target_include_directories( test_image PRIVATE @@ -124,6 +143,14 @@ target_include_directories( ${CEREAL_INCLUDE_DIR} ) +target_include_directories( + test_frame + PRIVATE + ${LIBDART_OPENMVG_INCLUDE_DIRS} + ${OpenMVG_INCLUDE_DIRS}/src + ${CEREAL_INCLUDE_DIR} +) + set_target_properties(test_image PROPERTIES LINKER_LANGUAGE CXX @@ -134,4 +161,9 @@ add_test ( COMMAND test_image ) +add_test ( + NAME test_frame + COMMAND test_frame +) + target_compile_definitions(${LIBDART_OPENMVG} PUBLIC DART_SHARED_LIB) \ No newline at end of file diff --git a/src/extlib/openMVG b/src/extlib/openMVG index 7fd19fc..aff37dd 160000 --- a/src/extlib/openMVG +++ b/src/extlib/openMVG @@ -1 +1 @@ -Subproject commit 7fd19fc22419a35481d39d2946f77e1dc00df37c +Subproject commit aff37dd005f85b3589aa50caca13b74ca7bd57e4 diff --git a/src/frame.cxx b/src/frame.cxx index f9e7b1e..2d727a5 100644 --- a/src/frame.cxx +++ b/src/frame.cxx @@ -90,6 +90,70 @@ openMVG::image::Image DartOpenMvg::imageFromFrame(const CFrame *frame) return openMVG::image::Image(eigenMatrix); } +DartOpenMvg::Frames::Frames(openMVG::sfm::Bundle_Adjustment_Ceres::BA_Ceres_options &options) +{ + mAdjustment = openMVG::sfm::Bundle_Adjustment_Ceres(options); +} + +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 + // they matcha gainst *ALL* images. However, since we know the order of the + // image sequences (video frames), we'll stick to the sequence order. + for (size_t i = 0; i < this->size() - 1; ++i) + { + const Frame &frame1 = this->at(i); + const Frame &frame2 = this->at(i + 1); + auto *regions1 = frame1.mRegions.get(); + auto *regions2 = frame2.mRegions.get(); + + // Initialize the matching interface + const std::unique_ptr matcher = + 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()) + { + return; + } + mFeatureMap[std::make_pair(i, i + 1)] = vec_putative_matches; + } +}; + +void DartOpenMvg::Frames::buildTracks() +{ + openMVG::tracks::TracksBuilder trackBuilder; + + openMVG::matching::PairWiseMatches matches; + + trackBuilder.Build(mFeatureMap); + trackBuilder.Filter(); + trackBuilder.ExportToSTL(mTracks); +} + +void DartOpenMvg::Frames::adjust() +{ + const openMVG::sfm::Optimize_Options ba_refine_options(openMVG::cameras::Intrinsic_Parameter_Type::ADJUST_ALL, + openMVG::sfm::Extrinsic_Parameter_Type::ADJUST_ALL, // Adjust camera motion + openMVG::sfm::Structure_Parameter_Type::ADJUST_ALL, // Adjust scene structure + openMVG::sfm::Control_Point_Parameter(), + false); + mAdjustment.Adjust(mSfmData, ba_refine_options); +} + void DartOpenMvg::Frame::calculateFeatures() { using namespace openMVG::image; @@ -99,30 +163,15 @@ void DartOpenMvg::Frame::calculateFeatures() mRegions = desc.Describe(image); } -openMVG::image::Image DartOpenMvg::Frame::getMvgImage() { +void DartOpenMvg::Frames::resection() { + // openMVG::tracks::TracksUtilsMap::GetFeatIndexPerViewAndTrackId( + // mTracks; + // ) +} + +openMVG::image::Image DartOpenMvg::Frame::getMvgImage() +{ return imageFromFrame(this->cFrame); } -void DartOpenMvg::Frames::computeMatches() -{ - using namespace openMVG::matching; - using namespace openMVG::matching_image_collection; - using namespace openMVG::sfm; - using namespace openMVG::image; - Matcher *matcher = nullptr; - - Regions_Provider provider = Regions_Provider(); - - matcher = new Matcher_Regions(0.8f, CASCADE_HASHING_L2); - - openMVG::Pair_Set pairs = openMVG::Pair_Set(); - Image im1 = this->at(0).getMvgImage(); - Image im2 = this->at(1).getMvgImage(); - auto pair = openMVG::Pair(0, 1); - pairs.insert(pair); - - PairWiseMatches map_punitive_matches; - - // matcher->Match(provider, pairs, map_punitive_matches, NULL); - #endif // __cplusplus \ No newline at end of file diff --git a/src/frame.h b/src/frame.h index 0b6b46c..3224081 100644 --- a/src/frame.h +++ b/src/frame.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,6 +19,19 @@ #include #include #include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -44,24 +59,19 @@ namespace DartOpenMvg { openMVG::image::Image imageFromFrame(const Frame *); - class InMemoryMatcherRegions : public openMVG::matching_image_collection::Matcher { - void Match( - const Pair_Set &, - PariWiseMatchesContainer &, - ) const override; - }; - class Frame { protected: - const CFrame *cFrame; std::stringstream mStream; int mW; int mH; int mDepth; - std::unique_ptr mRegions; public: + // TODO make this private + const CFrame *cFrame; + // TODO make this private + std::unique_ptr mRegions; Frame(const _Frame *f) : mW(f->w), mH(f->h), mDepth(f->depth) { cFrame = f; @@ -70,20 +80,28 @@ namespace DartOpenMvg read_buffer(f->stream, &buffer_data, &len); mStream = std::stringstream(std::string((char *)buffer_data)); } - openMVG::image::Image DartOpenMvg::Frame::getMvgImage(); + openMVG::image::Image getMvgImage(); void calculateFeatures(); }; - typedef std::pair FrameMatchKey; - typedef std::map FrameFeatureMatch; + typedef std::pair FrameMatchKey; + typedef std::map, openMVG::matching::IndMatches> FrameFeatureMatch; - class Frames : std::vector + class Frames : protected std::vector { protected: - FrameFeatureMatch mFeatureMap; + openMVG::matching::PairWiseMatches mFeatureMap; + openMVG::tracks::STLMAPTracks mTracks; + openMVG::sfm::SfM_Data mSfmData; + openMVG::sfm::Bundle_Adjustment_Ceres mAdjustment; public: + Frames(openMVG::sfm::Bundle_Adjustment_Ceres::BA_Ceres_options &); void computeMatches(); + void buildTracks(); + void adjust (); + void resection (); + void resectionAll (); }; } #endif @@ -94,4 +112,6 @@ Frame *new_frame_from_handle(FILE *, int, int, int); _FFI_PLUGIN Frame *new_frame_from_data(const uint8_t *, const size_t, int, int, int); +void frame_cleanup(Frame **); + #endif // __FRAME_H \ No newline at end of file diff --git a/src/tests/test_frame.cxx b/src/tests/test_frame.cxx new file mode 100644 index 0000000..f575ac0 --- /dev/null +++ b/src/tests/test_frame.cxx @@ -0,0 +1,85 @@ +#include +#include +#include "../image.h" +#include "../streamingview.hpp" +#include "../util.h" +#include +#ifdef __cplusplus +#include +#endif // __cplusplus + +#define STRLEN 2048 + +FILE *imageHandle = NULL; +char frame1Path[STRLEN]; + +#define HERE __FILE__ + +int setUp(void) +{ + char framesDir[STRLEN]; + size_t length; + cwk_path_get_dirname(HERE, &length); // archimedes_mobile_lib/src/tests + cwk_path_join(HERE, "../../../assets/test/frames", framesDir, STRLEN); + cwk_path_join(framesDir, "0001.png", frame1Path, STRLEN); + printf("Opening file %s\n", frame1Path); + return 0; +} + +Frame *get_frame() { + imageHandle = fopen(frame1Path, "rw+"); + Frame *f = new_frame_from_handle( + imageHandle, + 768, + 768, + 64); + return f; +} + +void destroy_frame() { + frame_ +} + +int tearDown(void) +{ + if (imageHandle) + { + fclose(imageHandle); + } + return 0; +} + +void test_calculate_fetures + +int main() +{ + CU_pSuite pSuite = NULL; + + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + /* add a suite to the registry */ + pSuite = CU_add_suite("ImageSuite", setUp, tearDown); + if (NULL == pSuite) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* add the tests to the suite */ + if ((NULL == CU_add_test(pSuite, "frame can be created", test_create_frame)) || + (NULL == CU_add_test(pSuite, "frame can be created from data", test_frame_from_data)) || + (NULL == CU_add_test(pSuite, "data can be retrieved from frame", test_archimedes_get_data)) || + (NULL == CU_add_test(pSuite, "Streaming view can read & write data", test_archimedes_streamed_view))) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_cleanup_registry(); + return CU_get_error(); +} \ No newline at end of file diff --git a/src/tests/test_image.cxx b/src/tests/test_image.cxx index 303bf87..ca7afda 100644 --- a/src/tests/test_image.cxx +++ b/src/tests/test_image.cxx @@ -2,6 +2,7 @@ #include #include "../image.h" #include "../streamingview.hpp" +#include "../util.h" #include #ifdef __cplusplus #include @@ -12,41 +13,6 @@ FILE *imageHandle = NULL; char frame1Path[STRLEN]; -/* - * Read the contents of a file into an array - * path: path to the file - * contents: array we'll write to that contains the contents of the file. - */ -size_t read_file(const char *path, uint8_t **contents) -{ - FILE *file = fopen(path, "rb"); - if (file == NULL) - { - printf("Error: Unable to open file.\n"); - return 0; - } - - // Determine the file size - fseek(file, 0, SEEK_END); - size_t file_size = ftell(file); - rewind(file); - - // Allocate memory for the contents array - *contents = (uint8_t *)malloc(file_size); - if (*contents == NULL) - { - printf("Error: Unable to allocate memory.\n"); - fclose(file); - return 0; - } - - // Read the file contents into the array - fread(*contents, 1, file_size, file); - fclose(file); - - return file_size; -} - #define HERE __FILE__ int setUp(void) diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..047d00d --- /dev/null +++ b/src/util.h @@ -0,0 +1,6 @@ +/* + * Read the contents of a file into an array + * path: path to the file + * contents: array we'll write to that contains the contents of the file. + */ +size_t read_file(const char *path, uint8_t **contents); \ No newline at end of file diff --git a/util.cpp b/util.cpp new file mode 100644 index 0000000..c9bdea9 --- /dev/null +++ b/util.cpp @@ -0,0 +1,29 @@ +size_t read_file(const char *path, uint8_t **contents) +{ + FILE *file = fopen(path, "rb"); + if (file == NULL) + { + printf("Error: Unable to open file.\n"); + return 0; + } + + // Determine the file size + fseek(file, 0, SEEK_END); + size_t file_size = ftell(file); + rewind(file); + + // Allocate memory for the contents array + *contents = (uint8_t *)malloc(file_size); + if (*contents == NULL) + { + printf("Error: Unable to allocate memory.\n"); + fclose(file); + return 0; + } + + // Read the file contents into the array + fread(*contents, 1, file_size, file); + fclose(file); + + return file_size; +} \ No newline at end of file