vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<int /*rows1*/, int /*cols1*/, int /*cols2*/> MatMulTestParams;
|
||||
class MatMulTest : public ::testing::TestWithParam<MatMulTestParams> {};
|
||||
|
||||
typedef std::tuple<Size, int /*depth*/, int /*op type*/> ArithmOpTestParams;
|
||||
class ArithmOpTest : public ::testing::TestWithParam<ArithmOpTestParams> {};
|
||||
|
||||
TEST_P(MatMulTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
int rows1 = std::get<0>(p);
|
||||
int cols1 = std::get<1>(p);
|
||||
int cols2 = std::get<2>(p);
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src1(rows1, cols1, CV_8SC1), src2(cols1, cols2, CV_8SC1);
|
||||
cvtest::randUni(rng, src1, Scalar::all(-128), Scalar::all(128));
|
||||
cvtest::randUni(rng, src2, Scalar::all(-128), Scalar::all(128));
|
||||
|
||||
Mat dst;
|
||||
cv::fastcv::matmuls8s32(src1, src2, dst);
|
||||
Mat fdst;
|
||||
dst.convertTo(fdst, CV_32F);
|
||||
|
||||
Mat fsrc1, fsrc2;
|
||||
src1.convertTo(fsrc1, CV_32F);
|
||||
src2.convertTo(fsrc2, CV_32F);
|
||||
Mat ref;
|
||||
cv::gemm(fsrc1, fsrc2, 1.0, noArray(), 0, ref, 0);
|
||||
|
||||
double normInf = cvtest::norm(ref, fdst, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(ref, fdst, cv::NORM_L2);
|
||||
|
||||
EXPECT_EQ(normInf, 0);
|
||||
EXPECT_EQ(normL2, 0);
|
||||
|
||||
if (cvtest::debugLevel > 0 && (normInf > 0 || normL2 > 0))
|
||||
{
|
||||
std::ofstream of(cv::format("out_%d_%d_%d.txt", rows1, cols1, cols2));
|
||||
of << ref << std::endl;
|
||||
of << dst << std::endl;
|
||||
of.close();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ArithmOpTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
Size sz = std::get<0>(p);
|
||||
int depth = std::get<1>(p);
|
||||
int op = std::get<2>(p);
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src1(sz, depth), src2(sz, depth);
|
||||
|
||||
cvtest::randUni(rng, src1, Scalar::all(0), Scalar::all(128));
|
||||
cvtest::randUni(rng, src2, Scalar::all(0), Scalar::all(128));
|
||||
|
||||
Mat dst;
|
||||
cv::fastcv::arithmetic_op(src1, src2, dst, op);
|
||||
|
||||
Mat ref;
|
||||
if(op == 0)
|
||||
cv::add(src1, src2, ref);
|
||||
else if(op == 1)
|
||||
cv::subtract(src1, src2, ref);
|
||||
|
||||
double normInf = cvtest::norm(ref, dst, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(ref, dst, cv::NORM_L2);
|
||||
|
||||
EXPECT_EQ(normInf, 0);
|
||||
EXPECT_EQ(normL2, 0);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size>> IntegrateYUVTest;
|
||||
|
||||
TEST_P(IntegrateYUVTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
Size srcSize = std::get<0>(p);
|
||||
int depth = CV_8U;
|
||||
|
||||
cv::Mat Y(srcSize, depth), CbCr(srcSize.height/2, srcSize.width, depth);
|
||||
cv::Mat IY, ICb, ICr;
|
||||
RNG& rng = cv::theRNG();
|
||||
cvtest::randUni(rng, Y, Scalar::all(0), Scalar::all(255));
|
||||
cvtest::randUni(rng, CbCr, Scalar::all(0), Scalar::all(255));
|
||||
|
||||
cv::fastcv::integrateYUV(Y, CbCr, IY, ICb, ICr);
|
||||
|
||||
CbCr = CbCr.reshape(2,0);
|
||||
std::vector<cv::Mat> ref;
|
||||
cv::fastcv::split(CbCr, ref);
|
||||
|
||||
cv::Mat IY_ref, ICb_ref, ICr_ref;
|
||||
cv::integral(Y,IY_ref,CV_32S);
|
||||
cv::integral(ref[0],ICb_ref,CV_32S);
|
||||
cv::integral(ref[1],ICr_ref,CV_32S);
|
||||
|
||||
EXPECT_EQ(IY_ref.at<int>(IY_ref.rows - 1, IY_ref.cols - 1), IY.at<int>(IY.rows - 1, IY.cols - 1));
|
||||
EXPECT_EQ(ICb_ref.at<int>(ICb_ref.rows - 1, ICb_ref.cols - 1), ICb.at<int>(ICb.rows - 1, ICb.cols - 1));
|
||||
EXPECT_EQ(ICr_ref.at<int>(ICr_ref.rows - 1, ICr_ref.cols - 1), ICr.at<int>(ICr.rows - 1, ICr.cols - 1));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, MatMulTest,
|
||||
::testing::Combine(::testing::Values(8, 16, 128, 256), // rows1
|
||||
::testing::Values(8, 16, 128, 256), // cols1
|
||||
::testing::Values(8, 16, 128, 256))); // cols2
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, ArithmOpTest,
|
||||
::testing::Combine(::testing::Values(perf::szVGA, perf::sz720p, perf::sz1080p), // sz
|
||||
::testing::Values(CV_8U, CV_16S), // depth
|
||||
::testing::Values(0,1))); // op type
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, IntegrateYUVTest,
|
||||
Values(perf::szVGA, perf::sz720p, perf::sz1080p)); // sz
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
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());
|
||||
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(255));
|
||||
|
||||
cv::Mat dst;
|
||||
|
||||
cv::fastcv::bilateralFilter(src, dst, d, sigmaColor, sigmaSpace);
|
||||
|
||||
EXPECT_FALSE(dst.empty());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, fcv_bilateralFilterTest, Combine(
|
||||
::testing::Values(Size(8, 8), Size(640, 480), Size(800, 600)),
|
||||
::testing::Values(5, 7, 9),
|
||||
::testing::Values(1., 10.)
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size, int, int, bool>> GaussianBlurTest;
|
||||
|
||||
TEST_P(GaussianBlurTest, accuracy)
|
||||
{
|
||||
cv::Size srcSize = get<0>(GetParam());
|
||||
int depth = get<1>(GetParam());
|
||||
int ksize = get<2>(GetParam());
|
||||
bool border = get<3>(GetParam());
|
||||
|
||||
// For some cases FastCV not support, so skip them
|
||||
if((ksize!=5) && (depth!=CV_8U))
|
||||
return;
|
||||
|
||||
cv::Mat src(srcSize, depth);
|
||||
cv::Mat dst,ref;
|
||||
RNG& rng = cv::theRNG();
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
|
||||
|
||||
cv::fastcv::gaussianBlur(src, dst, ksize, border);
|
||||
|
||||
if(depth == CV_32S)
|
||||
src.convertTo(src, CV_32F);
|
||||
cv::GaussianBlur(src,ref,Size(ksize,ksize),0,0,border);
|
||||
ref.convertTo(ref,depth);
|
||||
|
||||
cv::Mat difference;
|
||||
cv::absdiff(dst, ref, difference);
|
||||
|
||||
int num_diff_pixels = cv::countNonZero(difference);
|
||||
|
||||
EXPECT_LT(num_diff_pixels, (src.rows+src.cols)*ksize);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size, int, int>> Filter2DTest;
|
||||
|
||||
TEST_P(Filter2DTest, accuracy)
|
||||
{
|
||||
Size srcSize = get<0>(GetParam());
|
||||
int ddepth = get<1>(GetParam());
|
||||
int ksize = get<2>(GetParam());
|
||||
|
||||
cv::Mat src(srcSize, CV_8U);
|
||||
cv::Mat kernel;
|
||||
cv::Mat dst, ref;
|
||||
|
||||
switch (ddepth)
|
||||
{
|
||||
case CV_8U:
|
||||
case CV_16S:
|
||||
{
|
||||
kernel.create(ksize,ksize,CV_8S);
|
||||
break;
|
||||
}
|
||||
case CV_32F:
|
||||
{
|
||||
kernel.create(ksize,ksize,CV_32F);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
|
||||
cvtest::randUni(rng, kernel, Scalar::all(INT8_MIN), Scalar::all(INT8_MAX));
|
||||
|
||||
cv::fastcv::filter2D(src, dst, ddepth, kernel);
|
||||
cv::filter2D(src, ref, ddepth, kernel);
|
||||
|
||||
cv::Mat difference;
|
||||
dst.convertTo(dst, CV_8U);
|
||||
ref.convertTo(ref, CV_8U);
|
||||
cv::absdiff(dst, ref, difference);
|
||||
|
||||
int num_diff_pixels = cv::countNonZero(difference);
|
||||
EXPECT_LT(num_diff_pixels, (src.rows+src.cols)*ksize);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size, int>> SepFilter2DTest;
|
||||
|
||||
TEST_P(SepFilter2DTest, accuracy)
|
||||
{
|
||||
Size srcSize = get<0>(GetParam());
|
||||
int ksize = get<1>(GetParam());
|
||||
|
||||
cv::Mat src(srcSize, CV_8U);
|
||||
cv::Mat kernel(1,ksize,CV_8S);
|
||||
cv::Mat dst,ref;
|
||||
RNG& rng = cv::theRNG();
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
|
||||
cvtest::randUni(rng, kernel, Scalar::all(INT8_MIN), Scalar::all(INT8_MAX));
|
||||
|
||||
cv::fastcv::sepFilter2D(src, dst, CV_8U, kernel, kernel);
|
||||
cv::sepFilter2D(src,ref,CV_8U,kernel,kernel);
|
||||
|
||||
cv::Mat difference;
|
||||
cv::absdiff(dst, ref, difference);
|
||||
int num_diff_pixels = cv::countNonZero(difference);
|
||||
EXPECT_LT(num_diff_pixels, (src.rows+src.cols)*ksize);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<int>> NormalizeLocalBoxTest;
|
||||
|
||||
TEST_P(NormalizeLocalBoxTest, accuracy)
|
||||
{
|
||||
bool use_stddev = get<0>(GetParam());
|
||||
cv::Mat src, dst;
|
||||
src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
cv::fastcv::normalizeLocalBox(src, dst, Size(5,5), use_stddev);
|
||||
Scalar s = cv::mean(dst);
|
||||
|
||||
if(use_stddev)
|
||||
EXPECT_LT(s[0],1);
|
||||
else
|
||||
EXPECT_LT(s[0],50);
|
||||
}
|
||||
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, GaussianBlurTest, Combine(
|
||||
/*image size*/ ::testing::Values(perf::szVGA, perf::sz720p, perf::sz1080p),
|
||||
/*image depth*/ ::testing::Values(CV_8U,CV_16S,CV_32S),
|
||||
/*kernel size*/ ::testing::Values(3, 5),
|
||||
/*blur border*/ ::testing::Values(true,false)
|
||||
));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, Filter2DTest, Combine(
|
||||
/*image sie*/ Values(perf::szVGA, perf::sz720p, perf::sz1080p),
|
||||
/*dst depth*/ Values(CV_8U,CV_16S,CV_32F),
|
||||
/*kernel size*/ Values(3, 5, 7, 9, 11)
|
||||
));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, SepFilter2DTest, Combine(
|
||||
/*image size*/ Values(perf::szVGA, perf::sz720p, perf::sz1080p),
|
||||
/*kernel size*/ Values(3, 5, 7, 9, 11)
|
||||
));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, NormalizeLocalBoxTest, Values(0,1));
|
||||
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size, int, int>> Filter2DTest_DSP;
|
||||
|
||||
TEST_P(Filter2DTest_DSP, accuracy)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
|
||||
//Initialize DSP
|
||||
int initStatus = cv::fastcv::dsp::fcvdspinit();
|
||||
ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP";
|
||||
|
||||
Size srcSize = get<0>(GetParam());
|
||||
int ddepth = get<1>(GetParam());
|
||||
int ksize = get<2>(GetParam());
|
||||
|
||||
cv::Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator();
|
||||
src.create(srcSize, CV_8U);
|
||||
|
||||
cv::Mat kernel;
|
||||
cv::Mat dst, ref;
|
||||
kernel.allocator = cv::fastcv::getQcAllocator();
|
||||
dst.allocator = cv::fastcv::getQcAllocator();
|
||||
|
||||
switch (ddepth)
|
||||
{
|
||||
case CV_8U:
|
||||
case CV_16S:
|
||||
{
|
||||
kernel.create(ksize,ksize,CV_8S);
|
||||
break;
|
||||
}
|
||||
case CV_32F:
|
||||
{
|
||||
kernel.create(ksize,ksize,CV_32F);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
|
||||
cvtest::randUni(rng, kernel, Scalar::all(INT8_MIN), Scalar::all(INT8_MAX));
|
||||
|
||||
cv::fastcv::dsp::filter2D(src, dst, ddepth, kernel);
|
||||
|
||||
//De-Initialize DSP
|
||||
cv::fastcv::dsp::fcvdspdeinit();
|
||||
|
||||
cv::filter2D(src, ref, ddepth, kernel);
|
||||
cv::Mat difference;
|
||||
dst.convertTo(dst, CV_8U);
|
||||
ref.convertTo(ref, CV_8U);
|
||||
cv::absdiff(dst, ref, difference);
|
||||
|
||||
int num_diff_pixels = cv::countNonZero(difference);
|
||||
EXPECT_LT(num_diff_pixels, (src.rows+src.cols)*ksize);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, Filter2DTest_DSP, Combine(
|
||||
/*image size*/ Values(perf::szVGA, perf::sz720p),
|
||||
/*dst depth*/ Values(CV_8U,CV_16S,CV_32F),
|
||||
/*kernel size*/ Values(3, 5, 7, 9, 11)
|
||||
));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<Size, int> ChannelMergeTestParams;
|
||||
class ChannelMergeTest : public ::testing::TestWithParam<ChannelMergeTestParams> {};
|
||||
|
||||
typedef std::tuple<Size, int> ChannelSplitTestParams;
|
||||
class ChannelSplitTest : public ::testing::TestWithParam<ChannelSplitTestParams> {};
|
||||
|
||||
TEST_P(ChannelMergeTest, accuracy)
|
||||
{
|
||||
int depth = CV_8UC1;
|
||||
Size sz = std::get<0>(GetParam());
|
||||
int count = std::get<1>(GetParam());
|
||||
std::vector<Mat> src_mats;
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
Mat tmp(sz, depth);
|
||||
src_mats.push_back(tmp);
|
||||
cvtest::randUni(rng, src_mats[i], Scalar::all(0), Scalar::all(127));
|
||||
}
|
||||
|
||||
Mat dst;
|
||||
cv::fastcv::merge(src_mats, dst);
|
||||
|
||||
Mat ref;
|
||||
cv::merge(src_mats, ref);
|
||||
|
||||
double normInf = cvtest::norm(ref, dst, cv::NORM_INF);
|
||||
|
||||
EXPECT_EQ(normInf, 0);
|
||||
}
|
||||
|
||||
TEST_P(ChannelSplitTest, accuracy)
|
||||
{
|
||||
Size sz = std::get<0>(GetParam());
|
||||
int cn = std::get<1>(GetParam());
|
||||
std::vector<Mat> dst_mats(cn), ref_mats(cn);
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src(sz, CV_MAKE_TYPE(CV_8U,cn));
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(127));
|
||||
|
||||
cv::fastcv::split(src, dst_mats);
|
||||
|
||||
cv::split(src, ref_mats);
|
||||
|
||||
for(int i=0; i<cn; i++)
|
||||
{
|
||||
double normInf = cvtest::norm(ref_mats[i], dst_mats[i], cv::NORM_INF);
|
||||
EXPECT_EQ(normInf, 0);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, ChannelMergeTest,
|
||||
::testing::Combine(::testing::Values(perf::szODD, perf::szVGA, perf::sz720p, perf::sz1080p), // sz
|
||||
::testing::Values(2,3,4))); // count
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, ChannelSplitTest,
|
||||
::testing::Combine(::testing::Values(perf::szODD, perf::szVGA, perf::sz720p, perf::sz1080p), // sz
|
||||
::testing::Values(2,3,4))); // cn
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
// nPts, nDims, nClusters
|
||||
typedef std::tuple<int, int, int> ClusterEuclideanTestParams;
|
||||
class ClusterEuclideanTest : public ::testing::TestWithParam<ClusterEuclideanTestParams> {};
|
||||
|
||||
TEST_P(ClusterEuclideanTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
int nPts = std::get<0>(p);
|
||||
int nDims = std::get<1>(p);
|
||||
int nClusters = std::get<2>(p);
|
||||
|
||||
Mat points(nPts, nDims, CV_8U);
|
||||
Mat clusterCenters(nClusters, nDims, CV_32F);
|
||||
|
||||
Mat trueMeans(nClusters, nDims, CV_32F);
|
||||
Mat stddevs(nClusters, nDims, CV_32F);
|
||||
std::vector<int> trueClusterSizes(nClusters, 0);
|
||||
std::vector<int> trueClusterBindings(nPts, 0);
|
||||
std::vector<float> trueSumDists(nClusters, 0);
|
||||
|
||||
cv::RNG& rng = cv::theRNG();
|
||||
for (int i = 0; i < nClusters; i++)
|
||||
{
|
||||
Mat mean(1, nDims, CV_64F), stdev(1, nDims, CV_64F);
|
||||
rng.fill(mean, cv::RNG::UNIFORM, 0, 256);
|
||||
rng.fill(stdev, cv::RNG::UNIFORM, 5.f, 16);
|
||||
int lo = i * nPts / nClusters;
|
||||
int hi = (i + 1) * nPts / nClusters;
|
||||
|
||||
for (int d = 0; d < nDims; d++)
|
||||
{
|
||||
rng.fill(points.col(d).rowRange(lo, hi), cv::RNG::NORMAL,
|
||||
mean.at<double>(d), stdev.at<double>(d));
|
||||
}
|
||||
|
||||
float sd = 0;
|
||||
for (int j = lo; j < hi; j++)
|
||||
{
|
||||
Mat pts64f;
|
||||
points.row(j).convertTo(pts64f, CV_64F);
|
||||
sd += cv::norm(mean, pts64f, NORM_L2);
|
||||
trueClusterBindings.at(j) = i;
|
||||
trueClusterSizes.at(i)++;
|
||||
}
|
||||
trueSumDists.at(i) = sd;
|
||||
|
||||
// let's shift initial cluster center a bit
|
||||
Mat(mean + stdev * 0.5).copyTo(clusterCenters.row(i));
|
||||
|
||||
mean.copyTo(trueMeans.row(i));
|
||||
stdev.copyTo(stddevs.row(i));
|
||||
}
|
||||
|
||||
Mat newClusterCenters;
|
||||
std::vector<int> clusterSizes, clusterBindings;
|
||||
std::vector<float> clusterSumDists;
|
||||
cv::fastcv::clusterEuclidean(points, clusterCenters, newClusterCenters, clusterSizes, clusterBindings, clusterSumDists);
|
||||
|
||||
if (cvtest::debugLevel > 0 && nDims == 2)
|
||||
{
|
||||
Mat draw(256, 256, CV_8UC3, Scalar(0));
|
||||
for (int i = 0; i < nPts; i++)
|
||||
{
|
||||
int x = std::rint(points.at<uchar>(i, 0));
|
||||
int y = std::rint(points.at<uchar>(i, 1));
|
||||
draw.at<Vec3b>(y, x) = Vec3b::all(128);
|
||||
}
|
||||
for (int i = 0; i < nClusters; i++)
|
||||
{
|
||||
float cx = trueMeans.at<double>(i, 0);
|
||||
float cy = trueMeans.at<double>(i, 1);
|
||||
draw.at<Vec3b>(cy, cx) = Vec3b(0, 255, 0);
|
||||
|
||||
float sx = stddevs.at<double>(i, 0);
|
||||
float sy = stddevs.at<double>(i, 1);
|
||||
cv::ellipse(draw, Point(cx, cy), Size(sx, sy), 0, 0, 360, Scalar(255, 0, 0));
|
||||
|
||||
float ox = clusterCenters.at<float>(i, 0);
|
||||
float oy = clusterCenters.at<float>(i, 1);
|
||||
draw.at<Vec3b>(oy, ox) = Vec3b(0, 0, 255);
|
||||
|
||||
float nx = newClusterCenters.at<float>(i, 0);
|
||||
float ny = newClusterCenters.at<float>(i, 1);
|
||||
draw.at<Vec3b>(ny, nx) = Vec3b(255, 255, 0);
|
||||
}
|
||||
cv::imwrite(cv::format("draw_%d_%d_%d.png", nPts, nDims, nClusters), draw);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<double> diffs;
|
||||
for (int i = 0; i < nClusters; i++)
|
||||
{
|
||||
double cs = std::abs((trueClusterSizes[i] - clusterSizes[i]) / double(trueClusterSizes[i]));
|
||||
diffs.push_back(cs);
|
||||
}
|
||||
double normL2 = cv::norm(diffs, NORM_L2) / nClusters;
|
||||
|
||||
EXPECT_LT(normL2, 0.392);
|
||||
}
|
||||
|
||||
{
|
||||
Mat bindings8u, trueBindings8u;
|
||||
Mat(clusterBindings).convertTo(bindings8u, CV_8U);
|
||||
Mat(trueClusterBindings).convertTo(trueBindings8u, CV_8U);
|
||||
double normH = cv::norm(bindings8u, trueBindings8u, NORM_HAMMING) / nPts;
|
||||
EXPECT_LT(normH, 0.66);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, ClusterEuclideanTest,
|
||||
::testing::Combine(::testing::Values(100, 1000, 10000), // nPts
|
||||
::testing::Values(2, 10, 32), // nDims
|
||||
::testing::Values(5, 10, 16))); // nClusters
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
static inline void fillRandom8U(cv::Mat& m)
|
||||
{
|
||||
cv::RNG& rng = cv::theRNG();
|
||||
rng.fill(m, cv::RNG::UNIFORM, 0, 256);
|
||||
}
|
||||
|
||||
TEST(Fastcv_cvtColor, YUV420_to_YUV422_and_back_roundtrip)
|
||||
{
|
||||
const cv::Size sz(640, 480);
|
||||
|
||||
cv::Mat bgr(sz, CV_8UC3);
|
||||
fillRandom8U(bgr);
|
||||
|
||||
cv::Mat rgb;
|
||||
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
|
||||
|
||||
cv::Mat yuv420_before;
|
||||
yuv420_before.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(rgb, yuv420_before, cv::fastcv::COLOR_RGB2YUV_NV12);
|
||||
|
||||
cv::Mat yuv422;
|
||||
yuv422.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(yuv420_before, yuv422, cv::fastcv::COLOR_YUV2YUV422sp_NV12);
|
||||
|
||||
cv::Mat yuv422_to_bgr;
|
||||
|
||||
cv::Mat yuv420_after;
|
||||
yuv420_after.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(yuv422, yuv420_after, cv::fastcv::COLOR_YUV422sp2YUV_NV12);
|
||||
|
||||
ASSERT_EQ(yuv420_before.size(), yuv420_after.size());
|
||||
ASSERT_EQ(yuv420_before.type(), yuv420_after.type());
|
||||
|
||||
double maxDiff = cv::norm(yuv420_before, yuv420_after, cv::NORM_INF);
|
||||
std::cout << "Max difference YUV420 before vs after = " << maxDiff << std::endl;
|
||||
EXPECT_LE(maxDiff, 1.0);
|
||||
}
|
||||
|
||||
TEST(Fastcv_cvtColor, YUV444_to_YUV420_and_back_roundtrip)
|
||||
{
|
||||
const cv::Size sz(640, 480);
|
||||
|
||||
cv::Mat bgr(sz, CV_8UC3);
|
||||
fillRandom8U(bgr);
|
||||
cv::Mat rgb;
|
||||
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
|
||||
|
||||
cv::Mat yuv444_initial;
|
||||
yuv444_initial.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(rgb, yuv444_initial, cv::fastcv::COLOR_RGB2YUV444sp);
|
||||
|
||||
cv::Mat yuv420;
|
||||
yuv420.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(yuv444_initial, yuv420, cv::fastcv::COLOR_YUV444sp2YUV_NV12);
|
||||
|
||||
cv::Mat yuv444_final;
|
||||
yuv444_final.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(yuv420, yuv444_final, cv::fastcv::COLOR_YUV2YUV444sp_NV12);
|
||||
|
||||
ASSERT_EQ(yuv444_initial.size(), yuv444_final.size());
|
||||
ASSERT_EQ(yuv444_initial.type(), yuv444_final.type());
|
||||
|
||||
double maxDiff = cv::norm(yuv444_initial, yuv444_final, cv::NORM_INF);
|
||||
std::cout << "Max difference YUV444 before vs after roundtrip = " << maxDiff << std::endl;
|
||||
EXPECT_LE(maxDiff, 2.0);
|
||||
}
|
||||
|
||||
TEST(Fastcv_cvtColor, YUV444_to_YUV422_and_back_roundtrip)
|
||||
{
|
||||
const cv::Size sz(640, 480);
|
||||
|
||||
cv::Mat bgr(sz, CV_8UC3);
|
||||
fillRandom8U(bgr);
|
||||
cv::Mat rgb;
|
||||
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
|
||||
|
||||
cv::Mat yuv444_initial;
|
||||
yuv444_initial.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(rgb, yuv444_initial, cv::fastcv::COLOR_RGB2YUV444sp);
|
||||
|
||||
cv::Mat yuv422;
|
||||
yuv422.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(yuv444_initial, yuv422, cv::fastcv::COLOR_YUV444sp2YUV422sp);
|
||||
|
||||
cv::Mat yuv444_final;
|
||||
yuv444_final.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(yuv422, yuv444_final, cv::fastcv::COLOR_YUV422sp2YUV444sp);
|
||||
|
||||
ASSERT_EQ(yuv444_initial.size(), yuv444_final.size());
|
||||
ASSERT_EQ(yuv444_initial.type(), yuv444_final.type());
|
||||
|
||||
double maxDiff = cv::norm(yuv444_initial, yuv444_final, cv::NORM_INF);
|
||||
std::cout << "Max difference YUV444 before vs after roundtrip = " << maxDiff << std::endl;
|
||||
EXPECT_LE(maxDiff, 2.0);
|
||||
}
|
||||
|
||||
TEST(Fastcv_cvtColor, YUV444_to_RGB565_and_back_roundtrip)
|
||||
{
|
||||
const cv::Size sz(640, 480);
|
||||
cv::Mat bgr(sz, CV_8UC3);
|
||||
fillRandom8U(bgr);
|
||||
|
||||
cv::Mat rgb;
|
||||
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
|
||||
|
||||
cv::Mat yuv444_initial;
|
||||
yuv444_initial.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(rgb, yuv444_initial, cv::fastcv::COLOR_RGB2YUV444sp);
|
||||
|
||||
cv::Mat rgb565(sz, CV_8UC2);
|
||||
rgb565.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(yuv444_initial, rgb565, cv::fastcv::COLOR_YUV444sp2RGB565);
|
||||
|
||||
cv::Mat yuv444_roundtrip;
|
||||
yuv444_roundtrip.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::cvtColor(rgb565, yuv444_roundtrip, cv::fastcv::COLOR_RGB5652YUV444sp);
|
||||
|
||||
ASSERT_EQ(yuv444_initial.size(), yuv444_roundtrip.size());
|
||||
ASSERT_EQ(yuv444_initial.type(), yuv444_roundtrip.type());
|
||||
|
||||
double maxDiff = cv::norm(yuv444_initial, yuv444_roundtrip, cv::NORM_INF);
|
||||
std::cout << "Max difference YUV444 after RGB565 roundtrip = " << maxDiff << std::endl;
|
||||
|
||||
EXPECT_LE(maxDiff, 2.0);
|
||||
}
|
||||
|
||||
}} // namespace opencv_test
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size, int, int, int>> Sobel;
|
||||
typedef testing::TestWithParam<tuple<Size, int>> Sobel3x3u8;
|
||||
|
||||
TEST_P(Sobel,accuracy)
|
||||
{
|
||||
Size srcSize = get<0>(GetParam());
|
||||
int ksize = get<1>(GetParam());
|
||||
int border = get<2>(GetParam());
|
||||
int borderValue = get<3>(GetParam());
|
||||
|
||||
cv::Mat dx, dy, src(srcSize, CV_8U), refx, refy;
|
||||
RNG& rng = cv::theRNG();
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
|
||||
cv::fastcv::sobel(src, dx, dy, ksize, border, borderValue);
|
||||
|
||||
cv::Sobel(src, refx, CV_16S, 1, 0, ksize, 1.0, 0.0, border);
|
||||
cv::Sobel(src, refy, CV_16S, 0, 1, ksize, 1.0, 0.0, border);
|
||||
|
||||
cv::Mat difference_x, difference_y;
|
||||
cv::absdiff(dx, refx, difference_x);
|
||||
cv::absdiff(dy, refy, difference_y);
|
||||
|
||||
int num_diff_pixels_x = cv::countNonZero(difference_x);
|
||||
int num_diff_pixels_y = cv::countNonZero(difference_y);
|
||||
EXPECT_LT(num_diff_pixels_x, src.size().area()*0.1);
|
||||
EXPECT_LT(num_diff_pixels_y, src.size().area()*0.1);
|
||||
}
|
||||
|
||||
TEST_P(Sobel3x3u8,accuracy)
|
||||
{
|
||||
Size srcSize = get<0>(GetParam());
|
||||
int ddepth = get<1>(GetParam());
|
||||
|
||||
cv::Mat dx, dy, src(srcSize, CV_8U), refx, refy;
|
||||
RNG& rng = cv::theRNG();
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
|
||||
|
||||
cv::fastcv::sobel3x3u8(src, dx, dy, ddepth, 0);
|
||||
cv::Sobel(src, refx, ddepth, 1, 0);
|
||||
cv::Sobel(src, refy, ddepth, 0, 1);
|
||||
|
||||
cv::Mat difference_x, difference_y;
|
||||
cv::absdiff(dx, refx, difference_x);
|
||||
cv::absdiff(dy, refy, difference_y);
|
||||
|
||||
int num_diff_pixels_x = cv::countNonZero(difference_x);
|
||||
int num_diff_pixels_y = cv::countNonZero(difference_y);
|
||||
EXPECT_LT(num_diff_pixels_x, src.size().area()*0.1);
|
||||
EXPECT_LT(num_diff_pixels_y, src.size().area()*0.1);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, Sobel, Combine(
|
||||
/*image size*/ Values(perf::szVGA, perf::sz720p, perf::sz1080p),
|
||||
/*kernel size*/ Values(3,5,7),
|
||||
/*border*/ Values(BORDER_CONSTANT, BORDER_REPLICATE),
|
||||
/*border value*/ Values(0)
|
||||
));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, Sobel3x3u8, Combine(
|
||||
/*image size*/ Values(perf::szVGA, perf::sz720p, perf::sz1080p),
|
||||
/*dst depth*/ Values(CV_16S, CV_32F)
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(DSP_CannyTest, accuracy)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
|
||||
//Initialize DSP
|
||||
int initStatus = cv::fastcv::dsp::fcvdspinit();
|
||||
ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP";
|
||||
|
||||
cv::Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::imread(cvtest::findDataFile("cv/detectors_descriptors_evaluation/planar/box_in_scene.png"), src, cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(src.empty()) << "Could not read the image file.";
|
||||
|
||||
cv::Mat dst;
|
||||
dst.allocator = cv::fastcv::getQcAllocator();
|
||||
|
||||
int lowThreshold = 0;
|
||||
int highThreshold = 150;
|
||||
|
||||
cv::fastcv::dsp::Canny(src, dst, lowThreshold, highThreshold, 3, true);
|
||||
|
||||
//De-Initialize DSP
|
||||
cv::fastcv::dsp::fcvdspdeinit();
|
||||
|
||||
EXPECT_FALSE(dst.empty());
|
||||
EXPECT_EQ(src.size(), dst.size());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<bool /*useScores*/, int /*barrier*/, int /*border*/, bool /*nmsEnabled*/> Fast10TestParams;
|
||||
class Fast10Test : public ::testing::TestWithParam<Fast10TestParams> {};
|
||||
|
||||
TEST_P(Fast10Test, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
bool useScores = std::get<0>(p);
|
||||
int barrier = std::get<1>(p);
|
||||
int border = std::get<2>(p);
|
||||
bool nmsEnabled = std::get<3>(p);
|
||||
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
std::vector<int> coords, scores;
|
||||
cv::fastcv::FAST10(src, noArray(), coords, useScores ? scores : noArray(), barrier, border, nmsEnabled);
|
||||
|
||||
std::vector<KeyPoint> ocvKeypoints;
|
||||
int thresh = barrier;
|
||||
cv::FAST(src, ocvKeypoints, thresh, nmsEnabled, FastFeatureDetector::DetectorType::TYPE_9_16 );
|
||||
|
||||
if (useScores)
|
||||
{
|
||||
ASSERT_EQ(scores.size() * 2, coords.size());
|
||||
}
|
||||
|
||||
Mat ptsMap(src.size(), CV_8U, Scalar(255));
|
||||
for(size_t i = 0; i < coords.size() / 2; ++i)
|
||||
{
|
||||
ptsMap.at<uchar>(coords[2*i + 1], coords[2*i + 0]) = 0;
|
||||
}
|
||||
Mat distTrans(src.size(), CV_8U);
|
||||
cv::distanceTransform(ptsMap, distTrans, DIST_L2, DIST_MASK_PRECISE);
|
||||
|
||||
Mat refPtsMap(src.size(), CV_8U, Scalar(255));
|
||||
for(size_t i = 0; i < ocvKeypoints.size(); ++i)
|
||||
{
|
||||
refPtsMap.at<uchar>(ocvKeypoints[i].pt) = 0;
|
||||
}
|
||||
Mat refDistTrans(src.size(), CV_8U);
|
||||
cv::distanceTransform(refPtsMap, refDistTrans, DIST_L2, DIST_MASK_PRECISE);
|
||||
|
||||
double normInf = cvtest::norm(refDistTrans, distTrans, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(refDistTrans, distTrans, cv::NORM_L2) / src.size().area();
|
||||
|
||||
EXPECT_LT(normInf, 129.7);
|
||||
EXPECT_LT(normL2, 0.067);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, Fast10Test,
|
||||
::testing::Combine(::testing::Bool(), // useScores
|
||||
::testing::Values(10, 30, 50), // barrier
|
||||
::testing::Values( 4, 10, 32), // border
|
||||
::testing::Bool() // nonmax suppression
|
||||
));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class FFTExtTest : public ::testing::TestWithParam<cv::Size> {};
|
||||
|
||||
TEST_P(FFTExtTest, forward)
|
||||
{
|
||||
Size size = GetParam();
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src(size, CV_8UC1);
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256));
|
||||
|
||||
Mat srcFloat;
|
||||
src.convertTo(srcFloat, CV_32F);
|
||||
|
||||
Mat dst, ref;
|
||||
cv::fastcv::FFT(src, dst);
|
||||
|
||||
cv::dft(srcFloat, ref, DFT_COMPLEX_OUTPUT);
|
||||
|
||||
double normInf = cvtest::norm(dst, ref, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(dst, ref, cv::NORM_L2) / dst.size().area();
|
||||
|
||||
EXPECT_LT(normInf, 19.1); // for 512x512 case
|
||||
EXPECT_LT(normL2, 18.0 / 256.0 );
|
||||
}
|
||||
|
||||
TEST_P(FFTExtTest, inverse)
|
||||
{
|
||||
Size size = GetParam();
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src(size, CV_8UC1);
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256));
|
||||
|
||||
Mat srcFloat;
|
||||
src.convertTo(srcFloat, CV_32F);
|
||||
|
||||
Mat fwd, back;
|
||||
cv::fastcv::FFT(src, fwd);
|
||||
cv::fastcv::IFFT(fwd, back);
|
||||
Mat backFloat;
|
||||
back.convertTo(backFloat, CV_32F);
|
||||
|
||||
Mat fwdRef, backRef;
|
||||
cv::dft(srcFloat, fwdRef, DFT_COMPLEX_OUTPUT);
|
||||
cv::idft(fwdRef, backRef, DFT_REAL_OUTPUT);
|
||||
|
||||
backRef *= 1./(src.size().area());
|
||||
|
||||
double normInf = cvtest::norm(backFloat, backRef, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(backFloat, backRef, cv::NORM_L2) / src.size().area();
|
||||
|
||||
EXPECT_LT(normInf, 9.16e-05);
|
||||
EXPECT_LT(normL2, 1.228e-06);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, FFTExtTest, ::testing::Values(Size(8, 8), Size(128, 128), Size(32, 256), Size(512, 512),
|
||||
Size(32, 1), Size(512, 1)));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class FFT_DSPExtTest : public ::testing::TestWithParam<cv::Size> {};
|
||||
|
||||
TEST_P(FFT_DSPExtTest, forward)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
|
||||
//Initialize DSP
|
||||
int initStatus = cv::fastcv::dsp::fcvdspinit();
|
||||
ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP";
|
||||
|
||||
Size size = GetParam();
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
|
||||
Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator();
|
||||
src.create(size, CV_8UC1);
|
||||
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256));
|
||||
|
||||
Mat srcFloat;
|
||||
src.convertTo(srcFloat, CV_32F);
|
||||
|
||||
Mat dst, ref;
|
||||
dst.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::fastcv::dsp::FFT(src, dst);
|
||||
|
||||
//De-Initialize DSP
|
||||
cv::fastcv::dsp::fcvdspdeinit();
|
||||
|
||||
cv::dft(srcFloat, ref, DFT_COMPLEX_OUTPUT);
|
||||
|
||||
double normInf = cvtest::norm(dst, ref, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(dst, ref, cv::NORM_L2) / dst.size().area();
|
||||
|
||||
EXPECT_LT(normInf, 19.1); // for 512x512 case
|
||||
EXPECT_LT(normL2, 18.0 / 256.0 );
|
||||
}
|
||||
|
||||
TEST_P(FFT_DSPExtTest, inverse)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
|
||||
//Initialize DSP
|
||||
int initStatus = cv::fastcv::dsp::fcvdspinit();
|
||||
ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP";
|
||||
|
||||
Size size = GetParam();
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
|
||||
Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator();
|
||||
src.create(size, CV_8UC1);
|
||||
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256));
|
||||
|
||||
Mat srcFloat;
|
||||
src.convertTo(srcFloat, CV_32F);
|
||||
|
||||
Mat fwd, back;
|
||||
fwd.allocator = cv::fastcv::getQcAllocator();
|
||||
back.allocator = cv::fastcv::getQcAllocator();
|
||||
|
||||
cv::fastcv::dsp::FFT(src, fwd);
|
||||
cv::fastcv::dsp::IFFT(fwd, back);
|
||||
|
||||
//De-Initialize DSP
|
||||
cv::fastcv::dsp::fcvdspdeinit();
|
||||
|
||||
Mat backFloat;
|
||||
back.convertTo(backFloat, CV_32F);
|
||||
|
||||
Mat fwdRef, backRef;
|
||||
cv::dft(srcFloat, fwdRef, DFT_COMPLEX_OUTPUT);
|
||||
cv::idft(fwdRef, backRef, DFT_REAL_OUTPUT);
|
||||
|
||||
backRef *= 1./(src.size().area());
|
||||
|
||||
double normInf = cvtest::norm(backFloat, backRef, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(backFloat, backRef, cv::NORM_L2) / src.size().area();
|
||||
|
||||
EXPECT_LT(normInf, 9.16e-05);
|
||||
EXPECT_LT(normL2, 1.228e-06);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, FFT_DSPExtTest, ::testing::Values(Size(256, 256), Size(512, 512)));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef tuple<cv::Size /*imgSize*/, int /*nPts*/, int /*channels*/> FillConvexTestParams;
|
||||
class FillConvexTest : public ::testing::TestWithParam<FillConvexTestParams> {};
|
||||
|
||||
TEST_P(FillConvexTest, randomDraw)
|
||||
{
|
||||
auto p = GetParam();
|
||||
|
||||
Size imgSize = std::get<0>(p);
|
||||
int nPts = std::get<1>(p);
|
||||
int channels = std::get<2>(p);
|
||||
|
||||
cv::RNG rng = cv::theRNG();
|
||||
|
||||
std::vector<Point> allPts, contour;
|
||||
for (int i = 0; i < nPts; i++)
|
||||
{
|
||||
allPts.push_back(Point(rng() % imgSize.width, rng() % imgSize.height));
|
||||
}
|
||||
cv::convexHull(allPts, contour);
|
||||
|
||||
Scalar color(rng() % 256, rng() % 256, rng() % 256);
|
||||
|
||||
Mat imgRef(imgSize, CV_MAKE_TYPE(CV_8U, channels), Scalar(0));
|
||||
Mat imgFast = imgRef.clone();
|
||||
|
||||
cv::fillConvexPoly(imgRef, contour, color);
|
||||
cv::fastcv::fillConvexPoly(imgFast, contour, color);
|
||||
|
||||
double normInf = cvtest::norm(imgRef, imgFast, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(imgRef, imgFast, cv::NORM_L2);
|
||||
|
||||
EXPECT_EQ(normInf, 0);
|
||||
EXPECT_EQ(normL2, 0);
|
||||
}
|
||||
|
||||
TEST_P(FillConvexTest, circle)
|
||||
{
|
||||
auto p = GetParam();
|
||||
|
||||
Size imgSize = std::get<0>(p);
|
||||
int nPts = std::get<1>(p);
|
||||
int channels = std::get<2>(p);
|
||||
|
||||
cv::RNG rng = cv::theRNG();
|
||||
|
||||
float r = std::min(imgSize.width, imgSize.height) / 2 * 0.9f;
|
||||
float angle = CV_PI * 2.0f / (float)nPts;
|
||||
std::vector<Point> contour;
|
||||
for (int i = 0; i < nPts; i++)
|
||||
{
|
||||
Point2f pt(r * cos((float)i * angle),
|
||||
r * sin((float)i * angle));
|
||||
contour.push_back({ imgSize.width / 2 + int(pt.x),
|
||||
imgSize.height / 2 + int(pt.y)});
|
||||
}
|
||||
Scalar color(rng() % 256, rng() % 256, rng() % 256);
|
||||
|
||||
Mat imgRef(imgSize, CV_MAKE_TYPE(CV_8U, channels), Scalar(0));
|
||||
Mat imgFast = imgRef.clone();
|
||||
|
||||
cv::fillConvexPoly(imgRef, contour, color);
|
||||
cv::fastcv::fillConvexPoly(imgFast, contour, color);
|
||||
|
||||
double normInf = cvtest::norm(imgRef, imgFast, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(imgRef, imgFast, cv::NORM_L2);
|
||||
|
||||
EXPECT_EQ(normInf, 0);
|
||||
EXPECT_EQ(normL2, 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, FillConvexTest,
|
||||
::testing::Combine(testing::Values(Size(640, 480), Size(512, 512), Size(1920, 1080)), // imgSize
|
||||
testing::Values(4, 64, 1024), // nPts
|
||||
testing::Values(1, 2, 3, 4))); // channels
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<std::string /* file name */, double /* threshold */ > HoughLinesTestParams;
|
||||
class HoughLinesTest : public ::testing::TestWithParam<HoughLinesTestParams> {};
|
||||
|
||||
TEST_P(HoughLinesTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
std::string fname = std::get<0>(p);
|
||||
double threshold = std::get<1>(p);
|
||||
|
||||
cv::Mat src = imread(cvtest::findDataFile(fname), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
// make it aligned by 8
|
||||
cv::Mat withBorder;
|
||||
int bpix = ((src.cols & 0xfffffff8) + 8) - src.cols;
|
||||
cv::copyMakeBorder(src, withBorder, 0, 0, 0, bpix, BORDER_REFLECT101);
|
||||
src = withBorder;
|
||||
|
||||
cv::Mat contoured;
|
||||
cv::Canny(src, contoured, 100, 200);
|
||||
|
||||
std::vector<cv::Vec4f> lines;
|
||||
cv::fastcv::houghLines(contoured, lines, threshold);
|
||||
|
||||
std::vector<cv::Vec4f> refLines;
|
||||
double rho = 1.0, theta = 1.0 * CV_PI / 180.0;
|
||||
// cloned since image may be modified by the function
|
||||
cv::HoughLinesP(contoured.clone(), refLines, rho, theta, threshold);
|
||||
|
||||
for (const cv::Vec4f& l : lines)
|
||||
{
|
||||
cv::Point2f from(l[0], l[1]), to(l[2], l[3]);
|
||||
EXPECT_GE(from.x, 0);
|
||||
EXPECT_GE(from.y, 0);
|
||||
EXPECT_LE(from.x, src.cols);
|
||||
EXPECT_LE(from.y, src.rows);
|
||||
EXPECT_GE(to.x, 0);
|
||||
EXPECT_GE(to.y, 0);
|
||||
EXPECT_LE(to.x, src.cols);
|
||||
EXPECT_LE(to.y, src.rows);
|
||||
}
|
||||
|
||||
auto makeDistTrans = [src](const std::vector<Vec4f>& ls) -> cv::Mat
|
||||
{
|
||||
Mat lineMap(src.size(), CV_8U, Scalar(255));
|
||||
for (const cv::Vec4f& l : ls)
|
||||
{
|
||||
cv::Point from(l[0], l[1]), to(l[2], l[3]);
|
||||
cv::line(lineMap, from, to, Scalar::all(0));
|
||||
}
|
||||
Mat distTrans(src.size(), CV_8U);
|
||||
cv::distanceTransform(lineMap, distTrans, DIST_L2, DIST_MASK_PRECISE);
|
||||
return distTrans;
|
||||
};
|
||||
|
||||
cv::Mat distTrans = makeDistTrans(lines);
|
||||
cv::Mat refDistTrans = makeDistTrans(refLines);
|
||||
|
||||
double normInf = cvtest::norm(refDistTrans, distTrans, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(refDistTrans, distTrans, cv::NORM_L2) / src.size().area();
|
||||
|
||||
EXPECT_LT(normInf, 120.0);
|
||||
EXPECT_LT(normL2, 0.0361);
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
cv::Mat draw;
|
||||
cvtColor(src, draw, COLOR_GRAY2BGR);
|
||||
cv::Mat refDraw = draw.clone();
|
||||
|
||||
for (const cv::Vec4f& l : lines)
|
||||
{
|
||||
cv::Point from(l[0], l[1]), to(l[2], l[3]);
|
||||
cv::line(draw, from, to, Scalar(0, 255, 0));
|
||||
}
|
||||
size_t idx = fname.find_last_of("/\\");
|
||||
std::string fout = fname.substr(idx+1, fname.length() - idx - 5);
|
||||
cv::imwrite(cv::format("line_%s_t%5f_fcv.png", fout.c_str(), threshold), draw);
|
||||
|
||||
for (const cv::Vec4f& l : refLines)
|
||||
{
|
||||
cv::Point from(l[0], l[1]), to(l[2], l[3]);
|
||||
cv::line(refDraw, from, to, Scalar(0, 255, 0));
|
||||
}
|
||||
cv::imwrite(cv::format("line_%s_t%5f_ref.png", fout.c_str(), threshold), refDraw);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, HoughLinesTest,
|
||||
::testing::Combine(::testing::Values("cv/shared/pic5.png",
|
||||
"stitching/a1.png",
|
||||
"cv/shared/pic5.png",
|
||||
"cv/shared/pic1.png"), // images
|
||||
::testing::Values(0.05, 0.25, 0.5, 0.75) // threshold
|
||||
));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class DCTExtTest : public ::testing::TestWithParam<cv::Size> {};
|
||||
|
||||
TEST_P(DCTExtTest, forward)
|
||||
{
|
||||
Size size = GetParam();
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src(size, CV_8UC1);
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(255));
|
||||
Mat srcFloat;
|
||||
src.convertTo(srcFloat, CV_32F);
|
||||
|
||||
Mat dst, ref;
|
||||
cv::fastcv::DCT(src, dst);
|
||||
|
||||
cv::dct(srcFloat, ref);
|
||||
|
||||
Mat dstFloat;
|
||||
ref.convertTo(dstFloat, CV_32F);
|
||||
|
||||
double normInf = cvtest::norm(dstFloat, ref, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(dstFloat, ref, cv::NORM_L2) / dst.size().area();
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
std::cout << "dst:" << std::endl << dst << std::endl;
|
||||
std::cout << "ref:" << std::endl << ref << std::endl;
|
||||
}
|
||||
|
||||
EXPECT_EQ(normInf, 0);
|
||||
EXPECT_EQ(normL2, 0);
|
||||
}
|
||||
|
||||
TEST_P(DCTExtTest, inverse)
|
||||
{
|
||||
Size size = GetParam();
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src(size, CV_8UC1);
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256));
|
||||
|
||||
Mat srcFloat;
|
||||
src.convertTo(srcFloat, CV_32F);
|
||||
|
||||
Mat fwd, back;
|
||||
cv::fastcv::DCT(src, fwd);
|
||||
cv::fastcv::IDCT(fwd, back);
|
||||
Mat backFloat;
|
||||
back.convertTo(backFloat, CV_32F);
|
||||
|
||||
Mat fwdRef, backRef;
|
||||
cv::dct(srcFloat, fwdRef);
|
||||
cv::idct(fwdRef, backRef);
|
||||
|
||||
double normInf = cvtest::norm(backFloat, backRef, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(backFloat, backRef, cv::NORM_L2) / src.size().area();
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
std::cout << "src:" << std::endl << src << std::endl;
|
||||
std::cout << "back:" << std::endl << back << std::endl;
|
||||
std::cout << "backRef:" << std::endl << backRef << std::endl;
|
||||
}
|
||||
|
||||
EXPECT_LE(normInf, 7.00005);
|
||||
EXPECT_LT(normL2, 0.13);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, DCTExtTest, ::testing::Values(Size(8, 8), Size(128, 128), Size(32, 256), Size(512, 512)));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
static void initFastCVTests()
|
||||
{
|
||||
cvtest::registerGlobalSkipTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
}
|
||||
|
||||
CV_TEST_MAIN("", initFastCVTests())
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef testing::TestWithParam<tuple<bool,Size,int>> fcv_momentsTest;
|
||||
|
||||
TEST_P(fcv_momentsTest, accuracy)
|
||||
{
|
||||
const bool binaryImage = get<0>(GetParam());
|
||||
const Size srcSize = get<1>(GetParam());
|
||||
const MatDepth srcType = get<2>(GetParam());
|
||||
Mat src(srcSize, srcType);
|
||||
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(
|
||||
Values(false, true),
|
||||
Values(TYPICAL_MAT_SIZES),
|
||||
Values(CV_8UC1, CV_32SC1, CV_32FC1)
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
// we use such nested structure to combine test values
|
||||
typedef std::tuple< std::tuple<bool /* useBboxes */, bool /* useContourData */>,
|
||||
int /* numNeighbors */, std::string /*file path*/> MSERTestParams;
|
||||
class MSERTest : public ::testing::TestWithParam<MSERTestParams> {};
|
||||
|
||||
// compare results to OpenCV's MSER detector
|
||||
// by comparing resulting contours
|
||||
TEST_P(MSERTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
bool useBboxes = std::get<0>(std::get<0>(p));
|
||||
bool useContourData = std::get<1>(std::get<0>(p));
|
||||
int numNeighbors = std::get<1>(p); // 4 or 8
|
||||
std::string imgPath = std::get<2>(p);
|
||||
|
||||
cv::Mat src = imread(cvtest::findDataFile(imgPath), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
uint32_t delta = 2;
|
||||
uint32_t minArea = 256;
|
||||
uint32_t maxArea = (int)src.total()/4;
|
||||
float maxVariation = 0.15f;
|
||||
float minDiversity = 0.2f;
|
||||
|
||||
std::vector<std::vector<Point>> contours;
|
||||
std::vector<cv::Rect> bboxes;
|
||||
std::vector<cv::fastcv::FCVMSER::ContourData> contourData;
|
||||
cv::Ptr<cv::fastcv::FCVMSER> mser;
|
||||
mser = cv::fastcv::FCVMSER::create(src.size(), numNeighbors, delta, minArea, maxArea,
|
||||
maxVariation, minDiversity);
|
||||
if (useBboxes)
|
||||
{
|
||||
if (useContourData)
|
||||
{
|
||||
mser->detect(src, contours, bboxes, contourData);
|
||||
}
|
||||
else
|
||||
{
|
||||
mser->detect(src, contours, bboxes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mser->detect(src, contours);
|
||||
}
|
||||
|
||||
Rect imgRect(0, 0, src.cols, src.rows);
|
||||
if (useBboxes)
|
||||
{
|
||||
ASSERT_EQ(contours.size(), bboxes.size());
|
||||
for (size_t i = 0; i < contours.size(); i++)
|
||||
{
|
||||
ASSERT_TRUE(imgRect.contains(bboxes[i].tl()));
|
||||
ASSERT_TRUE(imgRect.contains(bboxes[i].br()));
|
||||
|
||||
for (size_t j = 0; j < contours[i].size(); j++)
|
||||
{
|
||||
ASSERT_TRUE(bboxes[i].contains(contours[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useContourData)
|
||||
{
|
||||
ASSERT_EQ(contours.size(), contourData.size());
|
||||
for (size_t i = 0; i < contours.size(); i++)
|
||||
{
|
||||
int polarity = contourData[i].polarity;
|
||||
EXPECT_TRUE(polarity == -1 || polarity == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// compare each pair of contours using dist transform of their points
|
||||
// find pair of contours by similar moments
|
||||
typedef cv::Matx<double, 10, 1> MomentVec;
|
||||
|
||||
auto calcEstimate = [](const std::vector<std::vector<Point>>& ctrs, Size srcSize) -> std::vector<std::pair<Mat, MomentVec>>
|
||||
{
|
||||
std::vector<std::pair<Mat, MomentVec>> res;
|
||||
for (size_t i = 0; i < ctrs.size(); i++)
|
||||
{
|
||||
const std::vector<Point>& contour = ctrs[i];
|
||||
Mat ptsMap(srcSize, CV_8U, Scalar(255));
|
||||
for(size_t j = 0; j < contour.size(); ++j)
|
||||
{
|
||||
ptsMap.at<uchar>(contour[j].y, contour[j].x) = 0;
|
||||
}
|
||||
Mat distTrans(srcSize, CV_8U);
|
||||
cv::distanceTransform(ptsMap, distTrans, DIST_L2, DIST_MASK_PRECISE);
|
||||
|
||||
cv::Moments m = cv::moments(contour);
|
||||
double invRows = 1.0 / srcSize.height, invCols = 1.0 / srcSize.width;
|
||||
double invRows2 = invRows / srcSize.height, invCols2 = invCols / srcSize.width;
|
||||
double invRows3 = invRows2 / srcSize.height, invCols3 = invCols2 / srcSize.width;
|
||||
MomentVec mx = { m.m00, m.m10 * invCols, m.m01 * invRows,
|
||||
m.m20 * invCols2, m.m11 * invCols * invRows, m.m02 * invRows2,
|
||||
m.m30 * invCols3,
|
||||
m.m21 * invCols2 * invRows,
|
||||
m.m12 * invCols * invRows2,
|
||||
m.m03 * invRows3};
|
||||
res.push_back({distTrans, mx});
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
std::vector<std::pair<Mat, MomentVec>> contourEstimate = calcEstimate(contours, src.size());
|
||||
|
||||
std::vector<std::vector<Point>> ocvContours;
|
||||
std::vector<cv::Rect> ocvBboxes;
|
||||
|
||||
cv::Ptr<MSER> ocvMser = cv::MSER::create(delta, minArea, maxArea, maxVariation, minDiversity);
|
||||
ocvMser->detectRegions(src, ocvContours, ocvBboxes);
|
||||
|
||||
std::vector<std::pair<Mat, MomentVec>> ocvContourEstimate = calcEstimate(ocvContours, src.size());
|
||||
|
||||
// brute force match by moments comparison
|
||||
double overallL2Sqr = 0;
|
||||
int nInliers = 0;
|
||||
for (size_t i = 0; i < contourEstimate.size(); i++)
|
||||
{
|
||||
double minDist = std::numeric_limits<double>::max();
|
||||
size_t minIdx = -1;
|
||||
for (size_t j = 0; j < ocvContourEstimate.size(); j++)
|
||||
{
|
||||
double d = cv::norm(contourEstimate[i].second - ocvContourEstimate[j].second);
|
||||
if (d < minDist)
|
||||
{
|
||||
minDist = d; minIdx = j;
|
||||
}
|
||||
}
|
||||
// compare dist transforms of contours
|
||||
Mat ref = ocvContourEstimate[minIdx].first;
|
||||
Mat fcv = contourEstimate[i].first;
|
||||
double normL2Sqr = cvtest::norm(ref, fcv, cv::NORM_L2SQR);
|
||||
double normInf = cvtest::norm(ref, fcv, cv::NORM_INF);
|
||||
normL2Sqr = normL2Sqr / src.size().area();
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
Mat draw(src.rows, src.cols*2, CV_8U);
|
||||
ref.copyTo(draw(Range::all(), Range(0, src.cols)));
|
||||
fcv.copyTo(draw(Range::all(), Range(src.cols, src.cols*2)));
|
||||
cv::putText(draw, cv::format("dM: %f L2^2: %f Inf: %f",minDist, normL2Sqr, normInf), Point(0, src.rows),
|
||||
cv::FONT_HERSHEY_COMPLEX, 1, Scalar::all(128));
|
||||
cv::imwrite(cv::format("dist_n%d_c%03d_r%03d.png", numNeighbors, (int)i, (int)minIdx), draw);
|
||||
}
|
||||
|
||||
if (normInf < 50.0)
|
||||
{
|
||||
overallL2Sqr += normL2Sqr;
|
||||
nInliers++;
|
||||
}
|
||||
}
|
||||
|
||||
double overallL2 = std::sqrt(overallL2Sqr);
|
||||
EXPECT_LT(std::sqrt(overallL2), 11.45);
|
||||
double ratioInliers = double(nInliers) / contourEstimate.size();
|
||||
EXPECT_GT(ratioInliers, 0.363);
|
||||
}
|
||||
|
||||
// BUG: https://github.com/opencv/opencv_contrib/issues/3957
|
||||
//INSTANTIATE_TEST_CASE_P(FastCV_Extension, MSERTest,
|
||||
// ::testing::Combine(::testing::Values( // useBboxes useContourData
|
||||
// std::tuple<bool, bool> { true, false},
|
||||
// std::tuple<bool, bool> {false, false},
|
||||
// std::tuple<bool, bool> { true, true}),
|
||||
// ::testing::Values(4, 8), // numNeighbors
|
||||
// ::testing::Values("cv/shared/baboon.png", "cv/mser/puzzle.png")
|
||||
// )
|
||||
// );
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <opencv2/ts.hpp>
|
||||
#include <opencv2/core/affine.hpp>
|
||||
#include <opencv2/geometry.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/video.hpp>
|
||||
|
||||
#include <opencv2/fastcv.hpp>
|
||||
|
||||
#define CV_TEST_TAG_FASTCV_SKIP_DSP "fastcv_skip_dsp"
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<bool /*useFloat*/, int /*nLevels*/, bool /*scaleBy2*/> PyramidTestParams;
|
||||
class PyramidTest : public ::testing::TestWithParam<PyramidTestParams> { };
|
||||
|
||||
TEST_P(PyramidTest, accuracy)
|
||||
{
|
||||
auto par = GetParam();
|
||||
|
||||
bool useFloat = std::get<0>(par);
|
||||
int nLevels = std::get<1>(par);
|
||||
bool scaleBy2 = std::get<2>(par);
|
||||
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
if (useFloat)
|
||||
{
|
||||
cv::Mat f;
|
||||
src.convertTo(f, CV_32F);
|
||||
src = f;
|
||||
}
|
||||
|
||||
std::vector<cv::Mat> pyr;
|
||||
cv::fastcv::buildPyramid(src, pyr, nLevels, scaleBy2);
|
||||
|
||||
ASSERT_EQ(pyr.size(), (size_t)nLevels);
|
||||
|
||||
std::vector<cv::Mat> refPyr;
|
||||
if (scaleBy2)
|
||||
{
|
||||
cv::buildPyramid(src, refPyr, nLevels - 1);
|
||||
}
|
||||
else // ORB downscaling
|
||||
{
|
||||
for (int i = 0; i < nLevels; i++)
|
||||
{
|
||||
// we don't know how exactly the bit-accurate size is calculated
|
||||
cv::Mat level;
|
||||
cv::resize(src, level, pyr[i].size(), 0, 0, cv::INTER_AREA);
|
||||
refPyr.push_back(level);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < nLevels; i++)
|
||||
{
|
||||
cv::Mat ref = refPyr[i];
|
||||
cv::Mat m = pyr[i];
|
||||
ASSERT_EQ(m.size(), ref.size());
|
||||
double l2diff = cv::norm(m, ref, cv::NORM_L2);
|
||||
double linfdiff = cv::norm(m, ref, cv::NORM_INF);
|
||||
|
||||
double l2Thresh = scaleBy2 ? 178.0 : 5216.0;
|
||||
double linfThresh = scaleBy2 ? 16.0 : 116.0;
|
||||
EXPECT_LE(l2diff, l2Thresh);
|
||||
EXPECT_LE(linfdiff, linfThresh);
|
||||
}
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
for (int i = 0; i < nLevels; i++)
|
||||
{
|
||||
char tchar = useFloat ? 'f' : 'i';
|
||||
std::string scaleStr = scaleBy2 ? "x2" : "xORB";
|
||||
cv::imwrite(cv::format("pyr_diff_%c_%d_%s_l%d.png", tchar, nLevels, scaleStr.c_str(), i), cv::abs(pyr[i] - refPyr[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, PyramidTest,
|
||||
// useFloat, nLevels, scaleBy2
|
||||
::testing::Values(
|
||||
PyramidTestParams { true, 2, true}, PyramidTestParams { true, 3, true}, PyramidTestParams { true, 4, true},
|
||||
PyramidTestParams {false, 2, true}, PyramidTestParams {false, 3, true}, PyramidTestParams {false, 4, true},
|
||||
PyramidTestParams {false, 2, false}, PyramidTestParams {false, 3, false}, PyramidTestParams {false, 4, false}
|
||||
));
|
||||
|
||||
typedef std::tuple<MatType, size_t> SobelPyramidTestParams;
|
||||
class SobelPyramidTest : public ::testing::TestWithParam<SobelPyramidTestParams> {};
|
||||
|
||||
TEST_P(SobelPyramidTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
int type = std::get<0>(p);
|
||||
size_t nLevels = std::get<1>(p);
|
||||
|
||||
// NOTE: test files should be manually loaded to folder on a device, for example like this:
|
||||
// adb push fastcv/misc/bilateral_recursive/ /sdcard/testdata/fastcv/bilateral/
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
std::vector<cv::Mat> pyr;
|
||||
cv::fastcv::buildPyramid(src, pyr, nLevels);
|
||||
|
||||
std::vector<cv::Mat> pyrDx, pyrDy;
|
||||
cv::fastcv::sobelPyramid(pyr, pyrDx, pyrDy, type);
|
||||
|
||||
ASSERT_EQ(pyrDx.size(), nLevels);
|
||||
ASSERT_EQ(pyrDy.size(), nLevels);
|
||||
|
||||
for (size_t i = 0; i < nLevels; i++)
|
||||
{
|
||||
ASSERT_EQ(pyrDx[i].type(), type);
|
||||
ASSERT_EQ(pyrDx[i].size(), pyr[i].size());
|
||||
ASSERT_EQ(pyrDy[i].type(), type);
|
||||
ASSERT_EQ(pyrDy[i].size(), pyr[i].size());
|
||||
}
|
||||
|
||||
std::vector<cv::Mat> refPyrDx(nLevels), refPyrDy(nLevels);
|
||||
for (size_t i = 0; i < nLevels; i++)
|
||||
{
|
||||
int stype = (type == CV_8S) ? CV_16S : type;
|
||||
cv::Mat dx, dy;
|
||||
cv::Sobel(pyr[i], dx, stype, 1, 0);
|
||||
cv::Sobel(pyr[i], dy, stype, 0, 1);
|
||||
dx.convertTo(refPyrDx[i], type, 1.0/8.0, 0.0);
|
||||
dy.convertTo(refPyrDy[i], type, 1.0/8.0, 0.0);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nLevels; i++)
|
||||
{
|
||||
cv::Mat ref, dst;
|
||||
double normInf, normL2;
|
||||
cv::Rect roi(1, 1, pyr[i].cols - 2, pyr[i].rows - 2);
|
||||
ref = refPyrDx[i](roi);
|
||||
dst = pyrDx[i](roi);
|
||||
normInf = cvtest::norm(dst, ref, cv::NORM_INF);
|
||||
normL2 = cvtest::norm(dst, ref, cv::NORM_L2) / dst.total();
|
||||
|
||||
EXPECT_LE(normInf, 76.1);
|
||||
EXPECT_LT(normL2, 0.4);
|
||||
|
||||
ref = refPyrDy[i](roi);
|
||||
dst = pyrDy[i](roi);
|
||||
normInf = cvtest::norm(dst, ref, cv::NORM_INF);
|
||||
normL2 = cvtest::norm(dst, ref, cv::NORM_L2) / dst.total();
|
||||
|
||||
EXPECT_LE(normInf, 66.6);
|
||||
EXPECT_LT(normL2, 0.4);
|
||||
}
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
std::map<int, std::string> typeToString =
|
||||
{
|
||||
{CV_8U, "8u"}, {CV_8S, "8s"}, {CV_16U, "16u"}, {CV_16S, "16s"},
|
||||
{CV_32S, "32s"}, {CV_32F, "32f"}, {CV_64F, "64f"}, {CV_16F, "16f"},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < nLevels; i++)
|
||||
{
|
||||
cv::imwrite(cv::format("pyr_l%zu.png", i), pyr[i]);
|
||||
cv::imwrite(cv::format("pyr_sobel_x_t%s_l%zu.png", typeToString.at(type).c_str(), i), pyrDx[i] + 128);
|
||||
cv::imwrite(cv::format("pyr_sobel_y_t%s_l%zu.png", typeToString.at(type).c_str(), i), pyrDy[i] + 128);
|
||||
|
||||
cv::imwrite(cv::format("ref_pyr_sobel_x_t%s_l%zu.png", typeToString.at(type).c_str(), i), refPyrDx[i] + 128);
|
||||
cv::imwrite(cv::format("ref_pyr_sobel_y_t%s_l%zu.png", typeToString.at(type).c_str(), i), refPyrDy[i] + 128);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, SobelPyramidTest, ::testing::Combine(
|
||||
::testing::Values(CV_8S, CV_16S, CV_32F), // depth
|
||||
::testing::Values(3, 6))); // nLevels
|
||||
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class RemapTest : public ::testing::TestWithParam<tuple<int, int, Size>> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Generate random source data
|
||||
Size size = get<2>(GetParam());
|
||||
src = Mat(size, get<0>(GetParam()));
|
||||
randu(src, Scalar::all(0), Scalar::all(255)); // Fill with random values
|
||||
|
||||
ASSERT_FALSE(src.empty()) << "Unable to generate the image!";
|
||||
|
||||
// Create map matrices
|
||||
map_x.create(src.size(), CV_32FC1);
|
||||
map_y.create(src.size(), CV_32FC1);
|
||||
|
||||
// Initialize the map matrices
|
||||
for (int i = 0; i < src.rows; i++) {
|
||||
for (int j = 0; j < src.cols; j++) {
|
||||
map_x.at<float>(i, j) = static_cast<float>(src.cols - j); //Flips the image horizonally
|
||||
map_y.at<float>(i, j) = static_cast<float>(i); //Keep y coordinate unchanged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mat src, map_x, map_y, dst;
|
||||
};
|
||||
|
||||
class RemapTestRGBA : public ::testing::TestWithParam<tuple<int, int, Size>> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Generate random source data
|
||||
Size size = get<2>(GetParam());
|
||||
src = Mat(size, get<0>(GetParam()));
|
||||
randu(src, Scalar::all(0), Scalar::all(255)); // Fill with random values
|
||||
|
||||
ASSERT_FALSE(src.empty()) << "Unable to generate the image!";
|
||||
|
||||
// Create map matrices
|
||||
map_x.create(src.size(), CV_32FC1);
|
||||
map_y.create(src.size(), CV_32FC1);
|
||||
|
||||
// Initialize the map matrices
|
||||
for (int i = 0; i < src.rows; i++) {
|
||||
for (int j = 0; j < src.cols; j++) {
|
||||
map_x.at<float>(i, j) = static_cast<float>(src.cols - j); //Flips the image horizonally
|
||||
map_y.at<float>(i, j) = static_cast<float>(i); //Keep y coordinate unchanged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mat src, map_x, map_y, dst;
|
||||
};
|
||||
|
||||
TEST_P(RemapTest, accuracy)
|
||||
{
|
||||
int type = get<0>(GetParam());
|
||||
int interpolation = get<1>(GetParam());
|
||||
|
||||
// Convert source image to the specified type
|
||||
Mat src_converted;
|
||||
src.convertTo(src_converted, type);
|
||||
|
||||
cv::fastcv::remap(src_converted, dst, map_x, map_y, interpolation);
|
||||
|
||||
// Check if the remapped image is not empty
|
||||
ASSERT_FALSE(dst.empty()) << "Remapped image is empty!";
|
||||
|
||||
cv::Mat remapOpenCV;
|
||||
cv::remap(src_converted, remapOpenCV, map_x, map_y, interpolation);
|
||||
|
||||
// Calculate the maximum difference
|
||||
double maxVal = cv::norm(dst, remapOpenCV, cv::NORM_INF);
|
||||
|
||||
// Assert if the difference is acceptable (max difference should be less than 10)
|
||||
CV_Assert(maxVal < 10 && "Difference between images is too high!");
|
||||
}
|
||||
|
||||
TEST_P(RemapTestRGBA, accuracy)
|
||||
{
|
||||
int type = get<0>(GetParam());
|
||||
int interpolation = get<1>(GetParam());
|
||||
|
||||
// Convert source image to the specified type
|
||||
Mat src_converted;
|
||||
src.convertTo(src_converted, type);
|
||||
|
||||
cv::fastcv::remapRGBA(src_converted, dst, map_x, map_y, interpolation);
|
||||
|
||||
// Check if the remapped image is not empty
|
||||
ASSERT_FALSE(dst.empty()) << "Remapped image is empty!";
|
||||
|
||||
cv::Mat remapOpenCV;
|
||||
cv::remap(src_converted, remapOpenCV, map_x, map_y, interpolation);
|
||||
|
||||
// Calculate the maximum difference
|
||||
double maxVal = cv::norm(dst, remapOpenCV, cv::NORM_INF);
|
||||
|
||||
// Assert if the difference is acceptable (max difference should be less than 10)
|
||||
CV_Assert(maxVal < 10 && "Difference between images is too high!");
|
||||
}
|
||||
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
RemapTests,
|
||||
RemapTest,
|
||||
::testing::Combine(
|
||||
::testing::Values(CV_8UC1),
|
||||
::testing::Values(INTER_LINEAR, INTER_NEAREST),
|
||||
::testing::Values(Size(640, 480), Size(1280, 720), Size(1920, 1080))
|
||||
)
|
||||
);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
RemapTests,
|
||||
RemapTestRGBA,
|
||||
::testing::Combine(
|
||||
::testing::Values(CV_8UC4),
|
||||
::testing::Values(INTER_LINEAR, INTER_NEAREST),
|
||||
::testing::Values(Size(640, 480), Size(1280, 720), Size(1920, 1080))
|
||||
)
|
||||
);
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
|
||||
//Initialize DSP
|
||||
int initStatus = cv::fastcv::dsp::fcvdspinit();
|
||||
ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP";
|
||||
|
||||
// Create an 8x8 template patch
|
||||
cv::Mat patch;
|
||||
patch.allocator = cv::fastcv::getQcAllocator();
|
||||
patch.create(8, 8, CV_8UC1);
|
||||
patch.setTo(cv::Scalar(0));
|
||||
|
||||
// Create a source image
|
||||
cv::Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator();
|
||||
src.create(512, 512, CV_8UC1);
|
||||
src.setTo(cv::Scalar(255));
|
||||
|
||||
cv::Mat dst;
|
||||
dst.allocator = cv::fastcv::getQcAllocator();
|
||||
|
||||
cv::fastcv::dsp::sumOfAbsoluteDiffs(patch, src, dst);
|
||||
|
||||
EXPECT_FALSE(dst.empty());
|
||||
|
||||
//De-Initialize DSP
|
||||
cv::fastcv::dsp::fcvdspdeinit();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(resizeDownBy2, accuracy)
|
||||
{
|
||||
cv::Mat inputImage = cv::imread(cvtest::findDataFile("cv/shared/box_in_scene.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
cv::Mat resized_image;
|
||||
|
||||
cv::fastcv::resizeDown(inputImage, resized_image, cv::Size(inputImage.cols / 2, inputImage.rows / 2), 0, 0);
|
||||
|
||||
EXPECT_FALSE(resized_image.empty());
|
||||
|
||||
cv::Mat resizedImageOpenCV;
|
||||
cv::resize(inputImage, resizedImageOpenCV, cv::Size(inputImage.cols / 2, inputImage.rows / 2), 0, 0, INTER_AREA);
|
||||
|
||||
double maxVal = cv::norm(resized_image, resizedImageOpenCV, cv::NORM_INF);
|
||||
|
||||
CV_Assert(maxVal < 10 && "Difference between images is too high!");
|
||||
}
|
||||
|
||||
TEST(resizeDownBy4, accuracy)
|
||||
{
|
||||
cv::Mat inputImage = cv::imread(cvtest::findDataFile("cv/shared/box_in_scene.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
Size dsize;
|
||||
cv::Mat resized_image;
|
||||
|
||||
cv::fastcv::resizeDown(inputImage, resized_image, dsize, 0.25, 0.25);
|
||||
|
||||
EXPECT_FALSE(resized_image.empty());
|
||||
|
||||
cv::Mat resizedImageOpenCV;
|
||||
cv::resize(inputImage, resizedImageOpenCV, cv::Size(inputImage.cols / 4, inputImage.rows / 4), 0, 0, INTER_AREA);
|
||||
|
||||
double maxVal = cv::norm(resized_image, resizedImageOpenCV, cv::NORM_INF);
|
||||
|
||||
CV_Assert(maxVal < 10 && "Difference between images is too high!");
|
||||
}
|
||||
|
||||
TEST(resizeDownMN, accuracy)
|
||||
{
|
||||
cv::Mat inputImage = cv::imread(cvtest::findDataFile("cv/cascadeandhog/images/class57.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
cv::Mat resized_image;
|
||||
|
||||
cv::fastcv::resizeDown(inputImage, resized_image, cv::Size(800, 640), 0, 0);
|
||||
|
||||
EXPECT_FALSE(resized_image.empty());
|
||||
|
||||
cv::Mat resizedImageOpenCV;
|
||||
cv::resize(inputImage, resizedImageOpenCV, cv::Size(800, 640), 0, 0, INTER_LINEAR);
|
||||
|
||||
double maxVal = cv::norm(resized_image, resizedImageOpenCV, cv::NORM_INF);
|
||||
|
||||
CV_Assert(maxVal < 78 && "Difference between images is too high!");
|
||||
}
|
||||
|
||||
TEST(resizeDownInterleaved, accuracy)
|
||||
{
|
||||
cv::Mat inputImage = cv::Mat::zeros(512, 512, CV_8UC2);
|
||||
cv::randu(inputImage, cv::Scalar(0), cv::Scalar(255));
|
||||
|
||||
|
||||
Size dsize;
|
||||
cv::Mat resized_image;
|
||||
|
||||
cv::fastcv::resizeDown(inputImage, resized_image, dsize, 0.500, 0.125);
|
||||
|
||||
EXPECT_FALSE(resized_image.empty());
|
||||
|
||||
|
||||
cv::Mat resizedImageOpenCV;
|
||||
cv::resize(inputImage, resizedImageOpenCV, dsize, 0.500, 0.125, INTER_AREA);
|
||||
|
||||
double maxVal = cv::norm(resized_image, resizedImageOpenCV, cv::NORM_INF);
|
||||
|
||||
CV_Assert(maxVal < 10 && "Difference between images is too high!");
|
||||
}
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<cv::Size, MatType, int /*iterations*/, float /*epsilon*/, Size /*winSize*/> MeanShiftTestParams;
|
||||
class MeanShiftTest : public ::testing::TestWithParam<MeanShiftTestParams> {};
|
||||
|
||||
TEST_P(MeanShiftTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
cv::Size size = std::get<0>(p);
|
||||
MatType type = std::get<1>(p);
|
||||
int iters = std::get<2>(p);
|
||||
float eps = std::get<3>(p);
|
||||
Size winSize = std::get<4>(p);
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
|
||||
const int nPts = 20;
|
||||
Mat ptsMap(size, CV_8UC1, Scalar(255));
|
||||
for(size_t i = 0; i < nPts; ++i)
|
||||
{
|
||||
ptsMap.at<uchar>(rng() % size.height, rng() % size.width) = 0;
|
||||
}
|
||||
Mat distTrans(size, CV_8UC1);
|
||||
cv::distanceTransform(ptsMap, distTrans, DIST_L2, DIST_MASK_PRECISE);
|
||||
Mat vsrc = 255 - distTrans;
|
||||
Mat src;
|
||||
vsrc.convertTo(src, type);
|
||||
|
||||
Point startPt(rng() % (size.width - winSize.width),
|
||||
rng() % (size.height - winSize.height));
|
||||
Rect startRect(startPt, winSize);
|
||||
|
||||
cv::TermCriteria termCrit( TermCriteria::EPS + TermCriteria::MAX_ITER, iters, eps);
|
||||
|
||||
Rect window = startRect;
|
||||
cv::fastcv::meanShift(src, window, termCrit);
|
||||
|
||||
Rect windowRef = startRect;
|
||||
cv::meanShift(vsrc, windowRef, termCrit);
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
Mat draw;
|
||||
cvtColor(vsrc, draw, COLOR_GRAY2RGB);
|
||||
cv::rectangle(draw, startRect, Scalar(0, 0, 255));
|
||||
cv::rectangle(draw, window, Scalar(255, 255, 0));
|
||||
cv::rectangle(draw, windowRef, Scalar(0, 255, 0));
|
||||
std::string stype = (type == CV_8U ? "8U" : (type == CV_32S ? "32S" : (type == CV_32F ? "F" : "?")));
|
||||
cv::imwrite(cv::format("src_%dx%d_%s_%dit_%feps_%dx%d.png", size.width, size.height, stype.c_str(),
|
||||
iters, eps, winSize.width, winSize.height),
|
||||
draw);
|
||||
}
|
||||
|
||||
cv::Point diff = (window.tl() - windowRef.tl());
|
||||
double dist = std::sqrt(diff.ddot(diff));
|
||||
|
||||
EXPECT_LE(dist, 3.0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, MeanShiftTest,
|
||||
::testing::Combine(::testing::Values(Size(128, 128), Size(640, 480), Size(800, 600)),
|
||||
::testing::Values(CV_8U, CV_32S, CV_32F), // type
|
||||
::testing::Values(2, 10, 100), // nIterations
|
||||
::testing::Values(0.01f, 0.1f, 1.f, 10.f), // epsilon
|
||||
::testing::Values(Size(8, 8), Size(13, 48), Size(64, 64)) // window size
|
||||
));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<float, float> BilateralTestParams;
|
||||
class BilateralRecursiveTest : public ::testing::TestWithParam<BilateralTestParams> {};
|
||||
|
||||
TEST_P(BilateralRecursiveTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
float sigmaColor = std::get<0>(p);
|
||||
float sigmaSpace = std::get<1>(p);
|
||||
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
Mat dst;
|
||||
cv::fastcv::bilateralRecursive(src, dst, sigmaColor, sigmaSpace);
|
||||
|
||||
// NOTE: test files should be manually loaded to folder on a device, for example like this:
|
||||
// adb push fastcv/misc/bilateral_recursive/ /sdcard/testdata/fastcv/bilateral/
|
||||
cv::Mat ref = imread(cvtest::findDataFile(cv::format("fastcv/bilateral/rec_%2f_%2f.png", sigmaColor, sigmaSpace)),
|
||||
IMREAD_GRAYSCALE);
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
cv::imwrite(cv::format("rec_%2f_%2f.png", sigmaColor, sigmaSpace), dst);
|
||||
}
|
||||
|
||||
double normInf = cvtest::norm(dst, ref, cv::NORM_INF);
|
||||
double normL2 = cvtest::norm(dst, ref, cv::NORM_L2);
|
||||
|
||||
ASSERT_LT(normInf, 1);
|
||||
ASSERT_LT(normL2, 1.f / src.size().area());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, BilateralRecursiveTest,
|
||||
::testing::Values(
|
||||
BilateralTestParams {0.01f, 1.00f},
|
||||
BilateralTestParams {0.10f, 0.01f},
|
||||
BilateralTestParams {1.00f, 0.01f},
|
||||
BilateralTestParams {1.00f, 1.00f},
|
||||
BilateralTestParams {5.00f, 0.01f},
|
||||
BilateralTestParams {5.00f, 0.10f},
|
||||
BilateralTestParams {5.00f, 5.00f}
|
||||
));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<cv::Size, int /*lowThresh*/, int /*highThresh*/, int /*trueValue*/, int /*falseValue*/> ThresholdRangeTestParams;
|
||||
class ThresholdRangeTest : public ::testing::TestWithParam<ThresholdRangeTestParams> {};
|
||||
|
||||
TEST_P(ThresholdRangeTest, accuracy)
|
||||
{
|
||||
auto p = GetParam();
|
||||
cv::Size size = std::get<0>(p);
|
||||
int loThresh = std::get<1>(p);
|
||||
int hiThresh = std::get<2>(p);
|
||||
int trueValue = std::get<3>(p);
|
||||
int falseValue = std::get<4>(p);
|
||||
|
||||
int lowThresh = std::min(loThresh, hiThresh);
|
||||
int highThresh = std::max(loThresh, hiThresh);
|
||||
|
||||
RNG& rng = cv::theRNG();
|
||||
Mat src(size, CV_8UC1);
|
||||
cvtest::randUni(rng, src, Scalar::all(0), Scalar::all(256));
|
||||
|
||||
Mat dst;
|
||||
cv::fastcv::thresholdRange(src, dst, lowThresh, highThresh, trueValue, falseValue);
|
||||
|
||||
Mat inr, ref(src.size(), CV_8UC1);
|
||||
cv::inRange(src, lowThresh, highThresh, inr);
|
||||
ref.setTo(trueValue, inr);
|
||||
ref.setTo(falseValue, ~inr);
|
||||
|
||||
double normInf = cvtest::norm(ref, dst, cv::NORM_INF);
|
||||
|
||||
EXPECT_EQ(normInf, 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, ThresholdRangeTest,
|
||||
::testing::Combine(::testing::Values(Size(8, 8), Size(640, 480), Size(800, 600)),
|
||||
::testing::Values(0, 15, 128, 255), // lowThresh
|
||||
::testing::Values(0, 15, 128, 255), // highThresh
|
||||
::testing::Values(0, 15, 128, 255), // trueValue
|
||||
::testing::Values(0, 15, 128, 255) // falseValue
|
||||
));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(ThresholdOtsuTest, accuracy)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
|
||||
//Initialize DSP
|
||||
int initStatus = cv::fastcv::dsp::fcvdspinit();
|
||||
ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP";
|
||||
|
||||
cv::Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::imread(cvtest::findDataFile("cv/detectors_descriptors_evaluation/planar/box_in_scene.png"), src, cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(src.empty()) << "Could not read the image file.";
|
||||
|
||||
cv::Mat dst;
|
||||
dst.allocator = cv::fastcv::getQcAllocator();
|
||||
|
||||
bool type = 0;
|
||||
|
||||
cv::fastcv::dsp::thresholdOtsu(src, dst, type);
|
||||
|
||||
// De-Initialize DSP
|
||||
cv::fastcv::dsp::fcvdspdeinit();
|
||||
|
||||
EXPECT_FALSE(dst.empty());
|
||||
EXPECT_EQ(src.size(), dst.size());
|
||||
|
||||
// Compare the result against the reference cv::threshold function with Otsu's method
|
||||
cv::Mat referenceDst;
|
||||
cv::threshold(src, referenceDst, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
|
||||
|
||||
double maxDifference = 10.0;
|
||||
cv::Mat diff;
|
||||
cv::absdiff(dst, referenceDst, diff);
|
||||
double maxVal;
|
||||
cv::minMaxLoc(diff, nullptr, &maxVal);
|
||||
|
||||
EXPECT_LE(maxVal, maxDifference) << "The custom threshold result differs from the reference result by more than the acceptable threshold.";
|
||||
}
|
||||
|
||||
TEST(ThresholdOtsuTest, inPlaceAccuracy)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_FASTCV_SKIP_DSP);
|
||||
|
||||
// Initialize DSP
|
||||
int initStatus = cv::fastcv::dsp::fcvdspinit();
|
||||
ASSERT_EQ(initStatus, 0) << "Failed to initialize FastCV DSP";
|
||||
|
||||
cv::Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator();
|
||||
cv::imread(cvtest::findDataFile("cv/detectors_descriptors_evaluation/planar/box_in_scene.png"), src, cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(src.empty()) << "Could not read the image file.";
|
||||
|
||||
// Use the same buffer for in-place operation
|
||||
cv::Mat dst;
|
||||
dst.allocator = cv::fastcv::getQcAllocator();
|
||||
src.copyTo(dst);
|
||||
|
||||
bool type = false;
|
||||
|
||||
// Call the thresholdOtsu function for in-place operation
|
||||
cv::fastcv::dsp::thresholdOtsu(dst, dst, type);
|
||||
|
||||
// De-Initialize DSP
|
||||
cv::fastcv::dsp::fcvdspdeinit();
|
||||
|
||||
// Check if the output is not empty
|
||||
EXPECT_FALSE(dst.empty());
|
||||
EXPECT_EQ(src.size(), dst.size());
|
||||
|
||||
// Compare the result against the reference cv::threshold function with Otsu's method
|
||||
cv::Mat referenceDst;
|
||||
cv::threshold(src, referenceDst, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
|
||||
|
||||
double maxDifference = 10.0;
|
||||
cv::Mat diff;
|
||||
cv::absdiff(dst, referenceDst, diff);
|
||||
double maxVal;
|
||||
cv::minMaxLoc(diff, nullptr, &maxVal);
|
||||
|
||||
EXPECT_LE(maxVal, maxDifference) << "The in-place threshold result differs from the reference result by more than the acceptable threshold.";
|
||||
}
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef std::tuple<int /*winSize*/, bool /*useSobelPyramid*/, bool /*useFastCvPyramids*/, bool /*useInitialEstimate*/ > TrackingTestParams;
|
||||
class TrackingTest : public ::testing::TestWithParam<TrackingTestParams> {};
|
||||
|
||||
TEST_P(TrackingTest, accuracy)
|
||||
{
|
||||
auto par = GetParam();
|
||||
|
||||
int winSz = std::get<0>(par);
|
||||
bool useSobelPyramid = std::get<1>(par);
|
||||
bool useFastCvPyramids = std::get<2>(par);
|
||||
bool useInitialEstimate = std::get<3>(par);
|
||||
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
double ang = 5.0 * CV_PI / 180.0;
|
||||
cv::Matx33d tr = {
|
||||
cos(ang), -sin(ang), 1,
|
||||
sin(ang), cos(ang), 2,
|
||||
0, 0, 1
|
||||
};
|
||||
cv::Matx33d orig {
|
||||
1, 0, -(double)src.cols / 2,
|
||||
0, 1, -(double)src.rows / 2,
|
||||
0, 0, 1
|
||||
};
|
||||
cv::Matx33d back {
|
||||
1, 0, (double)src.cols / 2,
|
||||
0, 1, (double)src.rows / 2,
|
||||
0, 0, 1
|
||||
};
|
||||
cv::Matx23d trans = (back * tr * orig).get_minor<2, 3>(0, 0);
|
||||
|
||||
cv::Mat dst;
|
||||
cv::warpAffine(src, dst, trans, src.size());
|
||||
|
||||
int nLevels = 4;
|
||||
std::vector<cv::Mat> srcPyr, dstPyr;
|
||||
|
||||
if (useFastCvPyramids)
|
||||
{
|
||||
cv::fastcv::buildPyramid(src, srcPyr, nLevels);
|
||||
cv::fastcv::buildPyramid(dst, dstPyr, nLevels);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::buildPyramid(src, srcPyr, nLevels - 1);
|
||||
cv::buildPyramid(dst, dstPyr, nLevels - 1);
|
||||
}
|
||||
|
||||
cv::Matx23f transf = trans;
|
||||
int nPts = 32;
|
||||
std::vector<cv::Point2f> ptsIn, ptsOut, ptsEst, ptsExpected;
|
||||
for (int i = 0; i < nPts; i++)
|
||||
{
|
||||
cv::Point2f p { (((float)cv::theRNG())*0.5f + 0.25f) * src.cols,
|
||||
(((float)cv::theRNG())*0.5f + 0.25f) * src.rows };
|
||||
ptsIn.push_back(p);
|
||||
ptsExpected.push_back(transf * cv::Vec3f(p.x, p.y, 1.0));
|
||||
ptsOut.push_back({ });
|
||||
ptsEst.push_back(p);
|
||||
}
|
||||
|
||||
cv::Mat statusVec(nPts, 1, CV_32S, cv::Scalar::all(0));
|
||||
|
||||
cv::TermCriteria termCrit;
|
||||
termCrit.type = cv::TermCriteria::COUNT | cv::TermCriteria::EPS;
|
||||
termCrit.maxCount = 7;
|
||||
termCrit.epsilon = 0.03f * 0.03f;
|
||||
|
||||
if (useSobelPyramid)
|
||||
{
|
||||
std::vector<cv::Mat> srcDxPyr, srcDyPyr;
|
||||
cv::fastcv::sobelPyramid(srcPyr, srcDxPyr, srcDyPyr, CV_8S);
|
||||
cv::fastcv::trackOpticalFlowLK(src, dst, srcPyr, dstPyr, srcDxPyr, srcDyPyr,
|
||||
ptsIn, ptsOut, statusVec, {winSz, winSz});
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::fastcv::trackOpticalFlowLK(src, dst, srcPyr, dstPyr, ptsIn, ptsOut, (useInitialEstimate ? ptsEst : noArray()),
|
||||
statusVec, {winSz, winSz}, termCrit);
|
||||
}
|
||||
|
||||
std::vector<cv::Point2f> ocvPtsOut;
|
||||
cv::Mat ocvStatusVec;
|
||||
std::vector<float> ocvErrVec;
|
||||
cv::calcOpticalFlowPyrLK(src, dst, ptsIn, ocvPtsOut, ocvStatusVec, ocvErrVec, {winSz, winSz}, nLevels - 1, termCrit);
|
||||
|
||||
cv::Mat refStatusVec(nPts, 1, CV_32S, Scalar::all(1));
|
||||
cv::Mat ocvStatusVecInt;
|
||||
ocvStatusVec.convertTo(ocvStatusVecInt, CV_32S);
|
||||
|
||||
double statusNormOcv = cv::norm(ocvStatusVecInt, refStatusVec, NORM_INF);
|
||||
double statusNorm = cv::norm(statusVec.t(), refStatusVec, NORM_INF);
|
||||
|
||||
EXPECT_EQ(statusNormOcv, 0);
|
||||
EXPECT_EQ(statusNorm, 0);
|
||||
|
||||
double diffNormOcv = cv::norm(ocvPtsOut, ptsExpected, NORM_L2);
|
||||
double diffNorm = cv::norm(ptsOut, ptsExpected, NORM_L2);
|
||||
|
||||
EXPECT_LT(diffNormOcv, 31.92);
|
||||
EXPECT_LT(diffNorm, 6.73);
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
auto drawPts = [ptsIn, dst](const std::vector<cv::Point2f>& ptsRes, const std::string fname)
|
||||
{
|
||||
cv::Mat draw = dst.clone();
|
||||
for (size_t i = 0; i < ptsIn.size(); i++)
|
||||
{
|
||||
cv::line(draw, ptsIn[i], ptsRes[i], Scalar::all(255));
|
||||
cv::circle(draw, ptsIn[i], 1, Scalar::all(255));
|
||||
cv::circle(draw, ptsRes[i], 3, Scalar::all(255));
|
||||
}
|
||||
cv::imwrite(fname, draw);
|
||||
};
|
||||
|
||||
drawPts(ptsOut, "track_w"+std::to_string(winSz)+"_warped.png");
|
||||
drawPts(ocvPtsOut, "track_ocv_warped.png");
|
||||
|
||||
std::cout << "status vec:" << std::endl << statusVec << std::endl;
|
||||
std::cout << "status vec ocv:" << std::endl << ocvStatusVec << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, TrackingTest,
|
||||
::testing::Combine(::testing::Values(5, 7, 9), // window size
|
||||
::testing::Bool(), // useSobelPyramid
|
||||
::testing::Bool(), // useFastCvPyramids
|
||||
::testing::Bool() // useInitialEstimate
|
||||
));
|
||||
|
||||
}} // namespaces opencv_test, ::
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
static void getInvertMatrix(Mat& src, Size dstSize, Mat& M)
|
||||
{
|
||||
RNG& rng = cv::theRNG();
|
||||
Point2f s[4], d[4];
|
||||
|
||||
s[0] = Point2f(0,0);
|
||||
d[0] = Point2f(0,0);
|
||||
s[1] = Point2f(src.cols-1.f,0);
|
||||
d[1] = Point2f(dstSize.width-1.f,0);
|
||||
s[2] = Point2f(src.cols-1.f,src.rows-1.f);
|
||||
d[2] = Point2f(dstSize.width-1.f,dstSize.height-1.f);
|
||||
s[3] = Point2f(0,src.rows-1.f);
|
||||
d[3] = Point2f(0,dstSize.height-1.f);
|
||||
|
||||
float buffer[16];
|
||||
Mat tmp( 1, 16, CV_32FC1, buffer );
|
||||
rng.fill( tmp, 1, Scalar::all(0.), Scalar::all(0.1) );
|
||||
|
||||
for(int i = 0; i < 4; i++ )
|
||||
{
|
||||
s[i].x += buffer[i*4]*src.cols/2;
|
||||
s[i].y += buffer[i*4+1]*src.rows/2;
|
||||
d[i].x += buffer[i*4+2]*dstSize.width/2;
|
||||
d[i].y += buffer[i*4+3]*dstSize.height/2;
|
||||
}
|
||||
|
||||
cv::getPerspectiveTransform( s, d ).convertTo( M, M.depth() );
|
||||
|
||||
// Invert the perspective matrix
|
||||
invert(M,M);
|
||||
}
|
||||
|
||||
static cv::Mat getInverseAffine(const cv::Mat& affine)
|
||||
{
|
||||
// Extract the 2x2 part
|
||||
cv::Mat rotationScaling = affine(cv::Rect(0, 0, 2, 2));
|
||||
|
||||
// Invert the 2x2 part
|
||||
cv::Mat inverseRotationScaling;
|
||||
cv::invert(rotationScaling, inverseRotationScaling);
|
||||
|
||||
// Extract the translation part
|
||||
cv::Mat translation = affine(cv::Rect(2, 0, 1, 2));
|
||||
|
||||
// Compute the new translation
|
||||
cv::Mat inverseTranslation = -inverseRotationScaling * translation;
|
||||
|
||||
// Construct the inverse affine matrix
|
||||
cv::Mat inverseAffine = cv::Mat::zeros(2, 3, CV_32F);
|
||||
inverseRotationScaling.copyTo(inverseAffine(cv::Rect(0, 0, 2, 2)));
|
||||
inverseTranslation.copyTo(inverseAffine(cv::Rect(2, 0, 1, 2)));
|
||||
|
||||
return inverseAffine;
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<cv::Size> WarpPerspective2Plane;
|
||||
|
||||
TEST_P(WarpPerspective2Plane, accuracy)
|
||||
{
|
||||
cv::Size dstSize = GetParam();
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
EXPECT_FALSE(src.empty());
|
||||
|
||||
cv::Mat dst1, dst2, matrix, ref1, ref2;
|
||||
matrix.create(3, 3, CV_32FC1);
|
||||
|
||||
getInvertMatrix(src, dstSize, matrix);
|
||||
|
||||
cv::fastcv::warpPerspective2Plane(src, src, dst1, dst2, matrix, dstSize);
|
||||
cv::warpPerspective(src, ref1, matrix, dstSize, (cv::INTER_LINEAR | cv::WARP_INVERSE_MAP),cv::BORDER_CONSTANT,Scalar(0));
|
||||
cv::warpPerspective(src, ref2, matrix, dstSize, (cv::INTER_LINEAR | cv::WARP_INVERSE_MAP),cv::BORDER_CONSTANT,Scalar(0));
|
||||
|
||||
cv::Mat difference1, difference2, mask1, mask2;
|
||||
cv::absdiff(dst1, ref1, difference1);
|
||||
cv::absdiff(dst2, ref2, difference2);
|
||||
|
||||
// There are 1 or 2 difference in pixel value because algorithm is different, ignore those difference
|
||||
cv::threshold(difference1, mask1, 5, 255, cv::THRESH_BINARY);
|
||||
cv::threshold(difference2, mask2, 5, 255, cv::THRESH_BINARY);
|
||||
int num_diff_pixels_1 = cv::countNonZero(mask1);
|
||||
int num_diff_pixels_2 = cv::countNonZero(mask2);
|
||||
|
||||
// The border is different
|
||||
EXPECT_LT(num_diff_pixels_1, (dstSize.width+dstSize.height)*5);
|
||||
EXPECT_LT(num_diff_pixels_2, (dstSize.width+dstSize.height)*5);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<Size, int, int>> WarpPerspective;
|
||||
|
||||
TEST_P(WarpPerspective, accuracy)
|
||||
{
|
||||
cv::Size dstSize = get<0>(GetParam());
|
||||
int interplation = get<1>(GetParam());
|
||||
int borderType = get<2>(GetParam());
|
||||
cv::Scalar borderValue = Scalar::all(100);
|
||||
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
EXPECT_FALSE(src.empty());
|
||||
|
||||
cv::Mat dst, matrix, ref;
|
||||
matrix.create(3, 3, CV_32FC1);
|
||||
|
||||
getInvertMatrix(src, dstSize, matrix);
|
||||
|
||||
cv::fastcv::warpPerspective(src, dst, matrix, dstSize, interplation, borderType, borderValue);
|
||||
cv::warpPerspective(src, ref, matrix, dstSize, (interplation | cv::WARP_INVERSE_MAP), borderType, borderValue);
|
||||
|
||||
cv::Mat difference, mask;
|
||||
cv::absdiff(dst, ref, difference);
|
||||
cv::threshold(difference, mask, 10, 255, cv::THRESH_BINARY);
|
||||
int num_diff_pixels = cv::countNonZero(mask);
|
||||
|
||||
EXPECT_LT(num_diff_pixels, src.size().area()*0.05);
|
||||
}
|
||||
|
||||
|
||||
// BUG: https://github.com/opencv/opencv_contrib/issues/3959
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, WarpPerspective,Combine(
|
||||
::testing::Values(perf::szVGA, perf::sz720p, perf::sz1080p),
|
||||
::testing::Values(INTER_NEAREST, INTER_LINEAR, INTER_AREA),
|
||||
::testing::Values(BORDER_CONSTANT, BORDER_REPLICATE /*, BORDER_TRANSPARENT*/)
|
||||
));
|
||||
INSTANTIATE_TEST_CASE_P(FastCV_Extension, WarpPerspective2Plane, Values(perf::szVGA, perf::sz720p, perf::sz1080p));
|
||||
|
||||
TEST(WarpAffine3ChannelTest, accuracy)
|
||||
{
|
||||
cv::Mat src = imread(cvtest::findDataFile("cv/shared/baboon.png"));
|
||||
|
||||
// Define the transformation matrix
|
||||
cv::Mat M = (cv::Mat_<float>(2, 3) << 2.0, 0, -50.0, 0, 2.0, -50.0);
|
||||
|
||||
cv::Size dsize(src.cols, src.rows);
|
||||
|
||||
cv::Mat dst;
|
||||
|
||||
cv::fastcv::warpAffine(src, dst, M, dsize);
|
||||
|
||||
EXPECT_FALSE(dst.empty());
|
||||
}
|
||||
|
||||
TEST(WarpAffineROITest, accuracy)
|
||||
{
|
||||
cv::Mat src = cv::imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
|
||||
// Define the position and affine matrix
|
||||
cv::Point2f position(src.cols / 2.0f, src.rows / 2.0f);
|
||||
|
||||
float angle = 180.0; // Rotation angle in degrees
|
||||
float radians = angle * CV_PI / 180.0;
|
||||
cv::Mat affine = (cv::Mat_<float>(2, 2) << cos(radians), -sin(radians), sin(radians), cos(radians));
|
||||
|
||||
cv::Mat patch;
|
||||
cv::Mat roi = src(cv::Rect(0, 0, 100, 100));
|
||||
cv::fastcv::warpAffine(roi, patch, affine, cv::Size(100, 100));
|
||||
|
||||
EXPECT_FALSE(patch.empty());
|
||||
EXPECT_EQ(patch.size(), cv::Size(100, 100));
|
||||
EXPECT_EQ(patch.type(), CV_8UC1);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<int, int>> WarpAffineTest;
|
||||
|
||||
TEST_P(WarpAffineTest, accuracy)
|
||||
{
|
||||
// Load the source image
|
||||
cv::Mat src = cv::imread(cvtest::findDataFile("cv/shared/baboon.png"), cv::IMREAD_GRAYSCALE);
|
||||
ASSERT_FALSE(src.empty());
|
||||
|
||||
float angle = 30.0;// Rotation angle in degrees
|
||||
float scale = 0.5;// Scale factor
|
||||
cv::Mat affine = cv::getRotationMatrix2D(cv::Point2f(100, 100), angle, scale);
|
||||
|
||||
// Compute the inverse affine matrix
|
||||
cv::Mat inverseAffine = getInverseAffine(affine);
|
||||
|
||||
// Define the destination size
|
||||
cv::Size dsize(src.cols, src.rows);
|
||||
|
||||
// Define the output matrix
|
||||
cv::Mat dst;
|
||||
|
||||
// Get the parameters
|
||||
int interpolation = std::get<0>(GetParam());
|
||||
int borderValue = std::get<1>(GetParam());
|
||||
|
||||
// Perform the affine transformation
|
||||
cv::fastcv::warpAffine(src, dst, inverseAffine, dsize, interpolation, borderValue);
|
||||
|
||||
// Check that the output is not empty
|
||||
EXPECT_FALSE(dst.empty());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
FastCV_Extension,
|
||||
WarpAffineTest,
|
||||
::testing::Combine(
|
||||
::testing::Values(INTER_NEAREST, INTER_LINEAR, INTER_AREA),
|
||||
::testing::Values(0, 255) // Black and white borders
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user