From f9e95678700c8bf8b3e484a548b9856e40995ffb Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Wed, 17 Apr 2024 14:19:05 +0300 Subject: [PATCH] Merge pull request #25424 from mshabunin:fix-features2d-test features2d: reduce accuracy test avg memory consumption #25424 **Merge with contrib**: https://github.com/opencv/opencv_contrib/pull/3722 I've observed high memory consumption in the `opencv_test_features2d` (x86_64, Ubuntu 22.04, Debug): ![image](https://github.com/opencv/opencv/assets/3304494/419d65d9-d727-4d1e-bdec-dbde6681c188) It's always more than 180 MiB with peak at 535 MiB This was caused by pointers to the algorithm object instances stored in the tests parameters. I've replaced them with factory functions/lambdas with the following result: ![image](https://github.com/opencv/opencv/assets/3304494/bd4ff0ea-3db4-4ab8-8e6d-192a3826e99c) Now peak is at 355 MiB and permanent consumption level is ~ 1-2 MiB **Note:** current peak is caused by KAZE features allocating 8x image size utility buffers. Not sure if we can or should do anything about it: https://github.com/opencv/opencv/blob/66fb5021e9253e3decab376d00322eaf2b279c89/modules/features2d/src/kaze/KAZEFeatures.cpp#L61-L68 --- .../features2d/test/ocl/test_feature2d.cpp | 9 ++++---- .../test/test_descriptors_invariance.cpp | 16 +++++++------- .../test/test_descriptors_invariance.impl.hpp | 11 +++++++--- .../test/test_detectors_invariance.cpp | 22 +++++++++---------- .../test/test_detectors_invariance.impl.hpp | 8 +++++-- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/modules/features2d/test/ocl/test_feature2d.cpp b/modules/features2d/test/ocl/test_feature2d.cpp index 7024854ce1..ad4008bb81 100644 --- a/modules/features2d/test/ocl/test_feature2d.cpp +++ b/modules/features2d/test/ocl/test_feature2d.cpp @@ -5,6 +5,7 @@ #include "../test_precomp.hpp" #include "cvconfig.h" #include "opencv2/ts/ocl_test.hpp" +#include #ifdef HAVE_OPENCL @@ -16,7 +17,7 @@ namespace ocl { "../stitching/a3.png", \ "../stitching/s2.jpg") -PARAM_TEST_CASE(Feature2DFixture, Ptr, std::string) +PARAM_TEST_CASE(Feature2DFixture, std::function()>, std::string) { std::string filename; Mat image, descriptors; @@ -27,7 +28,7 @@ PARAM_TEST_CASE(Feature2DFixture, Ptr, std::string) virtual void SetUp() { - feature = GET_PARAM(0); + feature = GET_PARAM(0)(); filename = GET_PARAM(1); image = readImage(filename); @@ -61,10 +62,10 @@ OCL_TEST_P(Feature2DFixture, DescriptorsSame) } OCL_INSTANTIATE_TEST_CASE_P(AKAZE, Feature2DFixture, - testing::Combine(testing::Values(AKAZE::create()), TEST_IMAGES)); + testing::Combine(testing::Values([]() { return AKAZE::create(); }), TEST_IMAGES)); OCL_INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, Feature2DFixture, - testing::Combine(testing::Values(AKAZE::create(AKAZE::DESCRIPTOR_KAZE)), TEST_IMAGES)); + testing::Combine(testing::Values([]() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }), TEST_IMAGES)); }//ocl }//cvtest diff --git a/modules/features2d/test/test_descriptors_invariance.cpp b/modules/features2d/test/test_descriptors_invariance.cpp index 9faf56a1c8..0ac381f667 100644 --- a/modules/features2d/test/test_descriptors_invariance.cpp +++ b/modules/features2d/test/test_descriptors_invariance.cpp @@ -18,31 +18,31 @@ const static std::string IMAGE_BIKES = "detectors_descriptors_evaluation/images_ */ INSTANTIATE_TEST_CASE_P(SIFT, DescriptorRotationInvariance, - Value(IMAGE_TSUKUBA, SIFT::create(), SIFT::create(), 0.98f)); + Value(IMAGE_TSUKUBA, []() { return SIFT::create(); }, []() { return SIFT::create(); }, 0.98f)); INSTANTIATE_TEST_CASE_P(BRISK, DescriptorRotationInvariance, - Value(IMAGE_TSUKUBA, BRISK::create(), BRISK::create(), 0.99f)); + Value(IMAGE_TSUKUBA, []() { return BRISK::create(); }, []() { return BRISK::create(); }, 0.99f)); INSTANTIATE_TEST_CASE_P(ORB, DescriptorRotationInvariance, - Value(IMAGE_TSUKUBA, ORB::create(), ORB::create(), 0.99f)); + Value(IMAGE_TSUKUBA, []() { return ORB::create(); }, []() { return ORB::create(); }, 0.99f)); INSTANTIATE_TEST_CASE_P(AKAZE, DescriptorRotationInvariance, - Value(IMAGE_TSUKUBA, AKAZE::create(), AKAZE::create(), 0.99f)); + Value(IMAGE_TSUKUBA, []() { return AKAZE::create(); }, []() { return AKAZE::create(); }, 0.99f)); INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DescriptorRotationInvariance, - Value(IMAGE_TSUKUBA, AKAZE::create(AKAZE::DESCRIPTOR_KAZE), AKAZE::create(AKAZE::DESCRIPTOR_KAZE), 0.99f)); + Value(IMAGE_TSUKUBA, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, 0.99f)); /* * Descriptor's scale invariance check */ INSTANTIATE_TEST_CASE_P(SIFT, DescriptorScaleInvariance, - Value(IMAGE_BIKES, SIFT::create(0, 3, 0.09), SIFT::create(0, 3, 0.09), 0.78f)); + Value(IMAGE_BIKES, []() { return SIFT::create(0, 3, 0.09); }, []() { return SIFT::create(0, 3, 0.09); }, 0.78f)); INSTANTIATE_TEST_CASE_P(AKAZE, DescriptorScaleInvariance, - Value(IMAGE_BIKES, AKAZE::create(), AKAZE::create(), 0.6f)); + Value(IMAGE_BIKES, []() { return AKAZE::create(); }, []() { return AKAZE::create(); }, 0.6f)); INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DescriptorScaleInvariance, - Value(IMAGE_BIKES, AKAZE::create(AKAZE::DESCRIPTOR_KAZE), AKAZE::create(AKAZE::DESCRIPTOR_KAZE), 0.55f)); + Value(IMAGE_BIKES, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, 0.55f)); }} // namespace diff --git a/modules/features2d/test/test_descriptors_invariance.impl.hpp b/modules/features2d/test/test_descriptors_invariance.impl.hpp index 780e86e724..055500b1f9 100644 --- a/modules/features2d/test/test_descriptors_invariance.impl.hpp +++ b/modules/features2d/test/test_descriptors_invariance.impl.hpp @@ -3,12 +3,17 @@ // of this distribution and at http://opencv.org/license.html #include "test_invariance_utils.hpp" +#include namespace opencv_test { namespace { #define SHOW_DEBUG_LOG 1 -typedef tuple, Ptr, float> +// NOTE: using factory function (function()>) instead of object instance (Ptr) as a +// test parameter, because parameters exist during whole test program run and consume a lot of memory +typedef std::function()> DetectorFactory; +typedef std::function()> ExtractorFactory; +typedef tuple String_FeatureDetector_DescriptorExtractor_Float_t; @@ -61,8 +66,8 @@ protected: image0 = imread(filename); ASSERT_FALSE(image0.empty()) << "couldn't read input image"; - featureDetector = get<1>(GetParam()); - descriptorExtractor = get<2>(GetParam()); + featureDetector = get<1>(GetParam())(); + descriptorExtractor = get<2>(GetParam())(); minInliersRatio = get<3>(GetParam()); } diff --git a/modules/features2d/test/test_detectors_invariance.cpp b/modules/features2d/test/test_detectors_invariance.cpp index 11e7ecfedc..72fe87f63e 100644 --- a/modules/features2d/test/test_detectors_invariance.cpp +++ b/modules/features2d/test/test_detectors_invariance.cpp @@ -18,40 +18,40 @@ const static std::string IMAGE_BIKES = "detectors_descriptors_evaluation/images_ */ INSTANTIATE_TEST_CASE_P(SIFT, DetectorRotationInvariance, - Value(IMAGE_TSUKUBA, SIFT::create(), 0.45f, 0.70f)); + Value(IMAGE_TSUKUBA, []() { return SIFT::create(); }, 0.45f, 0.70f)); INSTANTIATE_TEST_CASE_P(BRISK, DetectorRotationInvariance, - Value(IMAGE_TSUKUBA, BRISK::create(), 0.45f, 0.76f)); + Value(IMAGE_TSUKUBA, []() { return BRISK::create(); }, 0.45f, 0.76f)); INSTANTIATE_TEST_CASE_P(ORB, DetectorRotationInvariance, - Value(IMAGE_TSUKUBA, ORB::create(), 0.5f, 0.76f)); + Value(IMAGE_TSUKUBA, []() { return ORB::create(); }, 0.5f, 0.76f)); INSTANTIATE_TEST_CASE_P(AKAZE, DetectorRotationInvariance, - Value(IMAGE_TSUKUBA, AKAZE::create(), 0.5f, 0.71f)); + Value(IMAGE_TSUKUBA, []() { return AKAZE::create(); }, 0.5f, 0.71f)); INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DetectorRotationInvariance, - Value(IMAGE_TSUKUBA, AKAZE::create(AKAZE::DESCRIPTOR_KAZE), 0.5f, 0.71f)); + Value(IMAGE_TSUKUBA, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, 0.5f, 0.71f)); /* * Detector's scale invariance check */ INSTANTIATE_TEST_CASE_P(SIFT, DetectorScaleInvariance, - Value(IMAGE_BIKES, SIFT::create(0, 3, 0.09), 0.60f, 0.98f)); + Value(IMAGE_BIKES, []() { return SIFT::create(0, 3, 0.09); }, 0.60f, 0.98f)); INSTANTIATE_TEST_CASE_P(BRISK, DetectorScaleInvariance, - Value(IMAGE_BIKES, BRISK::create(), 0.08f, 0.49f)); + Value(IMAGE_BIKES, []() { return BRISK::create(); }, 0.08f, 0.49f)); INSTANTIATE_TEST_CASE_P(ORB, DetectorScaleInvariance, - Value(IMAGE_BIKES, ORB::create(), 0.08f, 0.49f)); + Value(IMAGE_BIKES, []() { return ORB::create(); }, 0.08f, 0.49f)); INSTANTIATE_TEST_CASE_P(KAZE, DetectorScaleInvariance, - Value(IMAGE_BIKES, KAZE::create(), 0.08f, 0.49f)); + Value(IMAGE_BIKES, []() { return KAZE::create(); }, 0.08f, 0.49f)); INSTANTIATE_TEST_CASE_P(AKAZE, DetectorScaleInvariance, - Value(IMAGE_BIKES, AKAZE::create(), 0.08f, 0.49f)); + Value(IMAGE_BIKES, []() { return AKAZE::create(); }, 0.08f, 0.49f)); INSTANTIATE_TEST_CASE_P(AKAZE_DESCRIPTOR_KAZE, DetectorScaleInvariance, - Value(IMAGE_BIKES, AKAZE::create(AKAZE::DESCRIPTOR_KAZE), 0.08f, 0.49f)); + Value(IMAGE_BIKES, []() { return AKAZE::create(AKAZE::DESCRIPTOR_KAZE); }, 0.08f, 0.49f)); }} // namespace diff --git a/modules/features2d/test/test_detectors_invariance.impl.hpp b/modules/features2d/test/test_detectors_invariance.impl.hpp index e50316fed9..a602333509 100644 --- a/modules/features2d/test/test_detectors_invariance.impl.hpp +++ b/modules/features2d/test/test_detectors_invariance.impl.hpp @@ -3,12 +3,16 @@ // of this distribution and at http://opencv.org/license.html #include "test_invariance_utils.hpp" +#include namespace opencv_test { namespace { #define SHOW_DEBUG_LOG 1 -typedef tuple, float, float> String_FeatureDetector_Float_Float_t; +// NOTE: using factory function (function()>) instead of object instance (Ptr) as a +// test parameter, because parameters exist during whole test program run and consume a lot of memory +typedef std::function()> DetectorFactory; +typedef tuple String_FeatureDetector_Float_Float_t; static @@ -56,7 +60,7 @@ protected: image0 = imread(filename); ASSERT_FALSE(image0.empty()) << "couldn't read input image"; - featureDetector = get<1>(GetParam()); + featureDetector = get<1>(GetParam())(); minKeyPointMatchesRatio = get<2>(GetParam()); minInliersRatio = get<3>(GetParam()); }