vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:11:13 +08:00
commit 12022378a3
3872 changed files with 2513409 additions and 0 deletions
+125
View File
@@ -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, ::
+38
View File
@@ -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.)
));
}
}
+150
View File
@@ -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, ::
+75
View File
@@ -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, ::
+72
View File
@@ -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, ::
+136
View File
@@ -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
+74
View File
@@ -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)
));
}
}
+39
View File
@@ -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());
}
}
}
+65
View File
@@ -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, ::
+68
View File
@@ -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, ::
+98
View File
@@ -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, ::
+85
View File
@@ -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, ::
+105
View File
@@ -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, ::
+80
View File
@@ -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, ::
+13
View File
@@ -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())
+50
View File
@@ -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)
));
}
}
+179
View File
@@ -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, ::
+14
View File
@@ -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"
+172
View File
@@ -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, ::
+131
View File
@@ -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, ::
+44
View File
@@ -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();
}
}
}
+87
View File
@@ -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, ::
+75
View File
@@ -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, ::
+52
View File
@@ -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, ::
+50
View File
@@ -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, ::
+92
View File
@@ -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, ::
+142
View File
@@ -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, ::
+212
View File
@@ -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
)
);
}
}