diff --git a/modules/fastcv/include/opencv2/fastcv.hpp b/modules/fastcv/include/opencv2/fastcv.hpp index 292e83a2dc3..18a26e78f63 100644 --- a/modules/fastcv/include/opencv2/fastcv.hpp +++ b/modules/fastcv/include/opencv2/fastcv.hpp @@ -30,6 +30,9 @@ #include "opencv2/fastcv/thresh.hpp" #include "opencv2/fastcv/tracking.hpp" #include "opencv2/fastcv/warp.hpp" +#include "opencv2/fastcv/allocator.hpp" +#include "opencv2/fastcv/dsp_init.hpp" +#include "opencv2/fastcv/sad_dsp.hpp" /** * @defgroup fastcv Module-wrapper for FastCV hardware accelerated functions diff --git a/modules/fastcv/include/opencv2/fastcv/allocator.hpp b/modules/fastcv/include/opencv2/fastcv/allocator.hpp new file mode 100644 index 00000000000..92c29c73000 --- /dev/null +++ b/modules/fastcv/include/opencv2/fastcv/allocator.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#ifndef OPENCV_FASTCV_ALLOCATOR_HPP +#define OPENCV_FASTCV_ALLOCATOR_HPP + +#include + +namespace cv { +namespace fastcv { + +//! @addtogroup fastcv +//! @{ + +/** + * @brief Gets the default FastCV allocator. + * This function returns a pointer to the default FastCV allocator, which is optimized + * for use with DSP. + * + * @return Pointer to the default FastCV allocator. + */ +CV_EXPORTS cv::MatAllocator* getDefaultFastCVAllocator(); +//! @} + +} // fastcv:: +} // cv:: + +#endif // OPENCV_FASTCV_ALLOCATOR_HPP diff --git a/modules/fastcv/include/opencv2/fastcv/dsp_init.hpp b/modules/fastcv/include/opencv2/fastcv/dsp_init.hpp new file mode 100644 index 00000000000..0251dc8545a --- /dev/null +++ b/modules/fastcv/include/opencv2/fastcv/dsp_init.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#ifndef OPENCV_FASTCV_DSP_INIT_HPP +#define OPENCV_FASTCV_DSP_INIT_HPP + +#include + +namespace cv { +namespace fastcv { +namespace dsp { + + //! @addtogroup fastcv + //! @{ + + /** + * @brief Initializes the FastCV DSP environment. + * + * This function sets up the necessary environment for FastCV DSP operations. + * It ensures that the DSP context is initialized and sets the custom memory allocator + * for FastCV operations. + * + * @return int Returns 0 on success, and a non-zero value on failure. + */ + CV_EXPORTS_W int fastcvq6init(); + + /** + * @brief Deinitializes the FastCV DSP environment. + * + * This function cleans up the FastCV DSP environment, releasing any resources + * that were allocated during initialization. + */ + CV_EXPORTS_W void fastcvq6deinit(); + //! @} + +} // dsp:: +} // fastcv:: +} // cv:: + +#endif // OPENCV_FASTCV_DSP_INIT_HPP diff --git a/modules/fastcv/include/opencv2/fastcv/sad_dsp.hpp b/modules/fastcv/include/opencv2/fastcv/sad_dsp.hpp new file mode 100644 index 00000000000..f3037dc237f --- /dev/null +++ b/modules/fastcv/include/opencv2/fastcv/sad_dsp.hpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#ifndef OPENCV_SAD_HPP +#define OPENCV_SAD_HPP + +#include + +namespace cv { +namespace fastcv { +namespace dsp { + +/** + * @defgroup fastcv Module-wrapper for FastCV hardware accelerated functions + */ + +//! @addtogroup fastcv +//! @{ +/** + * @brief Sum of absolute differences of an image against an 8x8 template. + * @param _patch The first input image data, type CV_8UC1 + * @param _src The input image data, type CV_8UC1 + * @param _dst The output image data, type CV_16UC1 +*/ +CV_EXPORTS_W void sumOfAbsoluteDiffs(cv::InputArray _patch, cv::InputArray _src, cv::OutputArray _dst); +//! @} + +} +} +} + +#endif diff --git a/modules/fastcv/perf/perf_sad_dsp.cpp b/modules/fastcv/perf/perf_sad_dsp.cpp new file mode 100644 index 00000000000..a2c6bf743b0 --- /dev/null +++ b/modules/fastcv/perf/perf_sad_dsp.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "perf_precomp.hpp" + +namespace opencv_test { + +typedef std::tuple SumOfAbsDiffsPerfParams; +typedef perf::TestBaseWithParam SumOfAbsDiffsPerfTest; + +PERF_TEST_P(SumOfAbsDiffsPerfTest, run, + ::testing::Values(cv::Size(640, 480), // VGA + cv::Size(1280, 720), // 720p + cv::Size(1920, 1080)) // 1080p +) +{ + // Initialize FastCV DSP + int initStatus = cv::fastcv::dsp::fastcvq6init(); + ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP"; + + auto p = GetParam(); + cv::Size srcSize = std::get<0>(p); + + RNG& rng = cv::theRNG(); + cv::Mat patch(8, 8, CV_8UC1); + cv::Mat src(srcSize, CV_8UC1); + cvtest::randUni(rng, patch, cv::Scalar::all(0), cv::Scalar::all(255)); + cvtest::randUni(rng, src, cv::Scalar::all(0), cv::Scalar::all(255)); + + cv::Mat dst; + while(next()) + { + startTimer(); + cv::fastcv::dsp::sumOfAbsoluteDiffs(patch, src, dst); + stopTimer(); + } + SANITY_CHECK_NOTHING(); +} + +} // namespace diff --git a/modules/fastcv/src/allocator.cpp b/modules/fastcv/src/allocator.cpp new file mode 100644 index 00000000000..6d4e5d6d425 --- /dev/null +++ b/modules/fastcv/src/allocator.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "precomp.hpp" + +namespace cv { +namespace fastcv { + +struct FastCVAllocator: public cv::MatAllocator +{ +public: + FastCVAllocator(); + ~FastCVAllocator(); + + cv::UMatData* allocate(int dims, const int* sizes, int type, void* data, size_t* step, cv::AccessFlag flags, cv::UMatUsageFlags usageFlags) const CV_OVERRIDE; + bool allocate(cv::UMatData* u, cv::AccessFlag accessFlags, cv::UMatUsageFlags usageFlags) const CV_OVERRIDE; + void deallocate(cv::UMatData* u) const CV_OVERRIDE; +}; + +FastCVAllocator::FastCVAllocator() +{ +} + +FastCVAllocator::~FastCVAllocator() +{ +} + +cv::UMatData* FastCVAllocator::allocate(int dims, const int* sizes, int type, + void* data0, size_t* step, cv::AccessFlag flags, + cv::UMatUsageFlags usageFlags) const +{ + CV_UNUSED(flags); + CV_UNUSED(usageFlags); + + size_t total = CV_ELEM_SIZE(type); + for( int i = dims-1; i >= 0; i-- ) + { + if( step ) + { + if( data0 && step[i] != CV_AUTOSTEP ) + { + CV_Assert(total <= step[i]); + total = step[i]; + } + else + step[i] = total; + } + total *= sizes[i]; + } + uchar* data = data0 ? (uchar*)data0 : (uchar*)fcvHwMemAlloc(total, 16); + cv::UMatData* u = new cv::UMatData(this); + u->data = u->origdata = data; + u->size = total; + if(data0) + u->flags |= cv::UMatData::USER_ALLOCATED; + + u->userdata = new std::string("QCOM"); + return u; +} + +bool FastCVAllocator::allocate(cv::UMatData* u, cv::AccessFlag accessFlags, cv::UMatUsageFlags usageFlags) const +{ + CV_UNUSED(accessFlags); + CV_UNUSED(usageFlags); + + return u != nullptr; +} + +void FastCVAllocator::deallocate(cv::UMatData* u) const +{ + if(!u) + return; + + CV_Assert(u->urefcount == 0); + CV_Assert(u->refcount == 0); + if( !(u->flags & cv::UMatData::USER_ALLOCATED) ) + { + fcvHwMemFree(u->origdata); + u->origdata = 0; + } + + if (u->userdata) + { + delete static_cast(u->userdata); + u->userdata = nullptr; + } + + delete u; +} + +cv::MatAllocator* getDefaultFastCVAllocator() +{ + static cv::MatAllocator* allocator = new FastCVAllocator; + return allocator; +} + +} +} diff --git a/modules/fastcv/src/dsp_init.cpp b/modules/fastcv/src/dsp_init.cpp new file mode 100644 index 00000000000..a956abeeddf --- /dev/null +++ b/modules/fastcv/src/dsp_init.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "precomp.hpp" + +namespace cv { +namespace fastcv { +namespace dsp { + +int fastcvq6init() +{ + // Get the DSP context + FastCvDspContext& context = FastCvDspContext::getContext(); + + // Check if DSP is initialized + if (!context.isDspInitialized) + { + CV_Error(cv::Error::StsBadArg, cv::format("DSP initialization failed!")); + return 1; + } + + // Get custom allocator + cv::MatAllocator* allocator = cv::fastcv::getDefaultFastCVAllocator(); + + // Ensure the allocator is not the standard one + CV_Assert(allocator != cv::Mat::getStdAllocator()); + + // Check if the current allocator is already set to the custom allocator + if (cv::Mat::getDefaultAllocator() != allocator) + { + // Set the custom allocator + cv::Mat::setDefaultAllocator(allocator); + } + + return 0; +} + +void fastcvq6deinit() +{ + // Deinitialize the DSP environment + fcvQ6DeInit(); +} + + +} // namespace dsp +} // namespace fastcv +} // namespace cv \ No newline at end of file diff --git a/modules/fastcv/src/precomp.hpp b/modules/fastcv/src/precomp.hpp index c2929d76cc1..2c394055b4b 100644 --- a/modules/fastcv/src/precomp.hpp +++ b/modules/fastcv/src/precomp.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ @@ -10,11 +10,12 @@ #include #include "opencv2/core/private.hpp" #include "opencv2/core/utils/logger.hpp" - +#include #include #include #include "fastcv.h" +#include "fastcvDsp.h" namespace cv { namespace fastcv { @@ -30,6 +31,7 @@ namespace fastcv { #define FCV_KernelSize_SHIFT 3 #define FCV_MAKETYPE(ksize,depth) ((ksize< fcvStatusStrings = { @@ -72,6 +74,46 @@ struct FastCvContext bool isInitialized; }; +namespace dsp { + + #define IS_FASTCV_ALLOCATED(mat) \ + ((mat.u && mat.u->userdata && \ + *static_cast(mat.u->userdata) == "QCOM") ? true : \ + (std::cerr << "Allocation check failed for " #mat \ + << ". Please ensure that cv::fastcv::dsp::fastcvq6init() has been called." \ + << std::endl, false)) + + struct FastCvDspContext + { + public: + // Initialize at first call + // Defines a static local variable context. + static FastCvDspContext& getContext() + { + //Instance is created only once. + static FastCvDspContext context; + return context; + } + + //Constructor is called when the FastCvDspContext instance is created + FastCvDspContext() + { + if (fcvQ6Init() != 0) + { + CV_LOG_WARNING(NULL, "Failed to switch FastCV DSP operation mode"); + isDspInitialized = false; + } + else + { + CV_LOG_INFO(NULL, "FastCV DSP Operation Mode Switched"); + isDspInitialized = true; + } + } + + bool isDspInitialized; + }; + +} // namespace dsp } // namespace fastcv } // namespace cv diff --git a/modules/fastcv/src/sad_dsp.cpp b/modules/fastcv/src/sad_dsp.cpp new file mode 100644 index 00000000000..1637a377f89 --- /dev/null +++ b/modules/fastcv/src/sad_dsp.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "precomp.hpp" + +namespace cv { +namespace fastcv { +namespace dsp { + +void sumOfAbsoluteDiffs(cv::InputArray _patch, cv::InputArray _src, cv::OutputArray _dst) { + cv::Mat patch = _patch.getMat(); + cv::Mat src = _src.getMat(); + + // Check if matrices are allocated by the fastcv allocator + CV_Assert(IS_FASTCV_ALLOCATED(patch)); + CV_Assert(IS_FASTCV_ALLOCATED(src)); + + CV_Assert(!_src.empty() && "src is empty"); + CV_Assert(_src.type() == CV_8UC1 && "src type is not CV_8UC1"); + CV_Assert(_src.step() * _src.rows() > MIN_REMOTE_BUF_SIZE && "src buffer size is too small"); + CV_Assert(!_patch.empty() && "patch is empty"); + CV_Assert(_patch.type() == CV_8UC1 && "patch type is not CV_8UC1"); + CV_Assert(_patch.size() == cv::Size(8, 8) && "patch size is not 8x8"); + + cv::Size size = _src.size(); + _dst.create(size, CV_16UC1); + cv::Mat dst = _dst.getMat(); + + CV_Assert(((intptr_t)src.data & 0x7) == 0 && "src data is not 8-byte aligned"); + CV_Assert(((intptr_t)dst.data & 0x7) == 0 && "dst data is not 8-byte aligned"); + + // Check if dst is allocated by the fastcv allocator + CV_Assert(IS_FASTCV_ALLOCATED(dst)); + + fcvSumOfAbsoluteDiffs8x8u8_v2Q((uint8_t*)patch.data, patch.step, (uint8_t*)src.data, src.cols, src.rows, src.step, (uint16_t*)dst.data, dst.step); +} + +} // dsp:: +} // fastcv:: +} // cv:: diff --git a/modules/fastcv/test/test_sad_dsp.cpp b/modules/fastcv/test/test_sad_dsp.cpp new file mode 100644 index 00000000000..ab2aa723f8a --- /dev/null +++ b/modules/fastcv/test/test_sad_dsp.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "test_precomp.hpp" + +using namespace cv::fastcv::dsp; + +namespace opencv_test { namespace { + +TEST(SadTest, accuracy) +{ + // Initialize FastCV DSP + int initStatus = cv::fastcv::dsp::fastcvq6init(); + ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP"; + + // Create an 8x8 template patch + cv::Mat patch = cv::Mat::zeros(8, 8, CV_8UC1); + + // Create a source image + cv::Mat src = cv::Mat::ones(512, 512, CV_8UC1) * 255; + + cv::Mat dst; + + cv::fastcv::dsp::sumOfAbsoluteDiffs(patch, src, dst); + + EXPECT_FALSE(dst.empty()); + + // Explicitly deallocate memory + patch.release(); + src.release(); + dst.release(); + + cv::fastcv::dsp::fastcvq6deinit(); +} + +} +}