From 72489721155fa5d0d2159d0de260c6aa11e8f0b7 Mon Sep 17 00:00:00 2001 From: Aditi Sharma Date: Wed, 4 Dec 2024 03:46:46 +0530 Subject: [PATCH] Adding extension of calcHist, bug fixes and other suggestions --- modules/fastcv/include/opencv2/fastcv.hpp | 1 + .../include/opencv2/fastcv/histogram.hpp | 29 +++++++ .../fastcv/include/opencv2/fastcv/moments.hpp | 3 +- modules/fastcv/perf/perf_bilateral.cpp | 2 +- modules/fastcv/perf/perf_histogram.cpp | 36 +++++++++ modules/fastcv/src/bilateralFilter.cpp | 30 +++---- modules/fastcv/src/histogram.cpp | 74 +++++++++++++++++ modules/fastcv/src/moments.cpp | 80 +++++++++---------- modules/fastcv/test/test_bilateral.cpp | 4 +- modules/fastcv/test/test_moments.cpp | 39 +++++---- 10 files changed, 217 insertions(+), 81 deletions(-) create mode 100644 modules/fastcv/include/opencv2/fastcv/histogram.hpp create mode 100644 modules/fastcv/perf/perf_histogram.cpp create mode 100644 modules/fastcv/src/histogram.cpp diff --git a/modules/fastcv/include/opencv2/fastcv.hpp b/modules/fastcv/include/opencv2/fastcv.hpp index 6ed8eba4a33..af188dfcb09 100644 --- a/modules/fastcv/include/opencv2/fastcv.hpp +++ b/modules/fastcv/include/opencv2/fastcv.hpp @@ -16,6 +16,7 @@ #include "opencv2/fastcv/edges.hpp" #include "opencv2/fastcv/fast10.hpp" #include "opencv2/fastcv/fft.hpp" +#include "opencv2/fastcv/histogram.hpp" #include "opencv2/fastcv/hough.hpp" #include "opencv2/fastcv/ipptransform.hpp" #include "opencv2/fastcv/moments.hpp" diff --git a/modules/fastcv/include/opencv2/fastcv/histogram.hpp b/modules/fastcv/include/opencv2/fastcv/histogram.hpp new file mode 100644 index 00000000000..f0bbd3c6f61 --- /dev/null +++ b/modules/fastcv/include/opencv2/fastcv/histogram.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#ifndef OPENCV_FASTCV_HISTOGRAM_HPP +#define OPENCV_FASTCV_HISTOGRAM_HPP + +#include + +namespace cv { +namespace fastcv { + +//! @addtogroup fastcv +//! @{ + +/** + * @brief Calculates histogram of input image. This function implements specific use case of + * 256-bin histogram calculation for 8u single channel images in an optimized way. + * @param _src Intput image with type CV_8UC1 + * @param _hist Output histogram of type int of 256 bins + */ +CV_EXPORTS_W void calcHist( InputArray _src, OutputArray _hist ); +//! @} + +} // fastcv:: +} // cv:: + +#endif // OPENCV_FASTCV_HISTOGRAM_HPP diff --git a/modules/fastcv/include/opencv2/fastcv/moments.hpp b/modules/fastcv/include/opencv2/fastcv/moments.hpp index 90034548571..13c9019841f 100644 --- a/modules/fastcv/include/opencv2/fastcv/moments.hpp +++ b/modules/fastcv/include/opencv2/fastcv/moments.hpp @@ -16,7 +16,8 @@ namespace fastcv { /** * @brief Calculates all of the moments up to the third order of the image pixels' intensities - The results are returned in the structure cv::Moments. + * The results are returned in the structure cv::Moments. This function cv::fastcv::moments() + * calculate the moments using floating point calculations whereas cv::moments() calculate moments using double. * @param _src Input image with type CV_8UC1, CV_32SC1, CV_32FC1 * @param binary If true, assumes the image to be binary (0x00 for black, 0xff for white), otherwise assumes the image to be * grayscale. diff --git a/modules/fastcv/perf/perf_bilateral.cpp b/modules/fastcv/perf/perf_bilateral.cpp index 63323d459cc..bfeb50f288c 100644 --- a/modules/fastcv/perf/perf_bilateral.cpp +++ b/modules/fastcv/perf/perf_bilateral.cpp @@ -52,7 +52,7 @@ PERF_TEST_P(BilateralPerfTest, run, RNG& rng = cv::theRNG(); Mat src(size, CV_8UC1); - cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256)); + cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255)); Mat dst; while (next()) diff --git a/modules/fastcv/perf/perf_histogram.cpp b/modules/fastcv/perf/perf_histogram.cpp new file mode 100644 index 00000000000..07dc7cd102b --- /dev/null +++ b/modules/fastcv/perf/perf_histogram.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "perf_precomp.hpp" + +namespace opencv_test { + +typedef std::tuple HistogramPerfParams; +typedef perf::TestBaseWithParam HistogramPerfTest; + + +PERF_TEST_P(HistogramPerfTest, run, + testing::Values(perf::szQVGA, perf::szVGA, perf::sz720p, perf::sz1080p) + ) +{ + auto p = GetParam(); + cv::Size size = std::get<0>(p); + + RNG& rng = cv::theRNG(); + Mat src(size, CV_8UC1); + cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255)); + Mat hist(1, 256, CV_32SC1); + + for (; next(); ) + { + startTimer(); + cv::fastcv::calcHist(src, hist); + stopTimer(); + } + + SANITY_CHECK_NOTHING(); +} + +} // namespace diff --git a/modules/fastcv/src/bilateralFilter.cpp b/modules/fastcv/src/bilateralFilter.cpp index a0995347b24..79e6b1067bc 100644 --- a/modules/fastcv/src/bilateralFilter.cpp +++ b/modules/fastcv/src/bilateralFilter.cpp @@ -22,13 +22,13 @@ class FcvFilterLoop_Invoker : public cv::ParallelLoopBody { int height_ = range.end - range.start; int width_ = width; - cv::Mat src_; - int n = knl/2; + cv::Mat src_; + int n = knl/2; src_ = cv::Mat(height_ + 2 * n, width_ + 2 * n, CV_8U); if (range.start == 0 && range.end == height) { - cv::copyMakeBorder(src, src_, n, n, n, n, bdr); + cv::copyMakeBorder(src(cv::Rect(0, 0, width, height)), src_, n, n, n, n, bdr); } else if (range.start == 0) { @@ -43,7 +43,7 @@ class FcvFilterLoop_Invoker : public cv::ParallelLoopBody cv::copyMakeBorder(src(cv::Rect(0, range.start - n, width_, height_ + 2 * n)), src_, 0, 0, n, n, bdr); } - cv::Mat dst_padded = cv::Mat(height_ + 2*n, width_ + 2*n, CV_8U); + cv::Mat dst_padded = cv::Mat(height_ + 2*n, width_ + 2*n, CV_8U); auto func = (knl == 5) ? fcvBilateralFilter5x5u8_v3 : (knl == 7) ? fcvBilateralFilter7x7u8_v3 : @@ -52,10 +52,10 @@ class FcvFilterLoop_Invoker : public cv::ParallelLoopBody func(src_.data, width_ + 2 * n, height_ + 2 * n, width_ + 2 * n, dst_padded.data, width_ + 2 * n, sigma_color, sigma_space, 0); - cv::Mat dst_temp1 = dst_padded(cv::Rect(n, n, width_, height_)); - cv::Mat dst_temp2 = dst(cv::Rect(0, range.start, width_, height_)); - dst_temp1.copyTo(dst_temp2); - } + cv::Mat dst_temp1 = dst_padded(cv::Rect(n, n, width_, height_)); + cv::Mat dst_temp2 = dst(cv::Rect(0, range.start, width_, height_)); + dst_temp1.copyTo(dst_temp2); + } private: const size_t src_step; @@ -67,8 +67,8 @@ class FcvFilterLoop_Invoker : public cv::ParallelLoopBody float32_t sigma_color; float32_t sigma_space; int ret; - cv::Mat src; - cv::Mat dst; + cv::Mat src; + cv::Mat dst; FcvFilterLoop_Invoker(const FcvFilterLoop_Invoker &); // = delete; const FcvFilterLoop_Invoker& operator= (const FcvFilterLoop_Invoker &); // = delete; @@ -82,24 +82,20 @@ void bilateralFilter( InputArray _src, OutputArray _dst, int d, CV_Assert(!_src.empty()); int type = _src.type(); - CV_Assert(type == CV_8UC1); - CV_Assert(d == 5 || d == 7 || d == 9); + CV_Assert(type == CV_8UC1); + CV_Assert(d == 5 || d == 7 || d == 9); Size size = _src.size(); - _dst.create( size, type ); + _dst.create( size, type ); Mat src = _src.getMat(); Mat dst = _dst.getMat(); CV_Assert(src.data != dst.data); if( sigmaColor <= 0 ) - { sigmaColor = 1; - } if( sigmaSpace <= 0 ) - { sigmaSpace = 1; - } int nStripes = (src.rows / 20 == 0) ? 1 : (src.rows / 20); cv::parallel_for_(cv::Range(0, src.rows), diff --git a/modules/fastcv/src/histogram.cpp b/modules/fastcv/src/histogram.cpp new file mode 100644 index 00000000000..e3ae4c13b75 --- /dev/null +++ b/modules/fastcv/src/histogram.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include "precomp.hpp" + +namespace cv { +namespace fastcv { + +class FcvHistogramLoop_Invoker : public cv::ParallelLoopBody +{ +public: + + FcvHistogramLoop_Invoker(const uchar * src_data_, size_t src_step_, int width_, int height_, int32_t* gl_hist_, int stripeHeight_, cv::Mutex* histogramLock, int nStripes_): + cv::ParallelLoopBody(), src_data(src_data_), src_step(src_step_), width(width_), height(height_), gl_hist(gl_hist_), stripeHeight(stripeHeight_), histogramLock_(histogramLock), nStripes(nStripes_) + { + } + + virtual void operator()(const cv::Range& range) const CV_OVERRIDE + { + int height_ = stripeHeight; + if(range.end == nStripes) + height_ += (height % nStripes); + const uchar* yS = src_data; + int32_t l_hist[256] = {0}; + fcvImageIntensityHistogram(yS, src_step, 0, range.start, width, height_, l_hist); + cv::AutoLock lock(*histogramLock_); + + for( int i = 0; i < 256; i++ ) + gl_hist[i] += l_hist[i]; + } + +private: + const uchar * src_data; + const size_t src_step; + const int width; + const int height; + int32_t *gl_hist; + int ret; + int stripeHeight; + cv::Mutex* histogramLock_; + int nStripes; + + FcvHistogramLoop_Invoker(const FcvHistogramLoop_Invoker &); // = delete; + const FcvHistogramLoop_Invoker& operator= (const FcvHistogramLoop_Invoker &); // = delete; +}; + +void calcHist( InputArray _src, OutputArray _hist ) +{ + INITIALIZATION_CHECK; + + CV_Assert(!_src.empty()); + int type = _src.type(); + CV_Assert(type == CV_8UC1); + + _hist.create( cv::Size(256, 1), CV_32SC1 ); + Mat src = _src.getMat(); + Mat hist = _hist.getMat(); + + for( int i = 0; i < 256; i++ ) + hist.ptr()[i] = 0; + + cv::Mutex histogramLockInstance; + + int nStripes = cv::getNumThreads();//(src.cols*src.rows)/(1<<8); + int stripeHeight = src.rows / nStripes; + + cv::parallel_for_(cv::Range(0, nStripes), + FcvHistogramLoop_Invoker(src.data, src.step[0], src.cols, src.rows, hist.ptr(), stripeHeight, &histogramLockInstance, nStripes), nStripes); +} + +} // fastcv:: +} // cv:: diff --git a/modules/fastcv/src/moments.cpp b/modules/fastcv/src/moments.cpp index 3a0c4249eef..38bae771df3 100644 --- a/modules/fastcv/src/moments.cpp +++ b/modules/fastcv/src/moments.cpp @@ -10,71 +10,63 @@ namespace fastcv { cv::Moments moments(InputArray _src, bool binary) { - INITIALIZATION_CHECK; + INITIALIZATION_CHECK; CV_Assert(!_src.empty()); int type = _src.type(); - CV_Assert(type == CV_8UC1 || type == CV_32SC1 || type == CV_32FC1); + CV_Assert(type == CV_8UC1 || type == CV_32SC1 || type == CV_32FC1); Size size = _src.size(); Mat src = _src.getMat(); cv::Moments m; - if( size.width == 0 || size.height == 0 ) - return m; - - fcvMoments* mFCV = new fcvMoments(); + fcvMoments mFCV; fcvStatus status = FASTCV_SUCCESS; - if(binary) + if(binary) + { + cv::Mat src_binary(size, CV_8UC1); + cv::compare( src, 0, src_binary, cv::CMP_NE ); + fcvImageMomentsu8(src_binary.data, src_binary.cols, + src_binary.rows, src_binary.step[0], &mFCV, binary); + } + else { - cv::Mat src_binary(size, CV_8UC1); - cv::compare( src, 0, src_binary, cv::CMP_NE ); - fcvImageMomentsu8(src_binary.data, src_binary.cols, - src_binary.rows, src_binary.step, mFCV, binary); + switch(type) + { + case CV_8UC1: + fcvImageMomentsu8(src.data, src.cols, src.rows, src.step[0], &mFCV, binary); + break; + case CV_32SC1: + fcvImageMomentss32(src.ptr(), src.cols, src.rows, src.step[0], &mFCV, binary); + break; + case CV_32FC1: + fcvImageMomentsf32(src.ptr(), src.cols, src.rows, src.step[0], &mFCV, binary); + break; + } } - else - { - switch(type) - { - case CV_8UC1: - fcvImageMomentsu8(src.data, src.cols, src.rows, - src.step, mFCV, binary); - break; - case CV_32SC1: - fcvImageMomentss32((const int*)src.data, src.cols, src.rows, - src.step, mFCV, binary); - break; - case CV_32FC1: - fcvImageMomentsf32((const float*)src.data, src.cols, src.rows, - src.step, mFCV, binary); - break; - } - } - if (status != FASTCV_SUCCESS) + if (status != FASTCV_SUCCESS) { CV_Error( cv::Error::StsError, cv::format("Error occurred!") ); - delete mFCV; return m; } - m.m00 = mFCV->m00; m.m10 = mFCV->m10; m.m01 = mFCV->m01; - m.m20 = mFCV->m20; m.m11 = mFCV->m11; m.m02 = mFCV->m02; - m.m30 = mFCV->m30; m.m21 = mFCV->m21; m.m12 = mFCV->m12; - m.m03 = mFCV->m03; m.mu02 = mFCV->mu02; m.m03 = mFCV->mu03; - m.mu11 = mFCV->mu11; m.mu12 = mFCV->mu12; m.mu20 = mFCV->mu20; - m.mu21 = mFCV->mu21; m.mu30 = mFCV->mu30; + m.m00 = mFCV.m00; m.m10 = mFCV.m10; m.m01 = mFCV.m01; + m.m20 = mFCV.m20; m.m11 = mFCV.m11; m.m02 = mFCV.m02; + m.m30 = mFCV.m30; m.m21 = mFCV.m21; m.m12 = mFCV.m12; + m.m03 = mFCV.m03; m.mu02 = mFCV.mu02; m.m03 = mFCV.mu03; + m.mu11 = mFCV.mu11; m.mu12 = mFCV.mu12; m.mu20 = mFCV.mu20; + m.mu21 = mFCV.mu21; m.mu30 = mFCV.mu30; - float32_t inv_m00 = 1.0/mFCV->m00; - float32_t inv_sqrt_m00 = mFCV->inv_sqrt_m00; + float32_t inv_m00 = 1.0/mFCV.m00; + float32_t inv_sqrt_m00 = mFCV.inv_sqrt_m00; float32_t s2 = inv_m00 * inv_m00, s3 = s2 * inv_sqrt_m00; - m.nu20 = mFCV->mu20 * s2; m.nu11 = mFCV->mu11 * s2; - m.nu02 = mFCV->mu02 * s2; m.nu30 = mFCV->mu30 * s3; - m.nu21 = mFCV->mu21 * s3; m.nu12 = mFCV->mu12 * s3; - m.nu03 = mFCV->mu03 * s3; + m.nu20 = mFCV.mu20 * s2; m.nu11 = mFCV.mu11 * s2; + m.nu02 = mFCV.mu02 * s2; m.nu30 = mFCV.mu30 * s3; + m.nu21 = mFCV.mu21 * s3; m.nu12 = mFCV.mu12 * s3; + m.nu03 = mFCV.mu03 * s3; - delete mFCV; return m; } diff --git a/modules/fastcv/test/test_bilateral.cpp b/modules/fastcv/test/test_bilateral.cpp index 5c883801a92..6ee8e6c409c 100644 --- a/modules/fastcv/test/test_bilateral.cpp +++ b/modules/fastcv/test/test_bilateral.cpp @@ -12,13 +12,13 @@ typedef testing::TestWithParam> fcv_bilateralFilterTest; TEST_P(fcv_bilateralFilterTest, accuracy) { cv::Size size = get<0>(GetParam()); - int d = get<1>(GetParam()); + int d = get<1>(GetParam()); double sigmaColor = get<2>(GetParam()); double sigmaSpace = sigmaColor; RNG& rng = cv::theRNG(); Mat src(size, CV_8UC1); - cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256)); + cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255)); cv::Mat dst; diff --git a/modules/fastcv/test/test_moments.cpp b/modules/fastcv/test/test_moments.cpp index d4ef89f98db..13e245f749d 100644 --- a/modules/fastcv/test/test_moments.cpp +++ b/modules/fastcv/test/test_moments.cpp @@ -15,22 +15,29 @@ TEST_P(fcv_momentsTest, accuracy) const Size srcSize = get<1>(GetParam()); const MatDepth srcType = get<2>(GetParam()); Mat src(srcSize, srcType); - - for(int j = 0; j < srcSize.width; ++j) - for(int i = 0; i < srcSize.height; ++i) - { - if(srcType == CV_8UC1) - src.at(i, j) = cv::randu(); - else if(srcType == CV_32SC1) - src.at(i, j) = cv::randu(); - else if(srcType == CV_32FC1) - src.at(i, j) = cv::randu(); - } - - cv::Moments m = cv::fastcv::moments(src, binaryImage); - - int len_m = sizeof(m)/sizeof(m.m00); - EXPECT_FALSE(len_m != 24); + cv::RNG& rng = cv::theRNG(); + if(srcType == CV_8UC1) + rng.fill(src, cv::RNG::UNIFORM, 0, 5); + else if(srcType == CV_32SC1) + rng.fill(src, cv::RNG::UNIFORM, 0, 5); + else if(srcType == CV_32FC1) + rng.fill(src, cv::RNG::UNIFORM, 0.f, 5.f); + + cv::Moments m = cv::fastcv::moments(src, binaryImage); + + cv::Scalar mean_val, stdDev; + float mean_val_fcv = m.m00/(srcSize.width * srcSize.height); + if(binaryImage) + { + cv::Mat src_binary(srcSize, CV_8UC1); + cv::compare( src, 0, src_binary, cv::CMP_NE ); + mean_val = cv::mean(src_binary); + mean_val_fcv *= 255; + } + else + mean_val = cv::mean(src); + + EXPECT_NEAR(mean_val[0], mean_val_fcv, 2); } INSTANTIATE_TEST_CASE_P(/*nothing*/, fcv_momentsTest, Combine(