From 1de6e2046344152f9c43edb5561d0991431f75fc Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 11 Feb 2025 17:25:48 +0300 Subject: [PATCH] Move OpenVX implementation for FAST to HAL. --- 3rdparty/openvx/hal/CMakeLists.txt | 1 + 3rdparty/openvx/hal/openvx_hal.cpp | 71 +++++++++++++++++++++++++ 3rdparty/openvx/hal/openvx_hal.hpp | 4 +- modules/features2d/src/fast.cpp | 75 ++------------------------- modules/features2d/test/test_fast.cpp | 34 +++++++++++- 5 files changed, 110 insertions(+), 75 deletions(-) diff --git a/3rdparty/openvx/hal/CMakeLists.txt b/3rdparty/openvx/hal/CMakeLists.txt index 4824c45a24..2c88c492b1 100644 --- a/3rdparty/openvx/hal/CMakeLists.txt +++ b/3rdparty/openvx/hal/CMakeLists.txt @@ -4,6 +4,7 @@ target_include_directories(openvx_hal PUBLIC ${OPENCV_3P_OPENVX_DIR}/include ${CMAKE_SOURCE_DIR}/modules/core/include ${CMAKE_SOURCE_DIR}/modules/imgproc/include + ${CMAKE_SOURCE_DIR}/modules/features2d/include ${OPENVX_INCLUDE_DIR}) target_link_libraries(openvx_hal PUBLIC ${OPENVX_LIBRARIES}) set_target_properties(openvx_hal PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH}) diff --git a/3rdparty/openvx/hal/openvx_hal.cpp b/3rdparty/openvx/hal/openvx_hal.cpp index 42920611ce..d03c60954c 100644 --- a/3rdparty/openvx/hal/openvx_hal.cpp +++ b/3rdparty/openvx/hal/openvx_hal.cpp @@ -1,5 +1,7 @@ #include "openvx_hal.hpp" +#include "opencv2/core/hal/interface.h" #include "opencv2/imgproc/hal/interface.h" +#include "opencv2/features2d/hal/interface.h" #define IVX_HIDE_INFO_WARNINGS #include "ivx.hpp" @@ -1334,3 +1336,72 @@ int ovx_hal_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, return CV_HAL_ERROR_OK; } + +template <> inline bool skipSmallImages(int w, int h) { return w*h < 800 * 600; } + +int ovx_hal_FAST(const uchar* src_data, size_t src_step, int width, int height, uchar* keypoints_data, size_t* keypoints_count, + int threshold, bool nonmax_suppression, int /*cv::FastFeatureDetector::DetectorType*/ dtype) +{ + // Nonmax suppression is done differently in OpenCV than in OpenVX + // 9/16 is the only supported mode in OpenVX + if(nonmax_suppression || dtype != CV_HAL_TYPE_9_16) + { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + if (skipSmallImages(width, height)) + { + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + try + { + ivx::Context context = getOpenVXHALContext(); + ivx::Image img = ivx::Image::createFromHandle(context, VX_DF_IMAGE_U8, + ivx::Image::createAddressing(width, height, 1, (vx_int32)src_step), + const_cast(src_data)); + + ivx::Scalar vxthreshold = ivx::Scalar::create(context, threshold); + vx_size capacity = width * height; + ivx::Array corners = ivx::Array::create(context, VX_TYPE_KEYPOINT, capacity); + + ivx::Scalar numCorners = ivx::Scalar::create(context, 0); + + ivx::IVX_CHECK_STATUS(vxuFastCorners(context, img, vxthreshold, (vx_bool)nonmax_suppression, corners, numCorners)); + + size_t nPoints = numCorners.getValue(); + std::vector vxCorners(nPoints); + corners.copyTo(vxCorners); + cvhalKeyPoint* keypoints = (cvhalKeyPoint*)keypoints_data; + for(size_t i = 0; i < std::min(nPoints, *keypoints_count); i++) + { + //if nonmaxSuppression is false, vxCorners[i].strength is undefined + keypoints[i].x = vxCorners[i].x; + keypoints[i].y = vxCorners[i].y; + keypoints[i].size = 7; + keypoints[i].angle = -1; + keypoints[i].response = vxCorners[i].strength; + } + + *keypoints_count = std::min(nPoints, *keypoints_count); + +#ifdef VX_VERSION_1_1 + //we should take user memory back before release + //(it's not done automatically according to standard) + img.swapHandle(); +#endif + } + catch (const ivx::RuntimeError & e) + { + PRINT_HALERR_MSG(runtime); + return CV_HAL_ERROR_UNKNOWN; + + } + catch (const ivx::WrapperError & e) + { + PRINT_HALERR_MSG(wrapper); + return CV_HAL_ERROR_UNKNOWN; + } + + return CV_HAL_ERROR_OK; +} diff --git a/3rdparty/openvx/hal/openvx_hal.hpp b/3rdparty/openvx/hal/openvx_hal.hpp index 5f7dff6626..539144f855 100644 --- a/3rdparty/openvx/hal/openvx_hal.hpp +++ b/3rdparty/openvx/hal/openvx_hal.hpp @@ -59,7 +59,8 @@ int ovx_hal_meanStdDev(const uchar* src_data, size_t src_step, int width, int he int ovx_hal_lut(const uchar *src_data, size_t src_step, size_t src_type, const uchar* lut_data, size_t lut_channel_size, size_t lut_channels, uchar *dst_data, size_t dst_step, int width, int height); int ovx_hal_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, int height, int depth, double* minVal, double* maxVal, int* minIdx, int* maxIdx, uchar* mask, size_t mask_step); - +int ovx_hal_FAST(const uchar* src_data, size_t src_step, int width, int height, uchar* keypoints_data, size_t* keypoints_count, + int threshold, bool nonmax_suppression, int /*cv::FastFeatureDetector::DetectorType*/ dtype); //================================================================================================== // functions redefinition // ... @@ -152,5 +153,6 @@ int ovx_hal_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, #define cv_hal_lut ovx_hal_lut #undef cv_hal_minMaxIdxMaskStep #define cv_hal_minMaxIdxMaskStep ovx_hal_minMaxIdxMaskStep +#define cv_hal_FAST ovx_hal_FAST #endif diff --git a/modules/features2d/src/fast.cpp b/modules/features2d/src/fast.cpp index cb088eb535..a9615da5bd 100644 --- a/modules/features2d/src/fast.cpp +++ b/modules/features2d/src/fast.cpp @@ -49,8 +49,6 @@ The references are: #include "opencv2/core/hal/intrin.hpp" #include "opencv2/core/utils/buffer_area.private.hpp" -#include "opencv2/core/openvx/ovx_defs.hpp" - namespace cv { @@ -370,72 +368,6 @@ static bool ocl_FAST( InputArray _img, std::vector& keypoints, } #endif - -#ifdef HAVE_OPENVX -namespace ovx { - template <> inline bool skipSmallImages(int w, int h) { return w*h < 800 * 600; } -} -static bool openvx_FAST(InputArray _img, std::vector& keypoints, - int _threshold, bool nonmaxSuppression, int type) -{ - using namespace ivx; - - // Nonmax suppression is done differently in OpenCV than in OpenVX - // 9/16 is the only supported mode in OpenVX - if(nonmaxSuppression || type != FastFeatureDetector::TYPE_9_16) - return false; - - Mat imgMat = _img.getMat(); - if(imgMat.empty() || imgMat.type() != CV_8UC1) - return false; - - if (ovx::skipSmallImages(imgMat.cols, imgMat.rows)) - return false; - - try - { - Context context = ovx::getOpenVXContext(); - Image img = Image::createFromHandle(context, Image::matTypeToFormat(imgMat.type()), - Image::createAddressing(imgMat), (void*)imgMat.data); - ivx::Scalar threshold = ivx::Scalar::create(context, _threshold); - vx_size capacity = imgMat.cols * imgMat.rows; - Array corners = Array::create(context, VX_TYPE_KEYPOINT, capacity); - - ivx::Scalar numCorners = ivx::Scalar::create(context, 0); - - IVX_CHECK_STATUS(vxuFastCorners(context, img, threshold, (vx_bool)nonmaxSuppression, corners, numCorners)); - - size_t nPoints = numCorners.getValue(); - keypoints.clear(); keypoints.reserve(nPoints); - std::vector vxCorners; - corners.copyTo(vxCorners); - for(size_t i = 0; i < nPoints; i++) - { - vx_keypoint_t kp = vxCorners[i]; - //if nonmaxSuppression is false, kp.strength is undefined - keypoints.push_back(KeyPoint((float)kp.x, (float)kp.y, 7.f, -1, kp.strength)); - } - -#ifdef VX_VERSION_1_1 - //we should take user memory back before release - //(it's not done automatically according to standard) - img.swapHandle(); -#endif - } - catch (const RuntimeError & e) - { - VX_DbgThrow(e.what()); - } - catch (const WrapperError & e) - { - VX_DbgThrow(e.what()); - } - - return true; -} - -#endif - static inline int hal_FAST(cv::Mat& src, std::vector& keypoints, int threshold, bool nonmax_suppression, FastFeatureDetector::DetectorType type) { if (threshold > 20) @@ -503,13 +435,12 @@ void FAST(InputArray _img, std::vector& keypoints, int threshold, bool cv::Mat img = _img.getMat(); CALL_HAL(fast_dense, hal_FAST, img, keypoints, threshold, nonmax_suppression, type); - size_t keypoints_count; + size_t keypoints_count = 10000; + keypoints.clear(); + keypoints.resize(keypoints_count); CALL_HAL(fast, cv_hal_FAST, img.data, img.step, img.cols, img.rows, (uchar*)(keypoints.data()), &keypoints_count, threshold, nonmax_suppression, type); - CV_OVX_RUN(true, - openvx_FAST(_img, keypoints, threshold, nonmax_suppression, type)) - switch(type) { case FastFeatureDetector::TYPE_5_8: FAST_t<8>(_img, keypoints, threshold, nonmax_suppression); diff --git a/modules/features2d/test/test_fast.cpp b/modules/features2d/test/test_fast.cpp index 2fc5602be5..8f8f587586 100644 --- a/modules/features2d/test/test_fast.cpp +++ b/modules/features2d/test/test_fast.cpp @@ -118,8 +118,8 @@ void CV_FastTest::run( int ) read( fs["exp_kps2"], exp_kps2, Mat() ); fs.release(); - if ( exp_kps1.size != kps1.size || 0 != cvtest::norm(exp_kps1, kps1, NORM_L2) || - exp_kps2.size != kps2.size || 0 != cvtest::norm(exp_kps2, kps2, NORM_L2)) + if ( exp_kps1.size != kps1.size || 0 != cvtest::norm(exp_kps1, kps1, NORM_L2) || + exp_kps2.size != kps2.size || 0 != cvtest::norm(exp_kps2, kps2, NORM_L2)) { ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); return; @@ -135,4 +135,34 @@ void CV_FastTest::run( int ) TEST(Features2d_FAST, regression) { CV_FastTest test; test.safe_run(); } +// #define DUMP_TEST_DATA + +TEST(Features2d_FAST, noNMS) +{ + Mat img = imread(string(cvtest::TS::ptr()->get_data_path()) + "inpaint/orig.png", cv::IMREAD_GRAYSCALE); + string xml = string(cvtest::TS::ptr()->get_data_path()) + "fast/result_no_nonmax.xml"; + + vector keypoints; + FAST(img, keypoints, 100, false, FastFeatureDetector::DetectorType::TYPE_9_16); + Mat kps(1, (int)(keypoints.size() * sizeof(KeyPoint)), CV_8U, &keypoints[0]); + + Mat gt_kps; + FileStorage fs(xml, FileStorage::READ); +#ifdef DUMP_TEST_DATA + if (!fs.isOpened()) + { + fs.open(xml, FileStorage::WRITE); + fs << "exp_kps" << kps; + fs.release(); + fs.open(xml, FileStorage::READ); + } +#endif + ASSERT_TRUE(fs.isOpened()); + fs["exp_kps"] >> gt_kps; + fs.release(); + ASSERT_GT(gt_kps.total(), size_t(0)); + + ASSERT_EQ( 0, cvtest::norm(gt_kps, kps, NORM_L2)); +} + }} // namespace