Merge pull request #3845 from CodeLinaro:adsha_2ndPost

FastCV Extension code for OpenCV 2ndpost-2 #3845

### Description:
- Add support for cv::fastcv::calcHist

Depends on: [opencv/opencv_contrib#3844](https://github.com/opencv/opencv_contrib/pull/3844)
Depends on: [opencv/opencv#26619](https://github.com/opencv/opencv/pull/26619)
Requires binary from: [opencv/opencv_3rdparty#90](https://github.com/opencv/opencv_3rdparty/pull/90)

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
pull/3854/head
adsha-quic 4 months ago committed by GitHub
parent 67815e94c8
commit a00b3f3296
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      modules/fastcv/include/opencv2/fastcv.hpp
  2. 29
      modules/fastcv/include/opencv2/fastcv/histogram.hpp
  3. 3
      modules/fastcv/include/opencv2/fastcv/moments.hpp
  4. 2
      modules/fastcv/perf/perf_bilateral.cpp
  5. 36
      modules/fastcv/perf/perf_histogram.cpp
  6. 30
      modules/fastcv/src/bilateralFilter.cpp
  7. 74
      modules/fastcv/src/histogram.cpp
  8. 80
      modules/fastcv/src/moments.cpp
  9. 4
      modules/fastcv/test/test_bilateral.cpp
  10. 39
      modules/fastcv/test/test_moments.cpp

@ -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"

@ -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 <opencv2/core.hpp>
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

@ -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.

@ -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())

@ -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<cv::Size> HistogramPerfParams;
typedef perf::TestBaseWithParam<HistogramPerfParams> 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);
while (next())
{
startTimer();
cv::fastcv::calcHist(src, hist);
stopTimer();
}
SANITY_CHECK_NOTHING();
}
} // namespace

@ -22,13 +22,13 @@ public:
{
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 @@ public:
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 @@ public:
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 @@ private:
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),

@ -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<int>()[i] = 0;
cv::Mutex histogramLockInstance;
int nStripes = cv::getNumThreads();
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<int>(), stripeHeight, &histogramLockInstance, nStripes), nStripes);
}
} // fastcv::
} // cv::

@ -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<int>(), src.cols, src.rows, src.step[0], &mFCV, binary);
break;
case CV_32FC1:
fcvImageMomentsf32(src.ptr<float>(), 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;
}

@ -12,13 +12,13 @@ typedef testing::TestWithParam<tuple<cv::Size,int,int>> 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;

@ -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<uchar>(i, j) = cv::randu<uchar>();
else if(srcType == CV_32SC1)
src.at<int>(i, j) = cv::randu<int>();
else if(srcType == CV_32FC1)
src.at<float>(i, j) = cv::randu<float>();
}
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(

Loading…
Cancel
Save