add part of opencv

This commit is contained in:
Tang1705
2020-01-27 19:26:57 +08:00
parent 0c4ac1d8bb
commit 54c5864e7e
6130 changed files with 2631746 additions and 0 deletions

View File

@@ -0,0 +1,500 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// FIXME: move out from Common
#include "../test_precomp.hpp"
#include <opencv2/gapi/cpu/core.hpp>
#include <ade/util/algorithm.hpp>
namespace opencv_test
{
namespace
{
G_TYPED_KERNEL(GCompoundDoubleAddC, <GMat(GMat, GScalar)>, "org.opencv.test.compound_double_addC")
{
static GMatDesc outMeta(GMatDesc in, GScalarDesc) { return in; }
};
GAPI_COMPOUND_KERNEL(GCompoundDoubleAddCImpl, GCompoundDoubleAddC)
{
static GMat expand(cv::GMat in, cv::GScalar s)
{
return cv::gapi::addC(cv::gapi::addC(in, s), s);
}
};
G_TYPED_KERNEL(GCompoundAddC, <GMat(GMat, GScalar)>, "org.opencv.test.compound_addC")
{
static GMatDesc outMeta(GMatDesc in, GScalarDesc) { return in; }
};
GAPI_COMPOUND_KERNEL(GCompoundAddCImpl, GCompoundAddC)
{
static GMat expand(cv::GMat in, cv::GScalar s)
{
return cv::gapi::addC(in, s);
}
};
using GMat3 = std::tuple<GMat,GMat,GMat>;
using GMat2 = std::tuple<GMat,GMat>;
G_TYPED_KERNEL_M(GCompoundMergeWithSplit, <GMat3(GMat, GMat, GMat)>, "org.opencv.test.compound_merge_split")
{
static std::tuple<GMatDesc,GMatDesc,GMatDesc> outMeta(GMatDesc a, GMatDesc b, GMatDesc c)
{
return std::make_tuple(a, b, c);
}
};
GAPI_COMPOUND_KERNEL(GCompoundMergeWithSplitImpl, GCompoundMergeWithSplit)
{
static GMat3 expand(cv::GMat a, cv::GMat b, cv::GMat c)
{
return cv::gapi::split3(cv::gapi::merge3(a, b, c));
}
};
G_TYPED_KERNEL(GCompoundAddWithAddC, <GMat(GMat, GMat, GScalar)>, "org.opencv.test.compound_add_with_addc")
{
static GMatDesc outMeta(GMatDesc in, GMatDesc, GScalarDesc)
{
return in;
}
};
GAPI_COMPOUND_KERNEL(GCompoundAddWithAddCImpl, GCompoundAddWithAddC)
{
static GMat expand(cv::GMat in1, cv::GMat in2, cv::GScalar s)
{
return cv::gapi::addC(cv::gapi::add(in1, in2), s);
}
};
G_TYPED_KERNEL_M(GCompoundSplitWithAdd, <GMat2(GMat)>, "org.opencv.test.compound_split_with_add")
{
static std::tuple<GMatDesc, GMatDesc> outMeta(GMatDesc in)
{
const auto out_depth = in.depth;
const auto out_desc = in.withType(out_depth, 1);
return std::make_tuple(out_desc, out_desc);
}
};
GAPI_COMPOUND_KERNEL(GCompoundSplitWithAddImpl, GCompoundSplitWithAdd)
{
static GMat2 expand(cv::GMat in)
{
cv::GMat a, b, c;
std::tie(a, b, c) = cv::gapi::split3(in);
return std::make_tuple(cv::gapi::add(a, b), c);
}
};
G_TYPED_KERNEL_M(GCompoundParallelAddC, <GMat2(GMat, GScalar)>, "org.opencv.test.compound_parallel_addc")
{
static std::tuple<GMatDesc, GMatDesc> outMeta(GMatDesc in, GScalarDesc)
{
return std::make_tuple(in, in);
}
};
GAPI_COMPOUND_KERNEL(GCompoundParallelAddCImpl, GCompoundParallelAddC)
{
static GMat2 expand(cv::GMat in, cv::GScalar s)
{
return std::make_tuple(cv::gapi::addC(in, s), cv::gapi::addC(in, s));
}
};
GAPI_COMPOUND_KERNEL(GCompoundAddImpl, cv::gapi::core::GAdd)
{
static GMat expand(cv::GMat in1, cv::GMat in2, int)
{
return cv::gapi::sub(cv::gapi::sub(in1, in2), in2);
}
};
G_TYPED_KERNEL(GCompoundAddWithAddCWithDoubleAddC, <GMat(GMat, GMat, GScalar)>, "org.opencv.test.compound_add_with_addC_with_double_addC")
{
static GMatDesc outMeta(GMatDesc in, GMatDesc, GScalarDesc)
{
return in;
}
};
GAPI_COMPOUND_KERNEL(GCompoundAddWithAddCWithDoubleAddCImpl, GCompoundAddWithAddCWithDoubleAddC)
{
static GMat expand(cv::GMat in1, cv::GMat in2, cv::GScalar s)
{
return GCompoundDoubleAddC::on(GCompoundAddWithAddC::on(in1, in2, s), s);
}
};
using GDoubleArray = cv::GArray<double>;
G_TYPED_KERNEL(GNegateArray, <GDoubleArray(GDoubleArray)>, "org.opencv.test.negate_array")
{
static GArrayDesc outMeta(const GArrayDesc&) { return empty_array_desc(); }
};
GAPI_OCV_KERNEL(GNegateArrayImpl, GNegateArray)
{
static void run(const std::vector<double>& in, std::vector<double>& out)
{
ade::util::transform(in, std::back_inserter(out), std::negate<double>());
}
};
G_TYPED_KERNEL(GMaxInArray, <GScalar(GDoubleArray)>, "org.opencv.test.max_in_array")
{
static GScalarDesc outMeta(const GArrayDesc&) { return empty_scalar_desc(); }
};
GAPI_OCV_KERNEL(GMaxInArrayImpl, GMaxInArray)
{
static void run(const std::vector<double>& in, cv::Scalar& out)
{
out = *std::max_element(in.begin(), in.end());
}
};
G_TYPED_KERNEL(GCompoundMaxInArray, <GScalar(GDoubleArray)>, "org.opencv.test.compound_max_in_array")
{
static GScalarDesc outMeta(const GArrayDesc&) { return empty_scalar_desc(); }
};
GAPI_COMPOUND_KERNEL(GCompoundMaxInArrayImpl, GCompoundMaxInArray)
{
static GScalar expand(GDoubleArray in)
{
return GMaxInArray::on(in);
}
};
G_TYPED_KERNEL(GCompoundNegateArray, <GDoubleArray(GDoubleArray)>, "org.opencv.test.compound_negate_array")
{
static GArrayDesc outMeta(const GArrayDesc&) { return empty_array_desc(); }
};
GAPI_COMPOUND_KERNEL(GCompoundNegateArrayImpl, GCompoundNegateArray)
{
static GDoubleArray expand(GDoubleArray in)
{
return GNegateArray::on(in);
}
};
G_TYPED_KERNEL(SetDiagKernel, <GMat(GMat, GDoubleArray)>, "org.opencv.test.empty_kernel")
{
static GMatDesc outMeta(GMatDesc in, GArrayDesc) { return in; }
};
void setDiag(cv::Mat& in, const std::vector<double>& diag)
{
GAPI_Assert(in.rows == static_cast<int>(diag.size()));
GAPI_Assert(in.cols == static_cast<int>(diag.size()));
for (int i = 0; i < in.rows; ++i)
{
in.at<uchar>(i, i) = static_cast<uchar>(diag[i]);
}
}
GAPI_OCV_KERNEL(SetDiagKernelImpl, SetDiagKernel)
{
static void run(const cv::Mat& in, const std::vector<double>& v, cv::Mat& out)
{
in.copyTo(out);
setDiag(out, v);
}
};
G_TYPED_KERNEL(GCompoundGMatGArrayGMat, <GMat(GMat, GDoubleArray, GMat)>, "org.opencv.test.compound_gmat_garray_gmat")
{
static GMatDesc outMeta(GMatDesc in, GArrayDesc, GMatDesc) { return in; }
};
GAPI_COMPOUND_KERNEL(GCompoundGMatGArrayGMatImpl, GCompoundGMatGArrayGMat)
{
static GMat expand(GMat a, GDoubleArray b, GMat c)
{
return SetDiagKernel::on(cv::gapi::add(a, c), b);
}
};
} // namespace
// FIXME avoid cv::combine that use custom and default kernels together
TEST(GCompoundKernel, ReplaceDefaultKernel)
{
cv::GMat in1, in2;
auto out = cv::gapi::add(in1, in2);
const auto custom_pkg = cv::gapi::kernels<GCompoundAddImpl>();
const auto full_pkg = cv::gapi::combine(cv::gapi::core::cpu::kernels(), custom_pkg);
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out));
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
out_mat(3, 3, CV_8UC1),
ref_mat(3, 3, CV_8UC1);
comp.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(full_pkg));
ref_mat = in_mat1 - in_mat2 - in_mat2;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GCompoundKernel, DoubleAddC)
{
cv::GMat in1, in2;
cv::GScalar s;
auto add_res = cv::gapi::add(in1, in2);
auto super = GCompoundDoubleAddC::on(add_res, s);
auto out = cv::gapi::addC(super, s);
const auto custom_pkg = cv::gapi::kernels<GCompoundDoubleAddCImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in1, in2, s), cv::GOut(out));
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
out_mat(3, 3, CV_8UC1),
ref_mat(3, 3, CV_8UC1);
cv::Scalar scalar = 2;
comp.apply(cv::gin(in_mat1, in_mat2, scalar), cv::gout(out_mat), cv::compile_args(full_pkg));
ref_mat = in_mat1 + in_mat2 + scalar + scalar + scalar;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GCompoundKernel, AddC)
{
cv::GMat in1, in2;
cv::GScalar s;
auto add_res = cv::gapi::add(in1, in2);
auto super = GCompoundAddC::on(add_res, s);
auto out = cv::gapi::addC(super, s);
const auto custom_pkg = cv::gapi::kernels<GCompoundAddCImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in1, in2, s), cv::GOut(out));
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
out_mat(3, 3, CV_8UC1),
ref_mat(3, 3, CV_8UC1);
cv::Scalar scalar = 2;
comp.apply(cv::gin(in_mat1, in_mat2, scalar), cv::gout(out_mat), cv::compile_args(full_pkg));
ref_mat = in_mat1 + in_mat2 + scalar + scalar;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GCompoundKernel, MergeWithSplit)
{
cv::GMat in, a1, b1, c1,
a2, b2, c2;
std::tie(a1, b1, c1) = cv::gapi::split3(in);
std::tie(a2, b2, c2) = GCompoundMergeWithSplit::on(a1, b1, c1);
auto out = cv::gapi::merge3(a2, b2, c2);
const auto custom_pkg = cv::gapi::kernels<GCompoundMergeWithSplitImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC3), out_mat, ref_mat;
comp.apply(cv::gin(in_mat), cv::gout(out_mat), cv::compile_args(full_pkg));
ref_mat = in_mat;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GCompoundKernel, AddWithAddC)
{
cv::GMat in1, in2;
cv::GScalar s;
auto out = GCompoundAddWithAddC::on(in1, in2, s);
const auto custom_pkg = cv::gapi::kernels<GCompoundAddWithAddCImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in1, in2, s), cv::GOut(out));
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
out_mat(3, 3, CV_8UC1),
ref_mat(3, 3, CV_8UC1);
cv::Scalar scalar = 2;
comp.apply(cv::gin(in_mat1, in_mat2, scalar), cv::gout(out_mat), cv::compile_args(full_pkg));
ref_mat = in_mat1 + in_mat2 + scalar;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GCompoundKernel, SplitWithAdd)
{
cv::GMat in, out1, out2;
std::tie(out1, out2) = GCompoundSplitWithAdd::on(in);
const auto custom_pkg = cv::gapi::kernels<GCompoundSplitWithAddImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in), cv::GOut(out1, out2));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC3),
out_mat1(3, 3, CV_8UC1),
out_mat2(3, 3, CV_8UC1),
ref_mat1(3, 3, CV_8UC1),
ref_mat2(3, 3, CV_8UC1);
comp.apply(cv::gin(in_mat), cv::gout(out_mat1, out_mat2), cv::compile_args(full_pkg));
std::vector<cv::Mat> channels(3);
cv::split(in_mat, channels);
ref_mat1 = channels[0] + channels[1];
ref_mat2 = channels[2];
EXPECT_EQ(0, cv::countNonZero(out_mat1 != ref_mat1));
EXPECT_EQ(0, cv::countNonZero(out_mat2 != ref_mat2));
}
TEST(GCompoundKernel, ParallelAddC)
{
cv::GMat in1, out1, out2;
cv::GScalar in2;
std::tie(out1, out2) = GCompoundParallelAddC::on(in1, in2);
const auto custom_pkg = cv::gapi::kernels<GCompoundParallelAddCImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out1, out2));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1),
out_mat1(3, 3, CV_8UC1),
out_mat2(3, 3, CV_8UC1),
ref_mat1(3, 3, CV_8UC1),
ref_mat2(3, 3, CV_8UC1);
cv::Scalar scalar = 2;
comp.apply(cv::gin(in_mat, scalar), cv::gout(out_mat1, out_mat2), cv::compile_args(full_pkg));
ref_mat1 = in_mat + scalar;
ref_mat2 = in_mat + scalar;
EXPECT_EQ(0, cv::countNonZero(out_mat1 != ref_mat1));
EXPECT_EQ(0, cv::countNonZero(out_mat2 != ref_mat2));
}
TEST(GCompoundKernel, GCompundKernelAndDefaultUseOneData)
{
cv::GMat in1, in2;
cv::GScalar s;
auto out = cv::gapi::add(GCompoundAddWithAddC::on(in1, in2, s), cv::gapi::addC(in2, s));
const auto custom_pkg = cv::gapi::kernels<GCompoundAddWithAddCImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in1, in2, s), cv::GOut(out));
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
out_mat(3, 3, CV_8UC1),
ref_mat(3, 3, CV_8UC1);
cv::Scalar scalar = 2;
comp.apply(cv::gin(in_mat1, in_mat2, scalar), cv::gout(out_mat), cv::compile_args(full_pkg));
ref_mat = in_mat1 + in_mat2 + scalar + in_mat2 + scalar;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GCompoundKernel, CompoundExpandedToCompound)
{
cv::GMat in1, in2;
cv::GScalar s;
auto out = GCompoundAddWithAddCWithDoubleAddC::on(in1, in2, s);
const auto custom_pkg = cv::gapi::kernels<GCompoundAddWithAddCWithDoubleAddCImpl,
GCompoundAddWithAddCImpl,
GCompoundDoubleAddCImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in1, in2, s), cv::GOut(out));
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
out_mat(3, 3, CV_8UC1),
ref_mat(3, 3, CV_8UC1);
cv::Scalar scalar = 2;
comp.apply(cv::gin(in_mat1, in_mat2, scalar), cv::gout(out_mat), cv::compile_args(full_pkg));
ref_mat = in_mat1 + in_mat2 + scalar + scalar + scalar;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GCompoundKernel, MaxInArray)
{
GDoubleArray in;
auto out = GCompoundMaxInArray::on(in);
const auto custom_pkg = cv::gapi::kernels<GCompoundMaxInArrayImpl, GMaxInArrayImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
std::vector<double> v = { 1, 5, -2, 3, 10, 2};
cv::Scalar out_scl;
cv::Scalar ref_scl(*std::max_element(v.begin(), v.end()));
comp.apply(cv::gin(v), cv::gout(out_scl), cv::compile_args(full_pkg));
EXPECT_EQ(out_scl, ref_scl);
}
TEST(GCompoundKernel, NegateArray)
{
GDoubleArray in;
GDoubleArray out = GCompoundNegateArray::on(in);
const auto custom_pkg = cv::gapi::kernels<GCompoundNegateArrayImpl, GNegateArrayImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
std::vector<double> in_v = {1, 5, -2, -10, 3};
std::vector<double> out_v;
std::vector<double> ref_v;
ade::util::transform(in_v, std::back_inserter(ref_v), std::negate<double>());
comp.apply(cv::gin(in_v), cv::gout(out_v), cv::compile_args(full_pkg));
EXPECT_EQ(out_v, ref_v);
}
TEST(GCompoundKernel, RightGArrayHandle)
{
cv::GMat in[2];
GDoubleArray a;
cv::GMat out = GCompoundGMatGArrayGMat::on(in[0], a, in[1]);
const auto custom_pkg = cv::gapi::kernels<GCompoundGMatGArrayGMatImpl, SetDiagKernelImpl>();
const auto full_pkg = cv::gapi::combine(custom_pkg, cv::gapi::core::cpu::kernels());
cv::GComputation comp(cv::GIn(in[0], a, in[1]), cv::GOut(out));
std::vector<double> in_v(3, 1.0);
cv::Mat in_mat1 = cv::Mat::eye(cv::Size(3, 3), CV_8UC1),
in_mat2 = cv::Mat::eye(cv::Size(3, 3), CV_8UC1),
out_mat;
cv::Mat ref_mat= in_mat1 + in_mat2;
setDiag(ref_mat, in_v);
comp.apply(cv::gin(in_mat1, in_v, in_mat2), cv::gout(out_mat), cv::compile_args(full_pkg));
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
} // opencv_test

View File

@@ -0,0 +1,9 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "gapi_core_tests_inl.hpp"

View File

@@ -0,0 +1,146 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#ifndef OPENCV_GAPI_CORE_TESTS_HPP
#define OPENCV_GAPI_CORE_TESTS_HPP
#include <iostream>
#include "gapi_tests_common.hpp"
namespace opencv_test
{
enum mathOp
{
ADD = 0,
SUB = 1,
MUL = 2,
DIV = 3
};
enum bitwiseOp
{
AND = 0,
OR = 1,
XOR = 2,
NOT = 3
};
// Note: namespace must match the namespace of the type of the printed object
inline std::ostream& operator<<(std::ostream& os, mathOp op)
{
#define CASE(v) case mathOp::v: os << #v; break
switch (op)
{
CASE(ADD);
CASE(SUB);
CASE(MUL);
CASE(DIV);
default: GAPI_Assert(false && "unknown mathOp value");
}
#undef CASE
return os;
}
// Note: namespace must match the namespace of the type of the printed object
inline std::ostream& operator<<(std::ostream& os, bitwiseOp op)
{
#define CASE(v) case bitwiseOp::v: os << #v; break
switch (op)
{
CASE(AND);
CASE(OR);
CASE(XOR);
CASE(NOT);
default: GAPI_Assert(false && "unknown bitwiseOp value");
}
#undef CASE
return os;
}
// Create new value-parameterized test fixture:
// MathOpTest - fixture name
// initMatsRandU - function that is used to initialize input/output data
// FIXTURE_API(mathOp,bool,double,bool) - test-specific parameters (types)
// 4 - number of test-specific parameters
// opType, testWithScalar, scale, doReverseOp - test-spcific parameters (names)
//
// We get:
// 1. Default parameters: int type, cv::Size sz, int dtype, getCompileArgs() function
// - available in test body
// 2. Input/output matrices will be initialized by initMatsRandU (in this fixture)
// 3. Specific parameters: opType, testWithScalar, scale, doReverseOp of corresponding types
// - created (and initialized) automatically
// - available in test body
// Note: all parameter _values_ (e.g. type CV_8UC3) are set via INSTANTIATE_TEST_CASE_P macro
GAPI_TEST_FIXTURE(MathOpTest, initMatsRandU, FIXTURE_API(mathOp,bool,double,bool), 4,
opType, testWithScalar, scale, doReverseOp)
// No specific parameters for MulDoubleTest, so "fixture API" is empty - <>
GAPI_TEST_FIXTURE(MulDoubleTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(DivTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(DivCTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(MeanTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(MaskTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(Polar2CartTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(Cart2PolarTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(CmpTest, initMatsRandU, FIXTURE_API(CmpTypes,bool), 2, opType, testWithScalar)
GAPI_TEST_FIXTURE(BitwiseTest, initMatsRandU, FIXTURE_API(bitwiseOp), 1, opType)
GAPI_TEST_FIXTURE(NotTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(SelectTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(MinTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(MaxTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(AbsDiffTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(AbsDiffCTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(SumTest, initMatrixRandU, FIXTURE_API(CompareScalars), 1, cmpF)
GAPI_TEST_FIXTURE(AddWeightedTest, initMatsRandU, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(NormTest, initMatrixRandU, FIXTURE_API(CompareScalars,NormTypes), 2,
cmpF, opType)
GAPI_TEST_FIXTURE(IntegralTest, initNothing, <>, 0)
GAPI_TEST_FIXTURE(ThresholdTest, initMatrixRandU, FIXTURE_API(int, cv::Scalar), 2, tt, maxval)
GAPI_TEST_FIXTURE(ThresholdOTTest, initMatrixRandU, FIXTURE_API(int), 1, tt)
GAPI_TEST_FIXTURE(InRangeTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(Split3Test, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(Split4Test, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(ResizeTest, initNothing, FIXTURE_API(CompareMats,int,cv::Size), 3,
cmpF, interp, sz_out)
GAPI_TEST_FIXTURE(ResizePTest, initNothing, FIXTURE_API(CompareMats,int,cv::Size), 3,
cmpF, interp, sz_out)
GAPI_TEST_FIXTURE(ResizeTestFxFy, initNothing, FIXTURE_API(CompareMats,int,double,double), 4,
cmpF, interp, fx, fy)
GAPI_TEST_FIXTURE(Merge3Test, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(Merge4Test, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(RemapTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(FlipTest, initMatrixRandU, FIXTURE_API(int), 1, flipCode)
GAPI_TEST_FIXTURE(CropTest, initMatrixRandU, FIXTURE_API(cv::Rect), 1, rect_to)
GAPI_TEST_FIXTURE(CopyTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(ConcatHorTest, initNothing, <>, 0)
GAPI_TEST_FIXTURE(ConcatVertTest, initNothing, <>, 0)
GAPI_TEST_FIXTURE(ConcatVertVecTest, initNothing, <>, 0)
GAPI_TEST_FIXTURE(ConcatHorVecTest, initNothing, <>, 0)
GAPI_TEST_FIXTURE(LUTTest, initNothing, <>, 0)
GAPI_TEST_FIXTURE(ConvertToTest, initNothing, FIXTURE_API(CompareMats, double, double), 3,
cmpF, alpha, beta)
GAPI_TEST_FIXTURE(PhaseTest, initMatsRandU, FIXTURE_API(bool), 1, angle_in_degrees)
GAPI_TEST_FIXTURE(SqrtTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(NormalizeTest, initNothing, FIXTURE_API(CompareMats,double,double,int,MatType2), 5,
cmpF, a, b, norm_type, ddepth)
struct BackendOutputAllocationTest : TestWithParamBase<>
{
BackendOutputAllocationTest()
{
in_mat1 = cv::Mat(sz, type);
in_mat2 = cv::Mat(sz, type);
cv::randu(in_mat1, cv::Scalar::all(1), cv::Scalar::all(15));
cv::randu(in_mat2, cv::Scalar::all(1), cv::Scalar::all(15));
}
};
// FIXME: move all tests from this fixture to the base class once all issues are resolved
struct BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest : BackendOutputAllocationTest {};
GAPI_TEST_FIXTURE(ReInitOutTest, initNothing, <cv::Size>, 1, out_sz)
} // opencv_test
#endif //OPENCV_GAPI_CORE_TESTS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "gapi_imgproc_tests_inl.hpp"

View File

@@ -0,0 +1,73 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_TESTS_HPP
#define OPENCV_GAPI_IMGPROC_TESTS_HPP
#include <iostream>
#include "gapi_tests_common.hpp"
namespace opencv_test
{
// Create new value-parameterized test fixture:
// Filter2DTest - fixture name
// initMatrixRandN - function that is used to initialize input/output data
// FIXTURE_API(CompareMats,int,int) - test-specific parameters (types)
// 3 - number of test-specific parameters
// cmpF, kernSize, borderType - test-spcific parameters (names)
//
// We get:
// 1. Default parameters: int type, cv::Size sz, int dtype, getCompileArgs() function
// - available in test body
// 2. Input/output matrices will be initialized by initMatrixRandN (in this fixture)
// 3. Specific parameters: cmpF, kernSize, borderType of corresponding types
// - created (and initialized) automatically
// - available in test body
// Note: all parameter _values_ (e.g. type CV_8UC3) are set via INSTANTIATE_TEST_CASE_P macro
GAPI_TEST_FIXTURE(Filter2DTest, initMatrixRandN, FIXTURE_API(CompareMats,cv::Size,int), 3,
cmpF, filterSize, borderType)
GAPI_TEST_FIXTURE(BoxFilterTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int), 3,
cmpF, filterSize, borderType)
GAPI_TEST_FIXTURE(SepFilterTest, initMatrixRandN, FIXTURE_API(CompareMats,int), 2, cmpF, kernSize)
GAPI_TEST_FIXTURE(BlurTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int), 3,
cmpF, filterSize, borderType)
GAPI_TEST_FIXTURE(GaussianBlurTest, initMatrixRandN, FIXTURE_API(CompareMats,int), 2, cmpF, kernSize)
GAPI_TEST_FIXTURE(MedianBlurTest, initMatrixRandN, FIXTURE_API(CompareMats,int), 2, cmpF, kernSize)
GAPI_TEST_FIXTURE(ErodeTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int), 3,
cmpF, kernSize, kernType)
GAPI_TEST_FIXTURE(Erode3x3Test, initMatrixRandN, FIXTURE_API(CompareMats,int), 2,
cmpF, numIters)
GAPI_TEST_FIXTURE(DilateTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int), 3,
cmpF, kernSize, kernType)
GAPI_TEST_FIXTURE(Dilate3x3Test, initMatrixRandN, FIXTURE_API(CompareMats,int), 2, cmpF, numIters)
GAPI_TEST_FIXTURE(SobelTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int,int), 4,
cmpF, kernSize, dx, dy)
GAPI_TEST_FIXTURE(SobelXYTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int,int,int), 5,
cmpF, kernSize, order, border_type, border_val)
GAPI_TEST_FIXTURE(EqHistTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(CannyTest, initMatrixRandN, FIXTURE_API(CompareMats,double,double,int,bool), 5,
cmpF, thrLow, thrUp, apSize, l2gr)
GAPI_TEST_FIXTURE(RGB2GrayTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(BGR2GrayTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(RGB2YUVTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(YUV2RGBTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toRGBTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toBGRpTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toRGBpTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(NV12toBGRTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(RGB2LabTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(BGR2LUVTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(LUV2BGRTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(BGR2YUVTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(YUV2BGRTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(RGB2HSVTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(BayerGR2RGBTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(RGB2YUV422Test, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
} // opencv_test
#endif //OPENCV_GAPI_IMGPROC_TESTS_HPP

View File

@@ -0,0 +1,735 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_TESTS_INL_HPP
#define OPENCV_GAPI_IMGPROC_TESTS_INL_HPP
#include <opencv2/gapi/imgproc.hpp>
#include "gapi_imgproc_tests.hpp"
namespace opencv_test
{
// FIXME avoid this code duplicate in perf tests
namespace
{
void rgb2yuyv(const uchar* rgb_line, uchar* yuv422_line, int width)
{
CV_Assert(width % 2 == 0);
for (int i = 0; i < width; i += 2)
{
uchar r = rgb_line[i * 3 ];
uchar g = rgb_line[i * 3 + 1];
uchar b = rgb_line[i * 3 + 2];
yuv422_line[i * 2 ] = cv::saturate_cast<uchar>(-0.14713 * r - 0.28886 * g + 0.436 * b + 128.f); // U0
yuv422_line[i * 2 + 1] = cv::saturate_cast<uchar>( 0.299 * r + 0.587 * g + 0.114 * b ); // Y0
yuv422_line[i * 2 + 2] = cv::saturate_cast<uchar>( 0.615 * r - 0.51499 * g - 0.10001 * b + 128.f); // V0
r = rgb_line[i * 3 + 3];
g = rgb_line[i * 3 + 4];
b = rgb_line[i * 3 + 5];
yuv422_line[i * 2 + 3] = cv::saturate_cast<uchar>(0.299 * r + 0.587 * g + 0.114 * b); // Y1
}
}
void convertRGB2YUV422Ref(const cv::Mat& in, cv::Mat &out)
{
out.create(in.size(), CV_8UC2);
for (int i = 0; i < in.rows; ++i)
{
const uchar* in_line_p = in.ptr<uchar>(i);
uchar* out_line_p = out.ptr<uchar>(i);
rgb2yuyv(in_line_p, out_line_p, in.cols);
}
}
}
TEST_P(Filter2DTest, AccuracyTest)
{
cv::Point anchor = {-1, -1};
double delta = 0;
cv::Mat kernel = cv::Mat(filterSize, CV_32FC1);
cv::Scalar kernMean, kernStddev;
const auto kernSize = filterSize.width * filterSize.height;
const auto bigKernSize = 49;
if (kernSize < bigKernSize)
{
kernMean = cv::Scalar(0.3);
kernStddev = cv::Scalar(0.5);
}
else
{
kernMean = cv::Scalar(0.008);
kernStddev = cv::Scalar(0.008);
}
randn(kernel, kernMean, kernStddev);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::filter2D(in, dtype, kernel, anchor, delta, borderType);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::filter2D(in_mat1, out_mat_ocv, dtype, kernel, anchor, delta, borderType);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(BoxFilterTest, AccuracyTest)
{
cv::Point anchor = {-1, -1};
bool normalize = true;
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::boxFilter(in, dtype, cv::Size(filterSize, filterSize), anchor, normalize,
borderType);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::boxFilter(in_mat1, out_mat_ocv, dtype, cv::Size(filterSize, filterSize), anchor,
normalize, borderType);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(SepFilterTest, AccuracyTest)
{
cv::Mat kernelX(kernSize, 1, CV_32F);
cv::Mat kernelY(kernSize, 1, CV_32F);
randu(kernelX, -1, 1);
randu(kernelY, -1, 1);
cv::Point anchor = cv::Point(-1, -1);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::sepFilter(in, dtype, kernelX, kernelY, anchor, cv::Scalar() );
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::sepFilter2D(in_mat1, out_mat_ocv, dtype, kernelX, kernelY );
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(BlurTest, AccuracyTest)
{
cv::Point anchor = {-1, -1};
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::blur(in, cv::Size(filterSize, filterSize), anchor, borderType);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::blur(in_mat1, out_mat_ocv, cv::Size(filterSize, filterSize), anchor, borderType);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(GaussianBlurTest, AccuracyTest)
{
cv::Size kSize = cv::Size(kernSize, kernSize);
double sigmaX = rand();
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::gaussianBlur(in, kSize, sigmaX);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::GaussianBlur(in_mat1, out_mat_ocv, kSize, sigmaX);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(MedianBlurTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::medianBlur(in, kernSize);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::medianBlur(in_mat1, out_mat_ocv, kernSize);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(ErodeTest, AccuracyTest)
{
cv::Mat kernel = cv::getStructuringElement(kernType, cv::Size(kernSize, kernSize));
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::erode(in, kernel);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::erode(in_mat1, out_mat_ocv, kernel);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(Erode3x3Test, AccuracyTest)
{
cv::Mat kernel = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(3,3));
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::erode3x3(in, numIters);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::erode(in_mat1, out_mat_ocv, kernel, cv::Point(-1, -1), numIters);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(DilateTest, AccuracyTest)
{
cv::Mat kernel = cv::getStructuringElement(kernType, cv::Size(kernSize, kernSize));
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::dilate(in, kernel);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::dilate(in_mat1, out_mat_ocv, kernel);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(Dilate3x3Test, AccuracyTest)
{
cv::Mat kernel = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(3,3));
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::dilate3x3(in, numIters);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::dilate(in_mat1, out_mat_ocv, kernel, cv::Point(-1,-1), numIters);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(SobelTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::Sobel(in, dtype, dx, dy, kernSize );
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::Sobel(in_mat1, out_mat_ocv, dtype, dx, dy, kernSize);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(SobelXYTest, AccuracyTest)
{
cv::Mat out_mat_ocv2;
cv::Mat out_mat_gapi2;
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::SobelXY(in, dtype, order, kernSize, 1, 0, border_type, border_val);
cv::GComputation c(cv::GIn(in), cv::GOut(std::get<0>(out), std::get<1>(out)));
c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi, out_mat_gapi2), getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
// workaround for cv::Sobel
cv::Mat temp_in;
if(border_type == cv::BORDER_CONSTANT)
{
int n_pixels = (kernSize - 1) / 2;
cv::copyMakeBorder(in_mat1, temp_in, n_pixels, n_pixels, n_pixels, n_pixels, border_type, border_val);
in_mat1 = temp_in(cv::Rect(n_pixels, n_pixels, in_mat1.cols, in_mat1.rows));
}
cv::Sobel(in_mat1, out_mat_ocv, dtype, order, 0, kernSize, 1, 0, border_type);
cv::Sobel(in_mat1, out_mat_ocv2, dtype, 0, order, kernSize, 1, 0, border_type);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_TRUE(cmpF(out_mat_gapi2, out_mat_ocv2));
EXPECT_EQ(out_mat_gapi.size(), sz);
EXPECT_EQ(out_mat_gapi2.size(), sz);
}
}
TEST_P(EqHistTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::equalizeHist(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::equalizeHist(in_mat1, out_mat_ocv);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(CannyTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::Canny(in, thrLow, thrUp, apSize, l2gr);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::Canny(in_mat1, out_mat_ocv, thrLow, thrUp, apSize, l2gr);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(RGB2GrayTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2Gray(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2GRAY);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(BGR2GrayTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BGR2Gray(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2GRAY);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(RGB2YUVTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2YUV(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2YUV);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(YUV2RGBTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::YUV2RGB(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2RGB);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(NV12toRGBTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in_y;
cv::GMat in_uv;
auto out = cv::gapi::NV12toRGB(in_y, in_uv);
// Additional mat for uv
cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2);
cv::randn(in_mat_uv, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out));
c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi), getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2RGB_NV12);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(NV12toBGRTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in_y;
cv::GMat in_uv;
auto out = cv::gapi::NV12toBGR(in_y, in_uv);
// Additional mat for uv
cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2);
cv::randn(in_mat_uv, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out));
c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi), getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2BGR_NV12);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
static void toPlanar(const cv::Mat& in, cv::Mat& out)
{
GAPI_Assert(out.depth() == in.depth());
GAPI_Assert(out.channels() == 1);
GAPI_Assert(in.channels() == 3);
GAPI_Assert(out.cols == in.cols);
GAPI_Assert(out.rows == 3*in.rows);
std::vector<cv::Mat> outs(3);
for (int i = 0; i < 3; i++) {
outs[i] = out(cv::Rect(0, i*in.rows, in.cols, in.rows));
}
cv::split(in, outs);
}
TEST_P(NV12toRGBpTest, AccuracyTest)
{
cv::Size sz_p = cv::Size(sz.width, sz.height * 3);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in_y;
cv::GMat in_uv;
auto out = cv::gapi::NV12toRGBp(in_y, in_uv);
// Additional mat for uv
cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2);
cv::randn(in_mat_uv, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out));
cv::Mat out_mat_gapi_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi_planar), getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
cv::Mat out_mat_ocv_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
{
cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2RGB_NV12);
toPlanar(out_mat_ocv, out_mat_ocv_planar);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi_planar, out_mat_ocv_planar));
EXPECT_EQ(out_mat_gapi_planar.size(), sz_p);
}
}
TEST_P(NV12toBGRpTest, AccuracyTest)
{
cv::Size sz_p = cv::Size(sz.width, sz.height * 3);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in_y;
cv::GMat in_uv;
auto out = cv::gapi::NV12toBGRp(in_y, in_uv);
// Additional mat for uv
cv::Mat in_mat_uv(cv::Size(sz.width / 2, sz.height / 2), CV_8UC2);
cv::randn(in_mat_uv, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::GComputation c(cv::GIn(in_y, in_uv), cv::GOut(out));
cv::Mat out_mat_gapi_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
c.apply(cv::gin(in_mat1, in_mat_uv), cv::gout(out_mat_gapi_planar), getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
cv::Mat out_mat_ocv_planar(cv::Size(sz.width, sz.height * 3), CV_8UC1);
{
cv::cvtColorTwoPlane(in_mat1, in_mat_uv, out_mat_ocv, cv::COLOR_YUV2BGR_NV12);
toPlanar(out_mat_ocv, out_mat_ocv_planar);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi_planar, out_mat_ocv_planar));
EXPECT_EQ(out_mat_gapi_planar.size(), sz_p);
}
}
TEST_P(RGB2LabTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2Lab(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2Lab);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(BGR2LUVTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BGR2LUV(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2Luv);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(LUV2BGRTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::LUV2BGR(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_Luv2BGR);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(BGR2YUVTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BGR2YUV(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2YUV);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(YUV2BGRTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::YUV2BGR(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2BGR);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(RGB2HSVTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2HSV(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2HSV);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(BayerGR2RGBTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BayerGR2RGB(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BayerGR2RGB);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(RGB2YUV422Test, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2YUV422(in);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
convertRGB2YUV422Ref(in_mat1, out_mat_ocv);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
} // opencv_test
#endif //OPENCV_GAPI_IMGPROC_TESTS_INL_HPP

View File

@@ -0,0 +1,9 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "gapi_operators_tests_inl.hpp"

View File

@@ -0,0 +1,209 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#ifndef OPENCV_GAPI_OPERATOR_TESTS_COMMON_HPP
#define OPENCV_GAPI_OPERATOR_TESTS_COMMON_HPP
#include "gapi_tests_common.hpp"
namespace opencv_test
{
struct g_api_ocv_pair_mat_scalar {
using g_api_function_t = std::function<cv::GMat(cv::GMat,cv::GScalar)>;
using ocv_function_t = std::function<void(cv::Mat const&, cv::Scalar, cv::Mat&)>;
std::string name;
g_api_function_t g_api_function;
ocv_function_t ocv_function;
g_api_ocv_pair_mat_scalar(std::string const& n, g_api_function_t const& g, ocv_function_t const& o)
: name(n), g_api_function(g), ocv_function(o) {}
g_api_ocv_pair_mat_scalar() = default;
friend std::ostream& operator<<(std::ostream& o, const g_api_ocv_pair_mat_scalar& p)
{
return o<<p.name;
}
};
struct g_api_ocv_pair_mat_mat {
using g_api_function_t = std::function<cv::GMat(cv::GMat,cv::GMat)>;
using ocv_function_t = std::function<void(cv::Mat const&, cv::Mat const&, cv::Mat&)>;
std::string name;
g_api_function_t g_api_function;
ocv_function_t ocv_function;
g_api_ocv_pair_mat_mat(std::string const& n, g_api_function_t const& g, ocv_function_t const& o)
: name(n), g_api_function(g), ocv_function(o) {}
g_api_ocv_pair_mat_mat() = default;
friend std::ostream& operator<<(std::ostream& o, const g_api_ocv_pair_mat_mat& p)
{
return o<<p.name;
}
};
////////////////////////////////////////////////////////////////////////////////
//
// FIXME: Please refactor this test to a template test (T,U) with enum (OP)
//
////////////////////////////////////////////////////////////////////////////////
namespace
{
//declare test cases for matrix and scalar operators
g_api_ocv_pair_mat_scalar opPlus = {std::string{"operator+"},
[](cv::GMat in,cv::GScalar c){return in+c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::add(in, c, out);}};
g_api_ocv_pair_mat_scalar opPlusR = {std::string{"rev_operator+"},
[](cv::GMat in,cv::GScalar c){return c+in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::add(c, in, out);}};
g_api_ocv_pair_mat_scalar opMinus = {std::string{"operator-"},
[](cv::GMat in,cv::GScalar c){return in-c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::subtract(in, c, out);}};
g_api_ocv_pair_mat_scalar opMinusR = {std::string{"rev_operator-"},
[](cv::GMat in,cv::GScalar c){return c-in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::subtract(c, in, out);}};
g_api_ocv_pair_mat_scalar opMul = {std::string{"operator*"},
[](cv::GMat in,cv::GScalar c){return in*c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::multiply(in, c, out);}};
g_api_ocv_pair_mat_scalar opMulR = {std::string{"rev_operator*"},
[](cv::GMat in,cv::GScalar c){return c*in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::multiply(c, in, out);}};
g_api_ocv_pair_mat_scalar opDiv = {std::string{"operator/"},
[](cv::GMat in,cv::GScalar c){return in/c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::divide(in, c, out);}};
g_api_ocv_pair_mat_scalar opDivR = {std::string{"rev_operator/"},
[](cv::GMat in,cv::GScalar c){return c/in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::divide(c, in, out);}};
g_api_ocv_pair_mat_scalar opGT = {std::string{"operator>"},
[](cv::GMat in,cv::GScalar c){return in>c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_GT);}};
g_api_ocv_pair_mat_scalar opLT = {std::string{"operator<"},
[](cv::GMat in,cv::GScalar c){return in<c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_LT);}};
g_api_ocv_pair_mat_scalar opGE = {std::string{"operator>="},
[](cv::GMat in,cv::GScalar c){return in>=c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_GE);}};
g_api_ocv_pair_mat_scalar opLE = {std::string{"operator<="},
[](cv::GMat in,cv::GScalar c){return in<=c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_LE);}};
g_api_ocv_pair_mat_scalar opEQ = {std::string{"operator=="},
[](cv::GMat in,cv::GScalar c){return in==c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_EQ);}};
g_api_ocv_pair_mat_scalar opNE = {std::string{"operator!="},
[](cv::GMat in,cv::GScalar c){return in!=c;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_NE);}};
g_api_ocv_pair_mat_scalar opGTR = {std::string{"rev_operator>"},
[](cv::GMat in,cv::GScalar c){return c>in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_GT);}};
g_api_ocv_pair_mat_scalar opLTR = {std::string{"rev_operator<"},
[](cv::GMat in,cv::GScalar c){return c<in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_LT);}};
g_api_ocv_pair_mat_scalar opGER = {std::string{"rev_operator>="},
[](cv::GMat in,cv::GScalar c){return c>=in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_GE);}};
g_api_ocv_pair_mat_scalar opLER = {std::string{"rev_operator<="},
[](cv::GMat in,cv::GScalar c){return c<=in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_LE);}};
g_api_ocv_pair_mat_scalar opEQR = {std::string{"rev_operator=="},
[](cv::GMat in,cv::GScalar c){return c==in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_EQ);}};
g_api_ocv_pair_mat_scalar opNER = {std::string{"rev_operator!="},
[](cv::GMat in,cv::GScalar c){return c!=in;},
[](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_NE);}};
g_api_ocv_pair_mat_scalar opAND = {std::string{"operator&"},
[](cv::GMat in1,cv::GScalar in2){return in1&in2;},
[](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_and(in1, in2, out);}};
g_api_ocv_pair_mat_scalar opOR = {std::string{"operator|"},
[](cv::GMat in1,cv::GScalar in2){return in1|in2;},
[](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_or(in1, in2, out);}};
g_api_ocv_pair_mat_scalar opXOR = {std::string{"operator^"},
[](cv::GMat in1,cv::GScalar in2){return in1^in2;},
[](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_xor(in1, in2, out);}};
g_api_ocv_pair_mat_scalar opANDR = {std::string{"rev_operator&"},
[](cv::GMat in1,cv::GScalar in2){return in2&in1;},
[](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_and(in2, in1, out);}};
g_api_ocv_pair_mat_scalar opORR = {std::string{"rev_operator|"},
[](cv::GMat in1,cv::GScalar in2){return in2|in1;},
[](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_or(in2, in1, out);}};
g_api_ocv_pair_mat_scalar opXORR = {std::string{"rev_operator^"},
[](cv::GMat in1,cv::GScalar in2){return in2^in1;},
[](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_xor(in2, in1, out);}};
// declare test cases for matrix and matrix operators
g_api_ocv_pair_mat_mat opPlusM = {std::string{"operator+"},
[](cv::GMat in1,cv::GMat in2){return in1+in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::add(in1, in2, out);}};
g_api_ocv_pair_mat_mat opMinusM = {std::string{"operator-"},
[](cv::GMat in,cv::GMat in2){return in-in2;},
[](const cv::Mat& in, const cv::Mat& in2, cv::Mat& out){cv::subtract(in, in2, out);}};
g_api_ocv_pair_mat_mat opDivM = {std::string{"operator/"},
[](cv::GMat in,cv::GMat in2){return in/in2;},
[](const cv::Mat& in, const cv::Mat& in2, cv::Mat& out){cv::divide(in, in2, out);}};
g_api_ocv_pair_mat_mat opGreater = {std::string{"operator>"},
[](cv::GMat in1,cv::GMat in2){return in1>in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_GT);}};
g_api_ocv_pair_mat_mat opGreaterEq = {std::string{"operator>="},
[](cv::GMat in1,cv::GMat in2){return in1>=in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_GE);}};
g_api_ocv_pair_mat_mat opLess = {std::string{"operator<"},
[](cv::GMat in1,cv::GMat in2){return in1<in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_LT);}};
g_api_ocv_pair_mat_mat opLessEq = {std::string{"operator<="},
[](cv::GMat in1,cv::GMat in2){return in1<=in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_LE);}};
g_api_ocv_pair_mat_mat opEq = {std::string{"operator=="},
[](cv::GMat in1,cv::GMat in2){return in1==in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_EQ);}};
g_api_ocv_pair_mat_mat opNotEq = {std::string{"operator!="},
[](cv::GMat in1,cv::GMat in2){return in1!=in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_NE);}};
g_api_ocv_pair_mat_mat opAnd = {std::string{"operator&"},
[](cv::GMat in1,cv::GMat in2){return in1&in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_and(in1, in2, out);}};
g_api_ocv_pair_mat_mat opOr = {std::string{"operator|"},
[](cv::GMat in1,cv::GMat in2){return in1|in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_or(in1, in2, out);}};
g_api_ocv_pair_mat_mat opXor = {std::string{"operator^"},
[](cv::GMat in1,cv::GMat in2){return in1^in2;},
[](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_xor(in1, in2, out);}};
} // anonymous namespace
// Create new value-parameterized test fixture:
// MathOperatorMatScalarTest - fixture name
// initMatsRandU - function that is used to initialize input/output data
// FIXTURE_API(CompareMats, g_api_ocv_pair_mat_scalar) - test-specific parameters (types)
// 2 - number of test-specific parameters
// cmpF, op - test-spcific parameters (names)
//
// We get:
// 1. Default parameters: int type, cv::Size sz, int dtype, getCompileArgs() function
// - available in test body
// 2. Input/output matrices will be initialized by initMatsRandU (in this fixture)
// 3. Specific parameters: cmpF, op of corresponding types
// - created (and initialized) automatically
// - available in test body
// Note: all parameter _values_ (e.g. type CV_8UC3) are set via INSTANTIATE_TEST_CASE_P macro
GAPI_TEST_FIXTURE(MathOperatorMatScalarTest, initMatsRandU,
FIXTURE_API(CompareMats, g_api_ocv_pair_mat_scalar), 2, cmpF, op)
GAPI_TEST_FIXTURE(MathOperatorMatMatTest, initMatsRandU,
FIXTURE_API(CompareMats, g_api_ocv_pair_mat_mat), 2, cmpF, op)
GAPI_TEST_FIXTURE(NotOperatorTest, initMatrixRandU, <>, 0)
} // opencv_test
#endif // OPENCV_GAPI_OPERATOR_TESTS_COMMON_HPP

View File

@@ -0,0 +1,82 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#ifndef OPENCV_GAPI_OPERATOR_TESTS_INL_COMMON_HPP
#define OPENCV_GAPI_OPERATOR_TESTS_INL_COMMON_HPP
#include "gapi_operators_tests.hpp"
namespace opencv_test
{
TEST_P(MathOperatorMatScalarTest, OperatorAccuracyTest )
{
auto fun_gapi = op.g_api_function;
auto fun_ocv = op.ocv_function ;
// G-API code & corresponding OpenCV code ////////////////////////////////
cv::GMat in1;
cv::GScalar in2;
auto out = fun_gapi(in1, in2);
cv::GComputation c(GIn(in1, in2), GOut(out));
c.apply(gin(in_mat1, sc), gout(out_mat_gapi), getCompileArgs());
fun_ocv(in_mat1, sc, out_mat_ocv);
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(MathOperatorMatMatTest, OperatorAccuracyTest )
{
auto fun_gapi = op.g_api_function;
auto fun_ocv = op.ocv_function ;
// G-API code & corresponding OpenCV code ////////////////////////////////
cv::GMat in1;
cv::GMat in2;
auto out = fun_gapi(in1, in2);
cv::GComputation c(GIn(in1, in2), GOut(out));
c.apply(gin(in_mat1, in_mat2), gout(out_mat_gapi), getCompileArgs());
fun_ocv(in_mat1, in_mat2, out_mat_ocv);
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
TEST_P(NotOperatorTest, OperatorAccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = ~in;
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, getCompileArgs());
// OpenCV code /////////////////////////////////////////////////////////////
{
out_mat_ocv =~in_mat1;
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_ocv != out_mat_gapi));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
} // opencv_test
#endif // OPENCV_GAPI_OPERATOR_TESTS_INL_COMMON_HPP

View File

@@ -0,0 +1,97 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "../test_precomp.hpp"
#include "gapi_render_tests.hpp"
namespace opencv_test
{
cv::Scalar cvtBGRToYUVC(const cv::Scalar& bgr)
{
double y = bgr[2] * 0.299000 + bgr[1] * 0.587000 + bgr[0] * 0.114000;
double u = bgr[2] * -0.168736 + bgr[1] * -0.331264 + bgr[0] * 0.500000 + 128;
double v = bgr[2] * 0.500000 + bgr[1] * -0.418688 + bgr[0] * -0.081312 + 128;
return {y, u, v};
}
void drawMosaicRef(const cv::Mat& mat, const cv::Rect &rect, int cellSz)
{
cv::Rect mat_rect(0, 0, mat.cols, mat.rows);
auto intersection = mat_rect & rect;
cv::Mat msc_roi = mat(intersection);
bool has_crop_x = false;
bool has_crop_y = false;
int cols = msc_roi.cols;
int rows = msc_roi.rows;
if (msc_roi.cols % cellSz != 0)
{
has_crop_x = true;
cols -= msc_roi.cols % cellSz;
}
if (msc_roi.rows % cellSz != 0)
{
has_crop_y = true;
rows -= msc_roi.rows % cellSz;
}
cv::Mat cell_roi;
for(int i = 0; i < rows; i += cellSz )
{
for(int j = 0; j < cols; j += cellSz)
{
cell_roi = msc_roi(cv::Rect(j, i, cellSz, cellSz));
cell_roi = cv::mean(cell_roi);
}
if (has_crop_x)
{
cell_roi = msc_roi(cv::Rect(cols, i, msc_roi.cols - cols, cellSz));
cell_roi = cv::mean(cell_roi);
}
}
if (has_crop_y)
{
for(int j = 0; j < cols; j += cellSz)
{
cell_roi = msc_roi(cv::Rect(j, rows, cellSz, msc_roi.rows - rows));
cell_roi = cv::mean(cell_roi);
}
if (has_crop_x)
{
cell_roi = msc_roi(cv::Rect(cols, rows, msc_roi.cols - cols, msc_roi.rows - rows));
cell_roi = cv::mean(cell_roi);
}
}
}
void blendImageRef(cv::Mat& mat, const cv::Point& org, const cv::Mat& img, const cv::Mat& alpha)
{
auto roi = mat(cv::Rect(org, img.size()));
cv::Mat img32f_w;
cv::merge(std::vector<cv::Mat>(3, alpha), img32f_w);
cv::Mat roi32f_w(roi.size(), CV_32FC3, cv::Scalar::all(1.0));
roi32f_w -= img32f_w;
cv::Mat img32f, roi32f;
img.convertTo(img32f, CV_32F, 1.0/255);
roi.convertTo(roi32f, CV_32F, 1.0/255);
cv::multiply(img32f, img32f_w, img32f);
cv::multiply(roi32f, roi32f_w, roi32f);
roi32f += img32f;
roi32f.convertTo(roi, CV_8U, 255.0);
};
} // namespace opencv_test

View File

@@ -0,0 +1,145 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#ifndef OPENCV_GAPI_RENDER_TESTS_HPP
#define OPENCV_GAPI_RENDER_TESTS_HPP
#include "gapi_tests_common.hpp"
namespace opencv_test
{
template<typename ...SpecificParams>
struct RenderParams : public Params<SpecificParams...>
{
using common_params_t = std::tuple<cv::Size>;
using specific_params_t = std::tuple<SpecificParams...>;
using params_t = std::tuple<cv::Size, SpecificParams...>;
static constexpr const size_t common_params_size = std::tuple_size<common_params_t>::value;
static constexpr const size_t specific_params_size = std::tuple_size<specific_params_t>::value;
template<size_t I>
static const typename std::tuple_element<I, common_params_t>::type&
getCommon(const params_t& t)
{
static_assert(I < common_params_size, "Index out of range");
return std::get<I>(t);
}
template<size_t I>
static const typename std::tuple_element<I, specific_params_t>::type&
getSpecific(const params_t& t)
{
static_assert(specific_params_size > 0,
"Impossible to call this function: no specific parameters specified");
static_assert(I < specific_params_size, "Index out of range");
return std::get<common_params_size + I>(t);
}
};
template<typename ...SpecificParams>
struct RenderTestBase : public TestWithParam<typename RenderParams<SpecificParams...>::params_t>
{
using AllParams = RenderParams<SpecificParams...>;
// Get common (pre-defined) parameter value by index
template<size_t I>
inline auto getCommonParam() const
-> decltype(AllParams::template getCommon<I>(this->GetParam()))
{
return AllParams::template getCommon<I>(this->GetParam());
}
// Get specific (user-defined) parameter value by index
template<size_t I>
inline auto getSpecificParam() const
-> decltype(AllParams::template getSpecific<I>(this->GetParam()))
{
return AllParams::template getSpecific<I>(this->GetParam());
}
cv::Size sz_ = getCommonParam<0>();
};
template <typename ...Args>
class RenderBGRTestBase : public RenderTestBase<Args...>
{
protected:
void Init(const cv::Size& sz)
{
MatType type = CV_8UC3;
ref_mat.create(sz, type);
gapi_mat.create(sz, type);
cv::randu(ref_mat, cv::Scalar::all(0), cv::Scalar::all(255));
ref_mat.copyTo(gapi_mat);
}
cv::Mat gapi_mat, ref_mat;
};
template <typename ...Args>
class RenderNV12TestBase : public RenderTestBase<Args...>
{
protected:
void Init(const cv::Size& sz)
{
auto create_rand_mats = [](const cv::Size& size, MatType type, cv::Mat& ref_mat, cv::Mat& gapi_mat) {
ref_mat.create(size, type);
cv::randu(ref_mat, cv::Scalar::all(0), cv::Scalar::all(255));
ref_mat.copyTo(gapi_mat);
};
create_rand_mats(sz, CV_8UC1, y_ref_mat , y_gapi_mat);
create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat , uv_gapi_mat);
}
cv::Mat y_ref_mat, uv_ref_mat, y_gapi_mat, uv_gapi_mat;
};
cv::Scalar cvtBGRToYUVC(const cv::Scalar& bgr);
void drawMosaicRef(const cv::Mat& mat, const cv::Rect &rect, int cellSz);
void blendImageRef(cv::Mat& mat,
const cv::Point& org,
const cv::Mat& img,
const cv::Mat& alpha);
#define GAPI_RENDER_TEST_FIXTURE_NV12(Fixture, API, Number, ...) \
struct Fixture : public RenderNV12TestBase API { \
__WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
Fixture() { \
Init(sz_); \
}; \
};
#define GAPI_RENDER_TEST_FIXTURE_BGR(Fixture, API, Number, ...) \
struct Fixture : public RenderBGRTestBase API { \
__WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
Fixture() { \
Init(sz_); \
}; \
};
#define GET_VA_ARGS(...) __VA_ARGS__
#define GAPI_RENDER_TEST_FIXTURES(Fixture, API, Number, ...) \
GAPI_RENDER_TEST_FIXTURE_BGR(RenderBGR##Fixture, GET_VA_ARGS(API), Number, __VA_ARGS__) \
GAPI_RENDER_TEST_FIXTURE_NV12(RenderNV12##Fixture, GET_VA_ARGS(API), Number, __VA_ARGS__) \
using Points = std::vector<cv::Point>;
GAPI_RENDER_TEST_FIXTURES(TestTexts, FIXTURE_API(std::string, cv::Point, double, cv::Scalar), 4, text, org, fs, color)
GAPI_RENDER_TEST_FIXTURES(TestRects, FIXTURE_API(cv::Rect, cv::Scalar, int), 3, rect, color, thick)
GAPI_RENDER_TEST_FIXTURES(TestCircles, FIXTURE_API(cv::Point, int, cv::Scalar, int), 4, center, radius, color, thick)
GAPI_RENDER_TEST_FIXTURES(TestLines, FIXTURE_API(cv::Point, cv::Point, cv::Scalar, int), 4, pt1, pt2, color, thick)
GAPI_RENDER_TEST_FIXTURES(TestMosaics, FIXTURE_API(cv::Rect, int, int), 3, mos, cellsz, decim)
GAPI_RENDER_TEST_FIXTURES(TestImages, FIXTURE_API(cv::Rect, cv::Scalar, double), 3, rect, color, transparency)
GAPI_RENDER_TEST_FIXTURES(TestPolylines, FIXTURE_API(Points, cv::Scalar, int), 3, points, color, thick)
} // opencv_test
#endif //OPENCV_GAPI_RENDER_TESTS_HPP

View File

@@ -0,0 +1,627 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#ifndef OPENCV_GAPI_TESTS_COMMON_HPP
#define OPENCV_GAPI_TESTS_COMMON_HPP
#include <iostream>
#include <tuple>
#include <type_traits>
#include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/util/util.hpp>
#include "gapi_tests_helpers.hpp"
#include <opencv2/gapi/render/render.hpp>
namespace
{
inline std::ostream& operator<<(std::ostream& o, const cv::GCompileArg& arg)
{
return o << (arg.tag.empty() ? "empty" : arg.tag);
}
inline std::ostream& operator<<(std::ostream& o, const cv::gapi::wip::draw::Prim& p)
{
using namespace cv::gapi::wip::draw;
switch (p.index())
{
case Prim::index_of<Rect>():
o << "cv::gapi::draw::Rect";
break;
case Prim::index_of<Text>():
o << "cv::gapi::draw::Text";
break;
case Prim::index_of<Circle>():
o << "cv::gapi::draw::Circle";
break;
case Prim::index_of<Line>():
o << "cv::gapi::draw::Line";
break;
case Prim::index_of<Mosaic>():
o << "cv::gapi::draw::Mosaic";
break;
case Prim::index_of<Image>():
o << "cv::gapi::draw::Image";
break;
case Prim::index_of<Poly>():
o << "cv::gapi::draw::Poly";
break;
default: o << "Unrecognized primitive";
}
return o;
}
}
namespace opencv_test
{
class TestFunctional
{
public:
cv::Mat in_mat1;
cv::Mat in_mat2;
cv::Mat out_mat_gapi;
cv::Mat out_mat_ocv;
cv::Scalar sc;
cv::Scalar initScalarRandU(unsigned upper)
{
auto& rng = cv::theRNG();
double s1 = rng(upper); // FIXIT: RNG result is 'int', not double
double s2 = rng(upper);
double s3 = rng(upper);
double s4 = rng(upper);
return cv::Scalar(s1, s2, s3, s4);
}
void initOutMats(cv::Size sz_in, int dtype)
{
if (dtype != -1)
{
out_mat_gapi = cv::Mat(sz_in, dtype);
out_mat_ocv = cv::Mat(sz_in, dtype);
}
}
void initMatsRandU(int type, cv::Size sz_in, int dtype, bool createOutputMatrices = true)
{
in_mat1 = cv::Mat(sz_in, type);
in_mat2 = cv::Mat(sz_in, type);
sc = initScalarRandU(100);
// Details: https://github.com/opencv/opencv/pull/16083
//if (CV_MAT_DEPTH(type) < CV_32F)
if (1)
{
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
}
else
{
const int fscale = 256; // avoid bits near ULP, generate stable test input
Mat in_mat32s(in_mat1.size(), CV_MAKE_TYPE(CV_32S, CV_MAT_CN(type)));
cv::randu(in_mat32s, cv::Scalar::all(0), cv::Scalar::all(255 * fscale));
in_mat32s.convertTo(in_mat1, type, 1.0f / fscale, 0);
cv::randu(in_mat32s, cv::Scalar::all(0), cv::Scalar::all(255 * fscale));
in_mat32s.convertTo(in_mat2, type, 1.0f / fscale, 0);
}
if (createOutputMatrices)
{
initOutMats(sz_in, dtype);
}
}
void initMatrixRandU(int type, cv::Size sz_in, int dtype, bool createOutputMatrices = true)
{
in_mat1 = cv::Mat(sz_in, type);
sc = initScalarRandU(100);
if (CV_MAT_DEPTH(type) < CV_32F)
{
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
}
else
{
const int fscale = 256; // avoid bits near ULP, generate stable test input
Mat in_mat32s(in_mat1.size(), CV_MAKE_TYPE(CV_32S, CV_MAT_CN(type)));
cv::randu(in_mat32s, cv::Scalar::all(0), cv::Scalar::all(255 * fscale));
in_mat32s.convertTo(in_mat1, type, 1.0f / fscale, 0);
}
if (createOutputMatrices)
{
initOutMats(sz_in, dtype);
}
}
void initMatrixRandN(int type, cv::Size sz_in, int dtype, bool createOutputMatrices = true)
{
in_mat1 = cv::Mat(sz_in, type);
cv::randn(in_mat1, cv::Scalar::all(127), cv::Scalar::all(40.f));
if (createOutputMatrices)
{
initOutMats(sz_in, dtype);
}
}
// empty function intended to show that nothing is to be initialized via TestFunctional methods
void initNothing(int, cv::Size, int, bool = true) {}
static cv::Mat nonZeroPixels(const cv::Mat& mat)
{
int channels = mat.channels();
std::vector<cv::Mat> split(channels);
cv::split(mat, split);
cv::Mat result;
for (int c=0; c < channels; c++)
{
if (c == 0)
result = split[c] != 0;
else
result = result | (split[c] != 0);
}
return result;
}
static int countNonZeroPixels(const cv::Mat& mat)
{
return cv::countNonZero( nonZeroPixels(mat) );
}
};
template<class T>
class TestParams: public TestFunctional, public TestWithParam<T>{};
template<class T>
class TestPerfParams: public TestFunctional, public perf::TestBaseWithParam<T>{};
using compare_f = std::function<bool(const cv::Mat &a, const cv::Mat &b)>;
using compare_scalar_f = std::function<bool(const cv::Scalar &a, const cv::Scalar &b)>;
// FIXME: re-use MatType. current problem: "special values" interpreted incorrectly (-1 is printed
// as 16FC512)
struct MatType2
{
public:
MatType2(int val = 0) : _value(val) {}
operator int() const { return _value; }
friend std::ostream& operator<<(std::ostream& os, const MatType2& t)
{
switch (t)
{
case -1: return os << "SAME_TYPE";
default: PrintTo(MatType(t), &os); return os;
}
}
private:
int _value;
};
// Universal parameter wrapper for common (pre-defined) and specific (user-defined) parameters
template<typename ...SpecificParams>
struct Params
{
using gcomp_args_function_t = cv::GCompileArgs(*)();
using common_params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t>;
using specific_params_t = std::tuple<SpecificParams...>;
using params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t, SpecificParams...>;
static constexpr const size_t common_params_size = std::tuple_size<common_params_t>::value;
static constexpr const size_t specific_params_size = std::tuple_size<specific_params_t>::value;
template<size_t I>
static const typename std::tuple_element<I, common_params_t>::type&
getCommon(const params_t& t)
{
static_assert(I < common_params_size, "Index out of range");
return std::get<I>(t);
}
template<size_t I>
static const typename std::tuple_element<I, specific_params_t>::type&
getSpecific(const params_t& t)
{
static_assert(specific_params_size > 0,
"Impossible to call this function: no specific parameters specified");
static_assert(I < specific_params_size, "Index out of range");
return std::get<common_params_size + I>(t);
}
};
// Base class for test fixtures
template<typename ...SpecificParams>
struct TestWithParamBase : TestFunctional,
TestWithParam<typename Params<SpecificParams...>::params_t>
{
using AllParams = Params<SpecificParams...>;
MatType2 type = getCommonParam<0>();
cv::Size sz = getCommonParam<1>();
MatType2 dtype = getCommonParam<2>();
// Get common (pre-defined) parameter value by index
template<size_t I>
inline auto getCommonParam() const
-> decltype(AllParams::template getCommon<I>(this->GetParam()))
{
return AllParams::template getCommon<I>(this->GetParam());
}
// Get specific (user-defined) parameter value by index
template<size_t I>
inline auto getSpecificParam() const
-> decltype(AllParams::template getSpecific<I>(this->GetParam()))
{
return AllParams::template getSpecific<I>(this->GetParam());
}
// Return G-API compile arguments specified for test fixture
inline cv::GCompileArgs getCompileArgs() const
{
return getCommonParam<3>()();
}
};
/**
* @private
* @brief Create G-API test fixture with TestWithParamBase base class
* @param Fixture test fixture name
* @param InitF callable that will initialize default available members (from TestFunctional)
* @param API base class API. Specifies types of user-defined parameters. If there are no such
* parameters, empty angle brackets ("<>") must be specified.
* @param Number number of user-defined parameters (corresponds to the number of types in API).
* if there are no such parameters, 0 must be specified.
* @param ... list of names of user-defined parameters. if there are no parameters, the list
* must be empty.
*/
#define GAPI_TEST_FIXTURE(Fixture, InitF, API, Number, ...) \
struct Fixture : public TestWithParamBase API { \
static_assert(Number == AllParams::specific_params_size, \
"Number of user-defined parameters doesn't match size of __VA_ARGS__"); \
__WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
Fixture() { InitF(type, sz, dtype); } \
};
// Wrapper for test fixture API. Use to specify multiple types.
// Example: FIXTURE_API(int, bool) expands to <int, bool>
#define FIXTURE_API(...) <__VA_ARGS__>
template<typename T1, typename T2>
struct CompareF
{
using callable_t = std::function<bool(const T1& a, const T2& b)>;
CompareF(callable_t&& cmp, std::string&& cmp_name) :
_comparator(std::move(cmp)), _name(std::move(cmp_name)) {}
bool operator()(const T1& a, const T2& b) const
{
return _comparator(a, b);
}
friend std::ostream& operator<<(std::ostream& os, const CompareF<T1, T2>& obj)
{
return os << obj._name;
}
private:
callable_t _comparator;
std::string _name;
};
using CompareMats = CompareF<cv::Mat, cv::Mat>;
using CompareScalars = CompareF<cv::Scalar, cv::Scalar>;
template<typename T>
struct Wrappable
{
compare_f to_compare_f()
{
T t = *static_cast<T*const>(this);
return [t](const cv::Mat &a, const cv::Mat &b)
{
return t(a, b);
};
}
CompareMats to_compare_obj()
{
T t = *static_cast<T*const>(this);
std::stringstream ss;
ss << t;
return CompareMats(to_compare_f(), ss.str());
}
};
template<typename T>
struct WrappableScalar
{
compare_scalar_f to_compare_f()
{
T t = *static_cast<T*const>(this);
return [t](const cv::Scalar &a, const cv::Scalar &b)
{
return t(a, b);
};
}
CompareScalars to_compare_obj()
{
T t = *static_cast<T*const>(this);
std::stringstream ss;
ss << t;
return CompareScalars(to_compare_f(), ss.str());
}
};
class AbsExact : public Wrappable<AbsExact>
{
public:
AbsExact() {}
bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
{
if (cv::norm(in1, in2, NORM_INF) != 0)
{
std::cout << "AbsExact error: G-API output and reference output matrixes are not bitexact equal." << std::endl;
return false;
}
else
{
return true;
}
}
friend std::ostream& operator<<(std::ostream& os, const AbsExact&)
{
return os << "AbsExact()";
}
};
class AbsTolerance : public Wrappable<AbsTolerance>
{
public:
AbsTolerance(double tol) : _tol(tol) {}
bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
{
if (cv::norm(in1, in2, NORM_INF) > _tol)
{
std::cout << "AbsTolerance error: Number of different pixels in " << std::endl;
std::cout << "G-API output and reference output matrixes exceeds " << _tol << " pixels threshold." << std::endl;
return false;
}
else
{
return true;
}
}
friend std::ostream& operator<<(std::ostream& os, const AbsTolerance& obj)
{
return os << "AbsTolerance(" << std::to_string(obj._tol) << ")";
}
private:
double _tol;
};
class Tolerance_FloatRel_IntAbs : public Wrappable<Tolerance_FloatRel_IntAbs>
{
public:
Tolerance_FloatRel_IntAbs(double tol, double tol8u) : _tol(tol), _tol8u(tol8u) {}
bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
{
int depth = CV_MAT_DEPTH(in1.type());
{
double err = depth >= CV_32F ? cv::norm(in1, in2, NORM_L1 | NORM_RELATIVE)
: cv::norm(in1, in2, NORM_INF);
double tolerance = depth >= CV_32F ? _tol : _tol8u;
if (err > tolerance)
{
std::cout << "Tolerance_FloatRel_IntAbs error: err=" << err
<< " tolerance=" << tolerance
<< " depth=" << cv::typeToString(depth) << std::endl;
return false;
}
else
{
return true;
}
}
}
friend std::ostream& operator<<(std::ostream& os, const Tolerance_FloatRel_IntAbs& obj)
{
return os << "Tolerance_FloatRel_IntAbs(" << obj._tol << ", " << obj._tol8u << ")";
}
private:
double _tol;
double _tol8u;
};
class AbsSimilarPoints : public Wrappable<AbsSimilarPoints>
{
public:
AbsSimilarPoints(double tol, double percent) : _tol(tol), _percent(percent) {}
bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
{
Mat diff;
cv::absdiff(in1, in2, diff);
Mat err_mask = diff > _tol;
int err_points = cv::countNonZero(err_mask.reshape(1));
double max_err_points = _percent * std::max((size_t)1000, in1.total());
if (err_points > max_err_points)
{
std::cout << "AbsSimilarPoints error: err_points=" << err_points
<< " max_err_points=" << max_err_points << " (total=" << in1.total() << ")"
<< " diff_tolerance=" << _tol << std::endl;
return false;
}
else
{
return true;
}
}
friend std::ostream& operator<<(std::ostream& os, const AbsSimilarPoints& obj)
{
return os << "AbsSimilarPoints(" << obj._tol << ", " << obj._percent << ")";
}
private:
double _tol;
double _percent;
};
class ToleranceFilter : public Wrappable<ToleranceFilter>
{
public:
ToleranceFilter(double tol, double tol8u, double inf_tol = 2.0) : _tol(tol), _tol8u(tol8u), _inf_tol(inf_tol) {}
bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
{
int depth = CV_MAT_DEPTH(in1.type());
{
double err_Inf = cv::norm(in1, in2, NORM_INF);
if (err_Inf > _inf_tol)
{
std::cout << "ToleranceFilter error: err_Inf=" << err_Inf << " tolerance=" << _inf_tol << std::endl;
return false;
}
double err = cv::norm(in1, in2, NORM_L2 | NORM_RELATIVE);
double tolerance = depth >= CV_32F ? _tol : _tol8u;
if (err > tolerance)
{
std::cout << "ToleranceFilter error: err=" << err << " tolerance=" << tolerance
<< " depth=" << cv::depthToString(depth)
<< std::endl;
return false;
}
}
return true;
}
friend std::ostream& operator<<(std::ostream& os, const ToleranceFilter& obj)
{
return os << "ToleranceFilter(" << obj._tol << ", " << obj._tol8u << ", "
<< obj._inf_tol << ")";
}
private:
double _tol;
double _tol8u;
double _inf_tol;
};
class ToleranceColor : public Wrappable<ToleranceColor>
{
public:
ToleranceColor(double tol, double inf_tol = 2.0) : _tol(tol), _inf_tol(inf_tol) {}
bool operator() (const cv::Mat& in1, const cv::Mat& in2) const
{
{
double err_Inf = cv::norm(in1, in2, NORM_INF);
if (err_Inf > _inf_tol)
{
std::cout << "ToleranceColor error: err_Inf=" << err_Inf << " tolerance=" << _inf_tol << std::endl;;
return false;
}
double err = cv::norm(in1, in2, NORM_L1 | NORM_RELATIVE);
if (err > _tol)
{
std::cout << "ToleranceColor error: err=" << err << " tolerance=" << _tol << std::endl;;
return false;
}
}
return true;
}
friend std::ostream& operator<<(std::ostream& os, const ToleranceColor& obj)
{
return os << "ToleranceColor(" << obj._tol << ", " << obj._inf_tol << ")";
}
private:
double _tol;
double _inf_tol;
};
class AbsToleranceScalar : public WrappableScalar<AbsToleranceScalar>
{
public:
AbsToleranceScalar(double tol) : _tol(tol) {}
bool operator() (const cv::Scalar& in1, const cv::Scalar& in2) const
{
double abs_err = std::abs(in1[0] - in2[0]) / std::max(1.0, std::abs(in2[0]));
if (abs_err > _tol)
{
std::cout << "AbsToleranceScalar error: abs_err=" << abs_err << " tolerance=" << _tol << " in1[0]" << in1[0] << " in2[0]" << in2[0] << std::endl;;
return false;
}
else
{
return true;
}
}
friend std::ostream& operator<<(std::ostream& os, const AbsToleranceScalar& obj)
{
return os << "AbsToleranceScalar(" << std::to_string(obj._tol) << ")";
}
private:
double _tol;
};
} // namespace opencv_test
namespace
{
inline std::ostream& operator<<(std::ostream& os, const opencv_test::compare_f&)
{
return os << "compare_f";
}
inline std::ostream& operator<<(std::ostream& os, const opencv_test::compare_scalar_f&)
{
return os << "compare_scalar_f";
}
} // anonymous namespace
// Note: namespace must match the namespace of the type of the printed object
namespace cv
{
inline std::ostream& operator<<(std::ostream& os, CmpTypes op)
{
#define CASE(v) case CmpTypes::v: os << #v; break
switch (op)
{
CASE(CMP_EQ);
CASE(CMP_GT);
CASE(CMP_GE);
CASE(CMP_LT);
CASE(CMP_LE);
CASE(CMP_NE);
default: GAPI_Assert(false && "unknown CmpTypes value");
}
#undef CASE
return os;
}
inline std::ostream& operator<<(std::ostream& os, NormTypes op)
{
#define CASE(v) case NormTypes::v: os << #v; break
switch (op)
{
CASE(NORM_INF);
CASE(NORM_L1);
CASE(NORM_L2);
CASE(NORM_L2SQR);
CASE(NORM_HAMMING);
CASE(NORM_HAMMING2);
CASE(NORM_RELATIVE);
CASE(NORM_MINMAX);
default: GAPI_Assert(false && "unknown NormTypes value");
}
#undef CASE
return os;
}
} // namespace cv
#endif //OPENCV_GAPI_TESTS_COMMON_HPP

View File

@@ -0,0 +1,81 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#ifndef OPENCV_GAPI_TESTS_HELPERS_HPP
#define OPENCV_GAPI_TESTS_HELPERS_HPP
#include <tuple>
#include <limits>
namespace opencv_test
{
// Ensure correct __VA_ARGS__ expansion on Windows
#define __WRAP_VAARGS(x) x
#define __TUPLE_PARAM_TYPE(i) std::tuple_element<i, AllParams::specific_params_t>::type
// implementation of recursive in-class declaration and initialization of member variables
#define __DEFINE_PARAMS_IMPL1(index, param_name) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>();
#define __DEFINE_PARAMS_IMPL2(index, param_name, ...) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>(); \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL1(index+1, __VA_ARGS__))
#define __DEFINE_PARAMS_IMPL3(index, param_name, ...) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>(); \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL2(index+1, __VA_ARGS__))
#define __DEFINE_PARAMS_IMPL4(index, param_name, ...) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>(); \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL3(index+1, __VA_ARGS__))
#define __DEFINE_PARAMS_IMPL5(index, param_name, ...) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>(); \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL4(index+1, __VA_ARGS__))
#define __DEFINE_PARAMS_IMPL6(index, param_name, ...) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>(); \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL5(index+1, __VA_ARGS__))
#define __DEFINE_PARAMS_IMPL7(index, param_name, ...) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>(); \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL6(index+1, __VA_ARGS__))
#define __DEFINE_PARAMS_IMPL8(index, param_name, ...) \
__TUPLE_PARAM_TYPE(index) param_name = getSpecificParam<index>(); \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL7(index+1, __VA_ARGS__))
// user interface to define member variables of specified names
#define DEFINE_SPECIFIC_PARAMS_0()
#define DEFINE_SPECIFIC_PARAMS_1(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL1(0, __VA_ARGS__))
#define DEFINE_SPECIFIC_PARAMS_2(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL2(0, __VA_ARGS__))
#define DEFINE_SPECIFIC_PARAMS_3(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL3(0, __VA_ARGS__))
#define DEFINE_SPECIFIC_PARAMS_4(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL4(0, __VA_ARGS__))
#define DEFINE_SPECIFIC_PARAMS_5(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL5(0, __VA_ARGS__))
#define DEFINE_SPECIFIC_PARAMS_6(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL6(0, __VA_ARGS__))
#define DEFINE_SPECIFIC_PARAMS_7(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL7(0, __VA_ARGS__))
#define DEFINE_SPECIFIC_PARAMS_8(...) \
__WRAP_VAARGS(__DEFINE_PARAMS_IMPL8(0, __VA_ARGS__))
} // namespace opencv_test
#endif //OPENCV_GAPI_TESTS_HELPERS_HPP

View File

@@ -0,0 +1,473 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_core_tests.hpp"
#include <opencv2/gapi/cpu/core.hpp>
namespace
{
#define CORE_CPU [] () { return cv::compile_args(cv::gapi::core::cpu::kernels()); }
} // anonymous namespace
namespace opencv_test
{
// FIXME: Wut? See MulTestCPU/MathOpTest below (duplicate?)
INSTANTIATE_TEST_CASE_P(AddTestCPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU),
Values(ADD, MUL),
testing::Bool(),
Values(1.0),
Values(false)));
INSTANTIATE_TEST_CASE_P(MulTestCPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU),
Values(MUL),
testing::Bool(),
Values(1.0, 0.5, 2.0),
Values(false)));
INSTANTIATE_TEST_CASE_P(SubTestCPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU),
Values(SUB),
testing::Bool(),
Values (1.0),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(DivTestCPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU),
Values(DIV),
testing::Bool(),
Values (1.0, 0.5, 2.0),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(MulTestCPU, MulDoubleTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(DivTestCPU, DivTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(DivCTestCPU, DivCTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(MeanTestCPU, MeanTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(MaskTestCPU, MaskTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(SelectTestCPU, SelectTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(Polar2CartCPU, Polar2CartTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_32FC1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(Cart2PolarCPU, Cart2PolarTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_32FC1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(PhaseCPU, PhaseTest,
Combine(Values(CV_32F, CV_32FC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
/* angle_in_degrees */ testing::Bool()));
INSTANTIATE_TEST_CASE_P(SqrtCPU, SqrtTest,
Combine(Values(CV_32F, CV_32FC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(CompareTestCPU, CmpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U),
Values(CORE_CPU),
Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(BitwiseTestCPU, BitwiseTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(AND, OR, XOR)));
INSTANTIATE_TEST_CASE_P(BitwiseNotTestCPU, NotTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(MinTestCPU, MinTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(MaxTestCPU, MaxTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(SumTestCPU, SumTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
//Values(1e-5),
Values(CORE_CPU),
Values(AbsToleranceScalar(1e-5).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(AbsDiffTestCPU, AbsDiffTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(AbsDiffCTestCPU, AbsDiffCTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(AddWeightedTestCPU, AddWeightedTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_CPU),
Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(NormTestCPU, NormTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(AbsToleranceScalar(1e-5).to_compare_obj()),
Values(NORM_INF, NORM_L1, NORM_L2)));
INSTANTIATE_TEST_CASE_P(IntegralTestCPU, IntegralTest,
Combine(Values( CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(ThresholdTestCPU, ThresholdTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC,
cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV),
Values(cv::Scalar(0, 0, 0, 0),
cv::Scalar(100, 100, 100, 100),
cv::Scalar(255, 255, 255, 255))));
INSTANTIATE_TEST_CASE_P(ThresholdTestCPU, ThresholdOTTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE)));
INSTANTIATE_TEST_CASE_P(InRangeTestCPU, InRangeTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(Split3TestCPU, Split3Test,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(Split4TestCPU, Split4Test,
Combine(Values(CV_8UC4),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(AbsSimilarPoints(2, 0.05).to_compare_obj()),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values(cv::Size(64,64),
cv::Size(30,30))));
INSTANTIATE_TEST_CASE_P(ResizePTestCPU, ResizePTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(AbsSimilarPoints(2, 0.05).to_compare_obj()),
Values(cv::INTER_LINEAR),
Values(cv::Size(64,64),
cv::Size(30,30))));
INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeTestFxFy,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(AbsSimilarPoints(2, 0.05).to_compare_obj()),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values(0.5, 0.1),
Values(0.5, 0.1)));
INSTANTIATE_TEST_CASE_P(Merge3TestCPU, Merge3Test,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC3),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(Merge4TestCPU, Merge4Test,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC4),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(RemapTestCPU, RemapTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(FlipTestCPU, FlipTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(0,1,-1)));
INSTANTIATE_TEST_CASE_P(CropTestCPU, CropTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50))));
INSTANTIATE_TEST_CASE_P(CopyTestCPU, CopyTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(LUTTestCPU, LUTTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(LUTTestCustomCPU, LUTTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC3),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(ConvertToCPU, ConvertToTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U, CV_16U, CV_16S, CV_32F),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
Values(2.5, 1.0, -1.0),
Values(250.0, 0.0, -128.0)));
INSTANTIATE_TEST_CASE_P(ConcatHorTestCPU, ConcatHorTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(ConcatVertTestCPU, ConcatVertTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(ConcatVertVecTestCPU, ConcatVertVecTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(ConcatHorVecTestCPU, ConcatHorVecTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(NormalizeTestCPU, NormalizeTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
Values(0.0, 15.0),
Values(1.0, 120.0, 255.0),
Values(NORM_MINMAX, NORM_INF, NORM_L1, NORM_L2),
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F)));
// PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestCPU, BackendOutputAllocationTest,
Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1),
Values(cv::Size(50, 50)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(BackendOutputAllocationLargeSizeWithCorrectSubmatrixTestCPU,
BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest,
Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1),
Values(cv::Size(50, 50)),
Values(-1),
Values(CORE_CPU)));
INSTANTIATE_TEST_CASE_P(ReInitOutTestCPU, ReInitOutTest,
Combine(Values(CV_8UC3, CV_16SC4, CV_32FC1),
Values(cv::Size(640, 480)),
Values(-1),
Values(CORE_CPU),
Values(cv::Size(640, 400),
cv::Size(10, 480))));
}

View File

@@ -0,0 +1,544 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_core_tests.hpp"
namespace
{
#define CORE_FLUID [] () { return cv::compile_args(cv::gapi::core::fluid::kernels()); }
} // anonymous namespace
namespace opencv_test
{
// FIXME: Windows accuracy problems after recent update!
INSTANTIATE_TEST_CASE_P(MathOpTestFluid, MathOpTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_FLUID),
Values(ADD, SUB, DIV, MUL),
testing::Bool(),
Values(1.0),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(MulSTestFluid, MulDoubleTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1), // FIXME: extend with more types
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(DivCTestFluid, DivCTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U, CV_32F),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(AbsDiffTestFluid, AbsDiffTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(AbsDiffCTestFluid, AbsDiffCTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(BitwiseTestFluid, BitwiseTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID),
Values(AND, OR, XOR)));
INSTANTIATE_TEST_CASE_P(BitwiseNotTestFluid, NotTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(MinTestFluid, MinTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(MaxTestFluid, MaxTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(CompareTestFluid, CmpTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U),
Values(CORE_FLUID),
Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(AddWeightedTestFluid, AddWeightedTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_FLUID),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(LUTTestFluid, LUTTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(ConvertToFluid, ConvertToTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U, CV_16U, CV_32F),
Values(CORE_FLUID),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj()),
Values(2.5, 1.0, -1.0),
Values(250.0, 0.0, -128.0)));
INSTANTIATE_TEST_CASE_P(Split3TestFluid, Split3Test,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(Split4TestFluid, Split4Test,
Combine(Values(CV_8UC4),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(Merge3TestFluid, Merge3Test,
Combine(Values(CV_8UC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC3),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(Merge4TestFluid, Merge4Test,
Combine(Values(CV_8UC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC4),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(SelectTestFluid, SelectTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(Polar2CartFluid, Polar2CartTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_32FC1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(Cart2PolarFluid, Cart2PolarTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_32FC1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(PhaseFluid, PhaseTest,
Combine(Values(CV_32F, CV_32FC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID),
/* angle_in_degrees */ testing::Bool()));
INSTANTIATE_TEST_CASE_P(SqrtFluid, SqrtTest,
Combine(Values(CV_32F, CV_32FC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(ThresholdTestFluid, ThresholdTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID),
Values(cv::THRESH_BINARY, cv::THRESH_BINARY_INV,
cv::THRESH_TRUNC,
cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV),
Values(cv::Scalar(0, 0, 0, 0),
cv::Scalar(100, 100, 100, 100),
cv::Scalar(255, 255, 255, 255))));
INSTANTIATE_TEST_CASE_P(InRangeTestFluid, InRangeTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1920, 1080),
cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(ResizeTestFluid, ResizeTest,
Combine(Values(CV_8UC3/*CV_8UC1, CV_16UC1, CV_16SC1*/),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128),
cv::Size(64, 64),
cv::Size(30, 30)),
Values(-1),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
Values(/*cv::INTER_NEAREST,*/ cv::INTER_LINEAR/*, cv::INTER_AREA*/),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128),
cv::Size(64, 64),
cv::Size(30, 30))));
INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestFluid, BackendOutputAllocationTest,
Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1),
Values(cv::Size(50, 50)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(BackendOutputAllocationLargeSizeWithCorrectSubmatrixTestFluid,
BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest,
Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1),
Values(cv::Size(50, 50)),
Values(-1),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(ReInitOutTestFluid, ReInitOutTest,
Combine(Values(CV_8UC3, CV_16SC4, CV_32FC1),
Values(cv::Size(640, 480)),
Values(-1),
Values(CORE_FLUID),
Values(cv::Size(640, 400),
cv::Size(10, 480))));
INSTANTIATE_TEST_CASE_P(CopyTestFluid, CopyTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
//----------------------------------------------------------------------
// FIXME: Clean-up test configurations which are enabled already
#if 0
INSTANTIATE_TEST_CASE_P(MathOpTestCPU, MathOpTest,
Combine(Values(ADD, DIV, MUL),
testing::Bool(),
Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
/*init output matrices or not*/ testing::Bool(),
Values(false)));
INSTANTIATE_TEST_CASE_P(SubTestCPU, MathOpTest,
Combine(Values(SUB),
testing::Bool(),
Values(CV_8UC1, CV_16SC1 , CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
/*init output matrices or not*/ testing::Bool(),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(MulSTestCPU, MulSTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(DivCTestCPU, DivCTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U, CV_32F),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(MeanTestCPU, MeanTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(SelectTestCPU, SelectTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(Polar2CartCPU, Polar2CartTest,
Combine(Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(Cart2PolarCPU, Cart2PolarTest,
Combine(Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(CompareTestCPU, CmpTest,
Combine(Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
testing::Bool(),
Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(BitwiseTestCPU, BitwiseTest,
Combine(Values(AND, OR, XOR),
Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(BitwiseNotTestCPU, NotTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(MinTestCPU, MinTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(MaxTestCPU, MaxTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(SumTestCPU, SumTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool())
Values(0.0),
);
INSTANTIATE_TEST_CASE_P(AbsDiffTestCPU, AbsDiffTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(AbsDiffCTestCPU, AbsDiffCTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(AddWeightedTestCPU, AddWeightedTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(NormTestCPU, NormTest,
Combine(Values(NORM_INF, NORM_L1, NORM_L2),
Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))),
Values(0.0));
INSTANTIATE_TEST_CASE_P(IntegralTestCPU, IntegralTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
INSTANTIATE_TEST_CASE_P(ThresholdTestCPU, ThresholdTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(ThresholdTestCPU, ThresholdOTTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(InRangeTestCPU, InRangeTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(Split3TestCPU, Split3Test,
(Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
INSTANTIATE_TEST_CASE_P(Split4TestCPU, Split4Test,
(Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
INSTANTIATE_TEST_CASE_P(Merge3TestCPU, Merge3Test,
(Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
INSTANTIATE_TEST_CASE_P(Merge4TestCPU, Merge4Test,
(Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
INSTANTIATE_TEST_CASE_P(RemapTestCPU, RemapTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(FlipTestCPU, FlipTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(0,1,-1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(CropTestCPU, CropTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50)),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ testing::Bool()));
INSTANTIATE_TEST_CASE_P(LUTTestCPU, LUTTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ Values(true)));
INSTANTIATE_TEST_CASE_P(LUTTestCustomCPU, LUTTest,
Combine(Values(CV_8UC3),
Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
/*init output matrices or not*/ Values(true)));
// PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
INSTANTIATE_TEST_CASE_P(ConvertToCPU, ConvertToTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
Values(CV_8U, CV_16U, CV_32F),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
INSTANTIATE_TEST_CASE_P(ConcatHorTestCPU, ConcatHorTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
INSTANTIATE_TEST_CASE_P(ConcatVertTestCPU, ConcatVertTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128))));
//----------------------------------------------------------------------
#endif // 0
}

View File

@@ -0,0 +1,326 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_imgproc_tests.hpp"
#include <opencv2/gapi/cpu/imgproc.hpp>
namespace
{
#define IMGPROC_CPU [] () { return cv::compile_args(cv::gapi::imgproc::cpu::kernels()); }
} // anonymous namespace
namespace opencv_test
{
INSTANTIATE_TEST_CASE_P(Filter2DTestCPU, Filter2DTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_32F),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(cv::Size(3, 3),
cv::Size(4, 4),
cv::Size(5, 5),
cv::Size(7, 7)),
Values(cv::BORDER_DEFAULT)));
INSTANTIATE_TEST_CASE_P(BoxFilterTestCPU, BoxFilterTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_32F),
Values(IMGPROC_CPU),
Values(AbsTolerance(0).to_compare_obj()),
Values(3,5),
Values(cv::BORDER_DEFAULT)));
INSTANTIATE_TEST_CASE_P(SepFilterTestCPU_8U, SepFilterTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_16S, CV_32F),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3)));
INSTANTIATE_TEST_CASE_P(SepFilterTestCPU_other, SepFilterTest,
Combine(Values(CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_32F),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3)));
INSTANTIATE_TEST_CASE_P(BlurTestCPU, BlurTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_CPU),
Values(AbsTolerance(0.0).to_compare_obj()),
Values(3,5),
Values(cv::BORDER_DEFAULT)));
INSTANTIATE_TEST_CASE_P(gaussBlurTestCPU, GaussianBlurTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5)));
INSTANTIATE_TEST_CASE_P(MedianBlurTestCPU, MedianBlurTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5)));
INSTANTIATE_TEST_CASE_P(ErodeTestCPU, ErodeTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(Erode3x3TestCPU, Erode3x3Test,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(1,2,4)));
INSTANTIATE_TEST_CASE_P(DilateTestCPU, DilateTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(Dilate3x3TestCPU, Dilate3x3Test,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(1,2,4)));
INSTANTIATE_TEST_CASE_P(SobelTestCPU, SobelTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_16S, CV_32F),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(0, 1),
Values(1, 2)));
INSTANTIATE_TEST_CASE_P(SobelTestCPU32F, SobelTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_32F),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(0, 1),
Values(1, 2)));
INSTANTIATE_TEST_CASE_P(SobelXYTestCPU, SobelXYTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_16S, CV_32F),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(1, 2),
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT),
Values(0, 1, 255)));
INSTANTIATE_TEST_CASE_P(SobelXYTestCPU32F, SobelXYTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_32F),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(1, 2),
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT),
Values(0, 1, 255)));
INSTANTIATE_TEST_CASE_P(EqHistTestCPU, EqHistTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(CannyTestCPU, CannyTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_CPU),
Values(AbsSimilarPoints(0, 0.05).to_compare_obj()),
Values(3.0, 120.0),
Values(125.0, 240.0),
Values(3, 5),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(RGB2GrayTestCPU, RGB2GrayTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BGR2GrayTestCPU, BGR2GrayTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2YUVTestCPU, RGB2YUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(YUV2RGBTestCPU, YUV2RGBTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(NV12toRGBTestCPU, NV12toRGBTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(NV12toBGRTestCPU, NV12toBGRTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(NV12toRGBpTestCPU, NV12toRGBpTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(NV12toBGRpTestCPU, NV12toBGRpTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2LabTestCPU, RGB2LabTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BGR2LUVTestCPU, BGR2LUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(LUV2BGRTestCPU, LUV2BGRTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BGR2YUVTestCPU, BGR2YUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(YUV2BGRTestCPU, YUV2BGRTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2HSVTestCPU, RGB2HSVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BayerGR2RGBTestCPU, BayerGR2RGBTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_CPU),
Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2YUV422TestCPU, RGB2YUV422Test,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC2),
Values(IMGPROC_CPU),
Values(AbsTolerance(1).to_compare_obj())));
} // opencv_test

View File

@@ -0,0 +1,220 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_imgproc_tests.hpp"
namespace
{
#define IMGPROC_FLUID [] () { return cv::compile_args(cv::gapi::imgproc::fluid::kernels()); }
} // anonymous namespace
namespace opencv_test
{
INSTANTIATE_TEST_CASE_P(RGB2GrayTestFluid, RGB2GrayTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_FLUID),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BGR2GrayTestFluid, BGR2GrayTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_FLUID),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2YUVTestFluid, RGB2YUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_FLUID),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(YUV2RGBTestFluid, YUV2RGBTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_FLUID),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2LabTestFluid, RGB2LabTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_FLUID),
Values(AbsSimilarPoints(1, 0.05).to_compare_obj())));
// FIXME: Not supported by Fluid yet (no kernel implemented)
INSTANTIATE_TEST_CASE_P(BGR2LUVTestFluid, BGR2LUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_FLUID),
Values(ToleranceColor(5e-3, 6).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2HSVTestFluid, RGB2HSVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_FLUID),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BayerGR2RGBTestFluid, BayerGR2RGBTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_FLUID),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2YUV422TestFluid, RGB2YUV422Test,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC2),
Values(IMGPROC_FLUID),
Values(AbsTolerance(1).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(blurTestFluid, BlurTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_FLUID),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(3), // add kernel size=5 when implementation is ready
Values(cv::BORDER_DEFAULT)));
INSTANTIATE_TEST_CASE_P(gaussBlurTestFluid, GaussianBlurTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_FLUID),
Values(ToleranceFilter(1e-3f, 0.01).to_compare_obj()),
Values(3, 5)));
INSTANTIATE_TEST_CASE_P(medianBlurTestFluid, MedianBlurTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_FLUID),
Values(AbsExact().to_compare_obj()),
Values(3))); // add kernel size=5 when implementation is ready
INSTANTIATE_TEST_CASE_P(erodeTestFluid, ErodeTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_FLUID),
Values(AbsExact().to_compare_obj()),
Values(3), // add kernel size=5 when implementation is ready
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(dilateTestFluid, DilateTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_FLUID),
Values(AbsExact().to_compare_obj()),
Values(3), // add kernel size=5 when implementation is ready
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(SobelTestFluid, SobelTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_16S, CV_32F),
Values(IMGPROC_FLUID),
Values(AbsExact().to_compare_obj()),
Values(3), // add kernel size=5 when implementation is ready
Values(0, 1),
Values(1, 2)));
INSTANTIATE_TEST_CASE_P(SobelTestFluid32F, SobelTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_32F),
Values(IMGPROC_FLUID),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(3), // add kernel size=5 when implementation is ready
Values(0, 1),
Values(1, 2)));
INSTANTIATE_TEST_CASE_P(SobelXYTestFluid, SobelXYTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_16S, CV_32F),
Values(IMGPROC_FLUID),
Values(AbsExact().to_compare_obj()),
Values(3),
Values(1, 2),
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101),
Values(0, 1, 255)));
INSTANTIATE_TEST_CASE_P(SobelXYTestFluid32F, SobelXYTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_32F),
Values(IMGPROC_FLUID),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(3),
Values(1, 2),
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101),
Values(0, 1, 255)));
INSTANTIATE_TEST_CASE_P(boxFilterTestFluid32, BoxFilterTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_32F),
Values(IMGPROC_FLUID),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(3), // add kernel size=5 when implementation is ready
Values(cv::BORDER_DEFAULT)));
INSTANTIATE_TEST_CASE_P(sepFilterTestFluid, SepFilterTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_32F),
Values(IMGPROC_FLUID),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(3))); // add kernel size=5 when implementation is ready
INSTANTIATE_TEST_CASE_P(filter2DTestFluid, Filter2DTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_32F),
Values(IMGPROC_FLUID),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(cv::Size(3, 3)), // add kernel size=4x4,5x5,7x7 when implementation ready
Values(cv::BORDER_DEFAULT)));
} // opencv_test

View File

@@ -0,0 +1,71 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_operators_tests.hpp"
#include <opencv2/gapi/cpu/core.hpp>
namespace
{
#define CORE_CPU [] () { return cv::compile_args(cv::gapi::core::cpu::kernels()); }
} // anonymous namespace
namespace opencv_test
{
// FIXME: CPU test runs are disabled since Fluid is an exclusive plugin now!
INSTANTIATE_TEST_CASE_P(MathOperatorTestCPU, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
Values( opPlusM, opMinusM, opDivM,
opGreater, opLess, opGreaterEq, opLessEq, opEq, opNotEq)));
INSTANTIATE_TEST_CASE_P(MathOperatorTestCPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
Values( opPlus, opPlusR, opMinus, opMinusR, opMul, opMulR, // FIXIT avoid division by values near zero: opDiv, opDivR,
opGT, opLT, opGE, opLE, opEQ, opNE,
opGTR, opLTR, opGER, opLER, opEQR, opNER)));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestCPU, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
Values( opAnd, opOr, opXor )));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestCPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
Values( opAND, opOR, opXOR, opANDR, opORR, opXORR )));
INSTANTIATE_TEST_CASE_P(BitwiseNotOperatorTestCPU, NotOperatorTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU)));
}

View File

@@ -0,0 +1,71 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_operators_tests.hpp"
namespace
{
#define CORE_FLUID [] () { return cv::compile_args(cv::gapi::core::fluid::kernels()); }
} // anonymous namespace
namespace opencv_test
{
INSTANTIATE_TEST_CASE_P(MathOperatorTestFluid, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
Values( opPlusM, opMinusM, opDivM,
opGreater, opLess, opGreaterEq, opLessEq, opEq, opNotEq)));
//FIXME: Some Mat/Scalar Fluid kernels are not there yet!
INSTANTIATE_TEST_CASE_P(DISABLED_MathOperatorTestFluid, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
Values( opPlus, opPlusR, opMinus, opMinusR, opMul, opMulR, // FIXIT avoid division by values near zero: opDiv, opDivR,
opGT, opLT, opGE, opLE, opEQ, opNE,
opGTR, opLTR, opGER, opLER, opEQR, opNER)));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestFluid, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
Values( opAnd, opOr, opXor )));
//FIXME: Some Mat/Scalar Fluid kernels are not there yet!
INSTANTIATE_TEST_CASE_P(DISABLED_BitwiseOperatorTestFluid, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
Values( opAND, opOR, opXOR, opANDR, opORR, opXORR )));
INSTANTIATE_TEST_CASE_P(BitwiseNotOperatorTestFluid, NotOperatorTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
}

View File

@@ -0,0 +1,190 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <vector>
#include <ade/util/algorithm.hpp>
namespace opencv_test
{
namespace ThisTest
{
using GPointArray = cv::GArray<cv::Point>;
G_TYPED_KERNEL(GeneratePoints, <GPointArray(GMat)>, "test.array.out_const")
{
static GArrayDesc outMeta(const GMatDesc&) { return empty_array_desc(); }
};
G_TYPED_KERNEL(FindCorners, <GPointArray(GMat)>, "test.array.out")
{
static GArrayDesc outMeta(const GMatDesc&) { return empty_array_desc(); }
};
G_TYPED_KERNEL(CountCorners, <GScalar(GPointArray)>, "test.array.in")
{
static GScalarDesc outMeta(const GArrayDesc &) { return empty_scalar_desc(); }
};
} // namespace ThisTest
namespace
{
GAPI_OCV_KERNEL(OCVGeneratePoints, ThisTest::GeneratePoints)
{
static void run(cv::Mat, std::vector<cv::Point> &out)
{
for (int i = 0; i < 10; i++)
out.emplace_back(i, i);
}
};
GAPI_OCV_KERNEL(OCVFindCorners, ThisTest::FindCorners)
{
static void run(cv::Mat in, std::vector<cv::Point> &out)
{
cv::goodFeaturesToTrack(in, out, 1024, 0.01, 3);
}
};
GAPI_OCV_KERNEL(OCVCountCorners, ThisTest::CountCorners)
{
static void run(const std::vector<cv::Point> &in, cv::Scalar &out)
{
out[0] = static_cast<double>(in.size());
}
};
cv::Mat cross(int w, int h)
{
cv::Mat mat = cv::Mat::eye(h, w, CV_8UC1)*255;
cv::Mat yee;
cv::flip(mat, yee, 0); // X-axis
mat |= yee; // make an "X" matrix;
return mat;
}
} // (anonymous namespace)
TEST(GArray, TestReturnValue)
{
// FIXME: Make .apply() able to take compile arguments
cv::GComputationT<ThisTest::GPointArray(cv::GMat)> c(ThisTest::FindCorners::on);
auto cc = c.compile(cv::GMatDesc{CV_8U,1,{32,32}},
cv::compile_args(cv::gapi::kernels<OCVFindCorners>()));
// Prepare input matrix
cv::Mat input = cross(32, 32);
std::vector<cv::Point> points;
cc(input, points);
// OCV goodFeaturesToTrack should find 5 points here (with these settings)
EXPECT_EQ(5u, points.size());
EXPECT_TRUE(ade::util::find(points, cv::Point(16,16)) != points.end());
EXPECT_TRUE(ade::util::find(points, cv::Point(30,30)) != points.end());
EXPECT_TRUE(ade::util::find(points, cv::Point( 1,30)) != points.end());
EXPECT_TRUE(ade::util::find(points, cv::Point(30, 1)) != points.end());
EXPECT_TRUE(ade::util::find(points, cv::Point( 1, 1)) != points.end());
}
TEST(GArray, TestInputArg)
{
cv::GComputationT<cv::GScalar(ThisTest::GPointArray)> c(ThisTest::CountCorners::on);
auto cc = c.compile(cv::empty_array_desc(),
cv::compile_args(cv::gapi::kernels<OCVCountCorners>()));
const std::vector<cv::Point> arr = {cv::Point(1,1), cv::Point(2,2)};
cv::Scalar out;
cc(arr, out);
EXPECT_EQ(2, out[0]);
}
TEST(GArray, TestPipeline)
{
cv::GComputationT<cv::GScalar(cv::GMat)> c([](cv::GMat in)
{
return ThisTest::CountCorners::on(ThisTest::FindCorners::on(in));
});
auto cc = c.compile(cv::GMatDesc{CV_8U,1,{32,32}},
cv::compile_args(cv::gapi::kernels<OCVFindCorners, OCVCountCorners>()));
cv::Mat input = cross(32, 32);
cv::Scalar out;
cc(input, out);
EXPECT_EQ(5, out[0]);
}
TEST(GArray, NoAggregationBetweenRuns)
{
cv::GComputationT<cv::GScalar(cv::GMat)> c([](cv::GMat in)
{
return ThisTest::CountCorners::on(ThisTest::GeneratePoints::on(in));
});
auto cc = c.compile(cv::GMatDesc{CV_8U,1,{32,32}},
cv::compile_args(cv::gapi::kernels<OCVGeneratePoints, OCVCountCorners>()));
cv::Mat input = cv::Mat::eye(32, 32, CV_8UC1);
cv::Scalar out;
cc(input, out);
EXPECT_EQ(10, out[0]);
// Last kernel in the graph counts number of elements in array, returned by the previous kernel
// (in this test, this variable is constant).
// After 10 executions, this number MUST remain the same - 1st kernel is adding new values on every
// run, but it is graph's responsibility to reset internal object state.
cv::Scalar out2;
for (int i = 0; i < 10; i++)
{
cc(input, out2);
}
EXPECT_EQ(10, out2[0]);
}
TEST(GArray, TestIntermediateOutput)
{
using Result = std::tuple<ThisTest::GPointArray, cv::GScalar>;
cv::GComputationT<Result(cv::GMat)> c([](cv::GMat in)
{
auto corners = ThisTest::GeneratePoints::on(in);
return std::make_tuple(corners, ThisTest::CountCorners::on(corners));
});
cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
std::vector<cv::Point> out_points;
cv::Scalar out_count;
auto cc = c.compile(cv::descr_of(in_mat),
cv::compile_args(cv::gapi::kernels<OCVGeneratePoints, OCVCountCorners>()));
cc(in_mat, out_points, out_count);
EXPECT_EQ(10u, out_points.size());
EXPECT_EQ(10, out_count[0]);
}
TEST(GArray_VectorRef, TestMov)
{
// Warning: this test is testing some not-very-public APIs
// Test how VectorRef's mov() (aka poor man's move()) is working.
using I = int;
using V = std::vector<I>;
const V vgold = { 1, 2, 3};
V vtest = vgold;
const I* vptr = vtest.data();
cv::detail::VectorRef vref(vtest);
cv::detail::VectorRef vmov;
vmov.reset<I>();
EXPECT_EQ(vgold, vref.rref<I>());
vmov.mov(vref);
EXPECT_EQ(vgold, vmov.rref<I>());
EXPECT_EQ(vptr, vmov.rref<I>().data());
EXPECT_EQ(V{}, vref.rref<I>());
EXPECT_EQ(V{}, vtest);
}
} // namespace opencv_test

View File

@@ -0,0 +1,526 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "test_precomp.hpp"
#include <opencv2/gapi/gcomputation_async.hpp>
#include <opencv2/gapi/gcompiled_async.hpp>
#include <opencv2/gapi/gasync_context.hpp>
#include <condition_variable>
#include <stdexcept>
namespace opencv_test
{
//Main idea behind these tests is to have the same test script that is parameterized in order to test all setups (GCompiled vs apply, callback vs future).
//So these differences are factored into devoted helper classes (mixins) which are then used by the common test script by help of CRTP.
//Actual GAPI Computation with parameters to run on is mixed into test via CRTP as well.
struct SumOfSum2x2 {
cv::GComputation sum_of_sum;
SumOfSum2x2() : sum_of_sum([]{
cv::GMat in;
cv::GScalar out = cv::gapi::sum(in + in);
return GComputation{in, out};
})
{}
const cv::Size sz{2, 2};
cv::Mat in_mat{sz, CV_8U, cv::Scalar(1)};
cv::Scalar out_sc;
cv::GCompiled compile(){
return sum_of_sum.compile(descr_of(in_mat));
}
cv::GComputation& computation(){
return sum_of_sum;
}
cv::GCompileArgs compile_args(){
return {};
}
cv::GRunArgs in_args(){
return cv::gin(in_mat);
}
cv::GRunArgsP out_args(){
return cv::gout(out_sc);
}
void verify(){
EXPECT_EQ(8, out_sc[0]);
}
};
namespace {
G_TYPED_KERNEL(GThrow, <GMat(GMat)>, "org.opencv.test.throw")
{
static GMatDesc outMeta(GMatDesc in) { return in; }
};
struct gthrow_exception : std::runtime_error {
using std::runtime_error::runtime_error;
};
GAPI_OCV_KERNEL(GThrowImpl, GThrow)
{
static void run(const cv::Mat& in, cv::Mat&)
{
//this condition is needed to avoid "Unreachable code" warning on windows inside OCVCallHelper
if (!in.empty())
{
throw gthrow_exception{"test"};
}
}
};
//TODO: unify with callback helper code
struct cancel_struct {
std::atomic<int> num_tasks_to_spawn;
cv::gapi::wip::GAsyncContext ctx;
cancel_struct(int tasks_to_spawn) : num_tasks_to_spawn(tasks_to_spawn) {}
};
G_TYPED_KERNEL(GCancelationAdHoc, <GMat(GMat, cancel_struct*)>, "org.opencv.test.cancel_ad_hoc")
{
static GMatDesc outMeta(GMatDesc in, cancel_struct* ) { return in; }
};
GAPI_OCV_KERNEL(GCancelationAdHocImpl, GCancelationAdHoc)
{
static void run(const cv::Mat& , cancel_struct* cancel_struct_p, cv::Mat&) {
auto& cancel_struct_ = * cancel_struct_p;
auto num_tasks_to_spawn = -- cancel_struct_.num_tasks_to_spawn;
cancel_struct_.ctx.cancel();
EXPECT_GT(num_tasks_to_spawn, 0)<<"Incorrect Test setup - to small number of tasks to feed the queue \n";
}
};
}
struct ExceptionOnExecution {
cv::GComputation throwing_gcomp;
ExceptionOnExecution() : throwing_gcomp([]{
cv::GMat in;
auto gout = GThrow::on(in);
return GComputation{in, gout};
})
{}
const cv::Size sz{2, 2};
cv::Mat in_mat{sz, CV_8U, cv::Scalar(1)};
cv::Mat out;
cv::GCompiled compile(){
return throwing_gcomp.compile(descr_of(in_mat), compile_args());
}
cv::GComputation& computation(){
return throwing_gcomp;
}
cv::GRunArgs in_args(){
return cv::gin(in_mat);
}
cv::GRunArgsP out_args(){
return cv::gout(out);
}
cv::GCompileArgs compile_args(){
auto pkg = cv::gapi::kernels<GThrowImpl>();
return cv::compile_args(pkg);
}
};
struct SelfCanceling {
cv::GComputation self_cancel;
SelfCanceling(cancel_struct* cancel_struct_p) : self_cancel([cancel_struct_p]{
cv::GMat in;
cv::GMat out = GCancelationAdHoc::on(in, cancel_struct_p);
return GComputation{in, out};
})
{}
const cv::Size sz{2, 2};
cv::Mat in_mat{sz, CV_8U, cv::Scalar(1)};
cv::Mat out_mat;
cv::GCompiled compile(){
return self_cancel.compile(descr_of(in_mat), compile_args());
}
cv::GComputation& computation(){
return self_cancel;
}
cv::GRunArgs in_args(){
return cv::gin(in_mat);
}
cv::GRunArgsP out_args(){
return cv::gout(out_mat);
}
cv::GCompileArgs compile_args(){
auto pkg = cv::gapi::kernels<GCancelationAdHocImpl>();
return cv::compile_args(pkg);
}
};
template<typename crtp_final_t>
struct crtp_cast {
template<typename crtp_base_t>
static crtp_final_t* crtp_cast_(crtp_base_t* this_)
{
return static_cast<crtp_final_t*>(this_);
}
};
//Test Mixin, hiding details of callback based notification
template<typename crtp_final_t>
struct CallBack: crtp_cast<crtp_final_t> {
std::atomic<bool> callback_called = {false};
std::mutex mtx;
std::exception_ptr ep;
std::condition_variable cv;
std::function<void(std::exception_ptr)> callback(){
return [&](std::exception_ptr ep_){
ep = ep_;
callback_called = true;
mtx.lock();
mtx.unlock();
cv.notify_one();
};
};
template<typename... Args >
void start_async(Args&&... args){
this->crtp_cast_(this)->async(callback(), std::forward<Args>(args)...);
}
template<typename... Args >
void start_async(cv::gapi::wip::GAsyncContext& ctx, Args&&... args){
this->crtp_cast_(this)->async(ctx, callback(), std::forward<Args>(args)...);
}
void wait_for_result()
{
std::unique_lock<std::mutex> lck{mtx};
cv.wait(lck,[&]{return callback_called == true;});
if (ep)
{
std::rethrow_exception(ep);
}
}
};
//Test Mixin, hiding details of future based notification
template<typename crtp_final_t>
struct Future: crtp_cast<crtp_final_t> {
std::future<void> f;
template<typename... Args >
void start_async(Args&&... args){
f = this->crtp_cast_(this)->async(std::forward<Args>(args)...);
}
void wait_for_result()
{
f.get();
}
};
//Test Mixin, hiding details of using compiled GAPI object
template<typename crtp_final_t>
struct AsyncCompiled : crtp_cast<crtp_final_t>{
template<typename... Args>
auto async(Args&&... args) -> decltype(cv::gapi::wip::async(std::declval<cv::GCompiled&>(), std::forward<Args>(args)...)){
auto gcmpld = this->crtp_cast_(this)->compile();
return cv::gapi::wip::async(gcmpld, std::forward<Args>(args)...);
}
template<typename... Args>
auto async(cv::gapi::wip::GAsyncContext& ctx, Args&&... args) ->
decltype(cv::gapi::wip::async(std::declval<cv::GCompiled&>(), std::forward<Args>(args)..., std::declval<cv::gapi::wip::GAsyncContext&>()))
{
auto gcmpld = this->crtp_cast_(this)->compile();
return cv::gapi::wip::async(gcmpld, std::forward<Args>(args)..., ctx);
}
};
//Test Mixin, hiding details of calling apply (async_apply) on GAPI Computation object
template<typename crtp_final_t>
struct AsyncApply : crtp_cast<crtp_final_t> {
template<typename... Args>
auto async(Args&&... args) ->
decltype(cv::gapi::wip::async_apply(std::declval<cv::GComputation&>(), std::forward<Args>(args)..., std::declval<cv::GCompileArgs>()))
{
return cv::gapi::wip::async_apply(
this->crtp_cast_(this)->computation(), std::forward<Args>(args)..., this->crtp_cast_(this)->compile_args()
);
}
template<typename... Args>
auto async(cv::gapi::wip::GAsyncContext& ctx, Args&&... args) ->
decltype(cv::gapi::wip::async_apply(std::declval<cv::GComputation&>(), std::forward<Args>(args)... , std::declval<cv::GCompileArgs>(), std::declval<cv::gapi::wip::GAsyncContext&>()))
{
return cv::gapi::wip::async_apply(
this->crtp_cast_(this)->computation(), std::forward<Args>(args)..., this->crtp_cast_(this)->compile_args(), ctx
);
}
};
template<typename case_t>
struct normal: ::testing::Test, case_t{};
TYPED_TEST_CASE_P(normal);
TYPED_TEST_P(normal, basic){
//Normal scenario: start function asynchronously and wait for the result, and verify it
this->start_async(this->in_args(), this->out_args());
this->wait_for_result();
this->verify();
}
REGISTER_TYPED_TEST_CASE_P(normal,
basic
);
template<typename case_t>
struct exception: ::testing::Test, case_t{};
TYPED_TEST_CASE_P(exception);
TYPED_TEST_P(exception, basic){
//Exceptional scenario: start function asynchronously and make sure exception is passed to the user
this->start_async(this->in_args(), this->out_args());
EXPECT_THROW(this->wait_for_result(), gthrow_exception);
}
REGISTER_TYPED_TEST_CASE_P(exception,
basic
);
template<typename case_t>
struct stress : ::testing::Test{};
TYPED_TEST_CASE_P(stress);
TYPED_TEST_P(stress, test){
//Some stress testing: use a number of threads to start a bunch of async requests
const std::size_t request_per_thread = 10;
const std::size_t number_of_threads = 4;
auto thread_body = [&](){
std::vector<TypeParam> requests(request_per_thread);
for (auto&& r : requests){
r.start_async(r.in_args(), r.out_args());
}
for (auto&& r : requests){
r.wait_for_result();
r.verify();
}
};
std::vector<std::thread> pool {number_of_threads};
for (auto&& t : pool){
t = std::thread{thread_body};
}
for (auto&& t : pool){
t.join();
}
}
REGISTER_TYPED_TEST_CASE_P(stress, test);
template<typename case_t>
struct cancel : ::testing::Test{};
TYPED_TEST_CASE_P(cancel);
TYPED_TEST_P(cancel, basic){
constexpr int num_tasks = 100;
cancel_struct cancel_struct_ {num_tasks};
std::vector<TypeParam> requests; requests.reserve(num_tasks);
for (auto i = num_tasks; i>0; i--){
requests.emplace_back(&cancel_struct_);
}
for (auto&& r : requests){
//first request will cancel other on it's execution
r.start_async(cancel_struct_.ctx, r.in_args(), r.out_args());
}
unsigned int canceled = 0 ;
for (auto&& r : requests){
try {
r.wait_for_result();
}catch (cv::gapi::wip::GAsyncCanceled&){
++canceled;
}
}
ASSERT_GT(canceled, 0u);
}
namespace {
GRunArgs deep_copy_out_args(const GRunArgsP& args ){
GRunArgs result; result.reserve(args.size());
for (auto&& arg : args){
//FIXME: replace this switch with use of visit() on variant, when it will be available
switch (arg.index()){
#if !defined(GAPI_STANDALONE)
case GRunArgP::index_of<cv::Mat*>() : result.emplace_back(*util::get<cv::Mat*>(arg)); break;
case GRunArgP::index_of<cv::Scalar*>() : result.emplace_back(*util::get<cv::Scalar*>(arg)); break;
case GRunArgP::index_of<cv::UMat*>() : result.emplace_back(*util::get<cv::UMat*>(arg)); break;
#endif // !defined(GAPI_STANDALONE)
case GRunArgP::index_of<cv::gapi::own::Mat*>() : result.emplace_back(*util::get<cv::gapi::own::Mat*> (arg)); break;
case GRunArgP::index_of<cv::gapi::own::Scalar*>() : result.emplace_back(*util::get<cv::gapi::own::Scalar*>(arg)); break;
case GRunArgP::index_of<cv::detail::VectorRef>() : result.emplace_back(util::get<cv::detail::VectorRef> (arg)); break;
default : ;
}
}
return result;
}
GRunArgsP args_p_from_args(GRunArgs& args){
GRunArgsP result; result.reserve(args.size());
for (auto&& arg : args){
switch (arg.index()){
#if !defined(GAPI_STANDALONE)
case GRunArg::index_of<cv::Mat>() : result.emplace_back(&util::get<cv::Mat>(arg)); break;
case GRunArg::index_of<cv::Scalar>() : result.emplace_back(&util::get<cv::Scalar>(arg)); break;
case GRunArg::index_of<cv::UMat>() : result.emplace_back(&util::get<cv::UMat>(arg)); break;
#endif // !defined(GAPI_STANDALONE)
case GRunArg::index_of<cv::gapi::own::Mat>() : result.emplace_back(&util::get<cv::gapi::own::Mat> (arg)); break;
case GRunArg::index_of<cv::gapi::own::Scalar>() : result.emplace_back(&util::get<cv::gapi::own::Scalar>(arg)); break;
case GRunArg::index_of<cv::detail::VectorRef>() : result.emplace_back(util::get<cv::detail::VectorRef> (arg)); break;
default : ;
}
}
return result;
}
}
REGISTER_TYPED_TEST_CASE_P(cancel, basic);
template<typename case_t>
struct output_args_lifetime : ::testing::Test{
static constexpr const int num_of_requests = 20;
};
TYPED_TEST_CASE_P(output_args_lifetime);
//There are intentionaly no actual checks (asserts and verify) in output_args_lifetime tests.
//They are more of example use-cases than real tests. (ASAN/valgrind can still catch issues here)
TYPED_TEST_P(output_args_lifetime, callback){
std::atomic<int> active_requests = {0};
for (int i=0; i<this->num_of_requests; i++)
{
TypeParam r;
//As output arguments are __captured by reference__ calling code
//__must__ ensure they live long enough to complete asynchronous activity.
//(i.e. live at least until callback is called)
auto out_args_ptr = std::make_shared<cv::GRunArgs>(deep_copy_out_args(r.out_args()));
//Extend lifetime of out_args_ptr content by capturing it into a callback
auto cb = [&active_requests, out_args_ptr](std::exception_ptr ){
--active_requests;
};
++active_requests;
r.async(cb, r.in_args(), args_p_from_args(*out_args_ptr));
}
while(active_requests){
std::this_thread::sleep_for(std::chrono::milliseconds{2});
}
}
TYPED_TEST_P(output_args_lifetime, future){
std::vector<std::future<void>> fs(this->num_of_requests);
std::vector<std::shared_ptr<cv::GRunArgs>> out_ptrs(this->num_of_requests);
for (int i=0; i<this->num_of_requests; i++)
{
TypeParam r;
//As output arguments are __captured by reference__ calling code
//__must__ ensure they live long enough to complete asynchronous activity.
//(i.e. live at least until future.get()/wait() is returned)
auto out_args_ptr = std::make_shared<cv::GRunArgs>(deep_copy_out_args(r.out_args()));
//Extend lifetime of out_args_ptr content
out_ptrs[i] = out_args_ptr;
fs[i] = r.async(r.in_args(), args_p_from_args(*out_args_ptr));
}
for (auto const& ftr : fs ){
ftr.wait();
}
}
REGISTER_TYPED_TEST_CASE_P(output_args_lifetime, callback, future);
//little helpers to match up all combinations of setups
template<typename compute_fixture_t, template<typename> class... args_t>
struct Case
: compute_fixture_t,
args_t<Case<compute_fixture_t, args_t...>> ...
{
template<typename... Args>
Case(Args&&... args) : compute_fixture_t(std::forward<Args>(args)...) { }
Case(Case const & ) = default;
Case(Case && ) = default;
Case() = default;
};
template<typename computation_t>
using cases = ::testing::Types<
Case<computation_t, CallBack, AsyncCompiled>,
Case<computation_t, CallBack, AsyncApply>,
Case<computation_t, Future, AsyncCompiled>,
Case<computation_t, Future, AsyncApply>
>;
INSTANTIATE_TYPED_TEST_CASE_P(AsyncAPINormalFlow_, normal, cases<SumOfSum2x2>);
INSTANTIATE_TYPED_TEST_CASE_P(AsyncAPIExceptionHandling_, exception, cases<ExceptionOnExecution>);
INSTANTIATE_TYPED_TEST_CASE_P(AsyncAPIStress, stress, cases<SumOfSum2x2>);
INSTANTIATE_TYPED_TEST_CASE_P(AsyncAPICancelation, cancel, cases<SelfCanceling>);
template<typename computation_t>
using explicit_wait_cases = ::testing::Types<
Case<computation_t, AsyncCompiled>,
Case<computation_t, AsyncApply>,
Case<computation_t, AsyncCompiled>,
Case<computation_t, AsyncApply>
>;
INSTANTIATE_TYPED_TEST_CASE_P(AsyncAPIOutArgsLifetTime, output_args_lifetime, explicit_wait_cases<SumOfSum2x2>);
} // namespace opencv_test

View File

@@ -0,0 +1,312 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include "gapi_mock_kernels.hpp"
#include <opencv2/gapi/fluid/gfluidkernel.hpp>
namespace opencv_test
{
namespace
{
GAPI_OCV_KERNEL(OCVFoo, I::Foo)
{
static void run(const cv::Mat &in, cv::Mat &out)
{
out = in + 2;
}
};
GAPI_OCV_KERNEL(OCVBar, I::Bar)
{
static void run(const cv::Mat &a, const cv::Mat &b, cv::Mat &out)
{
out = 4*(a + b);
}
};
void FluidFooRow(const uint8_t* in, uint8_t* out, int length)
{
for (int i = 0; i < length; i++)
{
out[i] = in[i] + 3;
}
}
void FluidBarRow(const uint8_t* in1, const uint8_t* in2, uint8_t* out, int length)
{
for (int i = 0; i < length; i++)
{
out[i] = 3*(in1[i] + in2[i]);
}
}
GAPI_FLUID_KERNEL(FFoo, I::Foo, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &out)
{
FluidFooRow(in.InLineB(0), out.OutLineB(), in.length());
}
};
GAPI_FLUID_KERNEL(FBar, I::Bar, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in1,
const cv::gapi::fluid::View &in2,
cv::gapi::fluid::Buffer &out)
{
FluidBarRow(in1.InLineB(0), in2.InLineB(0), out.OutLineB(), in1.length());
}
};
G_TYPED_KERNEL(FluidFooI, <cv::GMat(cv::GMat)>, "test.kernels.fluid_foo")
{
static cv::GMatDesc outMeta(const cv::GMatDesc &in) { return in; }
};
G_TYPED_KERNEL(FluidBarI, <cv::GMat(cv::GMat,cv::GMat)>, "test.kernels.fluid_bar")
{
static cv::GMatDesc outMeta(const cv::GMatDesc &in, const cv::GMatDesc &) { return in; }
};
GAPI_FLUID_KERNEL(FluidFoo, FluidFooI, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &out)
{
FluidFooRow(in.InLineB(0), out.OutLineB(), in.length());
}
};
GAPI_FLUID_KERNEL(FluidBar, FluidBarI, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in1,
const cv::gapi::fluid::View &in2,
cv::gapi::fluid::Buffer &out)
{
FluidBarRow(in1.InLineB(0), in2.InLineB(0), out.OutLineB(), in1.length());
}
};
GAPI_FLUID_KERNEL(FluidFoo2lpi, FluidFooI, false)
{
static const int Window = 1;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &out)
{
for (int l = 0; l < out.lpi(); l++)
{
FluidFooRow(in.InLineB(l), out.OutLineB(l), in.length());
}
}
};
cv::Mat ocvFoo(const cv::Mat &in)
{
cv::Mat out;
OCVFoo::run(in, out);
return out;
}
cv::Mat ocvBar(const cv::Mat &in1, const cv::Mat &in2)
{
cv::Mat out;
OCVBar::run(in1, in2, out);
return out;
}
cv::Mat fluidFoo(const cv::Mat &in)
{
cv::Mat out(in.rows, in.cols, in.type());
for (int y = 0; y < in.rows; y++)
{
FluidFooRow(in.ptr(y), out.ptr(y), in.cols);
}
return out;
}
cv::Mat fluidBar(const cv::Mat &in1, const cv::Mat &in2)
{
cv::Mat out(in1.rows, in1.cols, in1.type());
for (int y = 0; y < in1.rows; y++)
{
FluidBarRow(in1.ptr(y), in2.ptr(y), out.ptr(y), in1.cols);
}
return out;
}
} // anonymous namespace
struct GAPIHeteroTest: public ::testing::Test
{
cv::GComputation m_comp;
cv::gapi::GKernelPackage m_ocv_kernels;
cv::gapi::GKernelPackage m_fluid_kernels;
cv::gapi::GKernelPackage m_hetero_kernels;
cv::Mat m_in_mat;
cv::Mat m_out_mat;
GAPIHeteroTest();
};
GAPIHeteroTest::GAPIHeteroTest()
: m_comp([](){
cv::GMat in;
cv::GMat out = I::Bar::on(I::Foo::on(in),
I::Foo::on(in));
return cv::GComputation(in, out);
})
, m_ocv_kernels(cv::gapi::kernels<OCVFoo, OCVBar>())
, m_fluid_kernels(cv::gapi::kernels<FFoo, FBar>())
, m_hetero_kernels(cv::gapi::kernels<OCVFoo, FBar>())
, m_in_mat(cv::Mat::eye(cv::Size(64, 64), CV_8UC1))
{
}
TEST_F(GAPIHeteroTest, TestOCV)
{
EXPECT_TRUE(cv::gapi::cpu::backend() == m_ocv_kernels.lookup<I::Foo>());
EXPECT_TRUE(cv::gapi::cpu::backend() == m_ocv_kernels.lookup<I::Bar>());
cv::Mat ref = ocvBar(ocvFoo(m_in_mat), ocvFoo(m_in_mat));
EXPECT_NO_THROW(m_comp.apply(m_in_mat, m_out_mat, cv::compile_args(m_ocv_kernels)));
EXPECT_EQ(0, cv::countNonZero(ref != m_out_mat));
}
TEST_F(GAPIHeteroTest, TestFluid)
{
EXPECT_TRUE(cv::gapi::fluid::backend() == m_fluid_kernels.lookup<I::Foo>());
EXPECT_TRUE(cv::gapi::fluid::backend() == m_fluid_kernels.lookup<I::Bar>());
cv::Mat ref = fluidBar(fluidFoo(m_in_mat), fluidFoo(m_in_mat));
EXPECT_NO_THROW(m_comp.apply(m_in_mat, m_out_mat, cv::compile_args(m_fluid_kernels)));
EXPECT_EQ(0, cv::countNonZero(ref != m_out_mat));
}
TEST_F(GAPIHeteroTest, TestBoth)
{
EXPECT_TRUE(cv::gapi::cpu::backend() == m_hetero_kernels.lookup<I::Foo>());
EXPECT_TRUE(cv::gapi::fluid::backend() == m_hetero_kernels.lookup<I::Bar>());
cv::Mat ref = fluidBar(ocvFoo(m_in_mat), ocvFoo(m_in_mat));
EXPECT_NO_THROW(m_comp.apply(m_in_mat, m_out_mat, cv::compile_args(m_hetero_kernels)));
EXPECT_EQ(0, cv::countNonZero(ref != m_out_mat));
}
struct GAPIBigHeteroTest : public ::testing::TestWithParam<std::array<int, 9>>
{
cv::GComputation m_comp;
cv::gapi::GKernelPackage m_kernels;
cv::Mat m_in_mat;
cv::Mat m_out_mat1;
cv::Mat m_out_mat2;
cv::Mat m_ref_mat1;
cv::Mat m_ref_mat2;
GAPIBigHeteroTest();
};
// Foo7
// .-> Foo2 -> Foo3 -<
// Foo0 -> Foo1 Bar -> Foo6
// `-> Foo4 -> Foo5 -`
GAPIBigHeteroTest::GAPIBigHeteroTest()
: m_comp([&](){
auto flags = GetParam();
std::array<std::function<cv::GMat(cv::GMat)>, 8> foos;
for (int i = 0; i < 8; i++)
{
foos[i] = flags[i] ? &I::Foo::on : &FluidFooI::on;
}
auto bar = flags[8] ? &I::Bar::on : &FluidBarI::on;
cv::GMat in;
auto foo1Out = foos[1](foos[0](in));
auto foo3Out = foos[3](foos[2](foo1Out));
auto foo6Out = foos[6](bar(foo3Out,
foos[5](foos[4](foo1Out))));
auto foo7Out = foos[7](foo3Out);
return cv::GComputation(GIn(in), GOut(foo6Out, foo7Out));
})
, m_kernels(cv::gapi::kernels<OCVFoo, OCVBar, FluidFoo, FluidBar>())
, m_in_mat(cv::Mat::eye(cv::Size(64, 64), CV_8UC1))
{
auto flags = GetParam();
std::array<std::function<cv::Mat(cv::Mat)>, 8> foos;
for (int i = 0; i < 8; i++)
{
foos[i] = flags[i] ? ocvFoo : fluidFoo;
}
auto bar = flags[8] ? ocvBar : fluidBar;
cv::Mat foo1OutMat = foos[1](foos[0](m_in_mat));
cv::Mat foo3OutMat = foos[3](foos[2](foo1OutMat));
m_ref_mat1 = foos[6](bar(foo3OutMat,
foos[5](foos[4](foo1OutMat))));
m_ref_mat2 = foos[7](foo3OutMat);
}
TEST_P(GAPIBigHeteroTest, Test)
{
EXPECT_NO_THROW(m_comp.apply(gin(m_in_mat), gout(m_out_mat1, m_out_mat2), cv::compile_args(m_kernels)));
EXPECT_EQ(0, cv::countNonZero(m_ref_mat1 != m_out_mat1));
EXPECT_EQ(0, cv::countNonZero(m_ref_mat2 != m_out_mat2));
}
static auto configurations = []()
{
// Fill all possible configurations
// from 000000000 to 111111111
std::array<std::array<int, 9>, 512> arr;
for (auto n = 0; n < 512; n++)
{
for (auto i = 0; i < 9; i++)
{
arr[n][i] = (n >> (8 - i)) & 1;
}
}
return arr;
}();
INSTANTIATE_TEST_CASE_P(GAPIBigHeteroTest, GAPIBigHeteroTest,
::testing::ValuesIn(configurations));
TEST(GAPIHeteroTestLPI, Test)
{
cv::GMat in;
auto mid = FluidFooI::on(in);
auto out = FluidFooI::on(mid);
cv::gapi::island("isl0", GIn(in), GOut(mid));
cv::gapi::island("isl1", GIn(mid), GOut(out));
cv::GComputation c(in, out);
cv::Mat in_mat = cv::Mat::eye(cv::Size(64, 64), CV_8UC1);
cv::Mat out_mat;
EXPECT_NO_THROW(c.apply(in_mat, out_mat, cv::compile_args(cv::gapi::kernels<FluidFoo2lpi>())));
cv::Mat ref = fluidFoo(fluidFoo(in_mat));
EXPECT_EQ(0, cv::countNonZero(ref != out_mat));
}
} // namespace opencv_test

View File

@@ -0,0 +1,353 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <opencv2/gapi/cpu/gcpukernel.hpp>
namespace opencv_test
{
namespace
{
G_TYPED_KERNEL(KTest, <cv::GScalar(cv::GScalar)>, "org.opencv.test.scalar_kernel") {
static cv::GScalarDesc outMeta(cv::GScalarDesc in) { return in; }
};
GAPI_OCV_KERNEL(GOCVScalarTest, KTest)
{
static void run(const cv::Scalar &in, cv::Scalar &out) { out = in+cv::Scalar(1); }
};
}
TEST(GAPI_MetaDesc, MatDesc)
{
cv::Mat m1(240, 320, CV_8U);
const auto desc1 = cv::descr_of(m1);
EXPECT_EQ(CV_8U, desc1.depth);
EXPECT_EQ(1, desc1.chan);
EXPECT_EQ(320, desc1.size.width);
EXPECT_EQ(240, desc1.size.height);
EXPECT_FALSE(desc1.isND());
cv::Mat m2(480, 640, CV_8UC3);
const auto desc2 = cv::descr_of(m2);
EXPECT_EQ(CV_8U, desc2.depth);
EXPECT_EQ(3, desc2.chan);
EXPECT_EQ(640, desc2.size.width);
EXPECT_EQ(480, desc2.size.height);
EXPECT_FALSE(desc2.isND());
}
TEST(GAPI_MetaDesc, MatDescND)
{
std::vector<int> dims = {1,3,299,299};
cv::Mat m(dims, CV_32F);
const auto desc = cv::descr_of(m);
EXPECT_EQ(CV_32F, desc.depth);
EXPECT_EQ(-1, desc.chan);
EXPECT_EQ(1, desc.dims[0]);
EXPECT_EQ(3, desc.dims[1]);
EXPECT_EQ(299, desc.dims[2]);
EXPECT_EQ(299, desc.dims[3]);
EXPECT_TRUE(desc.isND());
}
TEST(GAPI_MetaDesc, VecMatDesc)
{
std::vector<cv::Mat> vec1 = {
cv::Mat(240, 320, CV_8U)};
const auto desc1 = cv::descrs_of(vec1);
EXPECT_EQ((GMatDesc{CV_8U, 1, {320, 240}}), get<GMatDesc>(desc1[0]));
std::vector<cv::UMat> vec2 = {
cv::UMat(480, 640, CV_8UC3)};
const auto desc2 = cv::descrs_of(vec2);
EXPECT_EQ((GMatDesc{CV_8U, 3, {640, 480}}), get<GMatDesc>(desc2[0]));
}
TEST(GAPI_MetaDesc, VecOwnMatDesc)
{
std::vector<cv::gapi::own::Mat> vec = {
cv::gapi::own::Mat(240, 320, CV_8U, nullptr),
cv::gapi::own::Mat(480, 640, CV_8UC3, nullptr)};
const auto desc = cv::gapi::own::descrs_of(vec);
EXPECT_EQ((GMatDesc{CV_8U, 1, {320, 240}}), get<GMatDesc>(desc[0]));
EXPECT_EQ((GMatDesc{CV_8U, 3, {640, 480}}), get<GMatDesc>(desc[1]));
}
TEST(GAPI_MetaDesc, AdlVecOwnMatDesc)
{
std::vector<cv::gapi::own::Mat> vec = {
cv::gapi::own::Mat(240, 320, CV_8U, nullptr),
cv::gapi::own::Mat(480, 640, CV_8UC3, nullptr)};
const auto desc = descrs_of(vec);
EXPECT_EQ((GMatDesc{CV_8U, 1, {320, 240}}), get<GMatDesc>(desc[0]));
EXPECT_EQ((GMatDesc{CV_8U, 3, {640, 480}}), get<GMatDesc>(desc[1]));
}
TEST(GAPI_MetaDesc, Compare_Equal_MatDesc)
{
const auto desc1 = cv::GMatDesc{CV_8U, 1, {64, 64}};
const auto desc2 = cv::GMatDesc{CV_8U, 1, {64, 64}};
EXPECT_TRUE(desc1 == desc2);
}
TEST(GAPI_MetaDesc, Compare_Not_Equal_MatDesc)
{
const auto desc1 = cv::GMatDesc{CV_8U, 1, {64, 64}};
const auto desc2 = cv::GMatDesc{CV_32F, 1, {64, 64}};
EXPECT_TRUE(desc1 != desc2);
}
TEST(GAPI_MetaDesc, Compare_Equal_MatDesc_ND)
{
const auto desc1 = cv::GMatDesc{CV_8U, {1,3,224,224}};
const auto desc2 = cv::GMatDesc{CV_8U, {1,3,224,224}};
EXPECT_TRUE(desc1 == desc2);
}
TEST(GAPI_MetaDesc, Compare_Not_Equal_MatDesc_ND_1)
{
const auto desc1 = cv::GMatDesc{CV_8U, {1,1000}};
const auto desc2 = cv::GMatDesc{CV_32F, {1,1000}};
EXPECT_TRUE(desc1 != desc2);
}
TEST(GAPI_MetaDesc, Compare_Not_Equal_MatDesc_ND_2)
{
const auto desc1 = cv::GMatDesc{CV_8U, {1,1000}};
const auto desc2 = cv::GMatDesc{CV_8U, {1,1400}};
EXPECT_TRUE(desc1 != desc2);
}
TEST(GAPI_MetaDesc, Compare_Not_Equal_MatDesc_ND_3)
{
const auto desc1 = cv::GMatDesc{CV_8U, {1,1000}};
const auto desc2 = cv::GMatDesc{CV_8U, 1, {32,32}};
EXPECT_TRUE(desc1 != desc2);
}
TEST(GAPI_MetaDesc, Compile_MatchMetaNumber_1)
{
cv::GMat in;
cv::GComputation cc(in, in+in);
const auto desc1 = cv::GMatDesc{CV_8U,1,{64,64}};
const auto desc2 = cv::GMatDesc{CV_32F,1,{128,128}};
EXPECT_NO_THROW(cc.compile(desc1));
EXPECT_NO_THROW(cc.compile(desc2));
// FIXME: custom exception type?
// It is worth checking if compilation fails with different number
// of meta parameters
EXPECT_THROW(cc.compile(desc1, desc1), std::logic_error);
EXPECT_THROW(cc.compile(desc1, desc2, desc2), std::logic_error);
}
TEST(GAPI_MetaDesc, Compile_MatchMetaNumber_2)
{
cv::GMat a, b;
cv::GComputation cc(cv::GIn(a, b), cv::GOut(a+b));
const auto desc1 = cv::GMatDesc{CV_8U,1,{64,64}};
EXPECT_NO_THROW(cc.compile(desc1, desc1));
const auto desc2 = cv::GMatDesc{CV_32F,1,{128,128}};
EXPECT_NO_THROW(cc.compile(desc2, desc2));
// FIXME: custom exception type?
EXPECT_THROW(cc.compile(desc1), std::logic_error);
EXPECT_THROW(cc.compile(desc2), std::logic_error);
EXPECT_THROW(cc.compile(desc2, desc2, desc2), std::logic_error);
}
TEST(GAPI_MetaDesc, Compile_MatchMetaType_Mat)
{
cv::GMat in;
cv::GComputation cc(in, in+in);
EXPECT_NO_THROW(cc.compile(cv::GMatDesc{CV_8U,1,{64,64}}));
// FIXME: custom exception type?
EXPECT_THROW(cc.compile(cv::empty_scalar_desc()), std::logic_error);
}
TEST(GAPI_MetaDesc, Compile_MatchMetaType_Scalar)
{
cv::GScalar in;
cv::GComputation cc(cv::GIn(in), cv::GOut(KTest::on(in)));
const auto desc1 = cv::descr_of(cv::Scalar(128));
const auto desc2 = cv::GMatDesc{CV_8U,1,{64,64}};
const auto pkg = cv::gapi::kernels<GOCVScalarTest>();
EXPECT_NO_THROW(cc.compile(desc1, cv::compile_args(pkg)));
// FIXME: custom exception type?
EXPECT_THROW(cc.compile(desc2, cv::compile_args(pkg)), std::logic_error);
}
TEST(GAPI_MetaDesc, Compile_MatchMetaType_Mixed)
{
cv::GMat a;
cv::GScalar v;
cv::GComputation cc(cv::GIn(a, v), cv::GOut(cv::gapi::addC(a, v)));
const auto desc1 = cv::GMatDesc{CV_8U,1,{64,64}};
const auto desc2 = cv::descr_of(cv::Scalar(4));
EXPECT_NO_THROW(cc.compile(desc1, desc2));
// FIXME: custom exception type(s)?
EXPECT_THROW(cc.compile(desc1), std::logic_error);
EXPECT_THROW(cc.compile(desc2), std::logic_error);
EXPECT_THROW(cc.compile(desc2, desc1), std::logic_error);
EXPECT_THROW(cc.compile(desc1, desc1, desc1), std::logic_error);
EXPECT_THROW(cc.compile(desc1, desc2, desc1), std::logic_error);
}
TEST(GAPI_MetaDesc, Typed_Compile_MatchMetaNumber_1)
{
cv::GComputationT<cv::GMat(cv::GMat)> cc([](cv::GMat in)
{
return in+in;
});
const auto desc1 = cv::GMatDesc{CV_8U,1,{64,64}};
const auto desc2 = cv::GMatDesc{CV_32F,1,{128,128}};
EXPECT_NO_THROW(cc.compile(desc1));
EXPECT_NO_THROW(cc.compile(desc2));
}
TEST(GAPI_MetaDesc, Typed_Compile_MatchMetaNumber_2)
{
cv::GComputationT<cv::GMat(cv::GMat,cv::GMat)> cc([](cv::GMat a, cv::GMat b)
{
return a + b;
});
const auto desc1 = cv::GMatDesc{CV_8U,1,{64,64}};
EXPECT_NO_THROW(cc.compile(desc1, desc1));
const auto desc2 = cv::GMatDesc{CV_32F,1,{128,128}};
EXPECT_NO_THROW(cc.compile(desc2, desc2));
}
TEST(GAPI_MetaDesc, Typed_Compile_MatchMetaType_Mat)
{
cv::GComputationT<cv::GMat(cv::GMat)> cc([](cv::GMat in)
{
return in+in;
});
EXPECT_NO_THROW(cc.compile(cv::GMatDesc{CV_8U,1,{64,64}}));
}
TEST(GAPI_MetaDesc, Typed_Compile_MatchMetaType_Scalar)
{
cv::GComputationT<cv::GScalar(cv::GScalar)> cc([](cv::GScalar in)
{
return KTest::on(in);
});
const auto desc1 = cv::descr_of(cv::Scalar(128));
const auto pkg = cv::gapi::kernels<GOCVScalarTest>();
// EXPECT_NO_THROW(cc.compile(desc1, cv::compile_args(pkg)));
cc.compile(desc1, cv::compile_args(pkg));
}
TEST(GAPI_MetaDesc, Typed_Compile_MatchMetaType_Mixed)
{
cv::GComputationT<cv::GMat(cv::GMat,cv::GScalar)> cc([](cv::GMat a, cv::GScalar v)
{
return cv::gapi::addC(a, v);
});
const auto desc1 = cv::GMatDesc{CV_8U,1,{64,64}};
const auto desc2 = cv::descr_of(cv::Scalar(4));
EXPECT_NO_THROW(cc.compile(desc1, desc2));
}
TEST(GAPI_MetaDesc, Compare_Planar)
{
const auto desc0 = cv::GMatDesc{CV_8U,3,{32,32},false};
const auto desc1 = cv::GMatDesc{CV_8U,3,{32,32},false};
const auto desc2 = cv::GMatDesc{CV_8U,3,{32,32},true};
const auto desc3 = cv::GMatDesc{CV_8U,3,{64,64},true};
EXPECT_TRUE(desc0 == desc1);
EXPECT_TRUE(desc1 != desc2);
EXPECT_TRUE(desc1 != desc3);
EXPECT_TRUE(desc2 != desc3);
}
TEST(GAPI_MetaDesc, Sanity_asPlanar)
{
constexpr int w = 32;
constexpr int h = 16;
const auto desc1 = cv::GMatDesc{CV_8U,3,{w,h},false};
const auto desc2 = cv::GMatDesc{CV_8U,3,{w,h},true};
EXPECT_NO_THROW(desc1.asPlanar());
EXPECT_NO_THROW(desc2.asInterleaved());
EXPECT_ANY_THROW(desc1.asInterleaved());
EXPECT_ANY_THROW(desc2.asPlanar());
}
TEST(GAPI_MetaDesc, Compare_asPlanar)
{
constexpr int w = 32;
constexpr int h = 64;
const auto desc0 = cv::GMatDesc{CV_8U,3,{w,h},false};
const auto desc1 = cv::GMatDesc{CV_8U,3,{w,h},true};
EXPECT_TRUE(desc0.asPlanar() == desc1);
EXPECT_TRUE(desc1.asInterleaved() == desc0);
}
TEST(GAPI_MetaDesc, Compare_asPlanarTransform)
{
constexpr int w = 64;
constexpr int h = 32;
const auto desc0 = cv::GMatDesc{CV_8U,3,{w,h},true};
const auto desc1 = cv::GMatDesc{CV_8U,1,{w,h*3},false};
EXPECT_ANY_THROW(desc0.asPlanar(3));
EXPECT_NO_THROW(desc1.asPlanar(3));
EXPECT_TRUE(desc1.asPlanar(3) == desc0);
}
TEST(GAPI_MetaDesc, CanDescribe)
{
constexpr int w = 15;
constexpr int h = 7;
cv::Mat m0(h, w, CV_8UC3);
cv::GMatDesc md0{CV_8U,3,{w,h},false};
cv::Mat m1(h*3, w, CV_8UC1);
cv::GMatDesc md10{CV_8U,3,{w,h},true};
cv::GMatDesc md11{CV_8U,1,{w,h*3},false};
EXPECT_TRUE (md0 .canDescribe(m0));
EXPECT_FALSE(md0 .canDescribe(m1));
EXPECT_TRUE (md10.canDescribe(m1));
EXPECT_TRUE (md11.canDescribe(m1));
}
} // namespace opencv_test

View File

@@ -0,0 +1,315 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "test_precomp.hpp"
#include "gapi_fluid_test_kernels.hpp"
namespace opencv_test
{
namespace {
cv::Mat randomMat(cv::Size img_sz, int type = CV_8UC1, cv::Scalar mean = cv::Scalar(127.0f), cv::Scalar stddev = cv::Scalar(40.f)){
cv::Mat mat(img_sz, type);
cv::randn(mat, mean, stddev);
return mat;
}
cv::GFluidParallelOutputRois asGFluidParallelOutputRois(const std::vector<cv::Rect>& rois){
cv::GFluidParallelOutputRois parallel_rois;
for (auto const& roi : rois) {
parallel_rois.parallel_rois.emplace_back(GFluidOutputRois{{to_own(roi)}});
}
return parallel_rois;
}
void adjust_empty_roi(cv::Rect& roi, cv::Size size){
if (roi.empty()) roi = cv::Rect{{0,0}, size};
}
cv::GCompileArgs combine(cv::GCompileArgs&& lhs, cv::GCompileArgs const& rhs){
lhs.insert(lhs.end(), rhs.begin(), rhs.end());
return std::move(lhs);
}
}
using namespace cv::gapi_test_kernels;
//As GTest can not simultaneously parameterize test with both types and values - lets use type-erasure and virtual interfaces
//to use different computation pipelines
struct ComputationPair {
void run_with_gapi(const cv::Mat& in_mat, cv::GCompileArgs const& compile_args, cv::Mat& out_mat){
run_with_gapi_impl(in_mat, combine(cv::compile_args(fluidTestPackage), compile_args), out_mat);
}
void run_with_gapi(const cv::Mat& in_mat, cv::GFluidParallelOutputRois const& parallel_rois, cv::Mat& out_mat){
run_with_gapi_impl(in_mat, cv::compile_args(fluidTestPackage, parallel_rois), out_mat);
}
virtual void run_with_ocv (const cv::Mat& in_mat, const std::vector<cv::Rect>& rois, cv::Mat& out_mat) = 0;
virtual std::string name() const { return {}; }
virtual ~ComputationPair () = default;
friend std::ostream& operator<<(std::ostream& o, ComputationPair const* cp){
std::string custom_name = cp->name();
return o << (custom_name.empty() ? typeid(cp).name() : custom_name );
}
private:
virtual void run_with_gapi_impl(const cv::Mat& in_mat, cv::GCompileArgs const& comp_args, cv::Mat& out_mat) = 0;
};
struct Blur3x3CP : ComputationPair{
static constexpr int borderType = BORDER_REPLICATE;
static constexpr int kernelSize = 3;
std::string name() const override { return "Blur3x3"; }
void run_with_gapi_impl(const cv::Mat& in_mat, cv::GCompileArgs const& comp_args, cv::Mat& out_mat_gapi) override {
cv::GMat in;
cv::GMat out = TBlur3x3::on(in, borderType, {});
cv::GComputation c(cv::GIn(in), cv::GOut(out));
// Run G-API
auto cc = c.compile(cv::descr_of(in_mat), comp_args);
cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
}
void run_with_ocv(const cv::Mat& in_mat, const std::vector<cv::Rect>& rois, cv::Mat& out_mat_ocv) override {
cv::Point anchor = {-1, -1};
// Check with OpenCV
for (auto roi : rois) {
adjust_empty_roi(roi, in_mat.size());
cv::blur(in_mat(roi), out_mat_ocv(roi), {kernelSize, kernelSize}, anchor, borderType);
}
}
};
struct AddCCP : ComputationPair{
std::string name() const override { return "AddC"; }
void run_with_gapi_impl(const cv::Mat& in_mat, cv::GCompileArgs const& comp_args, cv::Mat& out_mat_gapi) override {
cv::GMat in;
cv::GMat out = TAddCSimple::on(in, 1);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
// Run G-API
auto cc = c.compile(cv::descr_of(in_mat), comp_args);
cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
}
void run_with_ocv(const cv::Mat& in_mat, const std::vector<cv::Rect>& rois, cv::Mat& out_mat_ocv) override {
// Check with OpenCV
for (auto roi : rois) {
adjust_empty_roi(roi, in_mat.size());
out_mat_ocv(roi) = in_mat(roi) + 1u;
}
}
};
template<BorderTypes _borderType>
struct SequenceOfBlursCP : ComputationPair{
BorderTypes borderType = _borderType;
std::string name() const override { return "SequenceOfBlurs, border type: " + std::to_string(static_cast<int>(borderType)); }
void run_with_gapi_impl(const cv::Mat& in_mat, cv::GCompileArgs const& comp_args, cv::Mat& out_mat) override {
cv::Scalar borderValue(0);
GMat in;
auto mid = TBlur3x3::on(in, borderType, borderValue);
auto out = TBlur5x5::on(mid, borderType, borderValue);
GComputation c(GIn(in), GOut(out));
auto cc = c.compile(descr_of(in_mat), comp_args);
cc(cv::gin(in_mat), cv::gout(out_mat));
}
void run_with_ocv(const cv::Mat& in_mat, const std::vector<cv::Rect>& rois, cv::Mat& out_mat) override {
cv::Mat mid_mat_ocv = Mat::zeros(in_mat.size(), in_mat.type());
cv::Point anchor = {-1, -1};
for (auto roi : rois) {
adjust_empty_roi(roi, in_mat.size());
cv::blur(in_mat, mid_mat_ocv, {3,3}, anchor, borderType);
cv::blur(mid_mat_ocv(roi), out_mat(roi), {5,5}, anchor, borderType);
}
}
};
struct TiledComputation : public TestWithParam <std::tuple<ComputationPair*, cv::Size, std::vector<cv::Rect>, decltype(cv::GFluidParallelFor::parallel_for)>> {};
TEST_P(TiledComputation, Test)
{
ComputationPair* cp;
cv::Size img_sz;
std::vector<cv::Rect> rois ;
decltype(cv::GFluidParallelFor::parallel_for) pfor;
auto mat_type = CV_8UC1;
std::tie(cp, img_sz, rois, pfor) = GetParam();
cv::Mat in_mat = randomMat(img_sz, mat_type);
cv::Mat out_mat_gapi = cv::Mat::zeros(img_sz, mat_type);
cv::Mat out_mat_ocv = cv::Mat::zeros(img_sz, mat_type);
auto comp_args = combine(cv::compile_args(asGFluidParallelOutputRois(rois)), pfor ? cv::compile_args(cv::GFluidParallelFor{pfor}) : cv::GCompileArgs{});
cp->run_with_gapi(in_mat, comp_args, out_mat_gapi);
cp->run_with_ocv (in_mat, rois, out_mat_ocv);
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv))
<< "in_mat : \n" << in_mat << std::endl
<< "diff matrix :\n " << (out_mat_gapi != out_mat_ocv) << std::endl
<< "out_mat_gapi: \n" << out_mat_gapi << std::endl
<< "out_mat_ocv: \n" << out_mat_ocv << std::endl;;
}
namespace {
//this is ugly but other variants (like using shared_ptr) are IMHO even more ugly :)
template<typename T, typename... Arg>
T* addr_of_static(Arg... arg) {
static T obj(std::forward<Arg>(arg)...);
return &obj;
}
}
auto single_arg_computations = [](){
return Values( addr_of_static<Blur3x3CP>(),
addr_of_static<AddCCP>(),
addr_of_static<SequenceOfBlursCP<BORDER_CONSTANT>>(),
addr_of_static<SequenceOfBlursCP<BORDER_REPLICATE>>(),
addr_of_static<SequenceOfBlursCP<BORDER_REFLECT_101>>()
);
};
auto tilesets_8x10 = [](){
return Values(std::vector<cv::Rect>{cv::Rect{}},
std::vector<cv::Rect>{cv::Rect{0,0,8,5}, cv::Rect{0,5,8,5}},
std::vector<cv::Rect>{cv::Rect{0,1,8,3}, cv::Rect{0,4,8,3}},
std::vector<cv::Rect>{cv::Rect{0,2,8,3}, cv::Rect{0,5,8,2}},
std::vector<cv::Rect>{cv::Rect{0,3,8,4}, cv::Rect{0,9,8,1}});
};
auto tilesets_20x15 = [](){
return Values(std::vector<cv::Rect>{cv::Rect{}},
std::vector<cv::Rect>{cv::Rect{{0,0},cv::Size{20,7}},
cv::Rect{{0,7},cv::Size{20,8}}});
};
auto tilesets_320x240 = [](){
return Values(std::vector<cv::Rect>{cv::Rect{{0,0}, cv::Size{320,120}},
cv::Rect{{0,120}, cv::Size{320,120}}},
std::vector<cv::Rect>{cv::Rect{{0,0}, cv::Size{320,120}},
cv::Rect{{0,120}, cv::Size{320,120}}},
std::vector<cv::Rect>{cv::Rect{{0,0}, cv::Size{320,60}},
cv::Rect{{0,60}, cv::Size{320,60}},
cv::Rect{{0,120},cv::Size{320,120}}});
};
namespace{
auto no_custom_pfor = decltype(cv::GFluidParallelFor::parallel_for){};
}
INSTANTIATE_TEST_CASE_P(FluidTiledSerial8x10, TiledComputation,
Combine(
single_arg_computations(),
Values(cv::Size(8, 10)),
tilesets_8x10(),
Values(no_custom_pfor))
);
INSTANTIATE_TEST_CASE_P(FluidTiledSerial20x15, TiledComputation,
Combine(
single_arg_computations(),
Values(cv::Size(20, 15)),
tilesets_20x15(),
Values(no_custom_pfor))
);
INSTANTIATE_TEST_CASE_P(FluidTiledSerial320x240, TiledComputation,
Combine(
single_arg_computations(),
Values(cv::Size(320, 240)),
tilesets_320x240(),
Values(no_custom_pfor))
);
//FIXME: add multiple outputs tests
TEST(FluidTiledParallelFor, basic)
{
cv::Size img_sz{8,20};
auto mat_type = CV_8UC1;
cv::GMat in;
cv::GMat out = TAddCSimple::on(in, 1);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
cv::Mat in_mat = randomMat(img_sz, mat_type);
cv::Mat out_mat_gapi = cv::Mat::zeros(img_sz, mat_type);
auto parallel_rois = asGFluidParallelOutputRois( std::vector<cv::Rect>{cv::Rect{0,0,8,5}, cv::Rect{0,5,8,5}});
std::size_t items_count = 0;
auto pfor = [&items_count](std::size_t count, std::function<void(std::size_t)> ){
items_count = count;
};
// Run G-API
auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage, parallel_rois, GFluidParallelFor{pfor}));
cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
ASSERT_EQ(parallel_rois.parallel_rois.size(), items_count);
}
namespace {
auto serial_for = [](std::size_t count, std::function<void(std::size_t)> f){
for (std::size_t i = 0; i < count; ++i){
f(i);
}
};
auto cv_parallel_for = [](std::size_t count, std::function<void(std::size_t)> f){
cv::parallel_for_(cv::Range(0, static_cast<int>(count)), [f](const cv::Range& r){
for (auto i = r.start; i < r.end; ++i){
f(i);
} });
};
}
INSTANTIATE_TEST_CASE_P(FluidTiledParallel8x10, TiledComputation,
Combine(
single_arg_computations(),
Values(cv::Size(8, 10)),
tilesets_8x10(),
Values(serial_for, cv_parallel_for))
);
} // namespace opencv_test
//define custom printer for "parallel_for" test parameter
namespace std {
void PrintTo(decltype(cv::GFluidParallelFor::parallel_for) const& f, std::ostream* o);
}
//separate declaration and definition are needed to please the compiler
void std::PrintTo(decltype(cv::GFluidParallelFor::parallel_for) const& f, std::ostream* o){
if (f) {
using namespace opencv_test;
if (f.target<decltype(serial_for)>()){
*o <<"serial_for";
}
else if (f.target<decltype(cv_parallel_for)>()){
*o <<"cv_parallel_for";
}
else {
*o <<"parallel_for of type: " << f.target_type().name();
}
}
else
{
*o << "default parallel_for";
}
}

View File

@@ -0,0 +1,869 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include "gapi_fluid_test_kernels.hpp"
namespace opencv_test
{
using namespace cv::gapi_test_kernels;
G_TYPED_KERNEL(TCopy, <GMat(GMat)>, "test.fluid.copy")
{
static GMatDesc outMeta(const cv::GMatDesc &in) {
return in;
}
};
GAPI_FLUID_KERNEL(FCopy, TCopy, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &out)
{
const uint8_t* in_row = in .InLine <uint8_t>(0);
uint8_t* out_row = out.OutLine<uint8_t>();
for (int i = 0, w = in.length(); i < w; i++)
{
//std::cout << std::setw(4) << int(in_row[i]);
out_row[i] = in_row[i];
}
//std::cout << std::endl;
}
};
GAPI_FLUID_KERNEL(FResizeNN1Lpi, cv::gapi::core::GResize, false)
{
static const int Window = 1;
static const auto Kind = GFluidKernel::Kind::Resize;
static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/,
cv::gapi::fluid::Buffer& out)
{
auto length = out.length();
double vRatio = (double)in.meta().size.height / out.meta().size.height;
double hRatio = (double)in.length() / length;
auto y = out.y();
auto inY = in.y();
for (int l = 0; l < out.lpi(); l++)
{
auto sy = static_cast<int>((y+l) * vRatio);
int idx = sy - inY;
const auto src = in.InLine <unsigned char>(idx);
auto dst = out.OutLine<unsigned char>(l);
for (int x = 0; x < length; x++)
{
auto inX = static_cast<int>(x * hRatio);
dst[x] = src[inX];
}
}
}
};
namespace
{
namespace func
{
template <class Mapper>
void initScratch(const cv::GMatDesc& in, cv::Size outSz, cv::gapi::fluid::Buffer &scratch)
{
CV_Assert(in.depth == CV_8U && in.chan == 1);
cv::Size scratch_size{static_cast<int>(outSz.width * sizeof(typename Mapper::Unit)), 1};
cv::GMatDesc desc;
desc.chan = 1;
desc.depth = CV_8UC1;
desc.size = scratch_size;
cv::gapi::fluid::Buffer buffer(desc);
scratch = std::move(buffer);
auto mapX = scratch.OutLine<typename Mapper::Unit>();
double hRatio = (double)in.size.width / outSz.width;
for (int x = 0, w = outSz.width; x < w; x++)
{
mapX[x] = Mapper::map(hRatio, 0, in.size.width, x);
}
}
template <class Mapper>
inline void calcRow(const cv::gapi::fluid::View& in, cv::gapi::fluid::Buffer& out, cv::gapi::fluid::Buffer &scratch)
{
double vRatio = (double)in.meta().size.height / out.meta().size.height;
auto mapX = scratch.OutLine<typename Mapper::Unit>();
auto inY = in.y();
auto inH = in.meta().size.height;
auto outY = out.y();
auto length = out.length();
for (int l = 0; l < out.lpi(); l++)
{
auto mapY = Mapper::map(vRatio, inY, inH, outY + l);
const auto src0 = in.InLine <unsigned char>(mapY.s0);
const auto src1 = in.InLine <unsigned char>(mapY.s1);
auto dst = out.OutLine<unsigned char>(l);
for (int x = 0; x < length; x++)
{
auto alpha0 = mapX[x].alpha0;
auto alpha1 = mapX[x].alpha1;
auto sx0 = mapX[x].s0;
auto sx1 = mapX[x].s1;
int res0 = src0[sx0]*alpha0 + src0[sx1]*alpha1;
int res1 = src1[sx0]*alpha0 + src1[sx1]*alpha1;
dst[x] = uchar(( ((mapY.alpha0 * (res0 >> 4)) >> 16) + ((mapY.alpha1 * (res1 >> 4)) >> 16) + 2)>>2);
}
}
}
} // namespace func
constexpr static const int INTER_RESIZE_COEF_BITS = 11;
constexpr static const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
namespace linear
{
struct Mapper
{
struct Unit
{
short alpha0;
short alpha1;
int s0;
int s1;
};
static inline Unit map(double ratio, int start, int max, int outCoord)
{
auto f = static_cast<float>((outCoord + 0.5f) * ratio - 0.5f);
int s = cvFloor(f);
f -= s;
Unit u;
u.s0 = std::max(s - start, 0);
u.s1 = ((f == 0.0) || s + 1 >= max) ? s - start : s - start + 1;
u.alpha0 = saturate_cast<short>((1.0f - f) * INTER_RESIZE_COEF_SCALE);
u.alpha1 = saturate_cast<short>((f) * INTER_RESIZE_COEF_SCALE);
return u;
}
};
} // namespace linear
namespace areaUpscale
{
struct Mapper
{
struct Unit
{
short alpha0;
short alpha1;
int s0;
int s1;
};
static inline Unit map(double ratio, int start, int max, int outCoord)
{
int s = cvFloor(outCoord*ratio);
float f = (float)((outCoord+1) - (s+1)/ratio);
f = f <= 0 ? 0.f : f - cvFloor(f);
Unit u;
u.s0 = std::max(s - start, 0);
u.s1 = ((f == 0.0) || s + 1 >= max) ? s - start : s - start + 1;
u.alpha0 = saturate_cast<short>((1.0f - f) * INTER_RESIZE_COEF_SCALE);
u.alpha1 = saturate_cast<short>((f) * INTER_RESIZE_COEF_SCALE);
return u;
}
};
} // namespace areaUpscale
} // anonymous namespace
GAPI_FLUID_KERNEL(FResizeLinear1Lpi, cv::gapi::core::GResize, true)
{
static const int Window = 1;
static const auto Kind = GFluidKernel::Kind::Resize;
static void initScratch(const cv::GMatDesc& in,
cv::Size outSz, double /*fx*/, double /*fy*/, int /*interp*/,
cv::gapi::fluid::Buffer &scratch)
{
func::initScratch<linear::Mapper>(in, outSz, scratch);
}
static void resetScratch(cv::gapi::fluid::Buffer& /*scratch*/)
{}
static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/,
cv::gapi::fluid::Buffer& out, cv::gapi::fluid::Buffer &scratch)
{
func::calcRow<linear::Mapper>(in, out, scratch);
}
};
namespace
{
// FIXME
// Move to some common place (to reuse/align with ResizeAgent)
auto startInCoord = [](int outCoord, double ratio) {
return static_cast<int>(outCoord * ratio + 1e-3);
};
auto endInCoord = [](int outCoord, double ratio) {
return static_cast<int>(std::ceil((outCoord + 1) * ratio - 1e-3));
};
} // namespace
GAPI_FLUID_KERNEL(FResizeArea1Lpi, cv::gapi::core::GResize, false)
{
static const int Window = 1;
static const auto Kind = GFluidKernel::Kind::Resize;
static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/,
cv::gapi::fluid::Buffer& out)
{
auto firstOutLineIdx = out.y();
auto firstViewLineIdx = in.y();
auto length = out.length();
double vRatio = (double)in.meta().size.height / out.meta().size.height;
double hRatio = (double)in.length() / length;
for (int l = 0; l < out.lpi(); l++)
{
int outY = firstOutLineIdx + l;
int startY = startInCoord(outY, vRatio);
int endY = endInCoord (outY, vRatio);
auto dst = out.OutLine<unsigned char>(l);
for (int x = 0; x < length; x++)
{
float res = 0.0;
int startX = startInCoord(x, hRatio);
int endX = endInCoord (x, hRatio);
for (int inY = startY; inY < endY; inY++)
{
double startCoordY = inY / vRatio;
double endCoordY = startCoordY + 1/vRatio;
if (startCoordY < outY) startCoordY = outY;
if (endCoordY > outY + 1) endCoordY = outY + 1;
float fracY = static_cast<float>((inY == startY || inY == endY - 1) ? endCoordY - startCoordY : 1/vRatio);
const auto src = in.InLine <unsigned char>(inY - firstViewLineIdx);
float rowSum = 0.0f;
for (int inX = startX; inX < endX; inX++)
{
double startCoordX = inX / hRatio;
double endCoordX = startCoordX + 1/hRatio;
if (startCoordX < x) startCoordX = x;
if (endCoordX > x + 1) endCoordX = x + 1;
float fracX = static_cast<float>((inX == startX || inX == endX - 1) ? endCoordX - startCoordX : 1/hRatio);
rowSum += src[inX] * fracX;
}
res += rowSum * fracY;
}
dst[x] = static_cast<unsigned char>(std::rint(res));
}
}
}
};
GAPI_FLUID_KERNEL(FResizeAreaUpscale1Lpi, cv::gapi::core::GResize, true)
{
static const int Window = 1;
static const auto Kind = GFluidKernel::Kind::Resize;
static void initScratch(const cv::GMatDesc& in,
cv::Size outSz, double /*fx*/, double /*fy*/, int /*interp*/,
cv::gapi::fluid::Buffer &scratch)
{
func::initScratch<areaUpscale::Mapper>(in, outSz, scratch);
}
static void resetScratch(cv::gapi::fluid::Buffer& /*scratch*/)
{}
static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/,
cv::gapi::fluid::Buffer& out, cv::gapi::fluid::Buffer &scratch)
{
func::calcRow<areaUpscale::Mapper>(in, out, scratch);
}
};
#define ADD_RESIZE_KERNEL_WITH_LPI(interp, lpi, scratch) \
struct Resize##interp##lpi##LpiHelper : public FResize##interp##1Lpi { static const int LPI = lpi; }; \
struct FResize##interp##lpi##Lpi : public cv::GFluidKernelImpl<Resize##interp##lpi##LpiHelper, cv::gapi::core::GResize, scratch>{};
ADD_RESIZE_KERNEL_WITH_LPI(NN, 2, false)
ADD_RESIZE_KERNEL_WITH_LPI(NN, 3, false)
ADD_RESIZE_KERNEL_WITH_LPI(NN, 4, false)
ADD_RESIZE_KERNEL_WITH_LPI(Linear, 2, true)
ADD_RESIZE_KERNEL_WITH_LPI(Linear, 3, true)
ADD_RESIZE_KERNEL_WITH_LPI(Linear, 4, true)
ADD_RESIZE_KERNEL_WITH_LPI(Area, 2, false)
ADD_RESIZE_KERNEL_WITH_LPI(Area, 3, false)
ADD_RESIZE_KERNEL_WITH_LPI(Area, 4, false)
ADD_RESIZE_KERNEL_WITH_LPI(AreaUpscale, 2, true)
ADD_RESIZE_KERNEL_WITH_LPI(AreaUpscale, 3, true)
ADD_RESIZE_KERNEL_WITH_LPI(AreaUpscale, 4, true)
#undef ADD_RESIZE_KERNEL_WITH_LPI
static auto fluidResizeTestPackage = [](int interpolation, cv::Size szIn, cv::Size szOut, int lpi = 1)
{
using namespace cv;
using namespace cv::gapi;
bool upscale = szIn.width < szOut.width || szIn.height < szOut.height;
#define RESIZE_CASE(interp, lpi) \
case lpi: pkg = kernels<FCopy, FResize##interp##lpi##Lpi>(); break;
#define RESIZE_SWITCH(interp) \
switch(lpi) \
{ \
RESIZE_CASE(interp, 1) \
RESIZE_CASE(interp, 2) \
RESIZE_CASE(interp, 3) \
RESIZE_CASE(interp, 4) \
default: CV_Assert(false); \
}
GKernelPackage pkg;
switch (interpolation)
{
case INTER_NEAREST: RESIZE_SWITCH(NN); break;
case INTER_LINEAR: RESIZE_SWITCH(Linear); break;
case INTER_AREA:
{
if (upscale)
{
RESIZE_SWITCH(AreaUpscale)
}
else
{
RESIZE_SWITCH(Area);
}
}break;
default: CV_Assert(false);
}
return combine(pkg, fluidTestPackage);
#undef RESIZE_SWITCH
#undef RESIZE_CASE
};
struct ResizeTestFluid : public TestWithParam<std::tuple<int, int, cv::Size, std::tuple<cv::Size, cv::Rect>, int, double>> {};
TEST_P(ResizeTestFluid, SanityTest)
{
int type = 0, interp = 0;
cv::Size sz_in, sz_out;
int lpi = 0;
double tolerance = 0.0;
cv::Rect outRoi;
std::tuple<cv::Size, cv::Rect> outSizeAndRoi;
std::tie(type, interp, sz_in, outSizeAndRoi, lpi, tolerance) = GetParam();
std::tie(sz_out, outRoi) = outSizeAndRoi;
if (outRoi == cv::Rect{}) outRoi = {0,0,sz_out.width,sz_out.height};
if (outRoi.width == 0) outRoi.width = sz_out.width;
double fx = 0, fy = 0;
cv::Mat in_mat1 (sz_in, type );
cv::Scalar mean = cv::Scalar(127);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat1, mean, stddev);
cv::Mat out_mat = cv::Mat::zeros(sz_out, type);
cv::Mat out_mat_ocv = cv::Mat::zeros(sz_out, type);
cv::GMat in;
auto mid = TBlur3x3::on(in, cv::BORDER_REPLICATE, {});
auto out = cv::gapi::resize(mid, sz_out, fx, fy, interp);
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat, cv::compile_args(GFluidOutputRois{{outRoi}}, fluidResizeTestPackage(interp, sz_in, sz_out, lpi)));
cv::Mat mid_mat;
cv::blur(in_mat1, mid_mat, {3,3}, {-1,-1}, cv::BORDER_REPLICATE);
cv::resize(mid_mat, out_mat_ocv, sz_out, fx, fy, interp);
cv::Mat absDiff;
cv::absdiff(out_mat(outRoi), out_mat_ocv(outRoi), absDiff);
EXPECT_EQ(0, cv::countNonZero(absDiff > tolerance));
}
INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeTestFluid,
Combine(Values(CV_8UC1),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR),
Values(cv::Size(8, 7),
cv::Size(8, 8),
cv::Size(8, 64),
cv::Size(8, 25),
cv::Size(16, 8),
cv::Size(16, 7)),
Values(std::make_tuple(cv::Size(5, 4), cv::Rect{}),
std::make_tuple(cv::Size(5, 4), cv::Rect{0, 0, 0, 2}),
std::make_tuple(cv::Size(5, 4), cv::Rect{0, 1, 0, 2}),
std::make_tuple(cv::Size(5, 4), cv::Rect{0, 2, 0, 2}),
std::make_tuple(cv::Size(7, 7), cv::Rect{}),
std::make_tuple(cv::Size(7, 7), cv::Rect{0, 0, 0, 3}),
std::make_tuple(cv::Size(7, 7), cv::Rect{0, 2, 0, 2}),
std::make_tuple(cv::Size(7, 7), cv::Rect{0, 4, 0, 3}),
std::make_tuple(cv::Size(8, 4), cv::Rect{}),
std::make_tuple(cv::Size(8, 4), cv::Rect{0, 0, 0, 3}),
std::make_tuple(cv::Size(8, 4), cv::Rect{0, 1, 0, 2}),
std::make_tuple(cv::Size(8, 4), cv::Rect{0, 3, 0, 1})),
Values(1, 2, 3, 4), // lpi
Values(0.0)));
INSTANTIATE_TEST_CASE_P(ResizeAreaTestCPU, ResizeTestFluid,
Combine(Values(CV_8UC1),
Values(cv::INTER_AREA),
Values(cv::Size(8, 7),
cv::Size(8, 8),
cv::Size(8, 64),
cv::Size(8, 25),
cv::Size(16, 8),
cv::Size(16, 7)),
Values(std::make_tuple(cv::Size(5, 4), cv::Rect{}),
std::make_tuple(cv::Size(5, 4), cv::Rect{0, 0, 0, 2}),
std::make_tuple(cv::Size(5, 4), cv::Rect{0, 1, 0, 2}),
std::make_tuple(cv::Size(5, 4), cv::Rect{0, 2, 0, 2}),
std::make_tuple(cv::Size(7, 7), cv::Rect{}),
std::make_tuple(cv::Size(7, 7), cv::Rect{0, 0, 0, 3}),
std::make_tuple(cv::Size(7, 7), cv::Rect{0, 2, 0, 2}),
std::make_tuple(cv::Size(7, 7), cv::Rect{0, 4, 0, 3}),
std::make_tuple(cv::Size(8, 4), cv::Rect{}),
std::make_tuple(cv::Size(8, 4), cv::Rect{0, 0, 0, 3}),
std::make_tuple(cv::Size(8, 4), cv::Rect{0, 1, 0, 2}),
std::make_tuple(cv::Size(8, 4), cv::Rect{0, 3, 0, 1})),
Values(1, 2, 3, 4), // lpi
// Actually this tolerance only for cases where OpenCV
// uses ResizeAreaFast
Values(1.0)));
INSTANTIATE_TEST_CASE_P(ResizeUpscaleTestCPU, ResizeTestFluid,
Combine(Values(CV_8UC1),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values(cv::Size(1, 5),
cv::Size(3, 5),
cv::Size(7, 5),
cv::Size(1, 7),
cv::Size(3, 7),
cv::Size(7, 7)),
Values(std::make_tuple(cv::Size(8, 8), cv::Rect{0,0,8,2}),
std::make_tuple(cv::Size(8, 8), cv::Rect{0,2,8,2}),
std::make_tuple(cv::Size(8, 8), cv::Rect{0,4,8,2}),
std::make_tuple(cv::Size(8, 8), cv::Rect{0,6,8,2}),
std::make_tuple(cv::Size(8, 8), cv::Rect{0,0,8,8}),
std::make_tuple(cv::Size(16, 8), cv::Rect{}),
std::make_tuple(cv::Size(16, 64), cv::Rect{0, 0,16,16}),
std::make_tuple(cv::Size(16, 64), cv::Rect{0,16,16,16}),
std::make_tuple(cv::Size(16, 64), cv::Rect{0,32,16,16}),
std::make_tuple(cv::Size(16, 64), cv::Rect{0,48,16,16}),
std::make_tuple(cv::Size(16, 64), cv::Rect{0, 0,16,64}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0, 0,16, 7}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0, 7,16, 6}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0,13,16, 6}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0,19,16, 6}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0, 0,16, 7}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0, 7,16, 7}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0,14,16, 7}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0,21,16, 4}),
std::make_tuple(cv::Size(16, 25), cv::Rect{0, 0,16,25}),
std::make_tuple(cv::Size(16, 7), cv::Rect{}),
std::make_tuple(cv::Size(16, 8), cv::Rect{})),
Values(1, 2, 3, 4), // lpi
Values(0.0)));
INSTANTIATE_TEST_CASE_P(ResizeUpscaleOneDimDownscaleAnother, ResizeTestFluid,
Combine(Values(CV_8UC1),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values(cv::Size(6, 6),
cv::Size(8, 7),
cv::Size(8, 8),
cv::Size(8, 10),
cv::Size(10, 8),
cv::Size(10, 7)),
Values(std::make_tuple(cv::Size(11, 5), cv::Rect{}),
std::make_tuple(cv::Size(11, 5), cv::Rect{0, 0, 0, 2}),
std::make_tuple(cv::Size(11, 5), cv::Rect{0, 2, 0, 2}),
std::make_tuple(cv::Size(11, 5), cv::Rect{0, 4, 0, 1}),
std::make_tuple(cv::Size(12, 2), cv::Rect{}),
std::make_tuple(cv::Size(12, 2), cv::Rect{0, 0, 0, 1}),
std::make_tuple(cv::Size(12, 2), cv::Rect{0, 1, 0, 1}),
std::make_tuple(cv::Size(23, 3), cv::Rect{}),
std::make_tuple(cv::Size(23, 3), cv::Rect{0, 0, 0, 1}),
std::make_tuple(cv::Size(23, 3), cv::Rect{0, 1, 0, 1}),
std::make_tuple(cv::Size(23, 3), cv::Rect{0, 2, 0, 1}),
std::make_tuple(cv::Size(3, 24), cv::Rect{}),
std::make_tuple(cv::Size(3, 24), cv::Rect{0, 0, 0, 6}),
std::make_tuple(cv::Size(3, 24), cv::Rect{0, 6, 0, 6}),
std::make_tuple(cv::Size(3, 24), cv::Rect{0, 12, 0, 6}),
std::make_tuple(cv::Size(3, 24), cv::Rect{0, 18, 0, 6}),
std::make_tuple(cv::Size(5, 11), cv::Rect{}),
std::make_tuple(cv::Size(5, 11), cv::Rect{0, 0, 0, 3}),
std::make_tuple(cv::Size(5, 11), cv::Rect{0, 3, 0, 3}),
std::make_tuple(cv::Size(5, 11), cv::Rect{0, 6, 0, 3}),
std::make_tuple(cv::Size(5, 11), cv::Rect{0, 9, 0, 2})),
Values(1, 2, 3, 4), // lpi
Values(0.0)));
INSTANTIATE_TEST_CASE_P(Resize400_384TestCPU, ResizeTestFluid,
Combine(Values(CV_8UC1),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values(cv::Size(128, 400)),
Values(std::make_tuple(cv::Size(128, 384), cv::Rect{})),
Values(1, 2, 3, 4), // lpi
Values(0.0)));
INSTANTIATE_TEST_CASE_P(Resize220_400TestCPU, ResizeTestFluid,
Combine(Values(CV_8UC1),
Values(cv::INTER_LINEAR),
Values(cv::Size(220, 220)),
Values(std::make_tuple(cv::Size(400, 400), cv::Rect{})),
Values(1, 2, 3, 4), // lpi
Values(0.0)));
static auto cvBlur = [](const cv::Mat& in, cv::Mat& out, int kernelSize)
{
if (kernelSize == 1)
{
out = in;
}
else
{
cv::blur(in, out, {kernelSize, kernelSize});
}
};
using SizesWithRois = std::tuple<cv::Size, cv::Rect, cv::Size, cv::Rect>;
struct ResizeAndAnotherReaderTest : public TestWithParam<std::tuple<int, int, bool, SizesWithRois>>{};
TEST_P(ResizeAndAnotherReaderTest, SanityTest)
{
bool readFromInput = false;
int interp = -1, kernelSize = -1;
SizesWithRois sizesWithRois;
std::tie(interp, kernelSize, readFromInput, sizesWithRois) = GetParam();
cv::Size sz, resizedSz;
cv::Rect roi, resizedRoi;
std::tie(sz, roi, resizedSz, resizedRoi) = sizesWithRois;
cv::Mat in_mat(sz, CV_8UC1);
cv::Scalar mean = cv::Scalar(127);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Mat gapi_resize_out = cv::Mat::zeros(resizedSz, CV_8UC1);
cv::Mat gapi_blur_out = cv::Mat::zeros(sz, CV_8UC1);
auto blur = kernelSize == 1 ? &TBlur1x1::on : kernelSize == 3 ? &TBlur3x3::on : &TBlur5x5::on;
cv::GMat in, resize_out, blur_out;
if (readFromInput)
{
resize_out = gapi::resize(in, resizedSz, 0, 0, interp);
blur_out = blur(in, cv::BORDER_DEFAULT, {});
}
else
{
auto mid = TCopy::on(in);
resize_out = gapi::resize(mid, resizedSz, 0, 0, interp);
blur_out = blur(mid, cv::BORDER_DEFAULT, {});
}
cv::GComputation c(GIn(in), GOut(resize_out, blur_out));
c.apply(gin(in_mat), gout(gapi_resize_out, gapi_blur_out), cv::compile_args(GFluidOutputRois{{resizedRoi, roi}},
fluidResizeTestPackage(interp, sz, resizedSz)));
cv::Mat ocv_resize_out = cv::Mat::zeros(resizedSz, CV_8UC1);
cv::resize(in_mat, ocv_resize_out, resizedSz, 0, 0, interp);
cv::Mat ocv_blur_out = cv::Mat::zeros(sz, CV_8UC1);
cvBlur(in_mat, ocv_blur_out, kernelSize);
EXPECT_EQ(0, cv::countNonZero(gapi_resize_out(resizedRoi) != ocv_resize_out(resizedRoi)));
EXPECT_EQ(0, cv::countNonZero(gapi_blur_out(roi) != ocv_blur_out(roi)));
}
INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeAndAnotherReaderTest,
Combine(Values(cv::INTER_NEAREST, cv::INTER_LINEAR),
Values(1, 3, 5),
testing::Bool(), // Read from input directly or place a copy node at start
Values(std::make_tuple(cv::Size{8,8}, cv::Rect{0,0,8,8},
cv::Size{4,4}, cv::Rect{0,0,4,4}),
std::make_tuple(cv::Size{8,8}, cv::Rect{0,0,8,2},
cv::Size{4,4}, cv::Rect{0,0,4,1}),
std::make_tuple(cv::Size{8,8}, cv::Rect{0,2,8,4},
cv::Size{4,4}, cv::Rect{0,1,4,2}),
std::make_tuple(cv::Size{8,8}, cv::Rect{0,4,8,4},
cv::Size{4,4}, cv::Rect{0,2,4,2}),
std::make_tuple(cv::Size{64,64}, cv::Rect{0, 0,64,64},
cv::Size{49,49}, cv::Rect{0, 0,49,49}),
std::make_tuple(cv::Size{64,64}, cv::Rect{0, 0,64,15},
cv::Size{49,49}, cv::Rect{0, 0,49,11}),
std::make_tuple(cv::Size{64,64}, cv::Rect{0,11,64,23},
cv::Size{49,49}, cv::Rect{0, 9,49,17}),
std::make_tuple(cv::Size{64,64}, cv::Rect{0,50,64,14},
cv::Size{49,49}, cv::Rect{0,39,49,10}))));
struct BlursAfterResizeTest : public TestWithParam<std::tuple<int, int, int, bool, std::tuple<cv::Size, cv::Size, cv::Rect>>>{};
TEST_P(BlursAfterResizeTest, SanityTest)
{
bool readFromInput = false;
int interp = -1, kernelSize1 = -1, kernelSize2 = -1;
std::tuple<cv::Size, cv::Size, cv::Rect> sizesWithRoi;
std::tie(interp, kernelSize1, kernelSize2, readFromInput, sizesWithRoi) = GetParam();
cv::Size inSz, outSz;
cv::Rect outRoi;
std::tie(inSz, outSz, outRoi) = sizesWithRoi;
cv::Mat in_mat(inSz, CV_8UC1);
cv::Scalar mean = cv::Scalar(127);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Mat gapi_out1 = cv::Mat::zeros(outSz, CV_8UC1);
cv::Mat gapi_out2 = cv::Mat::zeros(outSz, CV_8UC1);
auto blur1 = kernelSize1 == 1 ? &TBlur1x1::on : kernelSize1 == 3 ? &TBlur3x3::on : &TBlur5x5::on;
auto blur2 = kernelSize2 == 1 ? &TBlur1x1::on : kernelSize2 == 3 ? &TBlur3x3::on : &TBlur5x5::on;
cv::GMat in, out1, out2;
if (readFromInput)
{
auto resized = gapi::resize(in, outSz, 0, 0, interp);
out1 = blur1(resized, cv::BORDER_DEFAULT, {});
out2 = blur2(resized, cv::BORDER_DEFAULT, {});
}
else
{
auto mid = TCopy::on(in);
auto resized = gapi::resize(mid, outSz, 0, 0, interp);
out1 = blur1(resized, cv::BORDER_DEFAULT, {});
out2 = blur2(resized, cv::BORDER_DEFAULT, {});
}
cv::GComputation c(GIn(in), GOut(out1, out2));
c.apply(gin(in_mat), gout(gapi_out1, gapi_out2), cv::compile_args(GFluidOutputRois{{outRoi, outRoi}},
fluidResizeTestPackage(interp, inSz, outSz)));
cv::Mat ocv_out1 = cv::Mat::zeros(outSz, CV_8UC1);
cv::Mat ocv_out2 = cv::Mat::zeros(outSz, CV_8UC1);
cv::Mat resized = cv::Mat::zeros(outSz, CV_8UC1);
cv::resize(in_mat, resized, outSz, 0, 0, interp);
cvBlur(resized, ocv_out1, kernelSize1);
cvBlur(resized, ocv_out2, kernelSize2);
EXPECT_EQ(0, cv::countNonZero(gapi_out1(outRoi) != ocv_out1(outRoi)));
EXPECT_EQ(0, cv::countNonZero(gapi_out2(outRoi) != ocv_out2(outRoi)));
}
INSTANTIATE_TEST_CASE_P(ResizeTestCPU, BlursAfterResizeTest,
Combine(Values(cv::INTER_NEAREST, cv::INTER_LINEAR),
Values(1, 3, 5),
Values(1, 3, 5),
testing::Bool(), // Read from input directly or place a copy node at start
Values(std::make_tuple(cv::Size{8,8},
cv::Size{4,4}, cv::Rect{0,0,4,4}),
std::make_tuple(cv::Size{8,8},
cv::Size{4,4}, cv::Rect{0,0,4,1}),
std::make_tuple(cv::Size{8,8},
cv::Size{4,4}, cv::Rect{0,1,4,2}),
std::make_tuple(cv::Size{8,8},
cv::Size{4,4}, cv::Rect{0,2,4,2}),
std::make_tuple(cv::Size{64,64},
cv::Size{49,49}, cv::Rect{0, 0,49,49}),
std::make_tuple(cv::Size{64,64},
cv::Size{49,49}, cv::Rect{0, 0,49,11}),
std::make_tuple(cv::Size{64,64},
cv::Size{49,49}, cv::Rect{0, 9,49,17}),
std::make_tuple(cv::Size{64,64},
cv::Size{49,49}, cv::Rect{0,39,49,10}))));
struct NV12PlusResizeTest : public TestWithParam <std::tuple<cv::Size, cv::Size, cv::Rect>> {};
TEST_P(NV12PlusResizeTest, Test)
{
cv::Size y_sz, out_sz;
cv::Rect roi;
std::tie(y_sz, out_sz, roi) = GetParam();
int interp = cv::INTER_LINEAR;
cv::Size uv_sz(y_sz.width / 2, y_sz.height / 2);
cv::Size in_sz(y_sz.width, y_sz.height*3/2);
cv::Mat in_mat = cv::Mat(in_sz, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Mat y_mat = cv::Mat(y_sz, CV_8UC1, in_mat.data);
cv::Mat uv_mat = cv::Mat(uv_sz, CV_8UC2, in_mat.data + in_mat.step1() * y_sz.height);
cv::Mat out_mat, out_mat_ocv;
cv::GMat y, uv;
auto rgb = cv::gapi::NV12toRGB(y, uv);
auto out = cv::gapi::resize(rgb, out_sz, 0, 0, interp);
cv::GComputation c(cv::GIn(y, uv), cv::GOut(out));
auto pkg = cv::gapi::combine(fluidTestPackage, cv::gapi::core::fluid::kernels());
c.apply(cv::gin(y_mat, uv_mat), cv::gout(out_mat)
,cv::compile_args(pkg, cv::GFluidOutputRois{{to_own(roi)}}));
cv::Mat rgb_mat;
cv::cvtColor(in_mat, rgb_mat, cv::COLOR_YUV2RGB_NV12);
cv::resize(rgb_mat, out_mat_ocv, out_sz, 0, 0, interp);
EXPECT_EQ(0, cv::countNonZero(out_mat(roi) != out_mat_ocv(roi)));
}
INSTANTIATE_TEST_CASE_P(Fluid, NV12PlusResizeTest,
Values(std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 0, 4, 4})
,std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 0, 4, 1})
,std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 1, 4, 2})
,std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 2, 4, 2})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 0, 49, 49})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 0, 49, 12})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 11, 49, 15})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 39, 49, 10})
,std::make_tuple(cv::Size{1920, 1080},
cv::Size{ 320, 256}, cv::Rect{0, 0, 320, 64})
,std::make_tuple(cv::Size{1920, 1080},
cv::Size{ 320, 256}, cv::Rect{0, 64, 320, 64})
,std::make_tuple(cv::Size{1920, 1080},
cv::Size{ 320, 256}, cv::Rect{0, 128, 320, 64})
,std::make_tuple(cv::Size{1920, 1080},
cv::Size{ 320, 256}, cv::Rect{0, 192, 320, 64})
,std::make_tuple(cv::Size{256, 400},
cv::Size{ 32, 64}, cv::Rect{0, 0, 32, 16})
,std::make_tuple(cv::Size{256, 400},
cv::Size{ 32, 64}, cv::Rect{0, 16, 32, 16})
,std::make_tuple(cv::Size{256, 400},
cv::Size{ 32, 64}, cv::Rect{0, 32, 32, 16})
,std::make_tuple(cv::Size{256, 400},
cv::Size{ 32, 64}, cv::Rect{0, 48, 32, 16})
));
struct Preproc4lpiTest : public TestWithParam <std::tuple<cv::Size, cv::Size, cv::Rect>>{};
TEST_P(Preproc4lpiTest, Test)
{
using namespace gapi_test_kernels;
cv::Size y_sz, out_sz;
cv::Rect roi;
std::tie(y_sz, out_sz, roi) = GetParam();
int interp = cv::INTER_LINEAR;
cv::Size uv_sz(y_sz.width / 2, y_sz.height / 2);
cv::Size in_sz(y_sz.width, y_sz.height*3/2);
cv::Mat in_mat = cv::Mat(in_sz, CV_8UC1);
cv::randn(in_mat, cv::Scalar::all(127.0f), cv::Scalar::all(40.f));
cv::Mat y_mat = cv::Mat(y_sz, CV_8UC1, in_mat.data);
cv::Mat uv_mat = cv::Mat(uv_sz, CV_8UC2, in_mat.data + in_mat.step1() * y_sz.height);
cv::Mat out_mat, out_mat_ocv;
cv::GMat y, uv;
auto rgb = cv::gapi::NV12toRGB(y, uv);
auto splitted = split3_4lpi(rgb);
cv::GMat resized[3] = { cv::gapi::resize(std::get<0>(splitted), out_sz, 0, 0, interp)
, cv::gapi::resize(std::get<1>(splitted), out_sz, 0, 0, interp)
, cv::gapi::resize(std::get<2>(splitted), out_sz, 0, 0, interp) };
auto out = merge3_4lpi(resized[0], resized[1], resized[2]);
cv::GComputation c(cv::GIn(y, uv), cv::GOut(out));
auto pkg = cv::gapi::combine(cv::gapi::core::fluid::kernels(),
fluidResizeTestPackage(interp, in_sz, out_sz, 4));
c.apply(cv::gin(y_mat, uv_mat), cv::gout(out_mat)
,cv::compile_args(pkg, cv::GFluidOutputRois{{to_own(roi)}}));
cv::Mat rgb_mat;
cv::cvtColor(in_mat, rgb_mat, cv::COLOR_YUV2RGB_NV12);
cv::resize(rgb_mat, out_mat_ocv, out_sz, 0, 0, interp);
EXPECT_EQ(0, cv::countNonZero(out_mat(roi) != out_mat_ocv(roi)));
}
INSTANTIATE_TEST_CASE_P(Fluid, Preproc4lpiTest,
Values(std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 0, 4, 4})
,std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 0, 4, 1})
,std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 1, 4, 2})
,std::make_tuple(cv::Size{8, 8},
cv::Size{4, 4}, cv::Rect{0, 2, 4, 2})
,std::make_tuple(cv::Size{24, 24},
cv::Size{12, 12}, cv::Rect{0, 0, 12, 3})
,std::make_tuple(cv::Size{24, 24},
cv::Size{12, 12}, cv::Rect{0, 3, 12, 3})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 0, 49, 49})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 0, 49, 12})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 11, 49, 15})
,std::make_tuple(cv::Size{64, 64},
cv::Size{49, 49}, cv::Rect{0, 39, 49, 10})
,std::make_tuple(cv::Size{640, 480},
cv::Size{300, 199}, cv::Rect{0, 0, 300, 50})
,std::make_tuple(cv::Size{640, 480},
cv::Size{300, 199}, cv::Rect{0, 50, 300, 50})
,std::make_tuple(cv::Size{640, 480},
cv::Size{300, 199}, cv::Rect{0, 100, 300, 50})
,std::make_tuple(cv::Size{640, 480},
cv::Size{300, 199}, cv::Rect{0, 150, 300, 49})
));
} // namespace opencv_test

View File

@@ -0,0 +1,197 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include "gapi_fluid_test_kernels.hpp"
namespace opencv_test
{
using namespace cv::gapi_test_kernels;
struct PartialComputation : public TestWithParam <std::tuple<cv::Rect>> {};
TEST_P(PartialComputation, Test)
{
cv::Rect roi;
std::tie(roi) = GetParam();
int borderType = BORDER_REPLICATE;
int kernelSize = 3;
cv::Point anchor = {-1, -1};
cv::GMat in;
cv::GMat out = TBlur3x3::on(in, borderType, {});
cv::GComputation c(cv::GIn(in), cv::GOut(out));
const auto sz = cv::Size(8, 10);
cv::Mat in_mat(sz, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Mat out_mat_gapi = cv::Mat::zeros(sz, CV_8UC1);
cv::Mat out_mat_ocv = cv::Mat::zeros(sz, CV_8UC1);
// Run G-API
auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage, GFluidOutputRois{{to_own(roi)}}));
cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
// Check with OpenCV
if (roi == cv::Rect{}) roi = cv::Rect{0,0,sz.width,sz.height};
cv::blur(in_mat(roi), out_mat_ocv(roi), {kernelSize, kernelSize}, anchor, borderType);
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
}
INSTANTIATE_TEST_CASE_P(Fluid, PartialComputation,
Values(cv::Rect{}, cv::Rect{0,0,8,6}, cv::Rect{0,1,8,3},
cv::Rect{0,2,8,3}, cv::Rect{0,3,8,5}, cv::Rect{0,4,8,6}));
struct PartialComputationAddC : public TestWithParam <std::tuple<cv::Rect>> {};
TEST_P(PartialComputationAddC, Test)
{
cv::Rect roi;
std::tie(roi) = GetParam();
cv::GMat in;
cv::GMat out = TAddCSimple::on(in, 1);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
const auto sz = cv::Size(8, 10);
cv::Mat in_mat(sz, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Mat out_mat_gapi = cv::Mat::zeros(sz, CV_8UC1);
cv::Mat out_mat_ocv = cv::Mat::zeros(sz, CV_8UC1);
// Run G-API
auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage, GFluidOutputRois{{to_own(roi)}}));
cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
// Check with OpenCV
if (roi == cv::Rect{}) roi = cv::Rect{0,0,sz.width,sz.height};
out_mat_ocv(roi) = in_mat(roi) + 1;
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
}
INSTANTIATE_TEST_CASE_P(FluidRoi, PartialComputationAddC,
Values(cv::Rect{}, cv::Rect{0,0,8,6}, cv::Rect{0,1,8,3},
cv::Rect{0,2,8,3}, cv::Rect{0,3,8,5}, cv::Rect{0,4,8,6}));
struct SequenceOfBlursRoiTest : public TestWithParam <std::tuple<int, cv::Rect>> {};
TEST_P(SequenceOfBlursRoiTest, Test)
{
cv::Size sz_in = { 320, 240 };
int borderType = 0;
cv::Rect roi;
std::tie(borderType, roi) = GetParam();
cv::Mat in_mat(sz_in, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Point anchor = {-1, -1};
cv::Scalar borderValue(0);
GMat in;
auto mid = TBlur3x3::on(in, borderType, borderValue);
auto out = TBlur5x5::on(mid, borderType, borderValue);
Mat out_mat_gapi = Mat::zeros(sz_in, CV_8UC1);
GComputation c(GIn(in), GOut(out));
auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage, GFluidOutputRois{{to_own(roi)}}));
cc(gin(in_mat), gout(out_mat_gapi));
cv::Mat mid_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
cv::Mat out_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
cv::blur(in_mat, mid_mat_ocv, {3,3}, anchor, borderType);
if (roi == cv::Rect{})
{
roi = cv::Rect{0, 0, sz_in.width, sz_in.height};
}
cv::blur(mid_mat_ocv(roi), out_mat_ocv(roi), {5,5}, anchor, borderType);
EXPECT_EQ(0, countNonZero(out_mat_ocv != out_mat_gapi));
}
INSTANTIATE_TEST_CASE_P(FluidRoi, SequenceOfBlursRoiTest,
Combine(Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101),
Values(cv::Rect{0,0,320,240}, cv::Rect{0,64,320,128}, cv::Rect{0,128,320,112})));
struct TwoBlursRoiTest : public TestWithParam <std::tuple<int, int, int, int, int, int, bool, cv::Rect>> {};
TEST_P(TwoBlursRoiTest, Test)
{
cv::Size sz_in = { 320, 240 };
int kernelSize1 = 0, kernelSize2 = 0;
int borderType1 = -1, borderType2 = -1;
cv::Scalar borderValue1{}, borderValue2{};
bool readFromInput = false;
cv::Rect outRoi;
std::tie(kernelSize1, borderType1, borderValue1, kernelSize2, borderType2, borderValue2, readFromInput, outRoi) = GetParam();
cv::Mat in_mat(sz_in, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Point anchor = {-1, -1};
auto blur1 = kernelSize1 == 3 ? &TBlur3x3::on : TBlur5x5::on;
auto blur2 = kernelSize2 == 3 ? &TBlur3x3::on : TBlur5x5::on;
GMat in, out1, out2;
if (readFromInput)
{
out1 = blur1(in, borderType1, borderValue1);
out2 = blur2(in, borderType2, borderValue2);
}
else
{
auto mid = TAddCSimple::on(in, 0);
out1 = blur1(mid, borderType1, borderValue1);
out2 = blur2(mid, borderType2, borderValue2);
}
Mat out_mat_gapi1 = Mat::zeros(sz_in, CV_8UC1);
Mat out_mat_gapi2 = Mat::zeros(sz_in, CV_8UC1);
GComputation c(GIn(in), GOut(out1, out2));
auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage, GFluidOutputRois{{outRoi, outRoi}}));
cc(gin(in_mat), gout(out_mat_gapi1, out_mat_gapi2));
cv::Mat out_mat_ocv1 = Mat::zeros(sz_in, CV_8UC1);
cv::Mat out_mat_ocv2 = Mat::zeros(sz_in, CV_8UC1);
cv::blur(in_mat(outRoi), out_mat_ocv1(outRoi), {kernelSize1, kernelSize1}, anchor, borderType1);
cv::blur(in_mat(outRoi), out_mat_ocv2(outRoi), {kernelSize2, kernelSize2}, anchor, borderType2);
EXPECT_EQ(0, countNonZero(out_mat_ocv1 != out_mat_gapi1));
EXPECT_EQ(0, countNonZero(out_mat_ocv2 != out_mat_gapi2));
}
INSTANTIATE_TEST_CASE_P(FluidRoi, TwoBlursRoiTest,
Combine(Values(3, 5),
Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
Values(0),
Values(3, 5),
Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
Values(0),
testing::Bool(), // Read from input directly or place a copy node at start
Values(cv::Rect{0,0,320,240}, cv::Rect{0,64,320,128}, cv::Rect{0,128,320,112})));
} // namespace opencv_test

View File

@@ -0,0 +1,906 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/fluid/gfluidbuffer.hpp>
#include <opencv2/gapi/fluid/gfluidkernel.hpp>
// FIXME: move these tests with priv() to internal suite
#include "backends/fluid/gfluidbuffer_priv.hpp"
#include "gapi_fluid_test_kernels.hpp"
#include "logger.hpp"
namespace opencv_test
{
using namespace cv::gapi_test_kernels;
namespace
{
void WriteFunction(uint8_t* row, int nr, int w) {
for (int i = 0; i < w; i++)
row[i] = static_cast<uint8_t>(nr+i);
};
void ReadFunction1x1(const uint8_t* row, int w) {
for (int i = 0; i < w; i++)
std::cout << std::setw(4) << static_cast<int>(row[i]) << " ";
std::cout << "\n";
};
void ReadFunction3x3(const uint8_t* rows[3], int w) {
for (int i = 0; i < 3; i++) {
for (int j = -1; j < w+1; j++) {
std::cout << std::setw(4) << static_cast<int>(rows[i][j]) << " ";
}
std::cout << "\n";
}
std::cout << "\n";
};
}
TEST(FluidBuffer, InputTest)
{
const cv::Size buffer_size = {8,8};
cv::Mat in_mat = cv::Mat::eye(buffer_size, CV_8U);
cv::gapi::fluid::Buffer buffer(to_own(in_mat), true);
cv::gapi::fluid::View view = buffer.mkView(0, false);
view.priv().allocate(1, {});
view.priv().reset(1);
int this_y = 0;
while (this_y < buffer_size.height)
{
view.priv().prepareToRead();
const uint8_t* rrow = view.InLine<uint8_t>(0);
ReadFunction1x1(rrow, buffer_size.width);
view.priv().readDone(1,1);
cv::Mat from_buffer(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow));
EXPECT_EQ(0, cv::countNonZero(in_mat.row(this_y) != from_buffer));
this_y++;
}
}
TEST(FluidBuffer, CircularTest)
{
const cv::Size buffer_size = {8,16};
cv::gapi::fluid::Buffer buffer(cv::GMatDesc{CV_8U,1,buffer_size}, 3, 1, 0, 1,
util::make_optional(cv::gapi::fluid::Border{cv::BORDER_CONSTANT, cv::gapi::own::Scalar(255)}));
cv::gapi::fluid::View view = buffer.mkView(1, {});
view.priv().reset(3);
view.priv().allocate(3, {});
buffer.debug(std::cout);
const auto whole_line_is = [](const uint8_t *line, int len, int value)
{
return std::all_of(line, line+len, [&](const uint8_t v){return v == value;});
};
// Store all read/written data in separate Mats to compare with
cv::Mat written_data(buffer_size, CV_8U);
// Simulate write/read process
int num_reads = 0, num_writes = 0;
while (num_reads < buffer_size.height)
{
if (num_writes < buffer_size.height)
{
uint8_t* wrow = buffer.OutLine<uint8_t>();
WriteFunction(wrow, num_writes, buffer_size.width);
buffer.priv().writeDone();
cv::Mat(1, buffer_size.width, CV_8U, wrow)
.copyTo(written_data.row(num_writes));
num_writes++;
}
buffer.debug(std::cout);
if (view.ready())
{
view.priv().prepareToRead();
const uint8_t* rrow[3] = {
view.InLine<uint8_t>(-1),
view.InLine<uint8_t>( 0),
view.InLine<uint8_t>( 1),
};
ReadFunction3x3(rrow, buffer_size.width);
view.priv().readDone(1,3);
buffer.debug(std::cout);
// Check borders right here
EXPECT_EQ(255u, rrow[0][-1]);
EXPECT_EQ(255u, rrow[0][buffer_size.width]);
if (num_reads == 0)
{
EXPECT_TRUE(whole_line_is(rrow[0]-1, buffer_size.width+2, 255u));
}
if (num_reads == buffer_size.height-1)
{
EXPECT_TRUE(whole_line_is(rrow[2]-1, buffer_size.width+2, 255u));
}
// Check window (without borders)
if (num_reads > 0 && num_reads < buffer_size.height-1)
{
// +1 everywhere since num_writes was just incremented above
cv::Mat written_lastLine2 = written_data.row(num_writes - (2+1));
cv::Mat written_lastLine1 = written_data.row(num_writes - (1+1));
cv::Mat written_lastLine0 = written_data.row(num_writes - (0+1));
cv::Mat read_prevLine(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow[0]));
cv::Mat read_thisLine(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow[1]));
cv::Mat read_nextLine(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow[2]));
EXPECT_EQ(0, cv::countNonZero(written_lastLine2 != read_prevLine));
EXPECT_EQ(0, cv::countNonZero(written_lastLine1 != read_thisLine));
EXPECT_EQ(0, cv::countNonZero(written_lastLine0 != read_nextLine));
}
num_reads++;
}
}
}
TEST(FluidBuffer, OutputTest)
{
const cv::Size buffer_size = {8,16};
cv::Mat out_mat = cv::Mat(buffer_size, CV_8U);
cv::gapi::fluid::Buffer buffer(to_own(out_mat), false);
int num_writes = 0;
while (num_writes < buffer_size.height)
{
uint8_t* wrow = buffer.OutLine<uint8_t>();
WriteFunction(wrow, num_writes, buffer_size.width);
buffer.priv().writeDone();
num_writes++;
}
GAPI_LOG_INFO(NULL, "\n" << out_mat);
// Validity check
for (int r = 0; r < buffer_size.height; r++)
{
for (int c = 0; c < buffer_size.width; c++)
{
EXPECT_EQ(r+c, out_mat.at<uint8_t>(r, c));
}
}
}
TEST(Fluid, AddC_WithScalar)
{
cv::GMat in;
cv::GScalar s;
cv::GComputation c(cv::GIn(in, s), cv::GOut(TAddScalar::on(in, s)));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1), out_mat(3, 3, CV_8UC1), ref_mat;
cv::Scalar in_s(100);
auto cc = c.compile(cv::descr_of(in_mat), cv::descr_of(in_s), cv::compile_args(fluidTestPackage));
cc(cv::gin(in_mat, in_s), cv::gout(out_mat));
ref_mat = in_mat + in_s;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(Fluid, Scalar_In_Middle_Graph)
{
cv::GMat in;
cv::GScalar s;
cv::GComputation c(cv::GIn(in, s), cv::GOut(TAddScalar::on(TAddCSimple::on(in, 5), s)));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1), out_mat(3, 3, CV_8UC1), ref_mat;
cv::Scalar in_s(100);
auto cc = c.compile(cv::descr_of(in_mat), cv::descr_of(in_s), cv::compile_args(fluidTestPackage));
cc(cv::gin(in_mat, in_s), cv::gout(out_mat));
ref_mat = (in_mat + 5) + in_s;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(Fluid, Add_Scalar_To_Mat)
{
cv::GMat in;
cv::GScalar s;
cv::GComputation c(cv::GIn(s, in), cv::GOut(TAddScalarToMat::on(s, in)));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1), out_mat(3, 3, CV_8UC1), ref_mat;
cv::Scalar in_s(100);
auto cc = c.compile(cv::descr_of(in_s), cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(cv::gin(in_s, in_mat), cv::gout(out_mat));
ref_mat = in_mat + in_s;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(Fluid, Sum_2_Mats_And_Scalar)
{
cv::GMat a, b;
cv::GScalar s;
cv::GComputation c(cv::GIn(a, s, b), cv::GOut(TSum2MatsAndScalar::on(a, s, b)));
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
out_mat(3, 3, CV_8UC1),
ref_mat;
cv::Scalar in_s(100);
auto cc = c.compile(cv::descr_of(in_mat1), cv::descr_of(in_s), cv::descr_of(in_mat2), cv::compile_args(fluidTestPackage));
cc(cv::gin(in_mat1, in_s, in_mat2), cv::gout(out_mat));
ref_mat = in_mat1 + in_mat2 + in_s;
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(Fluid, EqualizeHist)
{
cv::GMat in, out;
cv::GComputation c(cv::GIn(in), cv::GOut(TEqualizeHist::on(in, TCalcHist::on(in))));
cv::Mat in_mat(320, 480, CV_8UC1),
out_mat(320, 480, CV_8UC1),
ref_mat(320, 480, CV_8UC1);
cv::randu(in_mat, 200, 240);
auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(cv::gin(in_mat), cv::gout(out_mat));
cv::equalizeHist(in_mat, ref_mat);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(Fluid, Split3)
{
cv::GMat bgr;
cv::GMat r,g,b;
std::tie(b,g,r) = cv::gapi::split3(bgr);
auto rr = TAddSimple::on(r, TId::on(b));
auto rrr = TAddSimple::on(TId::on(rr), g);
cv::GComputation c(bgr, TId::on(rrr));
cv::Size sz(5120, 5120);
cv::Mat eye_1 = cv::Mat::eye(sz, CV_8UC1);
std::vector<cv::Mat> eyes = {eye_1, eye_1, eye_1};
cv::Mat in_mat;
cv::merge(eyes, in_mat);
cv::Mat out_mat(sz, CV_8UC1);
// G-API
auto cc = c.compile(cv::descr_of(in_mat),
cv::compile_args(fluidTestPackage));
cc(in_mat, out_mat);
// OCV
std::vector<cv::Mat> chans;
cv::split(in_mat, chans);
// Compare
EXPECT_EQ(0, cv::countNonZero(out_mat != (chans[2]*3)));
}
TEST(Fluid, ScratchTest)
{
cv::GMat in;
cv::GMat out = TPlusRow0::on(TPlusRow0::on(in));
cv::GComputation c(in, out);
cv::Size sz(8, 8);
cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
cv::Mat out_mat(sz, CV_8UC1);
// OpenCV (reference)
cv::Mat ref;
{
cv::Mat first_row = cv::Mat::zeros(1, sz.width, CV_8U);
cv::Mat remaining = cv::repeat(in_mat.row(0), sz.height-1, 1);
cv::Mat operand;
cv::vconcat(first_row, 2*remaining, operand);
ref = in_mat + operand;
}
GAPI_LOG_INFO(NULL, "\n" << ref);
// G-API
auto cc = c.compile(cv::descr_of(in_mat),
cv::compile_args(fluidTestPackage));
cc(in_mat, out_mat);
GAPI_LOG_INFO(NULL, "\n" << out_mat);
EXPECT_EQ(0, cv::countNonZero(ref != out_mat));
cc(in_mat, out_mat);
GAPI_LOG_INFO(NULL, "\n" << out_mat);
EXPECT_EQ(0, cv::countNonZero(ref != out_mat));
}
TEST(Fluid, MultipleOutRowsTest)
{
cv::GMat in;
cv::GMat out = TAddCSimple::on(TAddCSimple::on(in, 1), 2);
cv::GComputation c(in, out);
cv::Size sz(4, 4);
cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
cv::Mat out_mat(sz, CV_8UC1);
auto cc = c.compile(cv::descr_of(in_mat),
cv::compile_args(fluidTestPackage));
cc(in_mat, out_mat);
std::cout << out_mat << std::endl;
cv::Mat ocv_ref = in_mat + 1 + 2;
EXPECT_EQ(0, cv::countNonZero(ocv_ref != out_mat));
}
TEST(Fluid, LPIWindow)
{
cv::GMat in;
cv::GMat r,g,b;
std::tie(r,g,b) = cv::gapi::split3(in);
cv::GMat rr = TId7x7::on(r);
cv::GMat tmp = TAddSimple::on(rr, g);
cv::GMat out = TAddSimple::on(tmp, b);
cv::GComputation c(in, out);
cv::Size sz(8, 8);
cv::Mat eye_1 = cv::Mat::eye(sz, CV_8UC1);
std::vector<cv::Mat> eyes = {eye_1, eye_1, eye_1};
cv::Mat in_mat;
cv::merge(eyes, in_mat);
cv::Mat out_mat(sz, CV_8U);
auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(in_mat, out_mat);
//std::cout << out_mat << std::endl;
// OpenCV reference
cv::Mat ocv_ref = eyes[0]+eyes[1]+eyes[2];
EXPECT_EQ(0, cv::countNonZero(ocv_ref != out_mat));
}
TEST(Fluid, MultipleReaders_SameLatency)
{
// in -> AddC -> a -> AddC -> b -> Add -> out
// '--> AddC -> c -'
//
// b and c have the same skew
cv::GMat in;
cv::GMat a = TAddCSimple::on(in, 1); // FIXME - align naming (G, non-G)
cv::GMat b = TAddCSimple::on(a, 2);
cv::GMat c = TAddCSimple::on(a, 3);
cv::GMat out = TAddSimple::on(b, c);
cv::GComputation comp(in, out);
const auto sz = cv::Size(32, 32);
cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
cv::Mat out_mat_gapi(sz, CV_8UC1);
cv::Mat out_mat_ocv (sz, CV_8UC1);
// Run G-API
auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(in_mat, out_mat_gapi);
// Check with OpenCV
cv::Mat tmp = in_mat + 1;
out_mat_ocv = (tmp+2) + (tmp+3);
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
}
TEST(Fluid, MultipleReaders_DifferentLatency)
{
// in1 -> AddC -> a -> AddC -------------> b -> Add -> out
// '--------------> Add --> c -'
// '--> Id7x7-> d -'
//
// b and c have different skew (due to latency introduced by Id7x7)
// a is ready by multiple views with different latency.
cv::GMat in;
cv::GMat a = TAddCSimple::on(in, 1); // FIXME - align naming (G, non-G)
cv::GMat b = TAddCSimple::on(a, 2);
cv::GMat d = TId7x7::on(a);
cv::GMat c = TAddSimple::on(a, d);
cv::GMat out = TAddSimple::on(b, c);
cv::GComputation comp(in, out);
const auto sz = cv::Size(32, 32);
cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
cv::Mat out_mat_gapi(sz, CV_8UC1);
// Run G-API
auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(in_mat, out_mat_gapi);
// Check with OpenCV
cv::Mat ocv_a = in_mat + 1;
cv::Mat ocv_b = ocv_a + 2;
cv::Mat ocv_d = ocv_a;
cv::Mat ocv_c = ocv_a + ocv_d;
cv::Mat out_mat_ocv = ocv_b + ocv_c;
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
}
TEST(Fluid, MultipleOutputs)
{
// in -> AddC -> a -> AddC ------------------> out1
// `--> Id7x7 --> b --> AddC -> out2
cv::GMat in;
cv::GMat a = TAddCSimple::on(in, 1);
cv::GMat b = TId7x7::on(a);
cv::GMat out1 = TAddCSimple::on(a, 2);
cv::GMat out2 = TAddCSimple::on(b, 7);
cv::GComputation comp(cv::GIn(in), cv::GOut(out1, out2));
const auto sz = cv::Size(32, 32);
cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
cv::Mat out_mat_gapi1(sz, CV_8UC1), out_mat_gapi2(sz, CV_8UC1);
cv::Mat out_mat_ocv1(sz, CV_8UC1), out_mat_ocv2(sz, CV_8UC1);
// Run G-API
auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(cv::gin(in_mat), cv::gout(out_mat_gapi1, out_mat_gapi2));
// Check with OpenCV
out_mat_ocv1 = in_mat + 1 + 2;
out_mat_ocv2 = in_mat + 1 + 7;
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi1 != out_mat_ocv1));
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi2 != out_mat_ocv2));
}
TEST(Fluid, EmptyOutputMatTest)
{
cv::GMat in;
cv::GMat out = TAddCSimple::on(in, 2);
cv::GComputation c(in, out);
cv::Mat in_mat = cv::Mat::eye(cv::Size(32, 24), CV_8UC1);
cv::Mat out_mat;
auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(in_mat, out_mat);
EXPECT_EQ(CV_8UC1, out_mat.type());
EXPECT_EQ(32, out_mat.cols);
EXPECT_EQ(24, out_mat.rows);
EXPECT_TRUE(out_mat.ptr() != nullptr);
}
struct LPISequenceTest : public TestWithParam<int>{};
TEST_P(LPISequenceTest, LPISequenceTest)
{
// in -> AddC -> a -> Blur (2lpi) -> out
int kernelSize = GetParam();
cv::GMat in;
cv::GMat a = TAddCSimple::on(in, 1);
auto blur = kernelSize == 3 ? &TBlur3x3_2lpi::on : &TBlur5x5_2lpi::on;
cv::GMat out = blur(a, cv::BORDER_CONSTANT, cv::Scalar(0));
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
const auto sz = cv::Size(8, 10);
cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
cv::Mat out_mat_gapi(sz, CV_8UC1);
cv::Mat out_mat_ocv(sz, CV_8UC1);
// Run G-API
auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
// Check with OpenCV
cv::blur(in_mat + 1, out_mat_ocv, {kernelSize,kernelSize}, {-1,-1}, cv::BORDER_CONSTANT);
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
}
INSTANTIATE_TEST_CASE_P(Fluid, LPISequenceTest,
Values(3, 5));
struct InputImageBorderTest : public TestWithParam <std::tuple<int, int>> {};
TEST_P(InputImageBorderTest, InputImageBorderTest)
{
cv::Size sz_in = { 320, 240 };
int ks = 0;
int borderType = 0;
std::tie(ks, borderType) = GetParam();
cv::Mat in_mat1(sz_in, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat1, mean, stddev);
cv::Size kernelSize = {ks, ks};
cv::Point anchor = {-1, -1};
cv::Scalar borderValue(0);
auto gblur = ks == 3 ? &TBlur3x3::on : &TBlur5x5::on;
GMat in;
auto out = gblur(in, borderType, borderValue);
Mat out_mat_gapi = Mat::zeros(sz_in, CV_8UC1);
GComputation c(GIn(in), GOut(out));
auto cc = c.compile(descr_of(in_mat1), cv::compile_args(fluidTestPackage));
cc(gin(in_mat1), gout(out_mat_gapi));
cv::Mat out_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
cv::blur(in_mat1, out_mat_ocv, kernelSize, anchor, borderType);
EXPECT_EQ(0, countNonZero(out_mat_ocv != out_mat_gapi));
}
INSTANTIATE_TEST_CASE_P(Fluid, InputImageBorderTest,
Combine(Values(3, 5),
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101)));
struct SequenceOfBlursTest : public TestWithParam <std::tuple<int>> {};
TEST_P(SequenceOfBlursTest, Test)
{
cv::Size sz_in = { 320, 240 };
int borderType = 0;;
std::tie(borderType) = GetParam();
cv::Mat in_mat(sz_in, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Point anchor = {-1, -1};
cv::Scalar borderValue(0);
GMat in;
auto mid = TBlur3x3::on(in, borderType, borderValue);
auto out = TBlur5x5::on(mid, borderType, borderValue);
Mat out_mat_gapi = Mat::zeros(sz_in, CV_8UC1);
GComputation c(GIn(in), GOut(out));
auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(gin(in_mat), gout(out_mat_gapi));
cv::Mat mid_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
cv::Mat out_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
cv::blur(in_mat, mid_mat_ocv, {3,3}, anchor, borderType);
cv::blur(mid_mat_ocv, out_mat_ocv, {5,5}, anchor, borderType);
EXPECT_EQ(0, countNonZero(out_mat_ocv != out_mat_gapi));
}
INSTANTIATE_TEST_CASE_P(Fluid, SequenceOfBlursTest,
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101));
struct TwoBlursTest : public TestWithParam <std::tuple<int, int, int, int, int, int, bool>> {};
TEST_P(TwoBlursTest, Test)
{
cv::Size sz_in = { 320, 240 };
int kernelSize1 = 0, kernelSize2 = 0;
int borderType1 = -1, borderType2 = -1;
cv::Scalar borderValue1{}, borderValue2{};
bool readFromInput = false;
std::tie(kernelSize1, borderType1, borderValue1, kernelSize2, borderType2, borderValue2, readFromInput) = GetParam();
cv::Mat in_mat(sz_in, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Point anchor = {-1, -1};
auto blur1 = kernelSize1 == 3 ? &TBlur3x3::on : TBlur5x5::on;
auto blur2 = kernelSize2 == 3 ? &TBlur3x3::on : TBlur5x5::on;
GMat in, out1, out2;
if (readFromInput)
{
out1 = blur1(in, borderType1, borderValue1);
out2 = blur2(in, borderType2, borderValue2);
}
else
{
auto mid = TAddCSimple::on(in, 0);
out1 = blur1(mid, borderType1, borderValue1);
out2 = blur2(mid, borderType2, borderValue2);
}
Mat out_mat_gapi1 = Mat::zeros(sz_in, CV_8UC1);
Mat out_mat_gapi2 = Mat::zeros(sz_in, CV_8UC1);
GComputation c(GIn(in), GOut(out1, out2));
auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(gin(in_mat), gout(out_mat_gapi1, out_mat_gapi2));
cv::Mat out_mat_ocv1 = Mat::zeros(sz_in, CV_8UC1);
cv::Mat out_mat_ocv2 = Mat::zeros(sz_in, CV_8UC1);
cv::blur(in_mat, out_mat_ocv1, {kernelSize1, kernelSize1}, anchor, borderType1);
cv::blur(in_mat, out_mat_ocv2, {kernelSize2, kernelSize2}, anchor, borderType2);
EXPECT_EQ(0, countNonZero(out_mat_ocv1 != out_mat_gapi1));
EXPECT_EQ(0, countNonZero(out_mat_ocv2 != out_mat_gapi2));
}
INSTANTIATE_TEST_CASE_P(Fluid, TwoBlursTest,
Combine(Values(3, 5),
Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
Values(0),
Values(3, 5),
Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
Values(0),
testing::Bool())); // Read from input directly or place a copy node at start
struct TwoReadersTest : public TestWithParam <std::tuple<int, int, int, bool>> {};
TEST_P(TwoReadersTest, Test)
{
cv::Size sz_in = { 320, 240 };
int kernelSize = 0;
int borderType = -1;
cv::Scalar borderValue;
bool readFromInput = false;
std::tie(kernelSize, borderType, borderValue, readFromInput) = GetParam();
cv::Mat in_mat(sz_in, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Point anchor = {-1, -1};
auto blur = kernelSize == 3 ? &TBlur3x3::on : TBlur5x5::on;
GMat in, out1, out2;
if (readFromInput)
{
out1 = TAddCSimple::on(in, 0);
out2 = blur(in, borderType, borderValue);
}
else
{
auto mid = TAddCSimple::on(in, 0);
out1 = TAddCSimple::on(mid, 0);
out2 = blur(mid, borderType, borderValue);
}
Mat out_mat_gapi1 = Mat::zeros(sz_in, CV_8UC1);
Mat out_mat_gapi2 = Mat::zeros(sz_in, CV_8UC1);
GComputation c(GIn(in), GOut(out1, out2));
auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage));
cc(gin(in_mat), gout(out_mat_gapi1, out_mat_gapi2));
cv::Mat out_mat_ocv1 = Mat::zeros(sz_in, CV_8UC1);
cv::Mat out_mat_ocv2 = Mat::zeros(sz_in, CV_8UC1);
out_mat_ocv1 = in_mat;
cv::blur(in_mat, out_mat_ocv2, {kernelSize, kernelSize}, anchor, borderType);
EXPECT_EQ(0, countNonZero(out_mat_ocv1 != out_mat_gapi1));
EXPECT_EQ(0, countNonZero(out_mat_ocv2 != out_mat_gapi2));
}
INSTANTIATE_TEST_CASE_P(Fluid, TwoReadersTest,
Combine(Values(3, 5),
Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
Values(0),
testing::Bool())); // Read from input directly or place a copy node at start
TEST(FluidTwoIslands, SanityTest)
{
cv::Size sz_in{8,8};
GMat in1, in2;
auto out1 = TAddScalar::on(in1, {0});
auto out2 = TAddScalar::on(in2, {0});
cv::Mat in_mat1(sz_in, CV_8UC1);
cv::Mat in_mat2(sz_in, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat1, mean, stddev);
cv::randn(in_mat2, mean, stddev);
Mat out_mat1 = Mat::zeros(sz_in, CV_8UC1);
Mat out_mat2 = Mat::zeros(sz_in, CV_8UC1);
GComputation c(GIn(in1, in2), GOut(out1, out2));
EXPECT_NO_THROW(c.apply(gin(in_mat1, in_mat2), gout(out_mat1, out_mat2), cv::compile_args(fluidTestPackage)));
EXPECT_EQ(0, countNonZero(in_mat1 != out_mat1));
EXPECT_EQ(0, countNonZero(in_mat2 != out_mat2));
}
struct NV12RoiTest : public TestWithParam <std::pair<cv::Size, cv::Rect>> {};
TEST_P(NV12RoiTest, Test)
{
cv::Size y_sz;
cv::Rect roi;
std::tie(y_sz, roi) = GetParam();
cv::Size uv_sz(y_sz.width / 2, y_sz.height / 2);
cv::Size in_sz(y_sz.width, y_sz.height*3/2);
cv::Mat in_mat = cv::Mat(in_sz, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
cv::Mat y_mat = cv::Mat(y_sz, CV_8UC1, in_mat.data);
cv::Mat uv_mat = cv::Mat(uv_sz, CV_8UC2, in_mat.data + in_mat.step1() * y_sz.height);
cv::Mat out_mat, out_mat_ocv;
cv::GMat y, uv;
auto rgb = cv::gapi::NV12toRGB(y, uv);
cv::GComputation c(cv::GIn(y, uv), cv::GOut(rgb));
c.apply(cv::gin(y_mat, uv_mat), cv::gout(out_mat), cv::compile_args(fluidTestPackage, cv::GFluidOutputRois{{to_own(roi)}}));
cv::cvtColor(in_mat, out_mat_ocv, cv::COLOR_YUV2RGB_NV12);
EXPECT_EQ(0, cv::countNonZero(out_mat(roi) != out_mat_ocv(roi)));
}
INSTANTIATE_TEST_CASE_P(Fluid, NV12RoiTest,
Values(std::make_pair(cv::Size{8, 8}, cv::Rect{0, 0, 8, 2})
,std::make_pair(cv::Size{8, 8}, cv::Rect{0, 2, 8, 2})
,std::make_pair(cv::Size{8, 8}, cv::Rect{0, 4, 8, 2})
,std::make_pair(cv::Size{8, 8}, cv::Rect{0, 6, 8, 2})
,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 0, 1920, 270})
,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 270, 1920, 270})
,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 540, 1920, 270})
,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 710, 1920, 270})
));
TEST(Fluid, UnusedNodeOutputCompileTest)
{
cv::GMat in;
cv::GMat a, b, c, d;
std::tie(a, b, c, d) = cv::gapi::split4(in);
cv::GMat out = cv::gapi::merge3(a, b, c);
cv::Mat in_mat(cv::Size(8, 8), CV_8UC4);
cv::Mat out_mat(cv::Size(8, 8), CV_8UC3);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
ASSERT_NO_THROW(comp.apply(cv::gin(in_mat), cv::gout(out_mat),
cv::compile_args(cv::gapi::core::fluid::kernels())));
}
TEST(Fluid, UnusedNodeOutputReshapeTest)
{
const auto test_size = cv::Size(8, 8);
const auto get_compile_args =
[] () { return cv::compile_args(cv::gapi::core::fluid::kernels()); };
cv::GMat in;
cv::GMat a, b, c, d;
std::tie(a, b, c, d) = cv::gapi::split4(in);
cv::GMat out = cv::gapi::resize(cv::gapi::merge3(a, b, c), test_size, 0.0, 0.0,
cv::INTER_LINEAR);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
cv::Mat in_mat(test_size, CV_8UC4);
cv::Mat out_mat(test_size, CV_8UC3);
cv::GCompiled compiled;
ASSERT_NO_THROW(compiled = comp.compile(descr_of(in_mat), get_compile_args()));
in_mat = cv::Mat(test_size * 2, CV_8UC4);
ASSERT_TRUE(compiled.canReshape());
ASSERT_NO_THROW(compiled.reshape(descr_of(gin(in_mat)), get_compile_args()));
ASSERT_NO_THROW(compiled(in_mat, out_mat));
}
TEST(Fluid, InvalidROIs)
{
cv::GMat in;
cv::GMat out = cv::gapi::add(in, in);
cv::Mat in_mat(cv::Size(8, 8), CV_8UC3);
cv::Mat out_mat = in_mat.clone();
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(100));
std::vector<cv::Rect> invalid_rois =
{
cv::Rect(1, 0, 0, 0),
cv::Rect(0, 1, 0, 0),
cv::Rect(0, 0, 1, 0),
cv::Rect(0, 0, 0, 1),
cv::Rect(0, 0, out_mat.cols, 0),
cv::Rect(0, 0, 0, out_mat.rows),
cv::Rect(0, out_mat.rows, out_mat.cols, out_mat.rows),
cv::Rect(out_mat.cols, 0, out_mat.cols, out_mat.rows),
};
const auto compile_args = [] (cv::Rect roi) {
return cv::compile_args(cv::gapi::core::fluid::kernels(), GFluidOutputRois{{to_own(roi)}});
};
for (const auto& roi : invalid_rois)
{
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
EXPECT_THROW(comp.apply(cv::gin(in_mat), cv::gout(out_mat), compile_args(roi)),
std::exception);
}
}
namespace
{
#if defined(__linux__)
uint64_t currMemoryConsumption()
{
// check self-state via /proc information
constexpr const char stat_file_path[] = "/proc/self/statm";
std::ifstream proc_stat(stat_file_path);
if (!proc_stat.is_open() || !proc_stat.good())
{
CV_LOG_WARNING(NULL, "Failed to open stat file: " << stat_file_path);
return static_cast<uint64_t>(0);
}
std::string stat_line;
std::getline(proc_stat, stat_line);
uint64_t unused, rss;
// using resident set size
std::istringstream(stat_line) >> unused >> rss;
CV_Assert(rss != 0);
return rss;
}
#else
// FIXME: implement this part (at least for Windows?), right now it's enough to check Linux only
uint64_t currMemoryConsumption() { return static_cast<uint64_t>(0); }
#endif
} // anonymous namespace
TEST(Fluid, MemoryConsumptionDoesNotGrowOnReshape)
{
cv::GMat in;
cv::GMat a, b, c;
std::tie(a, b, c) = cv::gapi::split3(in);
cv::GMat merged = cv::gapi::merge4(a, b, c, a);
cv::GMat d, e, f, g;
std::tie(d, e, f, g) = cv::gapi::split4(merged);
cv::GMat out = cv::gapi::merge3(d, e, f);
cv::Mat in_mat(cv::Size(8, 8), CV_8UC3);
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(100));
cv::Mat out_mat;
const auto compile_args = [] () {
return cv::compile_args(cv::gapi::core::fluid::kernels());
};
cv::GCompiled compiled = cv::GComputation(cv::GIn(in), cv::GOut(out)).compile(
cv::descr_of(in_mat), compile_args());
ASSERT_TRUE(compiled.canReshape());
const auto mem_before = currMemoryConsumption();
for (int _ = 0; _ < 1000; ++_) compiled.reshape(cv::descr_of(cv::gin(in_mat)), compile_args());
const auto mem_after = currMemoryConsumption();
ASSERT_GE(mem_before, mem_after);
}
} // namespace opencv_test

View File

@@ -0,0 +1,627 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <iomanip>
#include <vector>
#include "gapi_fluid_test_kernels.hpp"
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/own/saturate.hpp>
namespace cv
{
namespace gapi_test_kernels
{
GAPI_FLUID_KERNEL(FAddSimple, TAddSimple, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &a,
const cv::gapi::fluid::View &b,
cv::gapi::fluid::Buffer &o)
{
// std::cout << "AddSimple {{{\n";
// std::cout << " a - "; a.debug(std::cout);
// std::cout << " b - "; b.debug(std::cout);
// std::cout << " o - "; o.debug(std::cout);
const uint8_t* in1 = a.InLine<uint8_t>(0);
const uint8_t* in2 = b.InLine<uint8_t>(0);
uint8_t* out = o.OutLine<uint8_t>();
// std::cout << "a: ";
// for (int i = 0, w = a.length(); i < w; i++)
// {
// std::cout << std::setw(4) << int(in1[i]);
// }
// std::cout << "\n";
// std::cout << "b: ";
// for (int i = 0, w = a.length(); i < w; i++)
// {
// std::cout << std::setw(4) << int(in2[i]);
// }
// std::cout << "\n";
for (int i = 0, w = a.length(); i < w; i++)
{
out[i] = in1[i] + in2[i];
}
// std::cout << "}}} " << std::endl;;
}
};
GAPI_FLUID_KERNEL(FAddCSimple, TAddCSimple, false)
{
static const int Window = 1;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &in,
const int cval,
cv::gapi::fluid::Buffer &out)
{
for (int l = 0, lpi = out.lpi(); l < lpi; l++)
{
const uint8_t* in_row = in .InLine <uint8_t>(l);
uint8_t* out_row = out.OutLine<uint8_t>(l);
//std::cout << "l=" << l << ": ";
for (int i = 0, w = in.length(); i < w; i++)
{
//std::cout << std::setw(4) << int(in_row[i]);
//FIXME: it seems that over kernels might need it as well
out_row[i] = cv::gapi::own::saturate<uint8_t>(in_row[i] + cval);
}
//std::cout << std::endl;
}
}
};
GAPI_FLUID_KERNEL(FAddScalar, TAddScalar, false)
{
static const int Window = 1;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &in,
const cv::Scalar &cval,
cv::gapi::fluid::Buffer &out)
{
for (int l = 0, lpi = out.lpi(); l < lpi; l++)
{
const uint8_t* in_row = in .InLine <uint8_t>(l);
uint8_t* out_row = out.OutLine<uint8_t>(l);
std::cout << "l=" << l << ": ";
for (int i = 0, w = in.length(); i < w; i++)
{
std::cout << std::setw(4) << int(in_row[i]);
out_row[i] = static_cast<uint8_t>(in_row[i] + cval[0]);
}
std::cout << std::endl;
}
}
};
GAPI_FLUID_KERNEL(FAddScalarToMat, TAddScalarToMat, false)
{
static const int Window = 1;
static const int LPI = 2;
static void run(const cv::Scalar &cval,
const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &out)
{
for (int l = 0, lpi = out.lpi(); l < lpi; l++)
{
const uint8_t* in_row = in .InLine <uint8_t>(l);
uint8_t* out_row = out.OutLine<uint8_t>(l);
std::cout << "l=" << l << ": ";
for (int i = 0, w = in.length(); i < w; i++)
{
std::cout << std::setw(4) << int(in_row[i]);
out_row[i] = static_cast<uint8_t>(in_row[i] + cval[0]);
}
std::cout << std::endl;
}
}
};
template<int kernelSize, int lpi = 1>
static void runBlur(const cv::gapi::fluid::View& src, cv::gapi::fluid::Buffer& dst)
{
const auto borderSize = (kernelSize - 1) / 2;
const unsigned char* ins[kernelSize];
for (int l = 0; l < lpi; l++)
{
for (int i = 0; i < kernelSize; i++)
{
ins[i] = src.InLine<unsigned char>(i - borderSize + l);
}
auto out = dst.OutLine<unsigned char>(l);
const auto width = dst.length();
for (int w = 0; w < width; w++)
{
float res = 0.0f;
for (int i = 0; i < kernelSize; i++)
{
for (int j = -borderSize; j < borderSize + 1; j++)
{
res += ins[i][w+j];
}
}
out[w] = static_cast<unsigned char>(std::rint(res / (kernelSize * kernelSize)));
}
}
}
GAPI_FLUID_KERNEL(FBlur1x1, TBlur1x1, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &src, int /*borderType*/,
cv::Scalar /*borderValue*/, cv::gapi::fluid::Buffer &dst)
{
runBlur<Window>(src, dst);
}
};
GAPI_FLUID_KERNEL(FBlur3x3, TBlur3x3, false)
{
static const int Window = 3;
static void run(const cv::gapi::fluid::View &src, int /*borderType*/,
cv::Scalar /*borderValue*/, cv::gapi::fluid::Buffer &dst)
{
runBlur<Window>(src, dst);
}
static cv::gapi::fluid::Border getBorder(const cv::GMatDesc &/*src*/, int borderType, cv::Scalar borderValue)
{
return { borderType, to_own(borderValue)};
}
};
GAPI_FLUID_KERNEL(FBlur5x5, TBlur5x5, false)
{
static const int Window = 5;
static void run(const cv::gapi::fluid::View &src, int /*borderType*/,
cv::Scalar /*borderValue*/, cv::gapi::fluid::Buffer &dst)
{
runBlur<Window>(src, dst);
}
static cv::gapi::fluid::Border getBorder(const cv::GMatDesc &/*src*/, int borderType, cv::Scalar borderValue)
{
return { borderType, to_own(borderValue)};
}
};
GAPI_FLUID_KERNEL(FBlur3x3_2lpi, TBlur3x3_2lpi, false)
{
static const int Window = 3;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &src, int /*borderType*/,
cv::Scalar /*borderValue*/, cv::gapi::fluid::Buffer &dst)
{
runBlur<Window, LPI>(src, dst);
}
static cv::gapi::fluid::Border getBorder(const cv::GMatDesc &/*src*/, int borderType, cv::Scalar borderValue)
{
return { borderType, to_own(borderValue)};
}
};
GAPI_FLUID_KERNEL(FBlur5x5_2lpi, TBlur5x5_2lpi, false)
{
static const int Window = 5;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &src, int /*borderType*/,
cv::Scalar /*borderValue*/, cv::gapi::fluid::Buffer &dst)
{
runBlur<Window, LPI>(src, dst);
}
static cv::gapi::fluid::Border getBorder(const cv::GMatDesc &/*src*/, int borderType, cv::Scalar borderValue)
{
return { borderType, to_own(borderValue )};
}
};
GAPI_FLUID_KERNEL(FIdentity, TId, false)
{
static const int Window = 3;
static void run(const cv::gapi::fluid::View &a,
cv::gapi::fluid::Buffer &o)
{
const uint8_t* in[3] = {
a.InLine<uint8_t>(-1),
a.InLine<uint8_t>( 0),
a.InLine<uint8_t>(+1)
};
uint8_t* out = o.OutLine<uint8_t>();
// ReadFunction3x3(in, a.length());
for (int i = 0, w = a.length(); i < w; i++)
{
out[i] = in[1][i];
}
}
static gapi::fluid::Border getBorder(const cv::GMatDesc &)
{
return { cv::BORDER_REPLICATE, cv::gapi::own::Scalar{} };
}
};
GAPI_FLUID_KERNEL(FId7x7, TId7x7, false)
{
static const int Window = 7;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &a,
cv::gapi::fluid::Buffer &o)
{
for (int l = 0, lpi = o.lpi(); l < lpi; l++)
{
const uint8_t* in[Window] = {
a.InLine<uint8_t>(-3 + l),
a.InLine<uint8_t>(-2 + l),
a.InLine<uint8_t>(-1 + l),
a.InLine<uint8_t>( 0 + l),
a.InLine<uint8_t>(+1 + l),
a.InLine<uint8_t>(+2 + l),
a.InLine<uint8_t>(+3 + l),
};
uint8_t* out = o.OutLine<uint8_t>(l);
// std::cout << "Id7x7 " << l << " of " << lpi << " {{{\n";
// std::cout << " a - "; a.debug(std::cout);
// std::cout << " o - "; o.debug(std::cout);
// std::cout << "}}} " << std::endl;;
// // std::cout << "Id7x7 at " << a.y() << "/L" << l << " {{{" << std::endl;
// for (int j = 0; j < Window; j++)
// {
// // std::cout << std::setw(2) << j-(Window-1)/2 << ": ";
// for (int i = 0, w = a.length(); i < w; i++)
// std::cout << std::setw(4) << int(in[j][i]);
// std::cout << std::endl;
// }
// std::cout << "}}}" << std::endl;
for (int i = 0, w = a.length(); i < w; i++)
out[i] = in[(Window-1)/2][i];
}
}
static cv::gapi::fluid::Border getBorder(const cv::GMatDesc&/* src*/)
{
return { cv::BORDER_REPLICATE, cv::gapi::own::Scalar{} };
}
};
GAPI_FLUID_KERNEL(FPlusRow0, TPlusRow0, true)
{
static const int Window = 1;
static void initScratch(const cv::GMatDesc &in,
cv::gapi::fluid::Buffer &scratch)
{
cv::Size scratch_size{in.size.width, 1};
cv::gapi::fluid::Buffer buffer(in.withSize(scratch_size));
scratch = std::move(buffer);
}
static void resetScratch(cv::gapi::fluid::Buffer &scratch)
{
// FIXME: only 1 line can be used!
uint8_t* out_row = scratch.OutLine<uint8_t>();
for (int i = 0, w = scratch.length(); i < w; i++)
{
out_row[i] = 0;
}
}
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &out,
cv::gapi::fluid::Buffer &scratch)
{
const uint8_t* in_row = in .InLine <uint8_t>(0);
uint8_t* out_row = out .OutLine<uint8_t>();
uint8_t* tmp_row = scratch.OutLine<uint8_t>();
if (in.y() == 0)
{
// Copy 1st row to scratch buffer
for (int i = 0, w = in.length(); i < w; i++)
{
out_row[i] = in_row[i];
tmp_row[i] = in_row[i];
}
}
else
{
// Output is 1st row + in
for (int i = 0, w = in.length(); i < w; i++)
{
out_row[i] = in_row[i] + tmp_row[i];
}
}
}
};
static void split3Row(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &o1,
cv::gapi::fluid::Buffer &o2,
cv::gapi::fluid::Buffer &o3)
{
for (int l = 0; l < o1.lpi(); l++)
{
// std::cout << "Split3 {{{\n";
// std::cout << " a - "; in.debug(std::cout);
// std::cout << " 1 - "; o1.debug(std::cout);
// std::cout << " 2 - "; o2.debug(std::cout);
// std::cout << " 3 - "; o3.debug(std::cout);
// std::cout << "}}} " << std::endl;;
const uint8_t* in_rgb = in.InLine<uint8_t>(l);
uint8_t* out_r = o1.OutLine<uint8_t>(l);
uint8_t* out_g = o2.OutLine<uint8_t>(l);
uint8_t* out_b = o3.OutLine<uint8_t>(l);
for (int i = 0, w = in.length(); i < w; i++)
{
out_r[i] = in_rgb[3*i];
out_g[i] = in_rgb[3*i+1];
out_b[i] = in_rgb[3*i+2];
}
}
}
GAPI_FLUID_KERNEL(FTestSplit3, cv::gapi::core::GSplit3, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &o1,
cv::gapi::fluid::Buffer &o2,
cv::gapi::fluid::Buffer &o3)
{
split3Row(in, o1, o2, o3);
}
};
GAPI_FLUID_KERNEL(FTestSplit3_4lpi, TSplit3_4lpi, false)
{
static const int Window = 1;
static const int LPI = 4;
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &o1,
cv::gapi::fluid::Buffer &o2,
cv::gapi::fluid::Buffer &o3)
{
split3Row(in, o1, o2, o3);
}
};
std::tuple<GMat, GMat, GMat> split3_4lpi(const GMat& src)
{
return TSplit3_4lpi::on(src);
}
GAPI_FLUID_KERNEL(FSum2MatsAndScalar, TSum2MatsAndScalar, false)
{
static const int Window = 1;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &a,
const cv::Scalar &cval,
const cv::gapi::fluid::View &b,
cv::gapi::fluid::Buffer &out)
{
for (int l = 0, lpi = out.lpi(); l < lpi; l++)
{
const uint8_t* in_row1 = a .InLine <uint8_t>(l);
const uint8_t* in_row2 = b .InLine <uint8_t>(l);
uint8_t* out_row = out.OutLine<uint8_t>(l);
std::cout << "l=" << l << ": ";
for (int i = 0, w = a.length(); i < w; i++)
{
std::cout << std::setw(4) << int(in_row1[i]);
std::cout << std::setw(4) << int(in_row2[i]);
out_row[i] = static_cast<uint8_t>(in_row1[i] + in_row2[i] + cval[0]);
}
std::cout << std::endl;
}
}
};
GAPI_FLUID_KERNEL(FEqualizeHist, TEqualizeHist, false)
{
static const int Window = 1;
static const int LPI = 2;
static void run(const cv::gapi::fluid::View &mat,
const std::vector<int> &arr,
cv::gapi::fluid::Buffer &out)
{
for (int l = 0, lpi = out.lpi(); l < lpi; l++)
{
const uint8_t* in_row = mat.InLine <uint8_t>(l);
uint8_t* out_row = out.OutLine<uint8_t>(l);
for (int i = 0, w = mat.length(); i < w; i++)
{
out_row[i] = static_cast<uint8_t>(arr[in_row[i]]);
}
}
}
};
GAPI_OCV_KERNEL(OCVCalcHist, TCalcHist)
{
static void run(const cv::Mat& in, std::vector<int>& out)
{
out = std::vector<int>(256, 0);
// Calculate normalized accumulated integral transformation array for gapi
for(int i = 0; i < in.rows; ++i)
for(int j = 0; j < in.cols; ++j)
++out[in.at<uint8_t>(i, j)];
for(unsigned int i = 1; i < out.size(); ++i)
out[i] += out[i-1];
int size = in.size().width * in.size().height;
int min = size;
for(unsigned int i = 0; i < out.size(); ++i)
if(out[i] != 0 && out[i] < min)
min = out[i];
for(auto & el : out)
{
// General histogram equalization formula
el = cvRound(((float)(el - min) / (float)(size - min))*255);
}
}
};
static const int ITUR_BT_601_CY = 1220542;
static const int ITUR_BT_601_CUB = 2116026;
static const int ITUR_BT_601_CUG = -409993;
static const int ITUR_BT_601_CVG = -852492;
static const int ITUR_BT_601_CVR = 1673527;
static const int ITUR_BT_601_SHIFT = 20;
static inline void uvToRGBuv(const uchar u, const uchar v, int& ruv, int& guv, int& buv)
{
int uu, vv;
uu = int(u) - 128;
vv = int(v) - 128;
ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * vv;
guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * vv + ITUR_BT_601_CUG * uu;
buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * uu;
}
static inline void yRGBuvToRGB(const uchar vy, const int ruv, const int guv, const int buv,
uchar& r, uchar& g, uchar& b)
{
int y = std::max(0, vy - 16) * ITUR_BT_601_CY;
r = saturate_cast<uchar>((y + ruv) >> ITUR_BT_601_SHIFT);
g = saturate_cast<uchar>((y + guv) >> ITUR_BT_601_SHIFT);
b = saturate_cast<uchar>((y + buv) >> ITUR_BT_601_SHIFT);
}
GAPI_FLUID_KERNEL(FNV12toRGB, cv::gapi::imgproc::GNV12toRGB, false)
{
static const int Window = 1;
static const int LPI = 2;
static const auto Kind = GFluidKernel::Kind::YUV420toRGB;
static void run(const cv::gapi::fluid::View &in1,
const cv::gapi::fluid::View &in2,
cv::gapi::fluid::Buffer &out)
{
const auto w = out.length();
GAPI_Assert(w % 2 == 0);
GAPI_Assert(out.lpi() == 2);
const uchar* uv_row = in2.InLineB(0);
const uchar* y_rows[] = {in1. InLineB(0), in1. InLineB(1)};
uchar* out_rows[] = {out.OutLineB(0), out.OutLineB(1)};
for (int i = 0; i < w/2; i++)
{
uchar u = uv_row[2*i];
uchar v = uv_row[2*i + 1];
int ruv, guv, buv;
uvToRGBuv(u, v, ruv, guv, buv);
for (int y = 0; y < 2; y++)
{
for (int x = 0; x < 2; x++)
{
uchar vy = y_rows[y][2*i + x];
uchar r, g, b;
yRGBuvToRGB(vy, ruv, guv, buv, r, g, b);
out_rows[y][3*(2*i + x)] = r;
out_rows[y][3*(2*i + x) + 1] = g;
out_rows[y][3*(2*i + x) + 2] = b;
}
}
}
}
};
GAPI_FLUID_KERNEL(FMerge3_4lpi, TMerge3_4lpi, false)
{
static const int Window = 1;
static const int LPI = 4;
static void run(const cv::gapi::fluid::View &src1,
const cv::gapi::fluid::View &src2,
const cv::gapi::fluid::View &src3,
cv::gapi::fluid::Buffer &dst)
{
for (int l = 0; l < dst.lpi(); l++)
{
const auto *in1 = src1.InLine<uchar>(l);
const auto *in2 = src2.InLine<uchar>(l);
const auto *in3 = src3.InLine<uchar>(l);
auto *out = dst.OutLine<uchar>(l);
for (int w = 0; w < dst.length(); w++)
{
out[3*w ] = in1[w];
out[3*w + 1] = in2[w];
out[3*w + 2] = in3[w];
}
}
}
};
GMat merge3_4lpi(const GMat& src1, const GMat& src2, const GMat& src3)
{
return TMerge3_4lpi::on(src1, src2, src3);
}
cv::gapi::GKernelPackage fluidTestPackage = cv::gapi::kernels
<FAddSimple
,FAddCSimple
,FAddScalar
,FAddScalarToMat
,FBlur1x1
,FBlur3x3
,FBlur5x5
,FBlur3x3_2lpi
,FBlur5x5_2lpi
,FIdentity
,FId7x7
,FMerge3_4lpi
,FNV12toRGB
,FPlusRow0
,FSum2MatsAndScalar
,FTestSplit3
,FTestSplit3_4lpi
,FEqualizeHist
,OCVCalcHist
>();
} // namespace gapi_test_kernels
} // namespace cv

View File

@@ -0,0 +1,138 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#ifndef GAPI_FLUID_TEST_KERNELS_HPP
#define GAPI_FLUID_TEST_KERNELS_HPP
#include <opencv2/gapi/fluid/gfluidkernel.hpp>
namespace cv
{
namespace gapi_test_kernels
{
using cv::gapi::core::GMat3;
using GMat2 = std::tuple<GMat, GMat>;
G_TYPED_KERNEL(TAddSimple, <GMat(GMat, GMat)>, "test.fluid.add_simple") {
static cv::GMatDesc outMeta(cv::GMatDesc a, cv::GMatDesc) {
return a;
}
};
G_TYPED_KERNEL(TAddCSimple, <GMat(GMat,int)>, "test.fluid.addc_simple")
{
static GMatDesc outMeta(const cv::GMatDesc &in, int) {
return in;
}
};
G_TYPED_KERNEL(TAddScalar, <GMat(GMat,GScalar)>, "test.fluid.addc_scalar")
{
static GMatDesc outMeta(const cv::GMatDesc &in, const cv::GScalarDesc&) {
return in;
}
};
G_TYPED_KERNEL(TAddScalarToMat, <GMat(GScalar,GMat)>, "test.fluid.add_scalar_to_mat")
{
static GMatDesc outMeta(const cv::GScalarDesc&, const cv::GMatDesc &in) {
return in;
}
};
G_TYPED_KERNEL(TBlur1x1, <GMat(GMat,int,Scalar)>, "org.opencv.imgproc.filters.blur1x1"){
static GMatDesc outMeta(GMatDesc in, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(TBlur3x3, <GMat(GMat,int,Scalar)>, "org.opencv.imgproc.filters.blur3x3"){
static GMatDesc outMeta(GMatDesc in, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(TBlur5x5, <GMat(GMat,int,Scalar)>, "org.opencv.imgproc.filters.blur5x5"){
static GMatDesc outMeta(GMatDesc in, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(TBlur3x3_2lpi, <GMat(GMat,int,Scalar)>, "org.opencv.imgproc.filters.blur3x3_2lpi"){
static GMatDesc outMeta(GMatDesc in, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(TBlur5x5_2lpi, <GMat(GMat,int,Scalar)>, "org.opencv.imgproc.filters.blur5x5_2lpi"){
static GMatDesc outMeta(GMatDesc in, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(TId, <GMat(GMat)>, "test.fluid.identity") {
static cv::GMatDesc outMeta(cv::GMatDesc a) {
return a;
}
};
G_TYPED_KERNEL(TId7x7, <GMat(GMat)>, "test.fluid.identity7x7") {
static cv::GMatDesc outMeta(cv::GMatDesc a) {
return a;
}
};
G_TYPED_KERNEL(TMerge3_4lpi, <GMat(GMat,GMat,GMat)>, "test.fluid.merge3_4lpi") {
static GMatDesc outMeta(GMatDesc in, GMatDesc, GMatDesc) {
return in.withType(in.depth, 3);
}
};
G_TYPED_KERNEL(TPlusRow0, <GMat(GMat)>, "test.fluid.plus_row0") {
static cv::GMatDesc outMeta(cv::GMatDesc a) {
return a;
}
};
G_TYPED_KERNEL(TSum2MatsAndScalar, <GMat(GMat,GScalar,GMat)>, "test.fluid.sum_2_mats_and_scalar")
{
static GMatDesc outMeta(const cv::GMatDesc &in, const cv::GScalarDesc&, const cv::GMatDesc&) {
return in;
}
};
G_TYPED_KERNEL_M(TSplit3_4lpi, <GMat3(GMat)>, "test.fluid.split3_4lpi") {
static std::tuple<GMatDesc, GMatDesc, GMatDesc> outMeta(GMatDesc in) {
const auto out_depth = in.depth;
const auto out_desc = in.withType(out_depth, 1);
return std::make_tuple(out_desc, out_desc, out_desc);
}
};
G_TYPED_KERNEL(TEqualizeHist, <GMat(GMat, GArray<int>)>, "test.fluid.equalize_hist")
{
static GMatDesc outMeta(GMatDesc in, const cv::GArrayDesc&) {
return in;
}
};
G_TYPED_KERNEL(TCalcHist, <GArray<int>(GMat)>, "test.ocv.calc_hist")
{
static GArrayDesc outMeta(GMatDesc) {
return {};
}
};
GMat merge3_4lpi(const GMat& src1, const GMat& src2, const GMat& src3);
std::tuple<GMat, GMat, GMat> split3_4lpi(const GMat& src);
extern cv::gapi::GKernelPackage fluidTestPackage;
} // namespace gapi_test_kernels
} // namespace cv
#endif // GAPI_FLUID_TEST_KERNELS_HPP

View File

@@ -0,0 +1,173 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
namespace opencv_test
{
namespace
{
static cv::GMat DemoCC(cv::GMat in, cv::GScalar scale)
{
return cv::gapi::medianBlur(in + in*scale, 3);
}
struct GCompiledValidateMetaTyped: public ::testing::Test
{
cv::GComputationT<cv::GMat(cv::GMat,cv::GScalar)> m_cc;
GCompiledValidateMetaTyped() : m_cc(DemoCC)
{
}
};
struct GCompiledValidateMetaUntyped: public ::testing::Test
{
cv::GMat in;
cv::GScalar scale;
cv::GComputation m_ucc;
GCompiledValidateMetaUntyped() : m_ucc(cv::GIn(in, scale),
cv::GOut(DemoCC(in, scale)))
{
}
};
} // anonymous namespace
TEST_F(GCompiledValidateMetaTyped, ValidMeta)
{
cv::Mat in = cv::Mat::eye(cv::Size(128, 32), CV_8UC1);
cv::Scalar sc(127);
auto f = m_cc.compile(cv::descr_of(in),
cv::descr_of(sc));
// Correct operation when meta is exactly the same
cv::Mat out;
EXPECT_NO_THROW(f(in, sc, out));
// Correct operation on next invocation with same meta
// taken from different input objects
cv::Mat in2 = cv::Mat::zeros(cv::Size(128, 32), CV_8UC1);
cv::Scalar sc2(64);
cv::Mat out2;
EXPECT_NO_THROW(f(in2, sc2, out2));
}
TEST_F(GCompiledValidateMetaTyped, InvalidMeta)
{
auto f = m_cc.compile(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(64,32)},
cv::empty_scalar_desc());
cv::Scalar sc(33);
cv::Mat out;
// 3 channels instead 1
cv::Mat in1 = cv::Mat::eye(cv::Size(64,32), CV_8UC3);
EXPECT_THROW(f(in1, sc, out), std::logic_error);
// 32f instead 8u
cv::Mat in2 = cv::Mat::eye(cv::Size(64,32), CV_32F);
EXPECT_THROW(f(in2, sc, out), std::logic_error);
// 32x32 instead of 64x32
cv::Mat in3 = cv::Mat::eye(cv::Size(32,32), CV_8UC1);
EXPECT_THROW(f(in3, sc, out), std::logic_error);
// All is wrong
cv::Mat in4 = cv::Mat::eye(cv::Size(128,64), CV_32FC3);
EXPECT_THROW(f(in4, sc, out), std::logic_error);
}
TEST_F(GCompiledValidateMetaUntyped, ValidMeta)
{
cv::Mat in1 = cv::Mat::eye(cv::Size(128, 32), CV_8UC1);
cv::Scalar sc(127);
auto f = m_ucc.compile(cv::descr_of(in1),
cv::descr_of(sc));
// Correct operation when meta is exactly the same
cv::Mat out1;
EXPECT_NO_THROW(f(cv::gin(in1, sc), cv::gout(out1)));
// Correct operation on next invocation with same meta
// taken from different input objects
cv::Mat in2 = cv::Mat::zeros(cv::Size(128, 32), CV_8UC1);
cv::Scalar sc2(64);
cv::Mat out2;
EXPECT_NO_THROW(f(cv::gin(in2, sc2), cv::gout(out2)));
}
TEST_F(GCompiledValidateMetaUntyped, InvalidMetaValues)
{
auto f = m_ucc.compile(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(64,32)},
cv::empty_scalar_desc());
cv::Scalar sc(33);
cv::Mat out;
// 3 channels instead 1
cv::Mat in1 = cv::Mat::eye(cv::Size(64,32), CV_8UC3);
EXPECT_THROW(f(cv::gin(in1, sc), cv::gout(out)), std::logic_error);
// 32f instead 8u
cv::Mat in2 = cv::Mat::eye(cv::Size(64,32), CV_32F);
EXPECT_THROW(f(cv::gin(in2, sc), cv::gout(out)), std::logic_error);
// 32x32 instead of 64x32
cv::Mat in3 = cv::Mat::eye(cv::Size(32,32), CV_8UC1);
EXPECT_THROW(f(cv::gin(in3, sc), cv::gout(out)), std::logic_error);
// All is wrong
cv::Mat in4 = cv::Mat::eye(cv::Size(128,64), CV_32FC3);
EXPECT_THROW(f(cv::gin(in4, sc), cv::gout(out)), std::logic_error);
}
TEST_F(GCompiledValidateMetaUntyped, InvalidMetaShape)
{
auto f = m_ucc.compile(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(64,32)},
cv::empty_scalar_desc());
cv::Mat in1 = cv::Mat::eye(cv::Size(64,32), CV_8UC1);
cv::Scalar sc(33);
cv::Mat out1;
// call as f(Mat,Mat) while f(Mat,Scalar) is expected
EXPECT_THROW(f(cv::gin(in1, in1), cv::gout(out1)), std::logic_error);
// call as f(Scalar,Mat) while f(Mat,Scalar) is expected
EXPECT_THROW(f(cv::gin(sc, in1), cv::gout(out1)), std::logic_error);
// call as f(Scalar,Scalar) while f(Mat,Scalar) is expected
EXPECT_THROW(f(cv::gin(sc, sc), cv::gout(out1)), std::logic_error);
}
TEST_F(GCompiledValidateMetaUntyped, InvalidMetaNumber)
{
auto f = m_ucc.compile(cv::GMatDesc{CV_8U,1,cv::Size(64,32)},
cv::empty_scalar_desc());
cv::Mat in1 = cv::Mat::eye(cv::Size(64,32), CV_8UC1);
cv::Scalar sc(33);
cv::Mat out1, out2;
// call as f(Mat,Scalar,Scalar) while f(Mat,Scalar) is expected
EXPECT_THROW(f(cv::gin(in1, sc, sc), cv::gout(out1)), std::logic_error);
// call as f(Scalar,Mat,Scalar) while f(Mat,Scalar) is expected
EXPECT_THROW(f(cv::gin(sc, in1, sc), cv::gout(out1)), std::logic_error);
// call as f(Scalar) while f(Mat,Scalar) is expected
EXPECT_THROW(f(cv::gin(sc), cv::gout(out1)), std::logic_error);
// call as f(Mat,Scalar,[out1],[out2]) while f(Mat,Scalar,[out]) is expected
EXPECT_THROW(f(cv::gin(in1, sc), cv::gout(out1, out2)), std::logic_error);
}
} // namespace opencv_test

View File

@@ -0,0 +1,137 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <opencv2/gapi/cpu/gcpukernel.hpp>
#include <ade/util/zip_range.hpp>
namespace opencv_test
{
namespace
{
G_TYPED_KERNEL(CustomResize, <cv::GMat(cv::GMat, cv::Size, double, double, int)>, "org.opencv.customk.resize")
{
static cv::GMatDesc outMeta(cv::GMatDesc in, cv::Size sz, double fx, double fy, int) {
if (sz.width != 0 && sz.height != 0)
{
return in.withSize(to_own(sz));
}
else
{
GAPI_Assert(fx != 0. && fy != 0.);
return in.withSize
(cv::gapi::own::Size(static_cast<int>(std::round(in.size.width * fx)),
static_cast<int>(std::round(in.size.height * fy))));
}
}
};
GAPI_OCV_KERNEL(CustomResizeImpl, CustomResize)
{
static void run(const cv::Mat& in, cv::Size sz, double fx, double fy, int interp, cv::Mat &out)
{
cv::resize(in, out, sz, fx, fy, interp);
}
};
struct GComputationApplyTest: public ::testing::Test
{
cv::GMat in;
cv::Mat in_mat;
cv::Mat out_mat;
cv::GComputation m_c;
GComputationApplyTest() : in_mat(300, 300, CV_8UC1),
m_c(cv::GIn(in), cv::GOut(CustomResize::on(in, cv::Size(100, 100),
0.0, 0.0, cv::INTER_LINEAR)))
{
}
};
struct GComputationVectorMatsAsOutput: public ::testing::Test
{
cv::Mat in_mat;
cv::GComputation m_c;
std::vector<cv::Mat> ref_mats;
GComputationVectorMatsAsOutput() : in_mat(300, 300, CV_8UC3),
m_c([&](){
cv::GMat in;
cv::GMat out[3];
std::tie(out[0], out[1], out[2]) = cv::gapi::split3(in);
return cv::GComputation({in}, {out[0], out[1], out[2]});
})
{
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
cv::split(in_mat, ref_mats);
}
void run(std::vector<cv::Mat>& out_mats)
{
m_c.apply({in_mat}, out_mats);
}
void check(const std::vector<cv::Mat>& out_mats)
{
for (const auto& it : ade::util::zip(ref_mats, out_mats))
{
const auto& ref_mat = std::get<0>(it);
const auto& out_mat = std::get<1>(it);
EXPECT_EQ(0, cv::countNonZero(ref_mat != out_mat));
}
}
};
}
TEST_F(GComputationApplyTest, ThrowDontPassCustomKernel)
{
EXPECT_THROW(m_c.apply(in_mat, out_mat), std::logic_error);
}
TEST_F(GComputationApplyTest, NoThrowPassCustomKernel)
{
const auto pkg = cv::gapi::kernels<CustomResizeImpl>();
ASSERT_NO_THROW(m_c.apply(in_mat, out_mat, cv::compile_args(pkg)));
}
TEST_F(GComputationVectorMatsAsOutput, OutputAllocated)
{
std::vector<cv::Mat> out_mats(3);
for (auto& out_mat : out_mats)
{
out_mat.create(in_mat.size(), CV_8UC1);
}
run(out_mats);
check(out_mats);
}
TEST_F(GComputationVectorMatsAsOutput, OutputNotAllocated)
{
std::vector<cv::Mat> out_mats(3);
run(out_mats);
check(out_mats);
}
TEST_F(GComputationVectorMatsAsOutput, OutputAllocatedWithInvalidMeta)
{
std::vector<cv::Mat> out_mats(3);
for (auto& out_mat : out_mats)
{
out_mat.create(in_mat.size() / 2, CV_8UC1);
}
run(out_mats);
check(out_mats);
}
} // namespace opencv_test

View File

@@ -0,0 +1,207 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include "logger.hpp"
#include "common/gapi_tests_common.hpp"
#include <opencv2/gapi/gpu/ggpukernel.hpp>
#include "opencl_kernels_test_gapi.hpp"
namespace cv
{
#ifdef HAVE_OPENCL
static void reference_symm7x7_CPU(const cv::Mat& in, const cv::Mat& kernel_coeff, int shift, cv::Mat &out)
{
cv::Point anchor = { -1, -1 };
double delta = 0;
const int* ci = kernel_coeff.ptr<int>();
float c_float[10];
float divisor = (float)(1 << shift);
for (int i = 0; i < 10; i++)
{
c_float[i] = ci[i] / divisor;
}
// J & I & H & G & H & I & J
// I & F & E & D & E & F & I
// H & E & C & B & C & E & H
// G & D & B & A & B & D & G
// H & E & C & B & C & E & H
// I & F & E & D & E & F & I
// J & I & H & G & H & I & J
// A & B & C & D & E & F & G & H & I & J
// 9 & 8 & 7 & 6 & 7 & 8 & 9
// 8 & 5 & 4 & 3 & 4 & 5 & 8
// 7 & 4 & 2 & 1 & 2 & 4 & 7
// 6 & 3 & 1 & 0 & 1 & 3 & 6
// 7 & 4 & 2 & 1 & 2 & 4 & 7
// 8 & 5 & 4 & 3 & 4 & 5 & 8
// 9 & 8 & 7 & 6 & 7 & 8 & 9
float coefficients[49] =
{
c_float[9], c_float[8], c_float[7], c_float[6], c_float[7], c_float[8], c_float[9],
c_float[8], c_float[5], c_float[4], c_float[3], c_float[4], c_float[5], c_float[8],
c_float[7], c_float[4], c_float[2], c_float[1], c_float[2], c_float[4], c_float[7],
c_float[6], c_float[3], c_float[1], c_float[0], c_float[1], c_float[3], c_float[6],
c_float[7], c_float[4], c_float[2], c_float[1], c_float[2], c_float[4], c_float[7],
c_float[8], c_float[5], c_float[4], c_float[3], c_float[4], c_float[5], c_float[8],
c_float[9], c_float[8], c_float[7], c_float[6], c_float[7], c_float[8], c_float[9]
};
cv::Mat kernel = cv::Mat(7, 7, CV_32FC1);
float* cf = kernel.ptr<float>();
for (int i = 0; i < 49; i++)
{
cf[i] = coefficients[i];
}
cv::filter2D(in, out, CV_8UC1, kernel, anchor, delta, cv::BORDER_REPLICATE);
}
namespace gapi_test_kernels
{
G_TYPED_KERNEL(TSymm7x7_test, <GMat(GMat, Mat, int)>, "org.opencv.imgproc.symm7x7_test") {
static GMatDesc outMeta(GMatDesc in, Mat, int) {
return in.withType(CV_8U, 1);
}
};
GAPI_GPU_KERNEL(GGPUSymm7x7_test, TSymm7x7_test)
{
static void run(const cv::UMat& in, const cv::Mat& kernel_coeff, int shift, cv::UMat &out)
{
if (cv::ocl::isOpenCLActivated())
{
cv::Size size = in.size();
size_t globalsize[2] = { (size_t)size.width, (size_t)size.height };
const cv::String moduleName = "gapi";
cv::ocl::ProgramSource source(moduleName, "symm7x7", opencl_symm7x7_src, "");
static const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_UNDEFINED" };
std::string build_options = " -D BORDER_CONSTANT_VALUE=" + std::to_string(0) +
" -D " + borderMap[1] +
" -D SCALE=1.f/" + std::to_string(1 << shift) + ".f";
cv::String errmsg;
cv::ocl::Program program(source, build_options, errmsg);
if (program.ptr() == NULL)
{
CV_Error_(cv::Error::OpenCLInitError, ("symm_7x7_test Can't compile OpenCL program: = %s with build_options = %s\n", errmsg.c_str(), build_options.c_str()));
}
if (!errmsg.empty())
{
std::cout << "OpenCL program build log:" << std::endl << errmsg << std::endl;
}
cv::ocl::Kernel kernel("symm_7x7_test", program);
if (kernel.empty())
{
CV_Error(cv::Error::OpenCLInitError, "symm_7x7_test Can't get OpenCL kernel\n");
}
cv::UMat gKer;
kernel_coeff.copyTo(gKer);
int tile_y = 0;
int idxArg = kernel.set(0, cv::ocl::KernelArg::PtrReadOnly(in));
idxArg = kernel.set(idxArg, (int)in.step);
idxArg = kernel.set(idxArg, (int)size.width);
idxArg = kernel.set(idxArg, (int)size.height);
idxArg = kernel.set(idxArg, cv::ocl::KernelArg::PtrWriteOnly(out));
idxArg = kernel.set(idxArg, (int)out.step);
idxArg = kernel.set(idxArg, (int)size.height);
idxArg = kernel.set(idxArg, (int)size.width);
idxArg = kernel.set(idxArg, (int)tile_y);
idxArg = kernel.set(idxArg, cv::ocl::KernelArg::PtrReadOnly(gKer));
if (!kernel.run(2, globalsize, NULL, false))
{
CV_Error(cv::Error::OpenCLApiCallError, "symm_7x7_test OpenCL kernel run failed\n");
}
}
else
{
//CPU fallback
cv::Mat in_Mat, out_Mat;
in_Mat = in.getMat(ACCESS_READ);
out_Mat = out.getMat(ACCESS_WRITE);
reference_symm7x7_CPU(in_Mat, kernel_coeff, shift, out_Mat);
}
}
};
cv::gapi::GKernelPackage gpuTestPackage = cv::gapi::kernels
<GGPUSymm7x7_test
>();
} // namespace gapi_test_kernels
#endif //HAVE_OPENCL
} // namespace cv
namespace opencv_test
{
#ifdef HAVE_OPENCL
using namespace cv::gapi_test_kernels;
TEST(GPU, Symm7x7_test)
{
const auto sz = cv::Size(1280, 720);
cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
cv::Mat out_mat_gapi(sz, CV_8UC1);
cv::Mat out_mat_ocv(sz, CV_8UC1);
cv::Scalar mean = cv::Scalar(127.0f);
cv::Scalar stddev = cv::Scalar(40.f);
cv::randn(in_mat, mean, stddev);
//Symm7x7 coefficients and shift
int coefficients_symm7x7[10] = { 1140, -118, 526, 290, -236, 64, -128, -5, -87, -7 };
int shift = 10;
cv::Mat kernel_coeff(10, 1, CV_32S);
int* ci = kernel_coeff.ptr<int>();
for (int i = 0; i < 10; i++)
{
ci[i] = coefficients_symm7x7[i];
}
// Run G-API
cv::GMat in;
auto out = TSymm7x7_test::on(in, kernel_coeff, shift);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(gpuTestPackage));
cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
// Run OpenCV
reference_symm7x7_CPU(in_mat, kernel_coeff, shift, out_mat_ocv);
compare_f cmpF = AbsSimilarPoints(1, 0.05).to_compare_f();
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
#endif
} // namespace opencv_test

View File

@@ -0,0 +1,526 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <opencv2/gapi/cpu/gcpukernel.hpp>
#include "gapi_mock_kernels.hpp"
#include <opencv2/gapi/cpu/gcpukernel.hpp> // cpu::backend
#include <opencv2/gapi/fluid/gfluidkernel.hpp> // fluid::backend
namespace opencv_test
{
namespace
{
namespace I
{
G_TYPED_KERNEL(GClone, <GMat(GMat)>, "org.opencv.test.clone")
{
static GMatDesc outMeta(GMatDesc in) { return in; }
};
}
enum class KernelTags
{
CPU_CUSTOM_BGR2GRAY,
CPU_CUSTOM_CLONE,
CPU_CUSTOM_ADD,
FLUID_CUSTOM_BGR2GRAY,
FLUID_CUSTOM_CLONE,
FLUID_CUSTOM_ADD
};
class HeteroGraph: public ::testing::Test
{
public:
HeteroGraph()
{
auto tmp = I::GClone::on(cv::gapi::add(in[0], in[1]));
out = cv::gapi::imgproc::GBGR2Gray::on(tmp);
}
static void registerCallKernel(KernelTags kernel_tag) {
kernel_calls.insert(kernel_tag);
}
bool checkCallKernel(KernelTags kernel_tag) {
return ade::util::contains(kernel_calls, kernel_tag);
}
protected:
void SetUp() override
{
if (!kernel_calls.empty())
cv::util::throw_error(std::logic_error("Kernel call log has not been cleared!!!"));
}
void TearDown() override
{
kernel_calls.clear();
}
protected:
cv::GMat in[2], out;
static std::set<KernelTags> kernel_calls;
};
namespace cpu
{
GAPI_OCV_KERNEL(GClone, I::GClone)
{
static void run(const cv::Mat&, cv::Mat)
{
HeteroGraph::registerCallKernel(KernelTags::CPU_CUSTOM_CLONE);
}
};
GAPI_OCV_KERNEL(BGR2Gray, cv::gapi::imgproc::GBGR2Gray)
{
static void run(const cv::Mat&, cv::Mat&)
{
HeteroGraph::registerCallKernel(KernelTags::CPU_CUSTOM_BGR2GRAY);
}
};
GAPI_OCV_KERNEL(GAdd, cv::gapi::core::GAdd)
{
static void run(const cv::Mat&, const cv::Mat&, int, cv::Mat&)
{
HeteroGraph::registerCallKernel(KernelTags::CPU_CUSTOM_ADD);
}
};
}
namespace fluid
{
GAPI_FLUID_KERNEL(GClone, I::GClone, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View&, cv::gapi::fluid::Buffer)
{
HeteroGraph::registerCallKernel(KernelTags::FLUID_CUSTOM_CLONE);
}
};
GAPI_FLUID_KERNEL(BGR2Gray, cv::gapi::imgproc::GBGR2Gray, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View&, cv::gapi::fluid::Buffer&)
{
HeteroGraph::registerCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY);
}
};
GAPI_FLUID_KERNEL(GAdd, cv::gapi::core::GAdd, false)
{
static const int Window = 1;
static void run(const cv::gapi::fluid::View&, const cv::gapi::fluid::View&,
int, cv::gapi::fluid::Buffer&)
{
HeteroGraph::registerCallKernel(KernelTags::FLUID_CUSTOM_ADD);
}
};
}
std::set<KernelTags> HeteroGraph::kernel_calls;
} // anonymous namespace
TEST(KernelPackage, Create)
{
namespace J = Jupiter;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar, J::Baz>();
EXPECT_EQ(3u, pkg.size());
}
TEST(KernelPackage, Includes)
{
namespace J = Jupiter;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar, J::Baz>();
EXPECT_TRUE (pkg.includes<J::Foo>());
EXPECT_TRUE (pkg.includes<J::Bar>());
EXPECT_TRUE (pkg.includes<J::Baz>());
EXPECT_FALSE(pkg.includes<J::Qux>());
}
TEST(KernelPackage, IncludesAPI)
{
namespace J = Jupiter;
namespace S = Saturn;
auto pkg = cv::gapi::kernels<J::Foo, S::Bar>();
EXPECT_TRUE (pkg.includesAPI<I::Foo>());
EXPECT_TRUE (pkg.includesAPI<I::Bar>());
EXPECT_FALSE(pkg.includesAPI<I::Baz>());
EXPECT_FALSE(pkg.includesAPI<I::Qux>());
}
TEST(KernelPackage, Include_Add)
{
namespace J = Jupiter;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar, J::Baz>();
EXPECT_FALSE(pkg.includes<J::Qux>());
pkg.include<J::Qux>();
EXPECT_TRUE(pkg.includes<J::Qux>());
}
TEST(KernelPackage, Include_REPLACE)
{
namespace J = Jupiter;
namespace S = Saturn;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar>();
EXPECT_FALSE(pkg.includes<S::Bar>());
pkg.include<S::Bar>();
EXPECT_FALSE(pkg.includes<J::Bar>());
EXPECT_TRUE(pkg.includes<S::Bar>());
}
TEST(KernelPackage, RemoveBackend)
{
namespace J = Jupiter;
namespace S = Saturn;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar, S::Baz>();
EXPECT_TRUE(pkg.includes<J::Foo>());
EXPECT_TRUE(pkg.includes<J::Bar>());
pkg.remove(J::backend());
EXPECT_FALSE(pkg.includes<J::Foo>());
EXPECT_FALSE(pkg.includes<J::Bar>());
EXPECT_TRUE(pkg.includes<S::Baz>());
};
TEST(KernelPackage, RemoveAPI)
{
namespace J = Jupiter;
namespace S = Saturn;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar>();
EXPECT_TRUE(pkg.includes<J::Foo>());
EXPECT_TRUE(pkg.includes<J::Bar>());
pkg.remove<I::Foo>();
EXPECT_TRUE(pkg.includes<J::Bar>());
EXPECT_FALSE(pkg.includes<J::Foo>());
};
TEST(KernelPackage, CreateHetero)
{
namespace J = Jupiter;
namespace S = Saturn;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar, J::Baz, S::Qux>();
EXPECT_EQ(4u, pkg.size());
}
TEST(KernelPackage, IncludesHetero)
{
namespace J = Jupiter;
namespace S = Saturn;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar, J::Baz, S::Qux>();
EXPECT_TRUE (pkg.includes<J::Foo>());
EXPECT_TRUE (pkg.includes<J::Bar>());
EXPECT_TRUE (pkg.includes<J::Baz>());
EXPECT_FALSE(pkg.includes<J::Qux>());
EXPECT_TRUE (pkg.includes<S::Qux>());
}
TEST(KernelPackage, IncludeHetero)
{
namespace J = Jupiter;
namespace S = Saturn;
auto pkg = cv::gapi::kernels<J::Foo, J::Bar, J::Baz>();
EXPECT_FALSE(pkg.includes<J::Qux>());
EXPECT_FALSE(pkg.includes<S::Qux>());
pkg.include<S::Qux>();
EXPECT_FALSE(pkg.includes<J::Qux>());
EXPECT_TRUE (pkg.includes<S::Qux>());
}
TEST(KernelPackage, Combine_REPLACE_Full)
{
namespace J = Jupiter;
namespace S = Saturn;
auto j_pkg = cv::gapi::kernels<J::Foo, J::Bar, J::Baz>();
auto s_pkg = cv::gapi::kernels<S::Foo, S::Bar, S::Baz>();
auto u_pkg = cv::gapi::combine(j_pkg, s_pkg);
EXPECT_EQ(3u, u_pkg.size());
EXPECT_FALSE(u_pkg.includes<J::Foo>());
EXPECT_FALSE(u_pkg.includes<J::Bar>());
EXPECT_FALSE(u_pkg.includes<J::Baz>());
EXPECT_TRUE (u_pkg.includes<S::Foo>());
EXPECT_TRUE (u_pkg.includes<S::Bar>());
EXPECT_TRUE (u_pkg.includes<S::Baz>());
}
TEST(KernelPackage, Combine_REPLACE_Partial)
{
namespace J = Jupiter;
namespace S = Saturn;
auto j_pkg = cv::gapi::kernels<J::Foo, J::Bar>();
auto s_pkg = cv::gapi::kernels<S::Bar>();
auto u_pkg = cv::gapi::combine(j_pkg, s_pkg);
EXPECT_EQ(2u, u_pkg.size());
EXPECT_TRUE (u_pkg.includes<J::Foo>());
EXPECT_FALSE(u_pkg.includes<J::Bar>());
EXPECT_TRUE (u_pkg.includes<S::Bar>());
}
TEST(KernelPackage, Combine_REPLACE_Append)
{
namespace J = Jupiter;
namespace S = Saturn;
auto j_pkg = cv::gapi::kernels<J::Foo, J::Bar>();
auto s_pkg = cv::gapi::kernels<S::Qux>();
auto u_pkg = cv::gapi::combine(j_pkg, s_pkg);
EXPECT_EQ(3u, u_pkg.size());
EXPECT_TRUE(u_pkg.includes<J::Foo>());
EXPECT_TRUE(u_pkg.includes<J::Bar>());
EXPECT_TRUE(u_pkg.includes<S::Qux>());
}
TEST(KernelPackage, TestWithEmptyLHS)
{
namespace J = Jupiter;
auto lhs = cv::gapi::kernels<>();
auto rhs = cv::gapi::kernels<J::Foo>();
auto pkg = cv::gapi::combine(lhs, rhs);
EXPECT_EQ(1u, pkg.size());
EXPECT_TRUE(pkg.includes<J::Foo>());
}
TEST(KernelPackage, TestWithEmptyRHS)
{
namespace J = Jupiter;
auto lhs = cv::gapi::kernels<J::Foo>();
auto rhs = cv::gapi::kernels<>();
auto pkg = cv::gapi::combine(lhs, rhs);
EXPECT_EQ(1u, pkg.size());
EXPECT_TRUE(pkg.includes<J::Foo>());
}
TEST(KernelPackage, Return_Unique_Backends)
{
auto pkg = cv::gapi::kernels<cpu::GClone, fluid::BGR2Gray, fluid::GAdd>();
EXPECT_EQ(2u, pkg.backends().size());
}
TEST(KernelPackage, Can_Use_Custom_Kernel)
{
cv::GMat in[2];
auto out = I::GClone::on(cv::gapi::add(in[0], in[1]));
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
auto pkg = cv::gapi::kernels<cpu::GClone>();
EXPECT_NO_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
compile({in_meta, in_meta}, cv::compile_args(pkg)));
}
TEST(KernelPackage, CombineMultiple)
{
namespace J = Jupiter;
namespace S = Saturn;
auto a = cv::gapi::kernels<J::Foo>();
auto b = cv::gapi::kernels<J::Bar>();
auto c = cv::gapi::kernels<S::Qux>();
auto pkg = cv::gapi::combine(a, b, c);
EXPECT_EQ(3u, pkg.size());
EXPECT_TRUE(pkg.includes<J::Foo>());
EXPECT_TRUE(pkg.includes<J::Bar>());
EXPECT_TRUE(pkg.includes<S::Qux>());
}
TEST_F(HeteroGraph, Call_Custom_Kernel_Default_Backend)
{
// in0 -> GCPUAdd -> tmp -> cpu::GClone -> GCPUBGR2Gray -> out
// ^
// |
// in1 -------`
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC3),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<cpu::GClone>();
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg));
EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_CLONE));
}
TEST_F(HeteroGraph, Call_Custom_Kernel_Not_Default_Backend)
{
// in0 -> GCPUAdd -> tmp -> fluid::GClone -> GCPUBGR2Gray -> out
// ^
// |
// in1 -------`
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC3),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<fluid::GClone>();
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg));
EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_CLONE));
}
TEST_F(HeteroGraph, Replace_Default_To_Same_Backend)
{
// in0 -> GCPUAdd -> tmp -> cpu::GClone -> cpu::BGR2Gray -> out
// ^
// |
// in1 -------`
cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC3),
in_mat2 = cv::Mat::eye(3, 3, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<cpu::GClone, cpu::BGR2Gray>();
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg));
EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_BGR2GRAY));
}
TEST_F(HeteroGraph, Replace_Default_To_Another_Backend)
{
//in0 -> GCPUAdd -> tmp -> cpu::GClone -> fluid::BGR2Gray -> out
// ^
// |
//in1 --------`
cv::Mat in_mat1(300, 300, CV_8UC3),
in_mat2(300, 300, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<cpu::GClone, fluid::BGR2Gray>();
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg));
EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY));
}
TEST_F(HeteroGraph, Use_Only_Same_Backend)
{
//in0 -> cpu::GAdd -> tmp -> cpu::GClone -> cpu::BGR2Gray -> out
// ^
// |
//in1 --------`
cv::Mat in_mat1(300, 300, CV_8UC3),
in_mat2(300, 300, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<cpu::GAdd, cpu::GClone, cpu::BGR2Gray>();
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg}));
EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_ADD));
EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_CLONE));
EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_BGR2GRAY));
}
TEST_F(HeteroGraph, Use_Only_Another_Backend)
{
//in0 -> fluid::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out
// ^
// |
//in1 --------`
cv::Mat in_mat1(300, 300, CV_8UC3),
in_mat2(300, 300, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<fluid::GAdd, fluid::GClone, fluid::BGR2Gray>();
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg}));
EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_ADD));
EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_CLONE));
EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY));
}
TEST_F(HeteroGraph, Use_Only_Hetero_Backend)
{
//in0 -> cpu::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out
// ^
// |
//in1 --------`
cv::Mat in_mat1(300, 300, CV_8UC3),
in_mat2(300, 300, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<cpu::GAdd, fluid::GClone, fluid::BGR2Gray>();
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg}));
EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_ADD));
EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_CLONE));
EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY));
}
TEST_F(HeteroGraph, Use_Only_Not_Found_Default)
{
//in0 -> GCPUAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out
// ^
// |
//in1 --------`
cv::Mat in_mat1(300, 300, CV_8UC3),
in_mat2(300, 300, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<fluid::GClone, fluid::BGR2Gray>();
EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg})));
}
TEST_F(HeteroGraph, Use_Only_Not_Found_Custom)
{
//in0 -> cpu::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out
// ^
// |
//in1 --------`
cv::Mat in_mat1(300, 300, CV_8UC3),
in_mat2(300, 300, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<cpu::GAdd, fluid::BGR2Gray>();
EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg})));
}
TEST_F(HeteroGraph, Use_Only_Other_Package_Ignored)
{
//in0 -> cpu::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out
// ^
// |
//in1 --------`
cv::Mat in_mat1(300, 300, CV_8UC3),
in_mat2(300, 300, CV_8UC3),
out_mat;
auto pkg = cv::gapi::kernels<cpu::GAdd, fluid::BGR2Gray>();
auto clone_pkg = cv::gapi::kernels<cpu::GClone>();
EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)).
apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat),
cv::compile_args(clone_pkg, cv::gapi::use_only{pkg})));
}
} // namespace opencv_test

View File

@@ -0,0 +1,123 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include <opencv2/gapi/cpu/gcpukernel.hpp>
#include "api/gbackend_priv.hpp" // directly instantiate GBackend::Priv
namespace opencv_test
{
namespace {
// FIXME: Currently every Kernel implementation in this test file has
// its own backend() method and it is incorrect! API classes should
// provide it out of the box.
namespace I
{
G_TYPED_KERNEL(Foo, <cv::GMat(cv::GMat)>, "test.kernels.foo")
{
static cv::GMatDesc outMeta(const cv::GMatDesc &in) { return in; }
};
G_TYPED_KERNEL(Bar, <cv::GMat(cv::GMat,cv::GMat)>, "test.kernels.bar")
{
static cv::GMatDesc outMeta(const cv::GMatDesc &in, const cv::GMatDesc &) { return in; }
};
G_TYPED_KERNEL(Baz, <cv::GScalar(cv::GMat)>, "test.kernels.baz")
{
static cv::GScalarDesc outMeta(const cv::GMatDesc &) { return cv::empty_scalar_desc(); }
};
G_TYPED_KERNEL(Qux, <cv::GMat(cv::GMat, cv::GScalar)>, "test.kernels.qux")
{
static cv::GMatDesc outMeta(const cv::GMatDesc &in, const cv::GScalarDesc &) { return in; }
};
G_TYPED_KERNEL(Quux, <cv::GMat(cv::GScalar, cv::GMat)>, "test.kernels.quux")
{
static cv::GMatDesc outMeta(const cv::GScalarDesc &, const cv::GMatDesc& in) { return in; }
};
}
// Kernel implementations for imaginary Jupiter device
namespace Jupiter
{
namespace detail
{
static cv::gapi::GBackend backend(std::make_shared<cv::gapi::GBackend::Priv>());
}
inline cv::gapi::GBackend backend() { return detail::backend; }
GAPI_OCV_KERNEL(Foo, I::Foo)
{
static void run(const cv::Mat &, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Bar, I::Bar)
{
static void run(const cv::Mat &, const cv::Mat &, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Baz, I::Baz)
{
static void run(const cv::Mat &, cv::Scalar &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Qux, I::Qux)
{
static void run(const cv::Mat &, const cv::Scalar&, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Quux, I::Quux)
{
static void run(const cv::Scalar&, const cv::Mat&, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
} // namespace Jupiter
// Kernel implementations for imaginary Saturn device
namespace Saturn
{
namespace detail
{
static cv::gapi::GBackend backend(std::make_shared<cv::gapi::GBackend::Priv>());
}
inline cv::gapi::GBackend backend() { return detail::backend; }
GAPI_OCV_KERNEL(Foo, I::Foo)
{
static void run(const cv::Mat &, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Bar, I::Bar)
{
static void run(const cv::Mat &, const cv::Mat &, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Baz, I::Baz)
{
static void run(const cv::Mat &, cv::Scalar &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Qux, I::Qux)
{
static void run(const cv::Mat &, const cv::Scalar&, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
GAPI_OCV_KERNEL(Quux, I::Quux)
{
static void run(const cv::Scalar&, const cv::Mat&, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return detail::backend; } // FIXME: Must be removed
};
} // namespace Saturn
} // anonymous namespace
} // namespace opencv_test

View File

@@ -0,0 +1,178 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#ifdef HAVE_PLAIDML
#include "test_precomp.hpp"
#include <stdexcept>
#include <ade/util/iota_range.hpp>
#include "logger.hpp"
#include <opencv2/gapi/plaidml/core.hpp>
#include <opencv2/gapi/plaidml/plaidml.hpp>
namespace opencv_test
{
inline cv::gapi::plaidml::config getConfig()
{
auto read_var_from_env = [](const char* env)
{
const char* raw = std::getenv(env);
if (!raw)
{
cv::util::throw_error(std::runtime_error(std::string(env) + " is't set"));
}
return std::string(raw);
};
auto dev_id = read_var_from_env("PLAIDML_DEVICE");
auto trg_id = read_var_from_env("PLAIDML_TARGET");
return cv::gapi::plaidml::config{std::move(dev_id),
std::move(trg_id)};
}
TEST(GAPI_PlaidML_Pipelines, SimpleArithmetic)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
cv::Mat in_mat1(size, type);
cv::Mat in_mat2(size, type);
// NB: What about overflow ? PlaidML doesn't handle it
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(127));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(127));
cv::Mat out_mat(size, type, cv::Scalar::all(0));
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in1, in2;
auto out = in1 + in2;
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out));
comp.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::add(in_mat1, in_mat2, ref_mat, cv::noArray(), type);
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
}
// FIXME PlaidML cpu backend does't support bitwise operations
TEST(GAPI_PlaidML_Pipelines, DISABLED_ComplexArithmetic)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
cv::Mat in_mat1(size, type);
cv::Mat in_mat2(size, type);
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
cv::Mat out_mat(size, type, cv::Scalar::all(0));
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in1, in2;
auto out = in1 | (in2 ^ (in1 & (in2 + (in1 - in2))));
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out));
comp.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::subtract(in_mat1, in_mat2, ref_mat, cv::noArray(), type);
cv::add(in_mat2, ref_mat, ref_mat, cv::noArray(), type);
cv::bitwise_and(in_mat1, ref_mat, ref_mat);
cv::bitwise_xor(in_mat2, ref_mat, ref_mat);
cv::bitwise_or(in_mat1, ref_mat, ref_mat);
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
}
TEST(GAPI_PlaidML_Pipelines, TwoInputOperations)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
constexpr int kNumInputs = 4;
std::vector<cv::Mat> in_mat(kNumInputs, cv::Mat(size, type));
for (int i = 0; i < kNumInputs; ++i)
{
cv::randu(in_mat[i], cv::Scalar::all(0), cv::Scalar::all(60));
}
cv::Mat out_mat(size, type, cv::Scalar::all(0));
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in[4];
auto out = (in[3] - in[0]) + (in[2] - in[1]);
cv::GComputation comp(cv::GIn(in[0], in[1], in[2], in[3]), cv::GOut(out));
// FIXME Doesn't work just apply(in_mat, out_mat, ...)
comp.apply(cv::gin(in_mat[0], in_mat[1], in_mat[2], in_mat[3]), cv::gout(out_mat),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::subtract(in_mat[3], in_mat[0], ref_mat, cv::noArray(), type);
cv::add(ref_mat, in_mat[2], ref_mat, cv::noArray(), type);
cv::subtract(ref_mat, in_mat[1], ref_mat, cv::noArray(), type);
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
}
TEST(GAPI_PlaidML_Pipelines, TwoOutputOperations)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
constexpr int kNumInputs = 4;
std::vector<cv::Mat> in_mat(kNumInputs, cv::Mat(size, type));
for (int i = 0; i < kNumInputs; ++i)
{
cv::randu(in_mat[i], cv::Scalar::all(0), cv::Scalar::all(60));
}
std::vector<cv::Mat> out_mat(kNumInputs, cv::Mat(size, type, cv::Scalar::all(0)));
std::vector<cv::Mat> ref_mat(kNumInputs, cv::Mat(size, type, cv::Scalar::all(0)));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in[4], out[2];
out[0] = in[0] + in[3];
out[1] = in[1] + in[2];
cv::GComputation comp(cv::GIn(in[0], in[1], in[2], in[3]), cv::GOut(out[0], out[1]));
// FIXME Doesn't work just apply(in_mat, out_mat, ...)
comp.apply(cv::gin(in_mat[0], in_mat[1], in_mat[2], in_mat[3]),
cv::gout(out_mat[0], out_mat[1]),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::add(in_mat[0], in_mat[3], ref_mat[0], cv::noArray(), type);
cv::add(in_mat[1], in_mat[2], ref_mat[1], cv::noArray(), type);
EXPECT_EQ(0, cv::norm(out_mat[0], ref_mat[0]));
EXPECT_EQ(0, cv::norm(out_mat[1], ref_mat[1]));
}
} // namespace opencv_test
#endif // HAVE_PLAIDML

View File

@@ -0,0 +1,205 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "test_precomp.hpp"
#include <opencv2/gapi/cpu/gcpukernel.hpp>
namespace opencv_test
{
G_TYPED_KERNEL(GResize3c3p, <GMatP(GMat,Size,int)>, "test.resize3c3p") {
static GMatDesc outMeta(GMatDesc in, Size sz, int) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
GAPI_Assert(in.planar == false);
return in.withSize(sz).asPlanar();
}
};
G_TYPED_KERNEL(GResize3p3p, <GMatP(GMatP,Size,int)>, "test.resize3p3p") {
static GMatDesc outMeta(GMatDesc in, Size sz, int) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
GAPI_Assert(in.planar);
return in.withSize(sz);
}
};
static GMatDesc NV12toRGBoutMeta(GMatDesc inY, GMatDesc inUV)
{
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
GAPI_Assert(inY.chan == 1);
GAPI_Assert(inY.planar == false);
GAPI_Assert(inUV.chan == 2);
GAPI_Assert(inUV.planar == false);
GAPI_Assert(inY.size.width == 2 * inUV.size.width);
GAPI_Assert(inY.size.height == 2 * inUV.size.height);
return inY.withType(CV_8U, 3);
}
G_TYPED_KERNEL(GNV12toRGBp, <GMatP(GMat,GMat)>, "test.nv12torgbp") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
return NV12toRGBoutMeta(inY, inUV).asPlanar();
}
};
static void toPlanar(const cv::Mat& in, cv::Mat& out)
{
GAPI_Assert(out.depth() == in.depth());
GAPI_Assert(out.channels() == 1);
GAPI_Assert(in.channels() == 3);
GAPI_Assert(out.cols == in.cols);
GAPI_Assert(out.rows == 3*in.rows);
std::vector<cv::Mat> outs(3);
for (int i = 0; i < 3; i++) {
outs[i] = out(cv::Rect(0, i*in.rows, in.cols, in.rows));
}
cv::split(in, outs);
}
GAPI_OCV_KERNEL(OCVResize3c3p, GResize3c3p)
{
static void run(const cv::Mat& in, cv::Size out_sz, int interp, cv::Mat& out)
{
cv::Mat resized_mat;
cv::resize(in, resized_mat, out_sz, 0, 0, interp);
std::vector<cv::Mat> outs(3);
for (int i = 0; i < 3; i++) {
outs[i] = out(cv::Rect(0, i*out_sz.height, out_sz.width, out_sz.height));
}
cv::split(resized_mat, outs);
}
};
GAPI_OCV_KERNEL(OCVResize3p3p, GResize3p3p)
{
static void run(const cv::Mat& in, cv::Size out_sz, int interp, cv::Mat& out)
{
std::vector<cv::Mat> ins(3);
std::vector<cv::Mat> outs(3);
int inH = in.rows / 3;
int inW = in.cols;
int outH = out.rows / 3;
int outW = out.cols;
for (int i = 0; i < 3; i++) {
ins [i] = in(cv::Rect(0, i*inH, inW, inH));
outs[i] = out(cv::Rect(0, i*outH, outW, outH));
cv::resize(ins[i], outs[i], out_sz, 0, 0, interp);
}
}
};
GAPI_OCV_KERNEL(OCVNV12toRGBp, GNV12toRGBp)
{
static void run(const cv::Mat& inY, const cv::Mat& inUV, cv::Mat& out)
{
cv::Mat rgb;
cv::cvtColorTwoPlane(inY, inUV, rgb, cv::COLOR_YUV2RGB_NV12);
toPlanar(rgb, out);
}
};
struct PlanarTest : public TestWithParam <std::pair<cv::Size, cv::Size>> {};
TEST_P(PlanarTest, Resize3c3p)
{
cv::Size in_sz, out_sz;
std::tie(in_sz, out_sz) = GetParam();
int interp = cv::INTER_NEAREST;
cv::Mat in_mat = cv::Mat(in_sz, CV_8UC3);
cv::randn(in_mat, cv::Scalar::all(127.0f), cv::Scalar::all(40.f));
cv::Mat out_mat = cv::Mat::zeros(out_sz.height*3, out_sz.width, CV_8UC1);
cv::Mat out_mat_ocv = cv::Mat::zeros(out_sz.height*3, out_sz.width, CV_8UC1);
cv::GMat in;
auto out = GResize3c3p::on(in, out_sz, interp);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
auto pkg = cv::gapi::kernels<OCVResize3c3p>();
c.apply(cv::gin(in_mat), cv::gout(out_mat), cv::compile_args(pkg));
cv::Mat resized_mat;
cv::resize(in_mat, resized_mat, out_sz, 0, 0, interp);
toPlanar(resized_mat, out_mat_ocv);
EXPECT_EQ(0, cv::countNonZero(out_mat != out_mat_ocv));
}
TEST_P(PlanarTest, Resize3p3p)
{
cv::Size in_sz, out_sz;
std::tie(in_sz, out_sz) = GetParam();
int interp = cv::INTER_NEAREST;
cv::Mat in_mat = cv::Mat(cv::Size{in_sz.width, in_sz.height*3}, CV_8UC1);
cv::randn(in_mat, cv::Scalar::all(127.0f), cv::Scalar::all(40.f));
cv::Mat out_mat = cv::Mat::zeros(out_sz.height*3, out_sz.width, CV_8UC1);
cv::Mat out_mat_ocv = cv::Mat::zeros(out_sz.height*3, out_sz.width, CV_8UC1);
cv::GMatP in;
auto out = GResize3p3p::on(in, out_sz, interp);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
auto pkg = cv::gapi::kernels<OCVResize3p3p>();
c.compile(cv::descr_of(in_mat).asPlanar(3), cv::compile_args(pkg))
(cv::gin(in_mat), cv::gout(out_mat));
for (int i = 0; i < 3; i++) {
const cv::Mat in_mat_roi = in_mat(cv::Rect(0, i*in_sz.height, in_sz.width, in_sz.height));
cv::Mat out_mat_roi = out_mat_ocv(cv::Rect(0, i*out_sz.height, out_sz.width, out_sz.height));
cv::resize(in_mat_roi, out_mat_roi, out_sz, 0, 0, interp);
}
EXPECT_EQ(0, cv::countNonZero(out_mat != out_mat_ocv));
}
TEST_P(PlanarTest, Pipeline)
{
cv::Size in_sz, out_sz;
std::tie(in_sz, out_sz) = GetParam();
int interp = cv::INTER_NEAREST;
cv::Mat in_mat = cv::Mat(cv::Size{in_sz.width, in_sz.height*3/2}, CV_8UC1);
cv::randn(in_mat, cv::Scalar::all(127.0f), cv::Scalar::all(40.f));
cv::Size uv_sz(in_sz.width / 2, in_sz.height / 2);
cv::Mat y_mat = cv::Mat(in_sz, CV_8UC1, in_mat.data);
cv::Mat uv_mat = cv::Mat(uv_sz, CV_8UC2, in_mat.data + in_mat.step1() * in_sz.height);
cv::Mat out_mat = cv::Mat::zeros(out_sz.height*3, out_sz.width, CV_8UC1);
cv::Mat out_mat_ocv = cv::Mat::zeros(out_sz.height*3, out_sz.width, CV_8UC1);
cv::GMat inY, inUV;
auto out = GResize3p3p::on(GNV12toRGBp::on(inY, inUV), out_sz, interp);
cv::GComputation c(cv::GIn(inY, inUV), cv::GOut(out));
auto pkg = cv::gapi::kernels<OCVNV12toRGBp, OCVResize3p3p>();
c.apply(cv::gin(y_mat, uv_mat), cv::gout(out_mat), cv::compile_args(pkg));
cv::Mat rgb, resized_mat;
cv::cvtColorTwoPlane(y_mat, uv_mat, rgb, cv::COLOR_YUV2RGB_NV12);
cv::resize(rgb, resized_mat, out_sz, 0, 0, interp);
toPlanar(resized_mat, out_mat_ocv);
EXPECT_EQ(0, cv::countNonZero(out_mat != out_mat_ocv));
}
INSTANTIATE_TEST_CASE_P(Sanity, PlanarTest,
Values(std::make_pair(cv::Size{8, 8}, cv::Size{4, 4})
,std::make_pair(cv::Size{960, 540}, cv::Size{224, 224})
,std::make_pair(cv::Size{64, 64}, cv::Size{224, 224})
));
} // namespace opencv_test

View File

@@ -0,0 +1,320 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <stdexcept>
#include <ade/util/iota_range.hpp>
#include "logger.hpp"
#include <opencv2/gapi/plaidml/core.hpp>
namespace opencv_test
{
namespace
{
G_TYPED_KERNEL(GInvalidResize, <GMat(GMat,Size,double,double,int)>, "org.opencv.test.invalid_resize")
{
static GMatDesc outMeta(GMatDesc in, Size, double, double, int) { return in; }
};
GAPI_OCV_KERNEL(GOCVInvalidResize, GInvalidResize)
{
static void run(const cv::Mat& in, cv::Size sz, double fx, double fy, int interp, cv::Mat &out)
{
cv::resize(in, out, sz, fx, fy, interp);
}
};
G_TYPED_KERNEL(GReallocatingCopy, <GMat(GMat)>, "org.opencv.test.reallocating_copy")
{
static GMatDesc outMeta(GMatDesc in) { return in; }
};
GAPI_OCV_KERNEL(GOCVReallocatingCopy, GReallocatingCopy)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
out = in.clone();
}
};
}
TEST(GAPI_Pipeline, OverloadUnary_MatMat)
{
cv::GMat in;
cv::GComputation comp(in, cv::gapi::bitwise_not(in));
cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
cv::Mat ref_mat = ~in_mat;
cv::Mat out_mat;
comp.apply(in_mat, out_mat);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
out_mat = cv::Mat();
auto cc = comp.compile(cv::descr_of(in_mat));
cc(in_mat, out_mat);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GAPI_Pipeline, OverloadUnary_MatScalar)
{
cv::GMat in;
cv::GComputation comp(in, cv::gapi::sum(in));
cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
cv::Scalar ref_scl = cv::sum(in_mat);
cv::Scalar out_scl;
comp.apply(in_mat, out_scl);
EXPECT_EQ(out_scl, ref_scl);
out_scl = cv::Scalar();
auto cc = comp.compile(cv::descr_of(in_mat));
cc(in_mat, out_scl);
EXPECT_EQ(out_scl, ref_scl);
}
TEST(GAPI_Pipeline, OverloadBinary_Mat)
{
cv::GMat a, b;
cv::GComputation comp(a, b, cv::gapi::add(a, b));
cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
cv::Mat ref_mat = (in_mat+in_mat);
cv::Mat out_mat;
comp.apply(in_mat, in_mat, out_mat);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
out_mat = cv::Mat();
auto cc = comp.compile(cv::descr_of(in_mat), cv::descr_of(in_mat));
cc(in_mat, in_mat, out_mat);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GAPI_Pipeline, OverloadBinary_Scalar)
{
cv::GMat a, b;
cv::GComputation comp(a, b, cv::gapi::sum(a + b));
cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
cv::Scalar ref_scl = cv::sum(in_mat+in_mat);
cv::Scalar out_scl;
comp.apply(in_mat, in_mat, out_scl);
EXPECT_EQ(out_scl, ref_scl);
out_scl = cv::Scalar();
auto cc = comp.compile(cv::descr_of(in_mat), cv::descr_of(in_mat));
cc(in_mat, in_mat, out_scl);
EXPECT_EQ(out_scl, ref_scl);
}
TEST(GAPI_Pipeline, Sharpen)
{
const cv::Size sz_in (1280, 720);
const cv::Size sz_out( 640, 480);
cv::Mat in_mat (sz_in, CV_8UC3);
in_mat = cv::Scalar(128, 33, 53);
cv::Mat out_mat(sz_out, CV_8UC3);
cv::Mat out_mat_y;
cv::Mat out_mat_ocv(sz_out, CV_8UC3);
float sharpen_coeffs[] = {
0.0f, -1.f, 0.0f,
-1.0f, 5.f, -1.0f,
0.0f, -1.f, 0.0f
};
cv::Mat sharpen_kernel(3, 3, CV_32F, sharpen_coeffs);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto vga = cv::gapi::resize(in, sz_out);
auto yuv = cv::gapi::RGB2YUV(vga);
auto yuv_p = cv::gapi::split3(yuv);
auto y_sharp = cv::gapi::filter2D(std::get<0>(yuv_p), -1, sharpen_kernel);
auto yuv_new = cv::gapi::merge3(y_sharp, std::get<1>(yuv_p), std::get<2>(yuv_p));
auto out = cv::gapi::YUV2RGB(yuv_new);
cv::GComputation c(cv::GIn(in), cv::GOut(y_sharp, out));
c.apply(cv::gin(in_mat), cv::gout(out_mat_y, out_mat));
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::Mat smaller;
cv::resize(in_mat, smaller, sz_out);
cv::Mat yuv_mat;
cv::cvtColor(smaller, yuv_mat, cv::COLOR_RGB2YUV);
std::vector<cv::Mat> yuv_planar(3);
cv::split(yuv_mat, yuv_planar);
cv::filter2D(yuv_planar[0], yuv_planar[0], -1, sharpen_kernel);
cv::merge(yuv_planar, yuv_mat);
cv::cvtColor(yuv_mat, out_mat_ocv, cv::COLOR_YUV2RGB);
}
// Comparison //////////////////////////////////////////////////////////////
{
cv::Mat diff = out_mat_ocv != out_mat;
std::vector<cv::Mat> diffBGR(3);
cv::split(diff, diffBGR);
EXPECT_EQ(0, cv::countNonZero(diffBGR[0]));
EXPECT_EQ(0, cv::countNonZero(diffBGR[1]));
EXPECT_EQ(0, cv::countNonZero(diffBGR[2]));
}
// Metadata check /////////////////////////////////////////////////////////
{
auto cc = c.compile(cv::descr_of(in_mat));
auto metas = cc.outMetas();
ASSERT_EQ(2u, metas.size());
auto out_y_meta = cv::util::get<cv::GMatDesc>(metas[0]);
auto out_meta = cv::util::get<cv::GMatDesc>(metas[1]);
// Y-output
EXPECT_EQ(CV_8U, out_y_meta.depth);
EXPECT_EQ(1, out_y_meta.chan);
EXPECT_EQ(640, out_y_meta.size.width);
EXPECT_EQ(480, out_y_meta.size.height);
// Final output
EXPECT_EQ(CV_8U, out_meta.depth);
EXPECT_EQ(3, out_meta.chan);
EXPECT_EQ(640, out_meta.size.width);
EXPECT_EQ(480, out_meta.size.height);
}
}
TEST(GAPI_Pipeline, CustomRGB2YUV)
{
const cv::Size sz(1280, 720);
// BEWARE:
//
// std::vector<cv::Mat> out_mats_cv(3, cv::Mat(sz, CV_8U))
//
// creates a vector of 3 elements pointing to the same Mat!
// FIXME: Make a G-API check for that
const int INS = 3;
std::vector<cv::Mat> in_mats(INS);
for (auto i : ade::util::iota(INS))
{
in_mats[i].create(sz, CV_8U);
cv::randu(in_mats[i], cv::Scalar::all(0), cv::Scalar::all(255));
}
const int OUTS = 3;
std::vector<cv::Mat> out_mats_cv(OUTS);
std::vector<cv::Mat> out_mats_gapi(OUTS);
for (auto i : ade::util::iota(OUTS))
{
out_mats_cv [i].create(sz, CV_8U);
out_mats_gapi[i].create(sz, CV_8U);
}
// G-API code //////////////////////////////////////////////////////////////
{
cv::GMat r, g, b;
cv::GMat y = 0.299f*r + 0.587f*g + 0.114f*b;
cv::GMat u = 0.492f*(b - y);
cv::GMat v = 0.877f*(r - y);
cv::GComputation customCvt({r, g, b}, {y, u, v});
customCvt.apply(in_mats, out_mats_gapi);
}
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::Mat r = in_mats[0], g = in_mats[1], b = in_mats[2];
cv::Mat y = 0.299f*r + 0.587f*g + 0.114f*b;
cv::Mat u = 0.492f*(b - y);
cv::Mat v = 0.877f*(r - y);
out_mats_cv[0] = y;
out_mats_cv[1] = u;
out_mats_cv[2] = v;
}
// Comparison //////////////////////////////////////////////////////////////
{
const auto diff = [](cv::Mat m1, cv::Mat m2, int t) {
return cv::abs(m1-m2) > t;
};
// FIXME: Not bit-accurate even now!
cv::Mat
diff_y = diff(out_mats_cv[0], out_mats_gapi[0], 2),
diff_u = diff(out_mats_cv[1], out_mats_gapi[1], 2),
diff_v = diff(out_mats_cv[2], out_mats_gapi[2], 2);
EXPECT_EQ(0, cv::countNonZero(diff_y));
EXPECT_EQ(0, cv::countNonZero(diff_u));
EXPECT_EQ(0, cv::countNonZero(diff_v));
}
}
TEST(GAPI_Pipeline, PipelineWithInvalidKernel)
{
cv::GMat in, out;
cv::Mat in_mat(500, 500, CV_8UC1), out_mat;
out = GInvalidResize::on(in, cv::Size(300, 300), 0.0, 0.0, cv::INTER_LINEAR);
const auto pkg = cv::gapi::kernels<GOCVInvalidResize>();
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
EXPECT_THROW(comp.apply(in_mat, out_mat, cv::compile_args(pkg)), std::logic_error);
}
TEST(GAPI_Pipeline, InvalidOutputComputation)
{
cv::GMat in1, out1, out2, out3;
std::tie(out1, out2, out2) = cv::gapi::split3(in1);
cv::GComputation c({in1}, {out1, out2, out3});
cv::Mat in_mat;
cv::Mat out_mat1, out_mat2, out_mat3, out_mat4;
std::vector<cv::Mat> u_outs = {out_mat1, out_mat2, out_mat3, out_mat4};
std::vector<cv::Mat> u_ins = {in_mat};
EXPECT_THROW(c.apply(u_ins, u_outs), std::logic_error);
}
TEST(GAPI_Pipeline, PipelineAllocatingKernel)
{
cv::GMat in, out;
cv::Mat in_mat(500, 500, CV_8UC1), out_mat;
out = GReallocatingCopy::on(in);
const auto pkg = cv::gapi::kernels<GOCVReallocatingCopy>();
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
EXPECT_THROW(comp.apply(in_mat, out_mat, cv::compile_args(pkg)), std::logic_error);
}
TEST(GAPI_Pipeline, CanUseOwnMatAsOutput)
{
cv::GMat in;
cv::GComputation comp(in, cv::gapi::bitwise_not(in));
cv::Mat in_mat(3, 3, CV_8UC1);
cv::Mat out_mat(3, 3, CV_8UC1);
cv::gapi::own::Mat in_own_mat(in_mat.rows, in_mat.cols, CV_8UC1, in_mat.data);
cv::gapi::own::Mat out_own_mat(out_mat.rows, out_mat.cols, CV_8UC1, out_mat.data);
// FIXME add overload for apply(cv::gapi::own::Mat in, cv::gapi::own::Mat& out)
EXPECT_NO_THROW(comp.apply({in_own_mat}, {out_own_mat}));
}
} // namespace opencv_test

View File

@@ -0,0 +1,117 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <iostream>
namespace opencv_test
{
TEST(GAPI_Scalar, Argument)
{
cv::Size sz(2, 2);
cv::Mat in_mat(sz, CV_8U);
cv::randn(in_mat, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::GComputationT<cv::GMat (cv::GMat, cv::GScalar)> mulS([](cv::GMat in, cv::GScalar c)
{
return in*c;
});
cv::Mat out_mat(sz, CV_8U);
mulS.apply(in_mat, cv::Scalar(2), out_mat);
cv::Mat reference = in_mat*2;
EXPECT_EQ(0, cv::countNonZero(cv::abs(out_mat - reference)));
}
TEST(GAPI_Scalar, ReturnValue)
{
const cv::Size sz(2, 2);
cv::Mat in_mat(sz, CV_8U, cv::Scalar(1));
cv::GComputationT<cv::GScalar (cv::GMat)> sum_of_sum([](cv::GMat in)
{
return cv::gapi::sum(in + in);
});
cv::Scalar out;
sum_of_sum.apply(in_mat, out);
EXPECT_EQ(8, out[0]);
}
TEST(GAPI_Scalar, TmpScalar)
{
const cv::Size sz(2, 2);
cv::Mat in_mat(sz, CV_8U, cv::Scalar(1));
cv::GComputationT<cv::GMat (cv::GMat)> mul_by_sum([](cv::GMat in)
{
return in * cv::gapi::sum(in);
});
cv::Mat out_mat(sz, CV_8U);
mul_by_sum.apply(in_mat, out_mat);
cv::Mat reference = cv::Mat(sz, CV_8U, cv::Scalar(4));
EXPECT_EQ(0, cv::countNonZero(cv::abs(out_mat - reference)));
}
TEST(GAPI_ScalarWithValue, Simple_Arithmetic_Pipeline)
{
GMat in;
GMat out = (in + 1) * 2;
cv::GComputation comp(in, out);
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1);
cv::Mat ref_mat, out_mat;
ref_mat = (in_mat + 1) * 2;
comp.apply(in_mat, out_mat);
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GAPI_ScalarWithValue, GScalar_Initilization)
{
cv::Scalar sc(2);
cv::GMat in;
cv::GScalar s(sc);
cv::GComputation comp(in, cv::gapi::mulC(in, s));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1);
cv::Mat ref_mat, out_mat;
cv::multiply(in_mat, sc, ref_mat, 1, CV_8UC1);
comp.apply(cv::gin(in_mat), cv::gout(out_mat));
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
TEST(GAPI_ScalarWithValue, Constant_GScalar_In_Middle_Graph)
{
cv::Scalar sc(5);
cv::GMat in1;
cv::GScalar in2;
cv::GScalar s(sc);
auto add_out = cv::gapi::addC(in1, in2);
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(cv::gapi::mulC(add_out, s)));
cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1);
cv::Scalar in_scalar(3);
cv::Mat ref_mat, out_mat, add_mat;
cv::add(in_mat, in_scalar, add_mat);
cv::multiply(add_mat, sc, ref_mat, 1, CV_8UC1);
comp.apply(cv::gin(in_mat, in_scalar), cv::gout(out_mat));
EXPECT_EQ(0, cv::countNonZero(out_mat != ref_mat));
}
} // namespace opencv_test

View File

@@ -0,0 +1,97 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
namespace opencv_test
{
TEST(GAPI, Mat_Create_NoLink)
{
cv::Mat m1;
cv::Mat m2 = m1;
m2.create(32, 32, CV_8U);
EXPECT_NE(m1.rows, m2.rows);
EXPECT_NE(m1.cols, m2.cols);
EXPECT_NE(m1.data, m2.data);
}
TEST(GAPI, Mat_Recreate)
{
cv::Mat m1 = cv::Mat::zeros(480, 640, CV_8U);
m1.at<uchar>(0, 0) = 128;
cv::Mat m2 = m1;
EXPECT_EQ(m1.rows, m2.rows);
EXPECT_EQ(m1.cols, m2.cols);
EXPECT_EQ(m1.data, m2.data);
EXPECT_EQ(m1.at<uchar>(0, 0), m2.at<uchar>(0, 0));
// Calling "create" with the same meta is NOOP - both m1 and m2 are the same
m1.create(480, 640, CV_8U);
EXPECT_EQ(m1.rows, m2.rows);
EXPECT_EQ(m1.cols, m2.cols);
EXPECT_EQ(m1.data, m2.data);
EXPECT_EQ(m1.at<uchar>(0, 0), m2.at<uchar>(0, 0));
// Calling "create" on m2 with different meta doesn't update original m1
// Now m1 and m2 are distinct
m2.create(720, 1280, CV_8U);
m2.at<uchar>(0, 0) = 64; // Initialize 0,0 element since m2 is a new buffer
EXPECT_NE(m1.rows, m2.rows);
EXPECT_NE(m1.cols, m2.cols);
EXPECT_NE(m1.data, m2.data);
EXPECT_NE(m1.at<uchar>(0, 0), m2.at<uchar>(0, 0));
// What if a Mat is created from handle?
uchar data[] = {
32, 0, 0,
0, 0, 0,
0, 0, 0
};
cv::Mat m3(3, 3, CV_8U, data);
cv::Mat m4 = m3;
EXPECT_EQ(m3.rows, m4.rows);
EXPECT_EQ(m3.cols, m4.cols);
EXPECT_EQ(m3.data, m4.data);
EXPECT_EQ(data, m3.data);
EXPECT_EQ(data, m4.data);
EXPECT_EQ(m3.at<uchar>(0, 0), m4.at<uchar>(0, 0));
// cv::Mat::create must be NOOP if we don't change the meta,
// even if the origianl mat is created from handle.
m4.create(3, 3, CV_8U);
EXPECT_EQ(m3.rows, m4.rows);
EXPECT_EQ(m3.cols, m4.cols);
EXPECT_EQ(m3.data, m4.data);
EXPECT_EQ(data, m3.data);
EXPECT_EQ(data, m4.data);
EXPECT_EQ(m3.at<uchar>(0, 0), m4.at<uchar>(0, 0));
}
TEST(GAPI, EmptyOutMat)
{
cv::Mat in_mat = cv::Mat(480, 640, CV_8U, cv::Scalar(64));
cv::GComputation cc([]()
{
cv::GMat in;
cv::GMat out = in + in;
return cv::GComputation(in, out);
});
cv::Mat out;
cc.apply(in_mat, out);
EXPECT_EQ(640, out.cols);
EXPECT_EQ(480, out.rows);
EXPECT_EQ(CV_8U, out.type());
EXPECT_EQ(0, cv::countNonZero(out - (in_mat+in_mat)));
}
}

View File

@@ -0,0 +1,245 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include <tuple>
#include "test_precomp.hpp"
#include "opencv2/gapi/gtransform.hpp"
#include "opencv2/gapi/gtype_traits.hpp"
// explicit include to use GComputation::Priv
#include "api/gcomputation_priv.hpp"
namespace opencv_test
{
namespace
{
using GMat = cv::GMat;
using GMat2 = std::tuple<GMat, GMat>;
using GMat3 = std::tuple<GMat, GMat, GMat>;
using GScalar = cv::GScalar;
template <typename T> using GArray = cv::GArray<T>;
using ArrayT = int;
using WrongArrayT = char;
GAPI_TRANSFORM(gmat_in_gmat_out, <GMat(GMat)>, "gmat_in_gmat_out")
{
static GMat pattern(GMat) { return {}; }
static GMat substitute(GMat) { return {}; }
};
GAPI_TRANSFORM(gmat2_in_gmat_out, <GMat(GMat, GMat)>, "gmat2_in_gmat_out")
{
static GMat pattern(GMat, GMat) { return {}; }
static GMat substitute(GMat, GMat) { return {}; }
};
GAPI_TRANSFORM(gmat2_in_gmat3_out, <GMat3(GMat, GMat)>, "gmat2_in_gmat3_out")
{
static GMat3 pattern(GMat, GMat) { return {}; }
static GMat3 substitute(GMat, GMat) { return {}; }
};
GAPI_TRANSFORM(gmatp_in_gmatp_out, <GMatP(GMatP)>, "gmatp_in_gmatp_out")
{
static GMatP pattern(GMatP) { return {}; }
static GMatP substitute(GMatP) { return {}; }
};
GAPI_TRANSFORM(gsc_in_gmat_out, <GMat(GScalar)>, "gsc_in_gmat_out")
{
static GMat pattern(GScalar) { return {}; }
static GMat substitute(GScalar) { return {}; }
};
GAPI_TRANSFORM(gmat_in_gsc_out, <GScalar(GMat)>, "gmat_in_gsc_out")
{
static GScalar pattern(GMat) { return {}; }
static GScalar substitute(GMat) { return {}; }
};
GAPI_TRANSFORM(garr_in_gmat_out, <GMat(GArray<ArrayT>)>, "garr_in_gmat_out")
{
static GMat pattern(GArray<ArrayT>) { return {}; }
static GMat substitute(GArray<ArrayT>) { return {}; }
};
GAPI_TRANSFORM(gmat_in_garr_out, <GArray<ArrayT>(GMat)>, "gmat_in_garr_out")
{
static GArray<ArrayT> pattern(GMat) { return {}; }
static GArray<ArrayT> substitute(GMat) { return {}; }
};
GAPI_TRANSFORM(garr_in_gscalar_out, <GScalar(GArray<ArrayT>)>, "garr_in_gscalar_out")
{
static GScalar pattern(GArray<ArrayT>) { return {}; }
static GScalar substitute(GArray<ArrayT>) { return {}; }
};
GAPI_TRANSFORM(gscalar_in_garr_out, <GArray<ArrayT>(GScalar)>, "gscalar_in_garr_out")
{
static GArray<ArrayT> pattern(GScalar) { return {}; }
static GArray<ArrayT> substitute(GScalar) { return {}; }
};
GAPI_TRANSFORM(gmat_gsc_garray_in_gmat2_out, <GMat2(GMat, GScalar, GArray<ArrayT>)>, "gmat_gsc_garray_in_gmat2_out")
{
static GMat2 pattern(GMat, GScalar, GArray<ArrayT>) { return {}; }
static GMat2 substitute(GMat, GScalar, GArray<ArrayT>) { return {}; }
};
} // anonymous namespace
TEST(KernelPackageTransform, CreatePackage)
{
auto pkg = cv::gapi::kernels
< gmat_in_gmat_out
, gmat2_in_gmat_out
, gmat2_in_gmat3_out
, gmatp_in_gmatp_out
, gsc_in_gmat_out
, gmat_in_gsc_out
, garr_in_gmat_out
, gmat_in_garr_out
, garr_in_gscalar_out
, gscalar_in_garr_out
, gmat_gsc_garray_in_gmat2_out
>();
auto tr = pkg.get_transformations();
EXPECT_EQ(11u, tr.size());
}
TEST(KernelPackageTransform, Include)
{
cv::gapi::GKernelPackage pkg;
pkg.include<gmat_in_gmat_out>();
pkg.include<gmat2_in_gmat_out>();
pkg.include<gmat2_in_gmat3_out>();
auto tr = pkg.get_transformations();
EXPECT_EQ(3u, tr.size());
}
TEST(KernelPackageTransform, Combine)
{
auto pkg1 = cv::gapi::kernels<gmat_in_gmat_out>();
auto pkg2 = cv::gapi::kernels<gmat2_in_gmat_out>();
auto pkg_comb = cv::gapi::combine(pkg1, pkg2);
auto tr = pkg_comb.get_transformations();
EXPECT_EQ(2u, tr.size());
}
namespace
{
template <typename T>
inline bool ProtoContainsT(const cv::GProtoArg &arg) {
return cv::GProtoArg::index_of<T>() == arg.index();
}
} // anonymous namespace
TEST(KernelPackageTransform, gmat_gsc_garray_in_gmat2_out)
{
auto tr = gmat_gsc_garray_in_gmat2_out::transformation();
auto check = [](const cv::GComputation &comp){
const auto &p = comp.priv();
EXPECT_EQ(3u, p.m_ins.size());
EXPECT_EQ(2u, p.m_outs.size());
EXPECT_TRUE(ProtoContainsT<GMat>(p.m_ins[0]));
EXPECT_TRUE(ProtoContainsT<GScalar>(p.m_ins[1]));
EXPECT_TRUE(ProtoContainsT<cv::detail::GArrayU>(p.m_ins[2]));
EXPECT_TRUE(cv::util::get<cv::detail::GArrayU>(p.m_ins[2]).holds<ArrayT>());
EXPECT_FALSE(cv::util::get<cv::detail::GArrayU>(p.m_ins[2]).holds<WrongArrayT>());
EXPECT_TRUE(ProtoContainsT<GMat>(p.m_outs[0]));
EXPECT_TRUE(ProtoContainsT<GMat>(p.m_outs[1]));
};
check(tr.pattern());
check(tr.substitute());
}
namespace
{
template<typename ArgT>
typename std::enable_if<(cv::detail::GTypeTraits<ArgT>::kind == cv::detail::ArgKind::GARRAY), void>::type
arg_check(const cv::GProtoArg &arg)
{
EXPECT_TRUE(ProtoContainsT<cv::detail::GArrayU>(arg));
EXPECT_TRUE(cv::util::get<cv::detail::GArrayU>(arg).holds<ArrayT>());
EXPECT_FALSE(cv::util::get<cv::detail::GArrayU>(arg).holds<WrongArrayT>());
}
template<typename ArgT>
typename std::enable_if<(cv::detail::GTypeTraits<ArgT>::kind != cv::detail::ArgKind::GARRAY), void>::type
arg_check(const cv::GProtoArg &arg)
{
EXPECT_TRUE(ProtoContainsT<ArgT>(arg));
}
template<typename InType, typename OutType>
void args_check(const cv::GComputation &comp)
{
const auto &p = comp.priv();
EXPECT_EQ(1u, p.m_ins.size());
EXPECT_EQ(1u, p.m_outs.size());
arg_check<InType>(p.m_ins[0]);
arg_check<OutType>(p.m_outs[0]);
}
} // anonymous namespace
template <typename Transformation, typename InType, typename OutType>
static void transformTest()
{
auto tr = Transformation::transformation();
args_check<InType, OutType>(tr.pattern());
args_check<InType, OutType>(tr.substitute());
}
TEST(KernelPackageTransform, gmat_in_gmat_out)
{
transformTest<gmat_in_gmat_out, GMat, GMat>();
}
TEST(KernelPackageTransform, gmatp_in_gmatp_out)
{
transformTest<gmatp_in_gmatp_out, GMatP, GMatP>();
}
TEST(KernelPackageTransform, gsc_in_gmat_out)
{
transformTest<gsc_in_gmat_out, GScalar, GMat>();
}
TEST(KernelPackageTransform, gmat_in_gsc_out)
{
transformTest<gmat_in_gsc_out, GMat, GScalar>();
}
TEST(KernelPackageTransform, garr_in_gmat_out)
{
transformTest<garr_in_gmat_out, GArray<ArrayT>, GMat>();
}
TEST(KernelPackageTransform, gmat_in_garr_out)
{
transformTest<gmat_in_garr_out, GMat, GArray<ArrayT>>();
}
TEST(KernelPackageTransform, garr_in_gscalar_out)
{
transformTest<garr_in_gscalar_out, GArray<ArrayT>, GScalar>();
}
TEST(KernelPackageTransform, gscalar_in_garr_out)
{
transformTest<gscalar_in_garr_out, GScalar, GArray<ArrayT>>();
}
} // namespace opencv_test

View File

@@ -0,0 +1,185 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
namespace opencv_test
{
namespace
{
cv::Mat diff(cv::Mat m1, cv::Mat m2, int t)
{
return cv::abs(m1-m2) > t;
}
int non_zero3(cv::Mat m3c)
{
std::vector<cv::Mat> mm(3);
cv::split(m3c, mm);
return ( cv::countNonZero(mm[0])
+ cv::countNonZero(mm[1])
+ cv::countNonZero(mm[2]));
}
}
TEST(GAPI_Typed, UnaryOp)
{
// Initialization //////////////////////////////////////////////////////////
const cv::Size sz(32, 32);
cv::Mat
in_mat (sz, CV_8UC3),
out_mat_untyped(sz, CV_8UC3),
out_mat_typed1 (sz, CV_8UC3),
out_mat_typed2 (sz, CV_8UC3),
out_mat_cv (sz, CV_8UC3);
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
// Untyped G-API ///////////////////////////////////////////////////////////
cv::GComputation cvtU([]()
{
cv::GMat in;
cv::GMat out = cv::gapi::RGB2YUV(in);
return cv::GComputation(in, out);
});
cvtU.apply(in_mat, out_mat_untyped);
// Typed G-API /////////////////////////////////////////////////////////////
cv::GComputationT<cv::GMat (cv::GMat)> cvtT(cv::gapi::RGB2YUV);
auto cvtTComp = cvtT.compile(cv::descr_of(in_mat));
cvtT.apply(in_mat, out_mat_typed1);
cvtTComp(in_mat, out_mat_typed2);
// Plain OpenCV ////////////////////////////////////////////////////////////
cv::cvtColor(in_mat, out_mat_cv, cv::COLOR_RGB2YUV);
// Comparison //////////////////////////////////////////////////////////////
// FIXME: There must be OpenCV comparison test functions already available!
cv::Mat
diff_u = diff(out_mat_cv, out_mat_untyped, 0),
diff_t = diff(out_mat_cv, out_mat_typed1, 0),
diff_tc = diff(out_mat_cv, out_mat_typed2, 0);
EXPECT_EQ(0, non_zero3(diff_u));
EXPECT_EQ(0, non_zero3(diff_t));
EXPECT_EQ(0, non_zero3(diff_tc));
}
TEST(GAPI_Typed, BinaryOp)
{
// Initialization //////////////////////////////////////////////////////////
const cv::Size sz(32, 32);
cv::Mat
in_mat1 (sz, CV_8UC1),
in_mat2 (sz, CV_8UC1),
out_mat_untyped(sz, CV_8UC1),
out_mat_typed1 (sz, CV_8UC1),
out_mat_typed2 (sz, CV_8UC1),
out_mat_cv (sz, CV_8UC1);
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
// Untyped G-API ///////////////////////////////////////////////////////////
cv::GComputation cvtU([]()
{
cv::GMat in1, in2;
cv::GMat out = cv::gapi::add(in1, in2);
return cv::GComputation({in1, in2}, {out});
});
std::vector<cv::Mat> u_ins = {in_mat1, in_mat2};
std::vector<cv::Mat> u_outs = {out_mat_untyped};
cvtU.apply(u_ins, u_outs);
// Typed G-API /////////////////////////////////////////////////////////////
cv::GComputationT<cv::GMat (cv::GMat, cv::GMat)> cvtT([](cv::GMat m1, cv::GMat m2)
{
return m1+m2;
});
auto cvtTC = cvtT.compile(cv::descr_of(in_mat1),
cv::descr_of(in_mat2));
cvtT.apply(in_mat1, in_mat2, out_mat_typed1);
cvtTC(in_mat1, in_mat2, out_mat_typed2);
// Plain OpenCV ////////////////////////////////////////////////////////////
cv::add(in_mat1, in_mat2, out_mat_cv);
// Comparison //////////////////////////////////////////////////////////////
// FIXME: There must be OpenCV comparison test functions already available!
cv::Mat
diff_u = diff(out_mat_cv, out_mat_untyped, 0),
diff_t = diff(out_mat_cv, out_mat_typed1, 0),
diff_tc = diff(out_mat_cv, out_mat_typed2, 0);
EXPECT_EQ(0, cv::countNonZero(diff_u));
EXPECT_EQ(0, cv::countNonZero(diff_t));
EXPECT_EQ(0, cv::countNonZero(diff_tc));
}
TEST(GAPI_Typed, MultipleOuts)
{
// Initialization //////////////////////////////////////////////////////////
const cv::Size sz(32, 32);
cv::Mat
in_mat (sz, CV_8UC1),
out_mat_unt1 (sz, CV_8UC1),
out_mat_unt2 (sz, CV_8UC1),
out_mat_typed1(sz, CV_8UC1),
out_mat_typed2(sz, CV_8UC1),
out_mat_comp1 (sz, CV_8UC1),
out_mat_comp2 (sz, CV_8UC1),
out_mat_cv1 (sz, CV_8UC1),
out_mat_cv2 (sz, CV_8UC1);
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
// Untyped G-API ///////////////////////////////////////////////////////////
cv::GComputation cvtU([]()
{
cv::GMat in;
cv::GMat out1 = in * 2.f;
cv::GMat out2 = in * 4.f;
return cv::GComputation({in}, {out1, out2});
});
std::vector<cv::Mat> u_ins = {in_mat};
std::vector<cv::Mat> u_outs = {out_mat_unt1, out_mat_unt2};
cvtU.apply(u_ins, u_outs);
// Typed G-API /////////////////////////////////////////////////////////////
cv::GComputationT<std::tuple<cv::GMat, cv::GMat> (cv::GMat)> cvtT([](cv::GMat in)
{
return std::make_tuple(in*2.f, in*4.f);
});
auto cvtTC = cvtT.compile(cv::descr_of(in_mat));
cvtT.apply(in_mat, out_mat_typed1, out_mat_typed2);
cvtTC(in_mat, out_mat_comp1, out_mat_comp2);
// Plain OpenCV ////////////////////////////////////////////////////////////
out_mat_cv1 = in_mat * 2.f;
out_mat_cv2 = in_mat * 4.f;
// Comparison //////////////////////////////////////////////////////////////
// FIXME: There must be OpenCV comparison test functions already available!
cv::Mat
diff_u1 = diff(out_mat_cv1, out_mat_unt1, 0),
diff_u2 = diff(out_mat_cv2, out_mat_unt2, 0),
diff_t1 = diff(out_mat_cv1, out_mat_typed1, 0),
diff_t2 = diff(out_mat_cv2, out_mat_typed2, 0),
diff_c1 = diff(out_mat_cv1, out_mat_comp1, 0),
diff_c2 = diff(out_mat_cv2, out_mat_comp2, 0);
EXPECT_EQ(0, cv::countNonZero(diff_u1));
EXPECT_EQ(0, cv::countNonZero(diff_u2));
EXPECT_EQ(0, cv::countNonZero(diff_t1));
EXPECT_EQ(0, cv::countNonZero(diff_t2));
EXPECT_EQ(0, cv::countNonZero(diff_c1));
EXPECT_EQ(0, cv::countNonZero(diff_c2));
}
} // opencv_test

View File

@@ -0,0 +1,43 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "test_precomp.hpp"
#include <type_traits>
#include <opencv2/gapi/util/util.hpp>
namespace opencv_test
{
TEST(GAPIUtil, AllSatisfy)
{
static_assert(true == cv::detail::all_satisfy<std::is_integral, long, int, char>::value,
"[long, int, char] are all integral types");
static_assert(true == cv::detail::all_satisfy<std::is_integral, char>::value,
"char is an integral type");
static_assert(false == cv::detail::all_satisfy<std::is_integral, float, int, char>::value,
"[float, int, char] are NOT all integral types");
static_assert(false == cv::detail::all_satisfy<std::is_integral, int, char, float>::value,
"[int, char, float] are NOT all integral types");
static_assert(false == cv::detail::all_satisfy<std::is_integral, float>::value,
"float is not an integral types");
}
TEST(GAPIUtil, AllButLast)
{
using test1 = cv::detail::all_but_last<long, int, float>::type;
static_assert(true == cv::detail::all_satisfy<std::is_integral, test1>::value,
"[long, int] are all integral types (float skipped)");
using test2 = cv::detail::all_but_last<int, float, char>::type;
static_assert(false == cv::detail::all_satisfy<std::is_integral, test2>::value,
"[int, float] are NOT all integral types");
}
} // namespace opencv_test

View File

@@ -0,0 +1,433 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_core_tests.hpp"
namespace
{
#define CORE_GPU [] () { return cv::compile_args(cv::gapi::core::gpu::kernels()); }
} // anonymous namespace
namespace opencv_test
{
// FIXME: Wut? See MulTestGPU/MathOpTest below (duplicate?)
INSTANTIATE_TEST_CASE_P(AddTestGPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU),
Values(ADD, MUL),
testing::Bool(),
Values(1.0),
Values(false)));
INSTANTIATE_TEST_CASE_P(MulTestGPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU),
Values(MUL),
testing::Bool(),
Values(1.0, 0.5, 2.0),
Values(false)));
INSTANTIATE_TEST_CASE_P(SubTestGPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU),
Values(SUB),
testing::Bool(),
Values (1.0),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(DivTestGPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU),
Values(DIV),
testing::Bool(),
Values (1.0, 0.5, 2.0),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(MulTestGPU, MulDoubleTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(DivTestGPU, DivTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(DivCTestGPU, DivCTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(MeanTestGPU, MeanTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
//TODO: mask test doesn't work
#if 0
INSTANTIATE_TEST_CASE_P(MaskTestGPU, MaskTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CORE_GPU)));
#endif
INSTANTIATE_TEST_CASE_P(SelectTestGPU, SelectTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(Polar2CartGPU, Polar2CartTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_32FC1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(Cart2PolarGPU, Cart2PolarTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_32FC1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(CompareTestGPU, CmpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U),
Values(CORE_GPU),
Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(BitwiseTestGPU, BitwiseTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(AND, OR, XOR)));
INSTANTIATE_TEST_CASE_P(BitwiseNotTestGPU, NotTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(MinTestGPU, MinTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(MaxTestGPU, MaxTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(SumTestGPU, SumTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(AbsToleranceScalar(1e-3).to_compare_obj())));//TODO: too relaxed?
INSTANTIATE_TEST_CASE_P(AbsDiffTestGPU, AbsDiffTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(AbsDiffCTestGPU, AbsDiffCTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(AddWeightedTestGPU, AddWeightedTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(CORE_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(NormTestGPU, NormTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(AbsToleranceScalar(1e-3).to_compare_obj()), //TODO: too relaxed?
Values(NORM_INF, NORM_L1, NORM_L2)));
INSTANTIATE_TEST_CASE_P(IntegralTestGPU, IntegralTest,
Combine(Values( CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(ThresholdTestGPU, ThresholdTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC,
cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV),
Values(cv::Scalar(0, 0, 0, 0),
cv::Scalar(100, 100, 100, 100),
cv::Scalar(255, 255, 255, 255))));
INSTANTIATE_TEST_CASE_P(ThresholdTestGPU, ThresholdOTTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE)));
INSTANTIATE_TEST_CASE_P(InRangeTestGPU, InRangeTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(Split3TestGPU, Split3Test,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(Split4TestGPU, Split4Test,
Combine(Values(CV_8UC4),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(ResizeTestGPU, ResizeTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(AbsSimilarPoints(2, 0.05).to_compare_obj()),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values(cv::Size(64,64),
cv::Size(30,30))));
INSTANTIATE_TEST_CASE_P(ResizeTestGPU, ResizeTestFxFy,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(AbsSimilarPoints(2, 0.05).to_compare_obj()),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values(0.5, 0.1),
Values(0.5, 0.1)));
INSTANTIATE_TEST_CASE_P(Merge3TestGPU, Merge3Test,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC3),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(Merge4TestGPU, Merge4Test,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC4),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(RemapTestGPU, RemapTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(FlipTestGPU, FlipTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(0,1,-1)));
INSTANTIATE_TEST_CASE_P(CropTestGPU, CropTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50))));
INSTANTIATE_TEST_CASE_P(CopyTestGPU, CopyTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(LUTTestGPU, LUTTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(LUTTestCustomGPU, LUTTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8UC3),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(ConvertToGPU, ConvertToTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CV_8U, CV_16U, CV_16S, CV_32F),
Values(CORE_GPU),
Values(AbsExact().to_compare_obj()),
Values(2.5, 1.0, -1.0),
Values(250.0, 0.0, -128.0)));
INSTANTIATE_TEST_CASE_P(ConcatHorTestGPU, ConcatHorTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(ConcatVertTestGPU, ConcatVertTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
// PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestGPU, BackendOutputAllocationTest,
Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1),
Values(cv::Size(50, 50)),
Values(-1),
Values(CORE_GPU)));
// FIXME: there's an issue in OCL backend with matrix reallocation that shouldn't happen
INSTANTIATE_TEST_CASE_P(DISABLED_BackendOutputAllocationLargeSizeWithCorrectSubmatrixTestGPU,
BackendOutputAllocationLargeSizeWithCorrectSubmatrixTest,
Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1),
Values(cv::Size(50, 50)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(ReInitOutTestGPU, ReInitOutTest,
Combine(Values(CV_8UC3, CV_16SC4, CV_32FC1),
Values(cv::Size(640, 480)),
Values(-1),
Values(CORE_GPU),
Values(cv::Size(640, 400),
cv::Size(10, 480))));
//TODO: fix this backend to allow ConcatVertVec ConcatHorVec
#if 0
INSTANTIATE_TEST_CASE_P(ConcatVertVecTestGPU, ConcatVertVecTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(ConcatHorVecTestGPU, ConcatHorVecTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(CORE_GPU)));
#endif
}

View File

@@ -0,0 +1,247 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018-2019 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_imgproc_tests.hpp"
namespace
{
#define IMGPROC_GPU [] () { return cv::compile_args(cv::gapi::imgproc::gpu::kernels()); }
} // anonymous namespace
namespace opencv_test
{
INSTANTIATE_TEST_CASE_P(Filter2DTestGPU, Filter2DTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_32F),
Values(IMGPROC_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj()),
Values(cv::Size(3, 3),
cv::Size(4, 4),
cv::Size(5, 5),
cv::Size(7, 7)),
Values(cv::BORDER_DEFAULT)));
INSTANTIATE_TEST_CASE_P(BoxFilterTestGPU, BoxFilterTest,
Combine(Values(/*CV_8UC1,*/ CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_32F),
Values(IMGPROC_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj()),
Values(3,5),
Values(cv::BORDER_DEFAULT))); //TODO: 8UC1 doesn't work
INSTANTIATE_TEST_CASE_P(SepFilterTestGPU_8U, SepFilterTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_16S, CV_32F),
Values(IMGPROC_GPU),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(3)));
INSTANTIATE_TEST_CASE_P(SepFilterTestGPU_other, SepFilterTest,
Combine(Values(CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_32F),
Values(IMGPROC_GPU),
Values(ToleranceFilter(1e-4f, 0.01).to_compare_obj()),
Values(3)));
INSTANTIATE_TEST_CASE_P(BlurTestGPU, BlurTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-4, 2).to_compare_obj()),
Values(3,5),
Values(cv::BORDER_DEFAULT)));
INSTANTIATE_TEST_CASE_P(gaussBlurTestGPU, GaussianBlurTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(ToleranceFilter(1e-5f, 0.01).to_compare_obj()),
Values(3))); // FIXIT 5
INSTANTIATE_TEST_CASE_P(MedianBlurTestGPU, MedianBlurTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5)));
INSTANTIATE_TEST_CASE_P(ErodeTestGPU, ErodeTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(Erode3x3TestGPU, Erode3x3Test,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(AbsExact().to_compare_obj()),
Values(1,2,4)));
INSTANTIATE_TEST_CASE_P(DilateTestGPU, DilateTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(AbsExact().to_compare_obj()),
Values(3, 5),
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(Dilate3x3TestGPU, Dilate3x3Test,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(AbsExact().to_compare_obj()),
Values(1,2,4)));
INSTANTIATE_TEST_CASE_P(SobelTestGPU, SobelTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1, CV_16S, CV_32F),
Values(IMGPROC_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-4, 2).to_compare_obj()),
Values(3, 5),
Values(0, 1),
Values(1, 2)));
INSTANTIATE_TEST_CASE_P(SobelTestGPU32F, SobelTest,
Combine(Values(CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_32F),
Values(IMGPROC_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-4, 2).to_compare_obj()),
Values(3, 5),
Values(0, 1),
Values(1, 2)));
INSTANTIATE_TEST_CASE_P(EqHistTestGPU, EqHistTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(-1),
Values(IMGPROC_GPU),
Values(AbsExact().to_compare_obj()))); // FIXIT Non reliable check
INSTANTIATE_TEST_CASE_P(CannyTestGPU, CannyTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_GPU),
Values(AbsSimilarPoints(0, 0.05).to_compare_obj()),
Values(3.0, 120.0),
Values(125.0, 240.0),
Values(3, 5),
testing::Bool()));
INSTANTIATE_TEST_CASE_P(RGB2GrayTestGPU, RGB2GrayTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_GPU),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BGR2GrayTestGPU, BGR2GrayTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC1),
Values(IMGPROC_GPU),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2YUVTestGPU, RGB2YUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_GPU),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(YUV2RGBTestGPU, YUV2RGBTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_GPU),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(RGB2LabTestGPU, RGB2LabTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_GPU),
Values(AbsSimilarPoints(1, 0.05).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BGR2LUVTestGPU, BGR2LUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_GPU),
Values(ToleranceColor(5e-3, 6).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(LUV2BGRTestGPU, LUV2BGRTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_GPU),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BGR2YUVTestGPU, BGR2YUVTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_GPU),
Values(ToleranceColor(1e-3).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(YUV2BGRTestGPU, YUV2BGRTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
cv::Size(640, 480)),
Values(CV_8UC3),
Values(IMGPROC_GPU),
Values(ToleranceColor(1e-3).to_compare_obj())));
} // opencv_test

View File

@@ -0,0 +1,69 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "../common/gapi_operators_tests.hpp"
namespace
{
#define CORE_GPU [] () { return cv::compile_args(cv::gapi::core::gpu::kernels()); }
} // anonymous namespace
namespace opencv_test
{
INSTANTIATE_TEST_CASE_P(MathOperatorTestGPU, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj()),
Values( opPlusM, opMinusM, opDivM,
opGreater, opLess, opGreaterEq, opLessEq, opEq, opNotEq)));
INSTANTIATE_TEST_CASE_P(MathOperatorTestGPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-4, 2).to_compare_obj()),
Values( opPlus, opPlusR, opMinus, opMinusR, opMul, opMulR, // FIXIT avoid division by values near zero: opDiv, opDivR,
opGT, opLT, opGE, opLE, opEQ, opNE,
opGTR, opLTR, opGER, opLER, opEQR, opNER)));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestGPU, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(AbsExact().to_compare_obj()),
Values( opAnd, opOr, opXor )));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestGPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
Values(AbsExact().to_compare_obj()),
Values( opAND, opOR, opXOR, opANDR, opORR, opXORR )));
INSTANTIATE_TEST_CASE_P(BitwiseNotOperatorTestGPU, NotOperatorTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
}

View File

@@ -0,0 +1,281 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "../test_precomp.hpp"
#ifdef HAVE_INF_ENGINE
#include <stdexcept>
////////////////////////////////////////////////////////////////////////////////
// FIXME: Suppress deprecation warnings for OpenVINO 2019R2+
// BEGIN {{{
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#ifdef _MSC_VER
#pragma warning(disable: 4996) // was declared deprecated
#endif
#if defined(__GNUC__)
#pragma GCC visibility push(default)
#endif
#include <inference_engine.hpp>
#if defined(__GNUC__)
#pragma GCC visibility pop
#endif
// END }}}
////////////////////////////////////////////////////////////////////////////////
#include <ade/util/iota_range.hpp>
#include <opencv2/gapi/infer/ie.hpp>
#include "backends/ie/util.hpp"
namespace opencv_test
{
namespace {
// FIXME: taken from DNN module
static void initDLDTDataPath()
{
#ifndef WINRT
static bool initialized = false;
if (!initialized)
{
const char* omzDataPath = getenv("OPENCV_OPEN_MODEL_ZOO_DATA_PATH");
if (omzDataPath)
cvtest::addDataSearchPath(omzDataPath);
const char* dnnDataPath = getenv("OPENCV_DNN_TEST_DATA_PATH");
if (dnnDataPath) {
// Add the dnnDataPath itself - G-API is using some images there directly
cvtest::addDataSearchPath(dnnDataPath);
cvtest::addDataSearchPath(dnnDataPath + std::string("/omz_intel_models"));
}
initialized = true;
}
#endif // WINRT
}
// FIXME: taken from the DNN module
void normAssert(cv::InputArray ref, cv::InputArray test,
const char *comment /*= ""*/,
double l1 = 0.00001, double lInf = 0.0001)
{
double normL1 = cvtest::norm(ref, test, cv::NORM_L1) / ref.getMat().total();
EXPECT_LE(normL1, l1) << comment;
double normInf = cvtest::norm(ref, test, cv::NORM_INF);
EXPECT_LE(normInf, lInf) << comment;
}
} // anonymous namespace
// TODO: Probably DNN/IE part can be further parametrized with a template
// NOTE: here ".." is used to leave the default "gapi/" search scope
TEST(TestAgeGenderIE, InferBasicTensor)
{
initDLDTDataPath();
const std::string path = "Retail/object_attributes/age_gender/dldt/age-gender-recognition-retail-0013";
const auto topology_path = findDataFile(path + ".xml", false);
const auto weights_path = findDataFile(path + ".bin", false);
// Load IE network, initialize input data using that.
namespace IE = InferenceEngine;
cv::Mat in_mat;
cv::Mat gapi_age, gapi_gender;
IE::Blob::Ptr ie_age, ie_gender;
{
IE::CNNNetReader reader;
reader.ReadNetwork(topology_path);
reader.ReadWeights(weights_path);
auto net = reader.getNetwork();
const auto &iedims = net.getInputsInfo().begin()->second->getTensorDesc().getDims();
auto cvdims = cv::gapi::ie::util::to_ocv(iedims);
in_mat.create(cvdims, CV_32F);
cv::randu(in_mat, -1, 1);
auto plugin = IE::PluginDispatcher().getPluginByDevice("CPU");
auto plugin_net = plugin.LoadNetwork(net, {});
auto infer_request = plugin_net.CreateInferRequest();
infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
infer_request.Infer();
ie_age = infer_request.GetBlob("age_conv3");
ie_gender = infer_request.GetBlob("prob");
}
// Configure & run G-API
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
cv::GMat in;
cv::GMat age, gender;
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender));
auto pp = cv::gapi::ie::Params<AgeGender> {
topology_path, weights_path, "CPU"
}.cfgOutputLayers({ "age_conv3", "prob" });
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
// Validate with IE itself (avoid DNN module dependency here)
normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" );
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
}
TEST(TestAgeGenderIE, InferBasicImage)
{
initDLDTDataPath();
const std::string path = "Retail/object_attributes/age_gender/dldt/age-gender-recognition-retail-0013";
const auto topology_path = findDataFile(path + ".xml", false);
const auto weights_path = findDataFile(path + ".bin", false);
// FIXME: Ideally it should be an image from disk
// cv::Mat in_mat = cv::imread(findDataFile("grace_hopper_227.png"));
cv::Mat in_mat(cv::Size(320, 240), CV_8UC3);
cv::randu(in_mat, 0, 255);
cv::Mat gapi_age, gapi_gender;
// Load & run IE network
namespace IE = InferenceEngine;
IE::Blob::Ptr ie_age, ie_gender;
{
IE::CNNNetReader reader;
reader.ReadNetwork(topology_path);
reader.ReadWeights(weights_path);
auto net = reader.getNetwork();
auto &ii = net.getInputsInfo().at("data");
ii->setPrecision(IE::Precision::U8);
ii->setLayout(IE::Layout::NHWC);
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
auto plugin = IE::PluginDispatcher().getPluginByDevice("CPU");
auto plugin_net = plugin.LoadNetwork(net, {});
auto infer_request = plugin_net.CreateInferRequest();
infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
infer_request.Infer();
ie_age = infer_request.GetBlob("age_conv3");
ie_gender = infer_request.GetBlob("prob");
}
// Configure & run G-API
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
cv::GMat in;
cv::GMat age, gender;
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender));
auto pp = cv::gapi::ie::Params<AgeGender> {
topology_path, weights_path, "CPU"
}.cfgOutputLayers({ "age_conv3", "prob" });
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
// Validate with IE itself (avoid DNN module dependency here)
normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" );
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
}
TEST(TestAgeGenderIE, InferROIList)
{
initDLDTDataPath();
const std::string path = "Retail/object_attributes/age_gender/dldt/age-gender-recognition-retail-0013";
const auto topology_path = findDataFile(path + ".xml", false);
const auto weights_path = findDataFile(path + ".bin", false);
// FIXME: Ideally it should be an image from disk
// cv::Mat in_mat = cv::imread(findDataFile("grace_hopper_227.png"));
cv::Mat in_mat(cv::Size(640, 480), CV_8UC3);
cv::randu(in_mat, 0, 255);
std::vector<cv::Rect> rois = {
cv::Rect(cv::Point{ 0, 0}, cv::Size{80, 120}),
cv::Rect(cv::Point{50, 100}, cv::Size{96, 160}),
};
std::vector<cv::Mat> gapi_age, gapi_gender;
// Load & run IE network
namespace IE = InferenceEngine;
std::vector<cv::Mat> ie_age, ie_gender;
{
IE::CNNNetReader reader;
reader.ReadNetwork(topology_path);
reader.ReadWeights(weights_path);
auto net = reader.getNetwork();
auto &ii = net.getInputsInfo().at("data");
ii->setPrecision(IE::Precision::U8);
ii->setLayout(IE::Layout::NHWC);
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
auto plugin = IE::PluginDispatcher().getPluginByDevice("CPU");
auto plugin_net = plugin.LoadNetwork(net, {});
auto infer_request = plugin_net.CreateInferRequest();
auto frame_blob = cv::gapi::ie::util::to_ie(in_mat);
for (auto &&rc : rois) {
const auto ie_rc = IE::ROI {
0u
, static_cast<std::size_t>(rc.x)
, static_cast<std::size_t>(rc.y)
, static_cast<std::size_t>(rc.width)
, static_cast<std::size_t>(rc.height)
};
infer_request.SetBlob("data", IE::make_shared_blob(frame_blob, ie_rc));
infer_request.Infer();
using namespace cv::gapi::ie::util;
ie_age.push_back(to_ocv(infer_request.GetBlob("age_conv3")).clone());
ie_gender.push_back(to_ocv(infer_request.GetBlob("prob")).clone());
}
}
// Configure & run G-API
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
cv::GArray<cv::Rect> rr;
cv::GMat in;
cv::GArray<cv::GMat> age, gender;
std::tie(age, gender) = cv::gapi::infer<AgeGender>(rr, in);
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
auto pp = cv::gapi::ie::Params<AgeGender> {
topology_path, weights_path, "CPU"
}.cfgOutputLayers({ "age_conv3", "prob" });
comp.apply(cv::gin(in_mat, rois), cv::gout(gapi_age, gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
// Validate with IE itself (avoid DNN module dependency here)
ASSERT_EQ(2u, ie_age.size() );
ASSERT_EQ(2u, ie_gender.size());
ASSERT_EQ(2u, gapi_age.size() );
ASSERT_EQ(2u, gapi_gender.size());
normAssert(ie_age [0], gapi_age [0], "0: Test age output");
normAssert(ie_gender[0], gapi_gender[0], "0: Test gender output");
normAssert(ie_age [1], gapi_age [1], "1: Test age output");
normAssert(ie_gender[1], gapi_gender[1], "1: Test gender output");
}
} // namespace opencv_test
#endif // HAVE_INF_ENGINE

View File

@@ -0,0 +1,86 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "../gapi_mock_kernels.hpp"
#include "compiler/gmodel.hpp"
#include "compiler/gcompiler.hpp"
namespace opencv_test {
namespace {
struct MockMeta
{
static const char* name() { return "MockMeta"; }
};
class GMockBackendImpl final: public cv::gapi::GBackend::Priv
{
virtual void unpackKernel(ade::Graph &,
const ade::NodeHandle &,
const cv::GKernelImpl &) override
{
// Do nothing here
}
virtual EPtr compile(const ade::Graph &,
const cv::GCompileArgs &,
const std::vector<ade::NodeHandle> &) const override
{
// Do nothing here as well
return {};
}
virtual void addBackendPasses(ade::ExecutionEngineSetupContext &ectx) override
{
ectx.addPass("transform", "set_mock_meta", [](ade::passes::PassContext &ctx) {
ade::TypedGraph<MockMeta> me(ctx.graph);
for (const auto &nh : me.nodes())
{
me.metadata(nh).set(MockMeta{});
}
});
}
};
static cv::gapi::GBackend mock_backend(std::make_shared<GMockBackendImpl>());
GAPI_OCV_KERNEL(MockFoo, I::Foo)
{
static void run(const cv::Mat &, cv::Mat &) { /*Do nothing*/ }
static cv::gapi::GBackend backend() { return mock_backend; } // FIXME: Must be removed
};
} // anonymous namespace
TEST(GBackend, CustomPassesExecuted)
{
cv::GMat in;
cv::GMat out = I::Foo::on(in);
cv::GComputation c(in, out);
// Prepare compilation parameters manually
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
const auto pkg = cv::gapi::kernels<MockFoo>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(c, {in_meta}, cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
// Inspect the graph and verify the metadata written by Mock backend
ade::TypedGraph<MockMeta> me(*graph);
EXPECT_LT(0u, static_cast<std::size_t>(me.nodes().size()));
for (const auto &nh : me.nodes())
{
EXPECT_TRUE(me.metadata(nh).contains<MockMeta>());
}
}
} // namespace opencv_test

View File

@@ -0,0 +1,83 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
namespace opencv_test
{
// FIXME: avoid code duplication
// The below graph and config is taken from ComplexIslands test suite
TEST(GExecutor, SmokeTest)
{
cv::GMat in[2];
cv::GMat tmp[4];
cv::GScalar scl;
cv::GMat out[2];
tmp[0] = cv::gapi::bitwise_not(cv::gapi::bitwise_not(in[0]));
tmp[1] = cv::gapi::boxFilter(in[1], -1, cv::Size(3,3));
tmp[2] = tmp[0] + tmp[1]; // FIXME: handle tmp[2] = tmp[0]+tmp[2] typo
scl = cv::gapi::sum(tmp[1]);
tmp[3] = cv::gapi::medianBlur(tmp[1], 3);
out[0] = tmp[2] + scl;
out[1] = cv::gapi::boxFilter(tmp[3], -1, cv::Size(3,3));
// isl0 #internal1
// ........................... .........
// (in1) -> NotNot ->(tmp0) --> Add ---------> (tmp2) --> AddC -------> (out1)
// :.....................^...: :..^....:
// : :
// : :
// #internal0 : :
// .....................:......... :
// (in2) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// :..........:..................: isl1
// : ..............................
// `------------> Median -> (tmp3) --> Blur -------> (out2)
// :............................:
cv::gapi::island("isl0", cv::GIn(in[0], tmp[1]), cv::GOut(tmp[2]));
cv::gapi::island("isl1", cv::GIn(tmp[1]), cv::GOut(out[1]));
cv::Mat in_mat1 = cv::Mat::eye(32, 32, CV_8UC1);
cv::Mat in_mat2 = cv::Mat::eye(32, 32, CV_8UC1);
cv::Mat out_gapi[2];
// Run G-API:
cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_gapi[0], out_gapi[1]));
// Run OpenCV
cv::Mat out_ocv[2];
{
cv::Mat ocv_tmp0;
cv::Mat ocv_tmp1;
cv::Mat ocv_tmp2;
cv::Mat ocv_tmp3;
cv::Scalar ocv_scl;
ocv_tmp0 = in_mat1; // skip !(!)
cv::boxFilter(in_mat2, ocv_tmp1, -1, cv::Size(3,3));
ocv_tmp2 = ocv_tmp0 + ocv_tmp1;
ocv_scl = cv::sum(ocv_tmp1);
cv::medianBlur(ocv_tmp1, ocv_tmp3, 3);
out_ocv[0] = ocv_tmp2 + ocv_scl;
cv::boxFilter(ocv_tmp3, out_ocv[1], -1, cv::Size(3,3));
}
EXPECT_EQ(0, cv::countNonZero(out_gapi[0] != out_ocv[0]));
EXPECT_EQ(0, cv::countNonZero(out_gapi[1] != out_ocv[1]));
// FIXME: check that GIslandModel has more than 1 island (e.g. fusion
// with breakdown worked)
}
// FIXME: Add explicit tests on GMat/GScalar/GArray<T> being connectors
// between executed islands
} // namespace opencv_test

View File

@@ -0,0 +1,101 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
namespace opencv_test {
// Tests on T/Kind matching ////////////////////////////////////////////////////
// {{
template<class T, cv::detail::ArgKind Exp>
struct Expected
{
using type = T;
static const constexpr cv::detail::ArgKind kind = Exp;
};
template<typename T>
struct GArgKind: public ::testing::Test
{
using Type = typename T::type;
const cv::detail::ArgKind Kind = T::kind;
};
// The reason here is to _manually_ list types and their kinds
// (and NOT reuse cv::detail::ArgKind::Traits<>, since it is a subject of testing)
using GArg_Test_Types = ::testing::Types
<
// G-API types
Expected<cv::GMat, cv::detail::ArgKind::GMAT>
, Expected<cv::GMatP, cv::detail::ArgKind::GMATP>
, Expected<cv::GScalar, cv::detail::ArgKind::GSCALAR>
, Expected<cv::GArray<int>, cv::detail::ArgKind::GARRAY>
, Expected<cv::GArray<float>, cv::detail::ArgKind::GARRAY>
, Expected<cv::GArray<cv::Point>, cv::detail::ArgKind::GARRAY>
, Expected<cv::GArray<cv::Rect>, cv::detail::ArgKind::GARRAY>
// Built-in types
, Expected<int, cv::detail::ArgKind::OPAQUE_VAL>
, Expected<float, cv::detail::ArgKind::OPAQUE_VAL>
, Expected<int*, cv::detail::ArgKind::OPAQUE_VAL>
, Expected<cv::Point, cv::detail::ArgKind::OPAQUE_VAL>
, Expected<std::string, cv::detail::ArgKind::OPAQUE_VAL>
, Expected<cv::Mat, cv::detail::ArgKind::OPAQUE_VAL>
, Expected<std::vector<int>, cv::detail::ArgKind::OPAQUE_VAL>
, Expected<std::vector<cv::Point>, cv::detail::ArgKind::OPAQUE_VAL>
>;
TYPED_TEST_CASE(GArgKind, GArg_Test_Types);
TYPED_TEST(GArgKind, LocalVar)
{
typename TestFixture::Type val{};
cv::GArg arg(val);
EXPECT_EQ(TestFixture::Kind, arg.kind);
}
TYPED_TEST(GArgKind, ConstLocalVar)
{
const typename TestFixture::Type val{};
cv::GArg arg(val);
EXPECT_EQ(TestFixture::Kind, arg.kind);
}
TYPED_TEST(GArgKind, RValue)
{
cv::GArg arg = cv::GArg(typename TestFixture::Type());
EXPECT_EQ(TestFixture::Kind, arg.kind);
}
// }}
////////////////////////////////////////////////////////////////////////////////
TEST(GArg, HasWrap)
{
static_assert(!cv::detail::has_custom_wrap<cv::GMat>::value,
"GMat has no custom marshalling logic");
static_assert(!cv::detail::has_custom_wrap<cv::GScalar>::value,
"GScalar has no custom marshalling logic");
static_assert(cv::detail::has_custom_wrap<cv::GArray<int> >::value,
"GArray<int> has custom marshalling logic");
static_assert(cv::detail::has_custom_wrap<cv::GArray<std::string> >::value,
"GArray<int> has custom marshalling logic");
}
TEST(GArg, GArrayU)
{
// Placing a GArray<T> into GArg automatically strips it to GArrayU
cv::GArg arg1 = cv::GArg(cv::GArray<int>());
EXPECT_NO_THROW(arg1.get<cv::detail::GArrayU>());
cv::GArg arg2 = cv::GArg(cv::GArray<cv::Point>());
EXPECT_NO_THROW(arg2.get<cv::detail::GArrayU>());
}
} // namespace opencv_test

View File

@@ -0,0 +1,201 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "api/gcomputation_priv.hpp"
namespace opencv_test
{
TEST(GMetaArg, Traits_Is_Positive)
{
using namespace cv::detail;
static_assert(is_meta_descr<cv::GScalarDesc>::value,
"GScalarDesc is a meta description type");
static_assert(is_meta_descr<cv::GMatDesc>::value,
"GMatDesc is a meta description type");
}
TEST(GMetaArg, Traits_Is_Negative)
{
using namespace cv::detail;
static_assert(!is_meta_descr<cv::GCompileArgs>::value,
"GCompileArgs is NOT a meta description type");
static_assert(!is_meta_descr<int>::value,
"int is NOT a meta description type");
static_assert(!is_meta_descr<std::string>::value,
"str::string is NOT a meta description type");
}
TEST(GMetaArg, Traits_Are_EntireList_Positive)
{
using namespace cv::detail;
static_assert(are_meta_descrs<cv::GScalarDesc>::value,
"GScalarDesc is a meta description type");
static_assert(are_meta_descrs<cv::GMatDesc>::value,
"GMatDesc is a meta description type");
static_assert(are_meta_descrs<cv::GMatDesc, cv::GScalarDesc>::value,
"Both GMatDesc and GScalarDesc are meta types");
}
TEST(GMetaArg, Traits_Are_EntireList_Negative)
{
using namespace cv::detail;
static_assert(!are_meta_descrs<cv::GCompileArgs>::value,
"GCompileArgs is NOT among meta types");
static_assert(!are_meta_descrs<int, std::string>::value,
"Both int and std::string is NOT among meta types");
static_assert(!are_meta_descrs<cv::GMatDesc, cv::GScalarDesc, int>::value,
"List of type is not valid for meta as there\'s int");
static_assert(!are_meta_descrs<cv::GMatDesc, cv::GScalarDesc, cv::GCompileArgs>::value,
"List of type is not valid for meta as there\'s GCompileArgs");
}
TEST(GMetaArg, Traits_Are_ButLast_Positive)
{
using namespace cv::detail;
static_assert(are_meta_descrs_but_last<cv::GScalarDesc, int>::value,
"List is valid (int is omitted)");
static_assert(are_meta_descrs_but_last<cv::GMatDesc, cv::GScalarDesc, cv::GCompileArgs>::value,
"List is valid (GCompileArgs are omitted)");
}
TEST(GMetaArg, Traits_Are_ButLast_Negative)
{
using namespace cv::detail;
static_assert(!are_meta_descrs_but_last<int, std::string>::value,
"Both int is NOT among meta types (std::string is omitted)");
static_assert(!are_meta_descrs_but_last<cv::GMatDesc, cv::GScalarDesc, int, int>::value,
"List of type is not valid for meta as there\'s two ints");
static_assert(!are_meta_descrs_but_last<cv::GMatDesc, cv::GScalarDesc, cv::GCompileArgs, float>::value,
"List of type is not valid for meta as there\'s GCompileArgs");
}
TEST(GMetaArg, Can_Get_Metas_From_Input_Run_Args)
{
cv::Mat m(3, 3, CV_8UC3);
cv::Scalar s;
std::vector<int> v;
GMatDesc m_desc;
GMetaArgs meta_args = descr_of(cv::gin(m, s, v));
EXPECT_EQ(meta_args.size(), 3u);
EXPECT_NO_THROW(m_desc = util::get<cv::GMatDesc>(meta_args[0]));
EXPECT_NO_THROW(util::get<cv::GScalarDesc>(meta_args[1]));
EXPECT_NO_THROW(util::get<cv::GArrayDesc>(meta_args[2]));
EXPECT_EQ(CV_8U, m_desc.depth);
EXPECT_EQ(3, m_desc.chan);
EXPECT_EQ(cv::gapi::own::Size(3, 3), m_desc.size);
}
TEST(GMetaArg, Can_Get_Metas_From_Output_Run_Args)
{
cv::Mat m(3, 3, CV_8UC3);
cv::Scalar s;
std::vector<int> v;
GMatDesc m_desc;
GRunArgsP out_run_args = cv::gout(m, s, v);
GMetaArg m_meta = descr_of(out_run_args[0]);
GMetaArg s_meta = descr_of(out_run_args[1]);
GMetaArg v_meta = descr_of(out_run_args[2]);
EXPECT_NO_THROW(m_desc = util::get<cv::GMatDesc>(m_meta));
EXPECT_NO_THROW(util::get<cv::GScalarDesc>(s_meta));
EXPECT_NO_THROW(util::get<cv::GArrayDesc>(v_meta));
EXPECT_EQ(CV_8U, m_desc.depth);
EXPECT_EQ(3, m_desc.chan);
EXPECT_EQ(cv::Size(3, 3), m_desc.size);
}
TEST(GMetaArg, Can_Describe_RunArg)
{
cv::Mat m(3, 3, CV_8UC3);
cv::UMat um(3, 3, CV_8UC3);
cv::Scalar s;
constexpr int w = 3, h = 3, c = 3;
uchar data[w*h*c];
cv::gapi::own::Mat om(h, w, CV_8UC3, data);
cv::gapi::own::Scalar os;
std::vector<int> v;
GMetaArgs metas = {GMetaArg(descr_of(m)),
GMetaArg(descr_of(um)),
GMetaArg(descr_of(s)),
GMetaArg(descr_of(om)),
GMetaArg(descr_of(os)),
GMetaArg(descr_of(v))};
auto in_run_args = cv::gin(m, um, s, om, os, v);
for (int i = 0; i < 3; i++) {
EXPECT_TRUE(can_describe(metas[i], in_run_args[i]));
}
}
TEST(GMetaArg, Can_Describe_RunArgs)
{
cv::Mat m(3, 3, CV_8UC3);
cv::Scalar s;
std::vector<int> v;
GMetaArgs metas0 = {GMetaArg(descr_of(m)), GMetaArg(descr_of(s)), GMetaArg(descr_of(v))};
auto in_run_args0 = cv::gin(m, s, v);
EXPECT_TRUE(can_describe(metas0, in_run_args0));
auto in_run_args01 = cv::gin(m, s);
EXPECT_FALSE(can_describe(metas0, in_run_args01));
}
TEST(GMetaArg, Can_Describe_RunArgP)
{
cv::Mat m(3, 3, CV_8UC3);
cv::UMat um(3, 3, CV_8UC3);
cv::Scalar s;
constexpr int w = 3, h = 3, c = 3;
uchar data[w*h*c];
cv::gapi::own::Mat om(h, w, CV_8UC3, data);
cv::gapi::own::Scalar os;
std::vector<int> v;
GMetaArgs metas = {GMetaArg(descr_of(m)),
GMetaArg(descr_of(um)),
GMetaArg(descr_of(s)),
GMetaArg(descr_of(om)),
GMetaArg(descr_of(os)),
GMetaArg(descr_of(v))};
auto out_run_args = cv::gout(m, um, s, om, os, v);
for (int i = 0; i < 3; i++) {
EXPECT_TRUE(can_describe(metas[i], out_run_args[i]));
}
}
} // namespace opencv_test

View File

@@ -0,0 +1,364 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <ade/util/zip_range.hpp> // util::indexed
#include <opencv2/gapi/gkernel.hpp>
#include "compiler/gmodelbuilder.hpp"
#include "compiler/gmodel.hpp" // RcDesc, GModel::init
namespace opencv_test
{
namespace test
{
namespace
{
cv::GMat unaryOp(cv::GMat m)
{
return cv::GCall(cv::GKernel{"gapi.test.unaryop", "", nullptr, { GShape::GMAT } }).pass(m).yield(0);
}
cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
{
return cv::GCall(cv::GKernel{"gapi.test.binaryOp", "", nullptr, { GShape::GMAT } }).pass(m1, m2).yield(0);
}
std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
{
std::vector<ade::NodeHandle> ops;
for (const auto& nh : gr.nodes())
{
if (gr.metadata(nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP)
ops.push_back(nh);
}
return ops;
}
ade::NodeHandle inputOf(cv::gimpl::GModel::Graph& gm, ade::NodeHandle nh, std::size_t port)
{
for (const auto& eh : nh->inEdges())
{
if (gm.metadata(eh).get<cv::gimpl::Input>().port == port)
{
return eh->srcNode();
}
}
util::throw_error(std::logic_error("port " + std::to_string(port) + " not found"));
}
}
}// namespace opencv_test::test
TEST(GModelBuilder, Unroll_TestUnary)
{
cv::GMat in;
cv::GMat out = test::unaryOp(in);
auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
EXPECT_EQ(1u, unrolled.all_ops.size()); // There is one operation
EXPECT_EQ(2u, unrolled.all_data.size()); // And two data objects (in, out)
// TODO check what the operation is, and so on, and so on
}
TEST(GModelBuilder, Unroll_TestUnaryOfUnary)
{
cv::GMat in;
cv::GMat out = test::unaryOp(test::unaryOp(in));
auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
EXPECT_EQ(2u, unrolled.all_ops.size()); // There're two operations
EXPECT_EQ(3u, unrolled.all_data.size()); // And three data objects (in, out)
// TODO check what the operation is, and so on, and so on
}
TEST(GModelBuilder, Unroll_Not_All_Protocol_Inputs_Are_Reached)
{
cv::GMat in1, in2; // in1 -> unaryOp() -> u_op1 -> unaryOp() -> out
auto u_op1 = test::unaryOp(in1); // in2 -> unaryOp() -> u_op2
auto u_op2 = test::unaryOp(in2);
auto out = test::unaryOp(u_op1);
EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args), std::logic_error);
}
TEST(GModelBuilder, Unroll_Parallel_Path)
{
cv::GMat in1, in2; // in1 -> unaryOp() -> out1
auto out1 = test::unaryOp(in1); // in2 -> unaryOp() -> out2
auto out2 = test::unaryOp(in2);
auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
EXPECT_EQ(unrolled.all_ops.size(), 2u);
EXPECT_EQ(unrolled.all_data.size(), 4u);
}
TEST(GModelBuilder, Unroll_WithBranch)
{
// in -> unaryOp() -> tmp -->unaryOp() -> out1
// `---->unaryOp() -> out2
GMat in;
auto tmp = test::unaryOp(in);
auto out1 = test::unaryOp(tmp);
auto out2 = test::unaryOp(tmp);
auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
EXPECT_EQ(unrolled.all_ops.size(), 3u);
EXPECT_EQ(unrolled.all_data.size(), 4u);
}
TEST(GModelBuilder, Build_Unary)
{
cv::GMat in;
cv::GMat out = test::unaryOp(in);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
EXPECT_EQ(3u, static_cast<std::size_t>(g.nodes().size())); // Generated graph should have three nodes
// TODO: Check what the nodes are
}
TEST(GModelBuilder, Constant_GScalar)
{
// in -> addC()-----(GMat)---->mulC()-----(GMat)---->unaryOp()----out
// ^ ^
// | |
// 3-------` c_s-------'
cv::GMat in;
cv::GScalar c_s = 5;
auto out = test::unaryOp((in + 3) * c_s); // 3 converted to GScalar
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
cv::gimpl::Protocol p;
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
auto in_nh = p.in_nhs.front();
auto addC_nh = in_nh->outNodes().front();
auto mulC_nh = addC_nh->outNodes().front()->outNodes().front();
ASSERT_TRUE(gm.metadata(addC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
ASSERT_TRUE(gm.metadata(mulC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
auto s_3 = test::inputOf(gm, addC_nh, 1);
auto s_5 = test::inputOf(gm, mulC_nh, 1);
EXPECT_EQ(9u, static_cast<std::size_t>(g.nodes().size())); // 6 data nodes (1 -input, 1 output, 2 constant, 2 temp) and 3 op nodes
EXPECT_EQ(2u, static_cast<std::size_t>(addC_nh->inNodes().size())); // in and 3
EXPECT_EQ(2u, static_cast<std::size_t>(mulC_nh->inNodes().size())); // addC output and c_s
EXPECT_EQ(3, (util::get<cv::gapi::own::Scalar>(gm.metadata(s_3).get<cv::gimpl::ConstValue>().arg))[0]);
EXPECT_EQ(5, (util::get<cv::gapi::own::Scalar>(gm.metadata(s_5).get<cv::gimpl::ConstValue>().arg))[0]);
}
TEST(GModelBuilder, Check_Multiple_Outputs)
{
// ------------------------------> r
// '
// ' -----------> i_out1
// ' '
// in ----> split3() ---> g ---> integral()
// ' '
// ' -----------> i_out2
// '
// '---------> b ---> unaryOp() ---> u_out
cv::GMat in, r, g, b, i_out1, i_out2, u_out;
std::tie(r, g, b) = cv::gapi::split3(in);
std::tie(i_out1, i_out2) = cv::gapi::integral(g, 1, 1);
u_out = test::unaryOp(b);
ade::Graph gr;
cv::gimpl::GModel::Graph gm(gr);
cv::gimpl::GModel::init(gm);
auto proto_slots = cv::gimpl::GModelBuilder(gr).put(cv::GIn(in).m_args, cv::GOut(r, i_out1, i_out2, u_out).m_args);
cv::gimpl::Protocol p;
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
EXPECT_EQ(4u, static_cast<std::size_t>(p.out_nhs.size()));
EXPECT_EQ(0u, gm.metadata(p.out_nhs[0]->inEdges().front()).get<cv::gimpl::Output>().port);
EXPECT_EQ(0u, gm.metadata(p.out_nhs[1]->inEdges().front()).get<cv::gimpl::Output>().port);
EXPECT_EQ(1u, gm.metadata(p.out_nhs[2]->inEdges().front()).get<cv::gimpl::Output>().port);
EXPECT_EQ(0u, gm.metadata(p.out_nhs[3]->inEdges().front()).get<cv::gimpl::Output>().port);
for (const auto& it : ade::util::indexed(p.out_nhs))
{
const auto& out_nh = ade::util::value(it);
EXPECT_EQ(cv::gimpl::NodeType::DATA, gm.metadata(out_nh).get<cv::gimpl::NodeType>().t);
EXPECT_EQ(GShape::GMAT, gm.metadata(out_nh).get<cv::gimpl::Data>().shape);
}
}
TEST(GModelBuilder, Unused_Outputs)
{
cv::GMat in;
auto yuv_p = cv::gapi::split3(in);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(std::get<0>(yuv_p)).m_args);
EXPECT_EQ(5u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 1 operation, 3 outputs
}
TEST(GModelBuilder, Work_With_One_Channel_From_Split3)
{
cv::GMat in, y, u, v;
std::tie(y, u, v) = cv::gapi::split3(in);
auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
}
TEST(GModelBuilder, Add_Nodes_To_Unused_Nodes)
{
cv::GMat in, y, u, v;
std::tie(y, u, v) = cv::gapi::split3(in);
auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
// unused nodes
auto u_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
auto v_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
}
TEST(GModelBuilder, Unlisted_Inputs)
{
// in1 -> binaryOp() -> out
// ^
// |
// in2 ----'
cv::GMat in1, in2;
auto out = test::binaryOp(in1, in2);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
// add required 2 inputs but pass 1
EXPECT_THROW(cv::gimpl::GModelBuilder(g).put(cv::GIn(in1).m_args, cv::GOut(out).m_args), std::logic_error);
}
TEST(GModelBuilder, Unroll_No_Link_Between_In_And_Out)
{
// in -> unaryOp() -> u_op
// other -> unaryOp() -> out
cv::GMat in, other;
auto u_op = test::unaryOp(in);
auto out = test::unaryOp(other);
EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args), std::logic_error);
}
TEST(GModel_builder, Check_Binary_Op)
{
// in1 -> binaryOp() -> out
// ^
// |
// in2 -----'
cv::GMat in1, in2;
auto out = test::binaryOp(in1, in2);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args);
cv::gimpl::Protocol p;
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
auto ops = test::collectOperations(g);
EXPECT_EQ(1u, ops.size());
EXPECT_EQ("gapi.test.binaryOp", gm.metadata(ops.front()).get<cv::gimpl::Op>().k.name);
EXPECT_EQ(2u, static_cast<std::size_t>(ops.front()->inEdges().size()));
EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outEdges().size()));
EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outNodes().size()));
}
TEST(GModelBuilder, Add_Operation_With_Two_Out_One_Time)
{
// in -> integral() --> out_b1 -> unaryOp() -> out1
// |
// '-------> out_b2 -> unaryOp() -> out2
cv::GMat in, out_b1, out_b2;
std::tie(out_b1, out_b2) = cv::gapi::integral(in, 1, 1);
auto out1 = test::unaryOp(out_b1);
auto out2 = test::unaryOp(out_b1);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
auto ops = test::collectOperations(gm);
cv::gimpl::Protocol p;
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
auto integral_nh = p.in_nhs.front()->outNodes().front();
EXPECT_EQ(3u, ops.size());
EXPECT_EQ("org.opencv.core.matrixop.integral", gm.metadata(integral_nh).get<cv::gimpl::Op>().k.name);
EXPECT_EQ(1u, static_cast<std::size_t>(integral_nh->inEdges().size()));
EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outEdges().size()));
EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outNodes().size()));
}
TEST(GModelBuilder, Add_Operation_With_One_Out_One_Time)
{
// in1 -> binaryOp() -> b_out -> unaryOp() -> out1
// ^ |
// | |
// in2 ------- '----> unaryOp() -> out2
cv::GMat in1, in2;
auto b_out = test::binaryOp(in1, in2);
auto out1 = test::unaryOp(b_out);
auto out2 = test::unaryOp(b_out);
ade::Graph g;
cv::gimpl::GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
cv::gimpl::Protocol p;
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
cv::gimpl::GModel::Graph gr(g);
auto binaryOp_nh = p.in_nhs.front()->outNodes().front();
EXPECT_EQ(2u, static_cast<std::size_t>(binaryOp_nh->inEdges().size()));
EXPECT_EQ(1u, static_cast<std::size_t>(binaryOp_nh->outEdges().size()));
EXPECT_EQ(8u, static_cast<std::size_t>(g.nodes().size()));
}
} // namespace opencv_test

View File

@@ -0,0 +1,528 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "compiler/transactions.hpp"
#include "../gapi_mock_kernels.hpp"
#include "compiler/gislandmodel.hpp"
#include "compiler/gcompiler.hpp"
#include "compiler/gmodel_priv.hpp"
namespace opencv_test
{
TEST(IslandFusion, TwoOps_OneIsland)
{
namespace J = Jupiter; // see mock_kernels.cpp
// Define a computation:
//
// (in) -> J::Foo1 -> (tmp0) -> J::Foo2 -> (out)
// : :
// : "island0" :
// :<----------------------------->:
cv::GMat in;
cv::GMat tmp0 = I::Foo::on(in);
cv::GMat out = I::Foo::on(tmp0);
cv::GComputation cc(in, out);
// Prepare compilation parameters manually
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)});
const auto pkg = cv::gapi::kernels<J::Foo>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
// Inspect the graph and verify the islands configuration
cv::gimpl::GModel::ConstGraph gm(*graph);
cv::gimpl::GModel::ConstLayoutGraph glm(*graph);
auto in_nh = cv::gimpl::GModel::dataNodeOf(glm, in);
auto tmp_nh = cv::gimpl::GModel::dataNodeOf(glm, tmp0);
auto out_nh = cv::gimpl::GModel::dataNodeOf(glm, out);
// in/out mats shouldn't be assigned to any Island
EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
// Since tmp is surrounded by two J kernels, tmp should be assigned
// to island J
EXPECT_TRUE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
}
TEST(IslandFusion, TwoOps_TwoIslands)
{
namespace J = Jupiter; // see mock_kernels.cpp
namespace S = Saturn; // see mock_kernels.cpp
// Define a computation:
//
// (in) -> J::Foo --> (tmp0) -> S::Bar --> (out)
// : : -> :
// : : : :
// :<-------->: :<-------->:
cv::GMat in;
cv::GMat tmp0 = I::Foo::on(in);
cv::GMat out = I::Bar::on(tmp0, tmp0);
cv::GComputation cc(in, out);
// Prepare compilation parameters manually
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)});
const auto pkg = cv::gapi::kernels<J::Foo, S::Bar>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
// Inspect the graph and verify the islands configuration
cv::gimpl::GModel::ConstGraph gm(*graph);
auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp0);
auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
// in/tmp/out mats shouldn't be assigned to any Island
EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
// There should be two islands in the GIslandModel
const auto is_island = [&](ade::NodeHandle nh) {
return (cv::gimpl::NodeKind::ISLAND
== gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
};
const std::size_t num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(2u, num_isl);
auto isl_foo_nh = cv::gimpl::GIslandModel::producerOf(gim, tmp_nh);
auto isl_bar_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
ASSERT_NE(nullptr, isl_foo_nh);
ASSERT_NE(nullptr, isl_bar_nh);
// Islands should be different
auto isl_foo_obj = gim.metadata(isl_foo_nh).get<cv::gimpl::FusedIsland>().object;
auto isl_bar_obj = gim.metadata(isl_bar_nh).get<cv::gimpl::FusedIsland>().object;
EXPECT_FALSE(isl_foo_obj == isl_bar_obj);
}
TEST(IslandFusion, ConsumerHasTwoInputs)
{
namespace J = Jupiter; // see mock_kernels.cpp
// Define a computation: island
// ............................
// (in0) ->:J::Foo -> (tmp) -> S::Bar :--> (out)
// :....................^.....:
// |
// (in1) -----------------------`
//
// Check that island is build correctly, when consumer has two inputs
GMat in[2];
GMat tmp = I::Foo::on(in[0]);
GMat out = I::Bar::on(tmp, in[1]);
cv::GComputation cc(cv::GIn(in[0], in[1]), cv::GOut(out));
// Prepare compilation parameters manually
cv::GMetaArgs in_metas = {GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)}),
GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)})};
const auto pkg = cv::gapi::kernels<J::Foo, J::Bar>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, std::move(in_metas), cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
cv::gimpl::GModel::ConstGraph gm(*graph);
auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
EXPECT_FALSE(gm.metadata(in0_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(in1_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
EXPECT_TRUE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
const auto is_island = [&](ade::NodeHandle nh) {
return (cv::gimpl::NodeKind::ISLAND
== gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
};
const std::size_t num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(1u, num_isl);
auto isl_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
auto isl_obj = gim.metadata(isl_nh).get<cv::gimpl::FusedIsland>().object;
EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp_nh));
EXPECT_EQ(2u, static_cast<std::size_t>(isl_nh->inNodes().size()));
EXPECT_EQ(1u, static_cast<std::size_t>(isl_nh->outNodes().size()));
}
TEST(IslandFusion, DataNodeUsedDifferentBackend)
{
// Define a computation:
//
// internal isl isl0
// ...........................
// (in1) -> :J::Foo--> (tmp) -> J::Foo: --> (out0)
// :............|............:
// | ........
// `---->:S::Baz: --> (out1)
// :......:
// Check that the node was not dropped out of the island
// because it is used by the kernel from another backend
namespace J = Jupiter;
namespace S = Saturn;
cv::GMat in, tmp, out0;
cv::GScalar out1;
tmp = I::Foo::on(in);
out0 = I::Foo::on(tmp);
out1 = I::Baz::on(tmp);
cv::GComputation cc(cv::GIn(in), cv::GOut(out0, out1));
// Prepare compilation parameters manually
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)});
const auto pkg = cv::gapi::kernels<J::Foo, S::Baz>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
// Inspect the graph and verify the islands configuration
cv::gimpl::GModel::ConstGraph gm(*graph);
auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out0);
auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out1);
EXPECT_TRUE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
auto isl_nh = cv::gimpl::GIslandModel::producerOf(gim, tmp_nh);
auto isl_obj = gim.metadata(isl_nh).get<cv::gimpl::FusedIsland>().object;
EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp_nh));
EXPECT_EQ(2u, static_cast<std::size_t>(isl_nh->outNodes().size()));
EXPECT_EQ(7u, static_cast<std::size_t>(gm.nodes().size()));
EXPECT_EQ(6u, static_cast<std::size_t>(gim.nodes().size()));
}
TEST(IslandFusion, LoopBetweenDifferentBackends)
{
// Define a computation:
//
//
// .............................
// (in) -> :J::Baz -> (tmp0) -> J::Quux: -> (out0)
// | :............|..........^....
// | ........ | | ........
// `---->:S::Foo: `----------|-------->:S::Qux:-> (out1)
// :....|.: | :....^.:
// | | |
// `-------------- (tmp1) -----------`
// Kernels S::Foo and S::Qux cannot merge, because there will be a cycle between islands
namespace J = Jupiter;
namespace S = Saturn;
cv::GScalar tmp0;
cv::GMat in, tmp1, out0, out1;
tmp0 = I::Baz::on(in);
tmp1 = I::Foo::on(in);
out1 = I::Qux::on(tmp1, tmp0);
out0 = I::Quux::on(tmp0, tmp1);
cv::GComputation cc(cv::GIn(in), cv::GOut(out1, out0));
// Prepare compilation parameters manually
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)});
const auto pkg = cv::gapi::kernels<J::Baz, J::Quux, S::Foo, S::Qux>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
cv::gimpl::GModel::ConstGraph gm(*graph);
auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp0);
auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp1);
auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out0);
auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out1);
EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out0_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out1_nh).contains<cv::gimpl::Island>());
// The node does not belong to the island so as not to form a cycle
EXPECT_FALSE(gm.metadata(tmp1_nh).contains<cv::gimpl::Island>());
EXPECT_TRUE(gm.metadata(tmp0_nh).contains<cv::gimpl::Island>());
// There should be three islands in the GIslandModel
const auto is_island = [&](ade::NodeHandle nh) {
return (cv::gimpl::NodeKind::ISLAND
== gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
};
const std::size_t num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(3u, num_isl);
}
TEST(IslandsFusion, PartionOverlapUserIsland)
{
// Define a computation:
//
// internal isl isl0
// ........ ........
// (in0) -> :J::Foo:--> (tmp) ->:S::Bar: --> (out)
// :......: :......:
// ^
// |
// (in1) --------------------------`
// Check that internal islands doesn't overlap user island
namespace J = Jupiter;
namespace S = Saturn;
GMat in[2];
GMat tmp = I::Foo::on(in[0]);
GMat out = I::Bar::on(tmp, in[1]);
cv::gapi::island("isl0", cv::GIn(tmp, in[1]), cv::GOut(out));
cv::GComputation cc(cv::GIn(in[0], in[1]), cv::GOut(out));
// Prepare compilation parameters manually
cv::GMetaArgs in_metas = {GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)}),
GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)})};
const auto pkg = cv::gapi::kernels<J::Foo, J::Bar>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, std::move(in_metas), cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
cv::gimpl::GModel::ConstGraph gm(*graph);
auto isl_model = gm.metadata().get<cv::gimpl::IslandModel>().model;
cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
auto foo_nh = cv::gimpl::GIslandModel::producerOf(gim, tmp_nh);
auto foo_obj = gim.metadata(foo_nh).get<cv::gimpl::FusedIsland>().object;
auto bar_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
auto bar_obj = gim.metadata(bar_nh).get<cv::gimpl::FusedIsland>().object;
EXPECT_FALSE(gm.metadata(in0_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(in1_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(foo_obj->is_user_specified());
EXPECT_TRUE(bar_obj->is_user_specified());
}
TEST(IslandsFusion, DISABLED_IslandContainsDifferentBackends)
{
// Define a computation:
//
// isl0
// ............................
// (in0) -> :J::Foo:--> (tmp) -> S::Bar: --> (out)
// :..........................:
// ^
// |
// (in1) --------------------------`
// Try create island contains different backends
namespace J = Jupiter;
namespace S = Saturn;
GMat in[2];
GMat tmp = I::Foo::on(in[0]);
GMat out = I::Bar::on(tmp, in[1]);
cv::gapi::island("isl0", cv::GIn(in[0], in[1]), cv::GOut(out));
cv::GComputation cc(cv::GIn(in[0], in[1]), cv::GOut(out));
// Prepare compilation parameters manually
cv::GMetaArgs in_metas = {GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)}),
GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)})};
const auto pkg = cv::gapi::kernels<J::Foo, S::Bar>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, std::move(in_metas), cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
EXPECT_ANY_THROW(compiler.runPasses(*graph));
}
TEST(IslandFusion, WithLoop)
{
namespace J = Jupiter; // see mock_kernels.cpp
// Define a computation:
//
// (in) -> J::Foo --> (tmp0) -> J::Foo --> (tmp1) -> J::Qux -> (out)
// : ^
// '--> J::Baz --> (scl0) --'
//
// The whole thing should be merged to a single island
// There's a cycle warning if Foo/Foo/Qux are merged first
// Then this island both produces data for Baz and consumes data
// from Baz. This is a cycle and it should be avoided by the merging code.
//
cv::GMat in;
cv::GMat tmp0 = I::Foo::on(in);
cv::GMat tmp1 = I::Foo::on(tmp0);
cv::GScalar scl0 = I::Baz::on(tmp0);
cv::GMat out = I::Qux::on(tmp1, scl0);
cv::GComputation cc(in, out);
// Prepare compilation parameters manually
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::gapi::own::Size(32,32)});
const auto pkg = cv::gapi::kernels<J::Foo, J::Baz, J::Qux>();
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(cc, {in_meta}, cv::compile_args(pkg));
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
// Inspect the graph and verify the islands configuration
cv::gimpl::GModel::ConstGraph gm(*graph);
auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp0);
auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp1);
auto scl0_nh = cv::gimpl::GModel::dataNodeOf(gm, scl0);
auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
// in/out mats shouldn't be assigned to any Island
EXPECT_FALSE(gm.metadata(in_nh ).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh).contains<cv::gimpl::Island>());
// tmp0/tmp1/scl should be assigned to island
EXPECT_TRUE(gm.metadata(tmp0_nh).contains<cv::gimpl::Island>());
EXPECT_TRUE(gm.metadata(tmp1_nh).contains<cv::gimpl::Island>());
EXPECT_TRUE(gm.metadata(scl0_nh).contains<cv::gimpl::Island>());
// Check that there's a single island object and it contains all
// that data object handles
cv::gimpl::GModel::ConstGraph cg(*graph);
auto isl_model = cg.metadata().get<cv::gimpl::IslandModel>().model;
cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
const auto is_island = [&](ade::NodeHandle nh) {
return (cv::gimpl::NodeKind::ISLAND
== gim.metadata(nh).get<cv::gimpl::NodeKind>().k);
};
const std::size_t num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(1u, num_isl);
auto isl_nh = cv::gimpl::GIslandModel::producerOf(gim, out_nh);
auto isl_obj = gim.metadata(isl_nh).get<cv::gimpl::FusedIsland>().object;
EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp0_nh));
EXPECT_TRUE(ade::util::contains(isl_obj->contents(), tmp1_nh));
EXPECT_TRUE(ade::util::contains(isl_obj->contents(), scl0_nh));
}
TEST(IslandFusion, Regression_ShouldFuseAll)
{
// Initially the merge procedure didn't work as expected and
// stopped fusion even if it could be continued (e.g. full
// GModel graph could be fused into a single GIsland node).
// Example of this is custom RGB 2 YUV pipeline as shown below:
cv::GMat r, g, b;
cv::GMat y = 0.299f*r + 0.587f*g + 0.114f*b;
cv::GMat u = 0.492f*(b - y);
cv::GMat v = 0.877f*(r - y);
cv::GComputation customCvt({r, g, b}, {y, u, v});
const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)});
// Directly instantiate G-API graph compiler and run partial compilation
cv::gimpl::GCompiler compiler(customCvt, {in_meta,in_meta,in_meta}, cv::compile_args());
cv::gimpl::GCompiler::GPtr graph = compiler.generateGraph();
compiler.runPasses(*graph);
cv::gimpl::GModel::ConstGraph cg(*graph);
auto isl_model = cg.metadata().get<cv::gimpl::IslandModel>().model;
cv::gimpl::GIslandModel::ConstGraph gim(*isl_model);
std::vector<ade::NodeHandle> data_nhs;
std::vector<ade::NodeHandle> isl_nhs;
for (auto &&nh : gim.nodes())
{
if (gim.metadata(nh).contains<cv::gimpl::FusedIsland>())
isl_nhs.push_back(std::move(nh));
else if (gim.metadata(nh).contains<cv::gimpl::DataSlot>())
data_nhs.push_back(std::move(nh));
else FAIL() << "GIslandModel node with unexpected metadata type";
}
EXPECT_EQ(6u, data_nhs.size()); // 3 input nodes + 3 output nodes
EXPECT_EQ(1u, isl_nhs.size()); // 1 island
}
// FIXME: add more tests on mixed (hetero) graphs
// ADE-222, ADE-223
// FIXME: add test on combination of user-specified island
// which should be heterogeneous (based on kernel availability)
// but as we don't support this, compilation should fail
// FIXME: add tests on automatic inferred islands which are
// connected via 1) gmat 2) gscalar 3) garray,
// check the case with executor
// check the case when this 1/2/3 interim object is also gcomputation output
} // namespace opencv_test

View File

@@ -0,0 +1,654 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "compiler/gmodel.hpp"
#include "compiler/gcompiled_priv.hpp"
#include "compiler/gmodel_priv.hpp"
namespace opencv_test
{
////////////////////////////////////////////////////////////////////////////////
// Tests on a plain graph
//
// (in) -> Blur1 -> (tmp0) -> Blur2 -> (tmp1) -> Blur3 -> (tmp2) -> Blur4 -> (out)
//
namespace
{
struct PlainIslandsFixture
{
cv::GMat in;
cv::GMat tmp[3];
cv::GMat out;
PlainIslandsFixture()
{
tmp[0] = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
tmp[1] = cv::gapi::boxFilter(tmp[0], -1, cv::Size(3,3));
tmp[2] = cv::gapi::boxFilter(tmp[1], -1, cv::Size(3,3));
out = cv::gapi::boxFilter(tmp[2], -1, cv::Size(3,3));
}
};
struct Islands: public ::testing::Test, public PlainIslandsFixture {};
using GIntArray = GArray<int>;
G_TYPED_KERNEL(CreateMatWithDiag, <GMat(GIntArray)>, "test.array.create_mat_with_diag")
{
static GMatDesc outMeta(const GArrayDesc&) { return cv::GMatDesc{CV_32S, 1,{3, 3}}; }
};
GAPI_OCV_KERNEL(CreateMatWithDiagImpl, CreateMatWithDiag)
{
static void run(const std::vector<int> &in, cv::Mat& out)
{
auto size = static_cast<int>(in.size());
out = Mat::zeros(size, size, CV_32SC1);
for(int i = 0; i < out.rows; i++)
{
auto* row = out.ptr<int>(i);
row[i] = in[i];
}
}
};
G_TYPED_KERNEL(Mat2Array, <GIntArray(GMat)>, "test.array.mat2array")
{
static GArrayDesc outMeta(const GMatDesc&) { return empty_array_desc(); }
};
GAPI_OCV_KERNEL(Mat2ArrayImpl, Mat2Array)
{
static void run(const cv::Mat& in, std::vector<int> &out)
{
GAPI_Assert(in.depth() == CV_32S && in.isContinuous());
out.reserve(in.cols * in.rows);
out.assign((int*)in.datastart, (int*)in.dataend);
}
};
}
TEST_F(Islands, SmokeTest)
{
// (in) -> Blur1 -> (tmp0) -> Blur2 -> (tmp1) -> Blur3 -> (tmp2) -> Blur4 -> (out)
// : "test" :
// :<------------------------->:
cv::gapi::island("test", cv::GIn(tmp[0]), cv::GOut(tmp[2]));
auto cc = cv::GComputation(in, out).compile(cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
// tmp1 and tmp3 is not a part of any island
EXPECT_FALSE(gm.metadata(tmp0_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp2_nh).contains<cv::gimpl::Island>());
// tmp2 is part of "test" island
EXPECT_TRUE(gm.metadata(tmp1_nh).contains<cv::gimpl::Island>());
EXPECT_EQ("test", gm.metadata(tmp1_nh).get<cv::gimpl::Island>().island);
}
TEST_F(Islands, TwoIslands)
{
// (in) -> Blur1 -> (tmp0) -> Blur2 -> (tmp1) -> Blur3 -> (tmp2) -> Blur4 -> (out)
// : "test1" : : "test2" :
// :<---------------------------->: :<--------------------------------->
EXPECT_NO_THROW(cv::gapi::island("test1", cv::GIn(in), cv::GOut(tmp[1])));
EXPECT_NO_THROW(cv::gapi::island("test2", cv::GIn(tmp[1]), cv::GOut(out)));
auto cc = cv::GComputation(in, out).compile(cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in);
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
const auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out);
// Only tmp0 and tmp2 should be listed in islands.
EXPECT_TRUE (gm.metadata(tmp0_nh).contains<cv::gimpl::Island>());
EXPECT_TRUE (gm.metadata(tmp2_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(in_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp1_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh) .contains<cv::gimpl::Island>());
EXPECT_EQ("test1", gm.metadata(tmp0_nh).get<cv::gimpl::Island>().island);
EXPECT_EQ("test2", gm.metadata(tmp2_nh).get<cv::gimpl::Island>().island);
}
// FIXME: Disabled since currently merge procedure merges two into one
// successfully
TEST_F(Islands, DISABLED_Two_Islands_With_Same_Name_Should_Fail)
{
// (in) -> Blur1 -> (tmp0) -> Blur2 -> (tmp1) -> Blur3 -> (tmp2) -> Blur4 -> (out)
// : "test1" : : "test1" :
// :<---------------------------->: :<--------------------------------->
EXPECT_NO_THROW(cv::gapi::island("test1", cv::GIn(in), cv::GOut(tmp[1])));
EXPECT_NO_THROW(cv::gapi::island("test1", cv::GIn(tmp[1]), cv::GOut(out)));
EXPECT_ANY_THROW(cv::GComputation(in, out).compile(cv::GMatDesc{CV_8U,1,{640,480}}));
}
// (in) -> Blur1 -> (tmp0) -> Blur2 -> (tmp1) -> Blur3 -> (tmp2) -> Blur4 -> (out)
// : "test1": : :
// :<----------------:----------->: :
// : :
// : "test2" :
// :<------------------------->:
TEST_F(Islands, OverlappingIslands1)
{
EXPECT_NO_THROW (cv::gapi::island("test1", cv::GIn(in), cv::GOut(tmp[1])));
EXPECT_ANY_THROW(cv::gapi::island("test2", cv::GIn(tmp[0]), cv::GOut(tmp[2])));
}
TEST_F(Islands, OverlappingIslands2)
{
EXPECT_NO_THROW (cv::gapi::island("test2", cv::GIn(tmp[0]), cv::GOut(tmp[2])));
EXPECT_ANY_THROW(cv::gapi::island("test1", cv::GIn(in), cv::GOut(tmp[1])));
}
////////////////////////////////////////////////////////////////////////////////
// Tests on a complex graph
//
// (in0) -> Not -> (tmp0) --> Add ---------> (tmp2) --> AddC -------> (out0)
// ^ ^
// (in1) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// :
// `------------> Median -> (tmp3) --> Blur -------> (out1)
//
namespace
{
struct ComplexIslandsFixture
{
cv::GMat in[2];
cv::GMat tmp[4];
cv::GScalar scl;
cv::GMat out[2];
ComplexIslandsFixture()
{
tmp[0] = cv::gapi::bitwise_not(in[0]);
tmp[1] = cv::gapi::boxFilter(in[1], -1, cv::Size(3,3));
tmp[2] = tmp[0] + tmp[1]; // FIXME: handle tmp[2] = tmp[0]+tmp[2] typo
scl = cv::gapi::sum(tmp[1]);
tmp[3] = cv::gapi::medianBlur(tmp[1], 3);
out[0] = tmp[2] + scl;
out[1] = cv::gapi::boxFilter(tmp[3], -1, cv::Size(3,3));
}
};
struct ComplexIslands: public ::testing::Test, public ComplexIslandsFixture {};
} // namespace
TEST_F(ComplexIslands, SmokeTest)
{
// isl0 #internal1
// ........................... ........
// (in0) -> Not -> (tmp0) --> Add ---------> (tmp2) --> AddC -------> (out0)
// :............ ........^...: :.^....:
// ... : :
// (in1) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// : isl1
// : ..............................
// `------------> Median -> (tmp3) --> Blur -------> (out1)
// :............................:
cv::gapi::island("isl0", cv::GIn(in[0], tmp[1]), cv::GOut(tmp[2]));
cv::gapi::island("isl1", cv::GIn(tmp[1]), cv::GOut(out[1]));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
const auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
const auto tmp3_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[3]);
const auto scl_nh = cv::gimpl::GModel::dataNodeOf(gm, scl);
const auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out[0]);
const auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out[1]);
// tmp0, tmp3 are in islands, others are not
EXPECT_TRUE(gm.metadata(tmp0_nh) .contains<cv::gimpl::Island>()); // isl0
EXPECT_TRUE(gm.metadata(tmp3_nh) .contains<cv::gimpl::Island>()); // isl1
EXPECT_FALSE(gm.metadata(in0_nh) .contains<cv::gimpl::Island>()); // (input is never fused)
EXPECT_FALSE(gm.metadata(in1_nh) .contains<cv::gimpl::Island>()); // (input is never fused)
EXPECT_TRUE (gm.metadata(tmp1_nh).contains<cv::gimpl::Island>()); // <internal island>
EXPECT_FALSE(gm.metadata(tmp2_nh).contains<cv::gimpl::Island>()); // #not fused as cycle-causing#
EXPECT_FALSE(gm.metadata(scl_nh) .contains<cv::gimpl::Island>()); // #not fused as cycle-causing#
EXPECT_FALSE(gm.metadata(out0_nh).contains<cv::gimpl::Island>()); // (output is never fused)
EXPECT_FALSE(gm.metadata(out1_nh).contains<cv::gimpl::Island>()); // (output is never fused)
EXPECT_EQ("isl0", gm.metadata(tmp0_nh).get<cv::gimpl::Island>().island);
EXPECT_EQ("isl1", gm.metadata(tmp3_nh).get<cv::gimpl::Island>().island);
EXPECT_NE("isl0", gm.metadata(tmp1_nh).get<cv::gimpl::Island>().island);
EXPECT_NE("isl1", gm.metadata(tmp1_nh).get<cv::gimpl::Island>().island);
// FIXME: Add a test with same graph for Fusion and check GIslandModel
}
TEST_F(ComplexIslands, DistinictIslandsWithSameName)
{
// isl0
// ...........................
// (in0) -> Not -> (tmp0) --> Add ---------> (tmp2) --> AddC -------> (out0)
// :............ ........^...: ^
// ... : :
// (in1) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// : isl0
// : ..............................
// `------------> Median -> (tmp3) --> Blur -------> (out1)
// :............................:
cv::gapi::island("isl0", cv::GIn(in[0], tmp[1]), cv::GOut(tmp[2]));
cv::gapi::island("isl0", cv::GIn(tmp[1]), cv::GOut(out[1]));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]));
EXPECT_ANY_THROW(cc.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}}));
}
TEST_F(ComplexIslands, FullGraph)
{
cv::gapi::island("isl0", cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
std::vector<ade::NodeHandle> handles_inside = {
cv::gimpl::GModel::dataNodeOf(gm, tmp[0]),
cv::gimpl::GModel::dataNodeOf(gm, tmp[1]),
cv::gimpl::GModel::dataNodeOf(gm, tmp[2]),
cv::gimpl::GModel::dataNodeOf(gm, tmp[3]),
cv::gimpl::GModel::dataNodeOf(gm, scl),
};
std::vector<ade::NodeHandle> handles_outside = {
cv::gimpl::GModel::dataNodeOf(gm, in[0]),
cv::gimpl::GModel::dataNodeOf(gm, in[1]),
cv::gimpl::GModel::dataNodeOf(gm, out[0]),
cv::gimpl::GModel::dataNodeOf(gm, out[1]),
};
for (auto nh_inside : handles_inside)
{
EXPECT_EQ("isl0", gm.metadata(nh_inside).get<cv::gimpl::Island>().island);
}
for (auto nh_outside : handles_outside)
{
EXPECT_FALSE(gm.metadata(nh_outside).contains<cv::gimpl::Island>());
}
}
TEST_F(ComplexIslands, ViaScalar)
{
//
// .........................................#internal0.
// (in0) -> Not -> (tmp0) --> Add ---------> (tmp2) --> AddC -------> (out0)
// :....................^.........................^...:
// : :
// .....................:.........(isl0). :
// (in1) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// :..........:.........................:
// :
// : ..................#internal1.
// `------------> Median -> (tmp3) --> Blur -------> (out1)
// :...........................:
cv::gapi::island("isl0", cv::GIn(in[1]), cv::GOut(scl));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
const auto tmp3_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[3]);
EXPECT_NE("isl0", gm.metadata(tmp0_nh).get<cv::gimpl::Island>().island); // <internal>
EXPECT_EQ("isl0", gm.metadata(tmp1_nh).get<cv::gimpl::Island>().island); // isl0
EXPECT_NE("isl0", gm.metadata(tmp2_nh).get<cv::gimpl::Island>().island); // <internal>
EXPECT_NE("isl0", gm.metadata(tmp3_nh).get<cv::gimpl::Island>().island); // <internal>
std::vector<ade::NodeHandle> handles_outside = {
cv::gimpl::GModel::dataNodeOf(gm, in[0]),
cv::gimpl::GModel::dataNodeOf(gm, in[1]),
cv::gimpl::GModel::dataNodeOf(gm, scl),
cv::gimpl::GModel::dataNodeOf(gm, out[0]),
cv::gimpl::GModel::dataNodeOf(gm, out[1]),
};
for (auto nh_outside : handles_outside)
{
EXPECT_FALSE(gm.metadata(nh_outside).contains<cv::gimpl::Island>());
}
}
TEST_F(ComplexIslands, BorderDataIsland)
{
// .................................(isl0)..
// : :
// (in0) -> Not -> (tmp0) --> Add ---------> (tmp2) --> AddC -------> (out0)
// : ^ : ^
// : : : :
// (in1) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// :...........:...........................:
// : : :
// : : :.........................................(isl1)..
// : `------------> Median -> (tmp3) --> Blur -------> (out1)
// : :
// :......................................................:
cv::gapi::island("isl0", cv::GIn(in[0], in[1]), cv::GOut(tmp[2], scl));
cv::gapi::island("isl1", cv::GIn(tmp[1]), cv::GOut(out[1]));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
const auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
const auto tmp3_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[3]);
const auto scl_nh = cv::gimpl::GModel::dataNodeOf(gm, scl);
const auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out[0]);
const auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out[1]);
// Check handles inside isl0
EXPECT_EQ("isl0", gm.metadata(tmp0_nh).get<cv::gimpl::Island>().island);
EXPECT_EQ("isl0", gm.metadata(tmp1_nh).get<cv::gimpl::Island>().island);
// ^^^ Important - tmp1 is assigned to isl0, not isl1
// Check handles inside isl1
EXPECT_EQ("isl1", gm.metadata(tmp3_nh).get<cv::gimpl::Island>().island);
// Check outside handles
EXPECT_FALSE(gm.metadata(in0_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(in1_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp2_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(scl_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out0_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out1_nh).contains<cv::gimpl::Island>());
}
TEST_F(ComplexIslands, IncompleteSpec)
{
// isl0
// ...........................
// (in0) -> Not -> (tmp0) --> Add ---------> (tmp2) --> AddC -------> (out0)
// :...........xxx.......^...: ^
// : :
// (in1) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// :
// :
// `------------> Median -> (tmp3) --> Blur -------> (out1)
//
// tmp1 is missing in the below spec
EXPECT_ANY_THROW(cv::gapi::island("isl0", cv::GIn(in[0]), cv::GOut(tmp[2])));
// empty range
EXPECT_ANY_THROW(cv::gapi::island("isl1", cv::GIn(tmp[2]), cv::GOut(tmp[2])));
}
TEST_F(ComplexIslands, InputOperationFromDifferentIslands)
{
// isl1
// ........................... ........
// (in0)--> Not -> (tmp0) --> Add :--------> (tmp2)-->: AddC : -------> (out0)
// :......................^..: : ^ :
// isl0 : : : :
// .......................:....................... : :
// (in1) :-> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----- :
// :....................................................:
// isl0 :
// `------------> Median -> (tmp3) --> Blur -------> (out1)
//
cv::gapi::island("isl0", cv::GIn(in[1], tmp[2]), cv::GOut(out[0]));
cv::gapi::island("isl1", cv::GIn(in[0], tmp[1]), cv::GOut(tmp[2]));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
EXPECT_EQ("isl1", gm.metadata(tmp0_nh).get<cv::gimpl::Island>().island);
EXPECT_EQ("isl0", gm.metadata(tmp1_nh).get<cv::gimpl::Island>().island);
EXPECT_FALSE(gm.metadata(tmp2_nh).contains<cv::gimpl::Island>());
}
TEST_F(ComplexIslands, NoWayBetweenNodes)
{
// (in0) -> Not -> (tmp0) --> Add ---------> (tmp2) --> AddC -------> (out0)
// ^ ^
// (in1) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
// :
// `------------> Median -> (tmp3) --> Blur -------> (out1)
EXPECT_ANY_THROW(cv::gapi::island("isl0", cv::GIn(in[1]), cv::GOut(tmp[0])));
}
TEST_F(ComplexIslands, IslandsContainUnusedPart)
{
// Unused part of the graph
// x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
// x x
// x(in0) -> Not -> (tmp0) --> Add ---------> (tmp2)---> AddC ---------> (out0) x
// x ^ ^ x
// x x x x x x x x x x x x x x x | x x | x
// | x | x
// ...... | x | x
// (in1) -> :Blur:----------> (tmp1) x-----> Sum ------> (scl0) x
// ...... : x x x x x x x x x x x x x x x x x x x x x x x x
// isl0
// :
// `------------> Median -> (tmp3) --> Blur -------> (out1)
cv::gapi::island("isl0", cv::GIn(in[1]), cv::GOut(scl));
auto cc = cv::GComputation(cv::GIn(in[1]), cv::GOut(out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
//The output 0 is not specified in the graph
//means that there will not be a node scl, so that tmp1 will not assign to the island
// FIXME Check that blur assigned to island using the function producerOf
// After merge islands fusion
EXPECT_FALSE(gm.metadata(tmp1_nh) .contains<cv::gimpl::Island>());
}
TEST_F(ComplexIslands, FullGraphInTwoIslands)
{
// isl0
// ..................................................
// (in0) -> :Not -> (tmp0) --> Add ---------> (tmp2) --> AddC: -------> (out0)
// ...................^.... ^ :
// ............... | : : :
// (in1) -> :Blur-> (tmp1):----'-->:Sum ----> (scl0) ----' :
// ........ | : ...........................
// isl1 : | :............................................
// : `------------> Median -> (tmp3) --> Blur ------->:(out1)
// ....................................................
cv::gapi::island("isl0", cv::GIn(in[0], tmp[1]), cv::GOut(out[0]));
cv::gapi::island("isl1", cv::GIn(in[1]), cv::GOut(out[1]));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
const auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
const auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
const auto tmp3_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[3]);
const auto scl_nh = cv::gimpl::GModel::dataNodeOf(gm, scl);
const auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out[0]);
const auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out[1]);
// Check handles inside isl0
EXPECT_EQ("isl0", gm.metadata(tmp0_nh).get<cv::gimpl::Island>().island);
EXPECT_EQ("isl0", gm.metadata(tmp2_nh).get<cv::gimpl::Island>().island);
EXPECT_EQ("isl0", gm.metadata(scl_nh).get<cv::gimpl::Island>().island);
// Check handles inside isl1
EXPECT_EQ("isl1", gm.metadata(tmp1_nh).get<cv::gimpl::Island>().island);
EXPECT_EQ("isl1", gm.metadata(tmp3_nh).get<cv::gimpl::Island>().island);
// Check outside handles
EXPECT_FALSE(gm.metadata(in0_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(in1_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out0_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out1_nh).contains<cv::gimpl::Island>());
}
TEST_F(ComplexIslands, OnlyOperationsAssignedToIslands)
{
cv::gapi::island("isl0", cv::GIn(in[1]), cv::GOut(tmp[1]));
cv::gapi::island("isl1", cv::GIn(tmp[1]), cv::GOut(scl));
cv::gapi::island("isl2", cv::GIn(scl, tmp[2]), cv::GOut(out[0]));
cv::gapi::island("isl3", cv::GIn(in[0]), cv::GOut(tmp[0]));
cv::gapi::island("isl4", cv::GIn(tmp[0], tmp[1]), cv::GOut(tmp[2]));
cv::gapi::island("isl5", cv::GIn(tmp[1]), cv::GOut(tmp[3]));
cv::gapi::island("isl6", cv::GIn(tmp[3]), cv::GOut(out[1]));
auto cc = cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
.compile(cv::GMatDesc{CV_8U,1,{640,480}},
cv::GMatDesc{CV_8U,1,{640,480}});
const auto &gm = cc.priv().model();
//FIXME: Check that operation handles are really assigned to isl0..isl6
const auto in0_nh = cv::gimpl::GModel::dataNodeOf(gm, in[0]);
const auto in1_nh = cv::gimpl::GModel::dataNodeOf(gm, in[1]);
const auto tmp0_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[0]);
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[1]);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[2]);
const auto tmp3_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp[3]);
const auto scl_nh = cv::gimpl::GModel::dataNodeOf(gm, scl);
const auto out0_nh = cv::gimpl::GModel::dataNodeOf(gm, out[0]);
const auto out1_nh = cv::gimpl::GModel::dataNodeOf(gm, out[1]);
EXPECT_FALSE(gm.metadata(in0_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(in1_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp0_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp1_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp2_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp3_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(scl_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out0_nh).contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out1_nh).contains<cv::gimpl::Island>());
}
namespace
{
struct IslandStructureWithGArray
{
GIntArray in, out;
GMat tmp;
IslandStructureWithGArray()
{
tmp = CreateMatWithDiag::on(in);
out = Mat2Array::on(tmp);
}
};
struct IslandsWithGArray: public ::testing::Test, public IslandStructureWithGArray {};
} // namespace
TEST_F(IslandsWithGArray, IslandWithGArrayAsInput)
{
cv::gapi::island("isl0", cv::GIn(in), cv::GOut(tmp));
const auto pkg = cv::gapi::kernels<CreateMatWithDiagImpl, Mat2ArrayImpl>();
auto cc = cv::GComputation(cv::GIn(in), GOut(out)).compile(cv::empty_array_desc(), cv::compile_args(pkg));
const auto &gm = cc.priv().model();
const auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in.strip());
const auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out.strip());
const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
GAPI_Assert(tmp_nh->inNodes().size() == 1);
const auto create_diag_mat_nh = tmp_nh->inNodes().front();
EXPECT_EQ("isl0", gm.metadata(create_diag_mat_nh).get<cv::gimpl::Island>().island);
EXPECT_FALSE(gm.metadata(in_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp_nh) .contains<cv::gimpl::Island>());
}
TEST_F(IslandsWithGArray, IslandWithGArrayAsOutput)
{
cv::gapi::island("isl0", cv::GIn(tmp), cv::GOut(out));
const auto pkg = cv::gapi::kernels<CreateMatWithDiagImpl, Mat2ArrayImpl>();
auto cc = cv::GComputation(cv::GIn(in), GOut(out)).compile(cv::empty_array_desc(), cv::compile_args(pkg));
const auto &gm = cc.priv().model();
const auto in_nh = cv::gimpl::GModel::dataNodeOf(gm, in.strip());
const auto out_nh = cv::gimpl::GModel::dataNodeOf(gm, out.strip());
const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(gm, tmp);
GAPI_Assert(tmp_nh->inNodes().size() == 1);
const auto mat2array_nh = out_nh->inNodes().front();
EXPECT_EQ("isl0", gm.metadata(mat2array_nh).get<cv::gimpl::Island>().island);
EXPECT_FALSE(gm.metadata(in_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(out_nh) .contains<cv::gimpl::Island>());
EXPECT_FALSE(gm.metadata(tmp_nh) .contains<cv::gimpl::Island>());
}
////////////////////////////////////////////////////////////////////////////////
// Wrong input tests on island name
//
namespace
{
struct CheckName : public TestWithParam<std::tuple<bool, const char*> >,
public PlainIslandsFixture
{
void assignIsland(const std::string &s)
{
cv::gapi::island(s, cv::GIn(tmp[0]), cv::GOut(tmp[2]));
};
};
TEST_P(CheckName, Test)
{
bool correct = false;
const char *name = "";
std::tie(correct, name) = GetParam();
if (correct) EXPECT_NO_THROW(assignIsland(name));
else EXPECT_ANY_THROW(assignIsland(name));
}
} // namespace
INSTANTIATE_TEST_CASE_P(IslandName, CheckName,
Values(std::make_tuple(true, "name"),
std::make_tuple(true, " name "),
std::make_tuple(true, " n a m e "),
std::make_tuple(true, " 123 $$ %%"),
std::make_tuple(true, ".: -"),
std::make_tuple(false, ""),
std::make_tuple(false, " "),
std::make_tuple(false, " \t "),
std::make_tuple(false, " \t \t ")));
// FIXME: add <internal> test on unrollExpr() use for islands
} // opencv_test

View File

@@ -0,0 +1,997 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "../test_precomp.hpp"
#include <stdexcept>
#include "compiler/gmodel.hpp"
#include "compiler/gmodel_priv.hpp"
#include "api/gcomputation_priv.hpp"
#include "compiler/gcompiler.hpp"
#include "compiler/gmodelbuilder.hpp"
#include "compiler/passes/passes.hpp"
#include "compiler/passes/pattern_matching.hpp"
#include "../common/gapi_tests_common.hpp"
#include "logger.hpp"
namespace opencv_test
{
namespace matching_test {
namespace {
using V = std::vector<ade::NodeHandle>;
using S = std::unordered_set< ade::NodeHandle
, ade::HandleHasher<ade::Node>
>;
void initGModel(ade::Graph& gr,
cv::GProtoInputArgs&& in,
cv::GProtoOutputArgs&& out) {
cv::gimpl::GModel::Graph gm(gr);
cv::gimpl::GModel::init(gm);
auto proto_slots = cv::gimpl::GModelBuilder(gr)
.put(in.m_args, out.m_args);
cv::gimpl::Protocol p;
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
gm.metadata().set(p);
}
bool isConsumedBy(const cv::gimpl::GModel::ConstGraph &gm, ade::NodeHandle data_nh, ade::NodeHandle op_nh) {
auto oi = cv::gimpl::GModel::orderedInputs(gm, op_nh);
return std::find(oi.begin(), oi.end(), data_nh) != oi.end();
}
std::string opName(const cv::gimpl::GModel::ConstGraph &gm, ade::NodeHandle op_nh) {
return gm.metadata(op_nh).get<cv::gimpl::Op>().k.name;
}
}
} // matching_test
TEST(PatternMatching, TestFuncDoesNotChangeTestGraph)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat out = cv::gapi::bitwise_not(in);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in;
GMat out = cv::gapi::bitwise_not(in);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::findMatches(pg, tg);
// Inspecting results:
matching_test::S nodes{ tgm.nodes().begin(), tgm.nodes().end() };
const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in);
const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out);
auto input_data_nhs = tgm.metadata().get<cv::gimpl::Protocol>().in_nhs;
auto output_data_nhs = tgm.metadata().get<cv::gimpl::Protocol>().out_nhs;
EXPECT_EQ(1u, input_data_nhs.size());
EXPECT_EQ(1u, output_data_nhs.size());
EXPECT_EQ(in_nh, *input_data_nhs.begin());
EXPECT_EQ(out_nh, *output_data_nhs.begin());
EXPECT_EQ(0u, in_nh->inEdges().size());
EXPECT_EQ(0u, out_nh->outEdges().size());
EXPECT_EQ(1u, in_nh->outEdges().size());
EXPECT_EQ(1u, out_nh->inEdges().size());
const auto op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh); //bitwise_not
EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh));
EXPECT_EQ(1u, op_nh->inEdges().size());
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh));
EXPECT_EQ(1u, op_nh->outEdges().size());
}
TEST(PatternMatching, TestSimple1)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat out = cv::gapi::bitwise_not(in);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in;
GMat out = cv::gapi::bitwise_not(in);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(3u, nodes.size());
const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in);
const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out);
const auto op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh);
EXPECT_EQ(matching_test::S({in_nh, out_nh, op_nh}), nodes);
EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh));
EXPECT_EQ(matching_test::S{op_nh}, match.startOps());
EXPECT_EQ(matching_test::S{op_nh}, match.finishOps());
EXPECT_EQ(matching_test::V{in_nh}, match.protoIns());
EXPECT_EQ(matching_test::V{out_nh}, match.protoOuts());
}
TEST(PatternMatching, TestSimple2)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat out = cv::gapi::bitwise_not(in);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in;
GMat tmp = cv::gapi::bitwise_not(in);
GMat out = cv::gapi::blur(tmp, cv::Size(3, 3));
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(3u, nodes.size());
const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in);
const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp);
const auto op_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh);
EXPECT_EQ(matching_test::S({in_nh, tmp_nh, op_nh}), nodes);
EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh));
EXPECT_EQ(matching_test::S{op_nh}, match.startOps());
EXPECT_EQ(matching_test::S{op_nh}, match.finishOps());
EXPECT_EQ(matching_test::V{in_nh}, match.protoIns());
EXPECT_EQ(matching_test::V{tmp_nh}, match.protoOuts());
}
TEST(PatternMatching, TestSimple3)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat out = cv::gapi::bitwise_not(in);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in;
GMat tmp = cv::gapi::blur(in, cv::Size(3, 3));
GMat out = cv::gapi::bitwise_not(tmp);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(3u, nodes.size());
const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp);
const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out);
const auto op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh);
EXPECT_EQ(matching_test::S({tmp_nh, out_nh, op_nh}), nodes);
EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp_nh, op_nh));
EXPECT_EQ(matching_test::S{op_nh}, match.startOps());
EXPECT_EQ(matching_test::S{op_nh}, match.finishOps());
EXPECT_EQ(matching_test::V{tmp_nh}, match.protoIns());
EXPECT_EQ(matching_test::V{out_nh}, match.protoOuts());
}
TEST(PatternMatching, TestMultiplePatternOuts)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat dx, dy;
std::tie(dx, dy) = cv::gapi::SobelXY(in, -1, 1);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(dx, dy));
}
// Test
ade::Graph tg;
GMat in;
GMat dx, dy;
std::tie(dx, dy) = cv::gapi::SobelXY(in, -1, 1);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(dx, dy));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(4u, nodes.size());
const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in);
const auto dx_nh = cv::gimpl::GModel::dataNodeOf(tgm, dx);
const auto dy_nh = cv::gimpl::GModel::dataNodeOf(tgm, dy);
const auto op_nh = cv::gimpl::GModel::producerOf(tgm, dx_nh);
EXPECT_EQ(op_nh, cv::gimpl::GModel::producerOf(tgm, dy_nh));
EXPECT_EQ(matching_test::S({in_nh, dx_nh, dy_nh, op_nh}), nodes);
EXPECT_EQ(cv::gapi::imgproc::GSobelXY::id(), matching_test::opName(tgm, op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh));
EXPECT_EQ(matching_test::S{op_nh}, match.startOps());
EXPECT_EQ(matching_test::S{op_nh}, match.finishOps());
EXPECT_EQ(matching_test::V{in_nh}, match.protoIns());
EXPECT_EQ(matching_test::V({dx_nh, dy_nh}), match.protoOuts());
}
TEST(PatternMatching, TestPrepResizeSplit3)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat tmp = cv::gapi::resize(in, cv::Size{224, 224});
GMat b, g, r;
std::tie(b, g, r) = cv::gapi::split3(tmp);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(b, g, r));
}
// Test
ade::Graph tg;
GMat y, uv;
GMat bgr = cv::gapi::NV12toBGR(y, uv);
GMat tmp = cv::gapi::resize(bgr, cv::Size{224, 224});
GMat b, g, r;
std::tie(b, g, r) = cv::gapi::split3(tmp);
matching_test::initGModel(tg, cv::GIn(y, uv), cv::GOut(b, g, r));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(7u, nodes.size());
const auto bgr_nh = cv::gimpl::GModel::dataNodeOf(tgm, bgr);
const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp);
const auto b_nh = cv::gimpl::GModel::dataNodeOf(tgm, b);
const auto g_nh = cv::gimpl::GModel::dataNodeOf(tgm, g);
const auto r_nh = cv::gimpl::GModel::dataNodeOf(tgm, r);
const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh); // 1st resize
const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, b_nh); // 2nd split3
EXPECT_EQ(op2_nh, cv::gimpl::GModel::producerOf(tgm, g_nh));
EXPECT_EQ(op2_nh, cv::gimpl::GModel::producerOf(tgm, r_nh));
EXPECT_EQ(matching_test::S({bgr_nh, tmp_nh, b_nh, g_nh,
r_nh, op1_nh, op2_nh}),
nodes);
EXPECT_EQ(cv::gapi::core::GResize::id(), matching_test::opName(tgm, op1_nh));
EXPECT_EQ(cv::gapi::core::GSplit3::id(), matching_test::opName(tgm, op2_nh));
EXPECT_EQ(1u, tmp_nh->outEdges().size());
EXPECT_TRUE(matching_test::isConsumedBy(tgm, bgr_nh, op1_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp_nh, op2_nh));
EXPECT_EQ(matching_test::S{ op1_nh }, match.startOps());
EXPECT_EQ(matching_test::S{ op2_nh }, match.finishOps());
EXPECT_EQ(matching_test::V{ bgr_nh }, match.protoIns());
EXPECT_EQ(matching_test::V({ b_nh, g_nh, r_nh }), match.protoOuts());
}
G_TYPED_KERNEL(GToNCHW, <GMatP(GMat)>, "test.toNCHW") {
static GMatDesc outMeta(GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
GAPI_Assert(in.planar == false);
return in.asPlanar();
}
};
static GMatP toNCHW(const GMat& src)
{
return GToNCHW::on(src);
}
TEST(PatternMatching, TestPrepResizeToNCHW)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat tmp = cv::gapi::resize(in, cv::Size{224, 224});
GMatP plr = toNCHW(tmp);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(plr));
}
// Test
ade::Graph tg;
GMat y, uv;
GMat bgr = cv::gapi::NV12toBGR(y, uv);
GMat tmp = cv::gapi::resize(bgr, cv::Size{224, 224});
GMatP plr = toNCHW(tmp);
matching_test::initGModel(tg, cv::GIn(y, uv), cv::GOut(plr));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(5u, nodes.size());
const auto bgr_nh = cv::gimpl::GModel::dataNodeOf(tgm, bgr);
const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp);
const auto plr_nh = cv::gimpl::GModel::dataNodeOf(tgm, plr);
const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh); // 1st resize
const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, plr_nh); // 2nd toNCHW
EXPECT_EQ(matching_test::S({bgr_nh, tmp_nh, plr_nh, op1_nh, op2_nh}),
nodes);
EXPECT_EQ(cv::gapi::core::GResize::id(), matching_test::opName(tgm, op1_nh));
EXPECT_EQ(GToNCHW::id(), matching_test::opName(tgm, op2_nh));
EXPECT_EQ(1u, tmp_nh->outEdges().size());
EXPECT_TRUE(matching_test::isConsumedBy(tgm, bgr_nh, op1_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp_nh, op2_nh));
EXPECT_EQ(matching_test::S{ op1_nh }, match.startOps());
EXPECT_EQ(matching_test::S{ op2_nh }, match.finishOps());
EXPECT_EQ(matching_test::V{ bgr_nh }, match.protoIns());
EXPECT_EQ(matching_test::V{ plr_nh }, match.protoOuts());
}
TEST(PatternMatching, TestPrepNV12toBGRToNCHW)
{
// Pattern
ade::Graph pg;
{
GMat y, uv;
GMat bgr = cv::gapi::NV12toBGR(y, uv);
GMatP plr = toNCHW(bgr);
matching_test::initGModel(pg, cv::GIn(y, uv), cv::GOut(plr));
}
// Test
ade::Graph tg;
GMat y, uv;
GMat bgr = cv::gapi::NV12toBGR(y, uv);
GMatP plr = toNCHW(bgr);
GMat rsz = cv::gapi::resizeP(plr, cv::Size{224, 224});
matching_test::initGModel(tg, cv::GIn(y, uv), cv::GOut(rsz));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(6u, nodes.size());
const auto y_nh = cv::gimpl::GModel::dataNodeOf(tgm, y);
const auto uv_nh = cv::gimpl::GModel::dataNodeOf(tgm, uv);
const auto bgr_nh = cv::gimpl::GModel::dataNodeOf(tgm, bgr);
const auto plr_nh = cv::gimpl::GModel::dataNodeOf(tgm, plr);
const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, bgr_nh); // 1st NV12toBGR
const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, plr_nh); // 2nd toNCHW
EXPECT_EQ(matching_test::S({y_nh, uv_nh, bgr_nh, plr_nh, op1_nh, op2_nh}),
nodes);
EXPECT_EQ(cv::gapi::imgproc::GNV12toBGR::id(), matching_test::opName(tgm, op1_nh));
EXPECT_EQ(GToNCHW::id(), matching_test::opName(tgm, op2_nh));
EXPECT_EQ(1u, bgr_nh->outEdges().size());
EXPECT_TRUE(matching_test::isConsumedBy(tgm, y_nh, op1_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, uv_nh, op1_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, bgr_nh, op2_nh));
EXPECT_EQ(matching_test::S{ op1_nh }, match.startOps());
EXPECT_EQ(matching_test::S{ op2_nh }, match.finishOps());
EXPECT_EQ(matching_test::V({ y_nh, uv_nh }), match.protoIns());
EXPECT_EQ(matching_test::V{ plr_nh }, match.protoOuts());
}
//FIXME: To switch from filter2d kernel (which shall be matched by params too) to another one
TEST(PatternMatching, MatchChainInTheMiddle)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat tmp = cv::gapi::filter2D(in, -1, {});
GMat out = cv::gapi::filter2D(tmp, -1, {});
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in;
GMat tmp1 = cv::gapi::erode3x3(in);
GMat tmp2 = cv::gapi::filter2D(tmp1, -1, {});
GMat tmp3 = cv::gapi::filter2D(tmp2, -1, {});
GMat out = cv::gapi::dilate3x3(tmp3);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(5u, nodes.size());
const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp1);
const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp2);
const auto tmp3_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp3);
const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, tmp2_nh); // 1st filter2D
const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, tmp3_nh); // 2nd filter2D
EXPECT_EQ(matching_test::S({tmp1_nh, tmp2_nh, tmp3_nh, op1_nh, op2_nh}), nodes);
EXPECT_EQ(cv::gapi::imgproc::GFilter2D::id(), matching_test::opName(tgm, op1_nh));
EXPECT_EQ(cv::gapi::imgproc::GFilter2D::id(), matching_test::opName(tgm, op2_nh));
EXPECT_EQ(1u, tmp2_nh->outEdges().size());
EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp1_nh, op1_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp2_nh, op2_nh));
EXPECT_EQ(matching_test::S({op1_nh}), match.startOps());
EXPECT_EQ(matching_test::S({op2_nh}), match.finishOps());
EXPECT_EQ(matching_test::V{ tmp1_nh }, match.protoIns());
EXPECT_EQ(matching_test::V{ tmp3_nh }, match.protoOuts());
}
TEST(PatternMatching, TestMultipleStartOps1)
{
// Pattern
ade::Graph pg;
{
GMat in1, in2;
GMat er = cv::gapi::erode3x3(in1);
GMat dil = cv::gapi::dilate3x3(in2);
GMat out = cv::gapi::add(er, dil);
matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in1, in2, in3, in4, in5, in6;
GMat er1 = cv::gapi::erode3x3(in1);
GMat er2 = cv::gapi::erode3x3(in2);
GMat er3 = cv::gapi::erode3x3(in3);
GMat er4 = cv::gapi::erode3x3(in4);
GMat dil1 = cv::gapi::dilate3x3(in5);
GMat dil2 = cv::gapi::dilate3x3(in6);
GMat out1 = cv::gapi::add(er1, er2);
GMat out2 = cv::gapi::add(er3, dil2);
matching_test::initGModel(tg, cv::GIn(in1, in2, in3, in4, in5, in6), cv::GOut(out1, out2, er4, dil1));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(8u, nodes.size());
const auto in3_nh = cv::gimpl::GModel::dataNodeOf(tgm, in3);
const auto in6_nh = cv::gimpl::GModel::dataNodeOf(tgm, in6);
const auto er3_nh = cv::gimpl::GModel::dataNodeOf(tgm, er3);
const auto dil2_nh = cv::gimpl::GModel::dataNodeOf(tgm, dil2);
const auto out2_nh = cv::gimpl::GModel::dataNodeOf(tgm, out2);
const auto er_op_nh = cv::gimpl::GModel::producerOf(tgm, er3_nh);
const auto dil_op_nh = cv::gimpl::GModel::producerOf(tgm, dil2_nh);
const auto add_op_nh = cv::gimpl::GModel::producerOf(tgm, out2_nh);
EXPECT_EQ(matching_test::S({in3_nh, in6_nh, er3_nh, dil2_nh, out2_nh,
er_op_nh, dil_op_nh, add_op_nh}),
nodes);
EXPECT_EQ(cv::gapi::imgproc::GErode::id(), matching_test::opName(tgm, er_op_nh));
EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, dil_op_nh));
EXPECT_EQ(cv::gapi::core::GAdd::id(), matching_test::opName(tgm, add_op_nh));
EXPECT_EQ(1u, er3_nh->outEdges().size());
EXPECT_EQ(1u, dil2_nh->outEdges().size());
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in3_nh, er_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in6_nh, dil_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, er3_nh, add_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, dil2_nh, add_op_nh));
EXPECT_EQ(matching_test::S({ er_op_nh, dil_op_nh }), match.startOps());
EXPECT_EQ(matching_test::S{ add_op_nh }, match.finishOps());
EXPECT_EQ(matching_test::V({ in3_nh, in6_nh }), match.protoIns());
EXPECT_EQ(matching_test::V{ out2_nh }, match.protoOuts());
}
TEST(PatternMatching, TestMultipleStartOps2)
{
// Pattern
ade::Graph pg;
{
GMat in1, in2;
GMat er = cv::gapi::erode3x3(in1);
GMat dil = cv::gapi::dilate3x3(in2);
GMat out = cv::gapi::add(er, dil);
matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in1, in2;
GMat er = cv::gapi::erode3x3(in1);
GMat dil1 = cv::gapi::dilate3x3(in2);
GMat dil2 = cv::gapi::dilate3x3(dil1);
GMat out = cv::gapi::add(er, dil2);
matching_test::initGModel(tg, cv::GIn(in1, in2), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(8u, nodes.size());
const auto in1_nh = cv::gimpl::GModel::dataNodeOf(tgm, in1);
const auto dil1_nh = cv::gimpl::GModel::dataNodeOf(tgm, dil1);
const auto er_nh = cv::gimpl::GModel::dataNodeOf(tgm, er);
const auto dil2_nh = cv::gimpl::GModel::dataNodeOf(tgm, dil2);
const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out);
const auto er_op_nh = cv::gimpl::GModel::producerOf(tgm, er_nh);
const auto dil_op_nh = cv::gimpl::GModel::producerOf(tgm, dil2_nh);
const auto add_op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh);
EXPECT_EQ(matching_test::S({in1_nh, dil1_nh, er_nh, dil2_nh, out_nh,
er_op_nh, dil_op_nh, add_op_nh}),
nodes);
EXPECT_EQ(cv::gapi::imgproc::GErode::id(), matching_test::opName(tgm, er_op_nh));
EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, dil_op_nh));
EXPECT_EQ(cv::gapi::core::GAdd::id(), matching_test::opName(tgm, add_op_nh));
EXPECT_EQ(1u, er_nh->outEdges().size());
EXPECT_EQ(1u, dil2_nh->outEdges().size());
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in1_nh, er_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, dil1_nh, dil_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, er_nh, add_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, dil2_nh, add_op_nh));
EXPECT_EQ(matching_test::S({ er_op_nh, dil_op_nh }), match.startOps());
EXPECT_EQ(matching_test::S{ add_op_nh }, match.finishOps());
EXPECT_EQ(matching_test::V({ in1_nh, dil1_nh }), match.protoIns());
EXPECT_EQ(matching_test::V{ out_nh }, match.protoOuts());
}
TEST(PatternMatching, TestInexactMatchOfInOutData)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat out = cv::gapi::dilate3x3(in);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in;
GMat out1 = cv::gapi::erode3x3(in);
GMat out2 = cv::gapi::boxFilter(in, -1, cv::Size(3, 3));
GMat tmp = cv::gapi::dilate3x3(in);
GScalar out3 = cv::gapi::sum(tmp);
GScalar out4 = cv::gapi::mean(tmp);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out1, out2, out3, out4));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(3u, nodes.size());
const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in);
const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp);
const auto op_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh); // dilate3x3
EXPECT_EQ(matching_test::S({in_nh, tmp_nh, op_nh}),
nodes);
EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh));
EXPECT_EQ(matching_test::S{ op_nh }, match.startOps());
EXPECT_EQ(matching_test::S{ op_nh }, match.finishOps());
EXPECT_EQ(matching_test::V{ in_nh }, match.protoIns());
EXPECT_EQ(matching_test::V{ tmp_nh }, match.protoOuts());
EXPECT_GT(in_nh->outEdges().size(), 1u);
EXPECT_GT(tmp_nh->outEdges().size(), 1u);
}
//FIXME: The start ops matching shall be reworked to more smarter way.
// Start ops matching shall get rid of non valid matchings sample,
// where two identical start ops in the pattern refer to the only one in the test.
TEST(PatternMatching, TestManySameStartOpsAndHinge)
{
// Pattern
ade::Graph pg;
{
GMat in1, in2, in3;
GMat er1 = cv::gapi::erode3x3(in1);
GMat er2 = cv::gapi::erode3x3(in2);
GMat er3 = cv::gapi::erode3x3(in3);
GMat mrg = cv::gapi::merge3(er1, er2, er3);
matching_test::initGModel(pg, cv::GIn(in1, in2, in3), cv::GOut(mrg));
}
// Test
ade::Graph tg;
GMat in1, in2, in3;
GMat er1 = cv::gapi::erode3x3(in1);
GMat er2 = cv::gapi::erode3x3(in2);
GMat er3 = cv::gapi::erode3x3(in3);
GMat mrg = cv::gapi::merge3(er1, er2, er3);
matching_test::initGModel(tg, cv::GIn(in1, in2, in3), cv::GOut(mrg));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(11u, nodes.size());
EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()),
nodes);
}
//FIXME: The start ops matching shall be reworked to more smarter way.
// Start ops matching shall get rid of non valid matchings sample,
// where two identical start ops in the pattern refer to the only one in the test.
TEST(PatternMatching, TestManySameStartOpsAndHinge2)
{
// Pattern
ade::Graph pg;
{
GMat in1, in2, in3;
GMat er1 = cv::gapi::erode3x3(in1);
GMat er2 = cv::gapi::erode3x3(in2);
GMat er3 = cv::gapi::erode3x3(in3);
GMat dil1 = cv::gapi::dilate3x3(er1);
GMat dil2 = cv::gapi::dilate3x3(er2);
GMat dil3 = cv::gapi::dilate3x3(er3);
GMat mrg = cv::gapi::merge3(dil1, dil2, dil3);
matching_test::initGModel(pg, cv::GIn(in1, in2, in3), cv::GOut(mrg));
}
// Test
ade::Graph tg;
GMat in1, in2, in3;
GMat er1 = cv::gapi::erode3x3(in1);
GMat er2 = cv::gapi::erode3x3(in2);
GMat er3 = cv::gapi::erode3x3(in3);
GMat dil1 = cv::gapi::dilate3x3(er1);
GMat dil2 = cv::gapi::dilate3x3(er2);
GMat dil3 = cv::gapi::dilate3x3(er3);
GMat mrg = cv::gapi::merge3(dil1, dil2, dil3);
matching_test::initGModel(tg, cv::GIn(in1, in2, in3), cv::GOut(mrg));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(17u, nodes.size());
EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()),
nodes);
}
//FIXME: The start ops matching shall be reworked to more smarter way.
// Start ops matching shall get rid of non valid matchings sample,
// where two identical start ops in the pattern refer to the only one in the test.
TEST(PatternMatching, TestTwoChainsOnTheHingeIsomorphism)
{
// Pattern
ade::Graph pg;
{
GMat in1, in2;
GMat er1 = cv::gapi::erode3x3(in1);
GMat er2 = cv::gapi::erode3x3(in2);
GMat mdb = cv::gapi::medianBlur(er1, 3);
GMat gb = cv::gapi::gaussianBlur(er2, cv::Size(5, 5), 0.12);
GMat conc = cv::gapi::concatVert(mdb, gb);
matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(conc));
}
// Test
ade::Graph tg;
GMat in1, in2;
GMat er1 = cv::gapi::erode3x3(in1);
GMat er2 = cv::gapi::erode3x3(in2);
GMat gb = cv::gapi::gaussianBlur(er1, cv::Size(5, 5), 0.12);
GMat mdb = cv::gapi::medianBlur(er2, 3);
GMat conc = cv::gapi::concatVert(mdb, gb);
matching_test::initGModel(tg, cv::GIn(in1, in2), cv::GOut(conc));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(12u, nodes.size());
EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()),
nodes);
const auto in1_nh = cv::gimpl::GModel::dataNodeOf(tgm, in1);
const auto in2_nh = cv::gimpl::GModel::dataNodeOf(tgm, in2);
EXPECT_EQ(matching_test::V({ in2_nh, in1_nh }), match.protoIns());
}
TEST(PatternMatching, TestPatternHasMoreInDataNodes)
{
// Pattern
ade::Graph pg;
{
GMat in1, in2, in3;
GMat out = cv::gapi::merge3(in1, in2, in3);
matching_test::initGModel(pg, cv::GIn(in1, in2, in3), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in;
GMat out = cv::gapi::merge3(in, in, in);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(3u, nodes.size());
EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()),
nodes);
const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in);
EXPECT_EQ(matching_test::V({ in_nh, in_nh, in_nh }), match.protoIns());
}
TEST(PatternMatching, TestPatternHasFewerInDataNodes)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat out = cv::gapi::merge3(in, in, in);
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in1, in2, in3;
GMat out = cv::gapi::merge3(in1, in2, in3);
matching_test::initGModel(tg, cv::GIn(in1, in2, in3), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_FALSE(match.ok());
}
TEST(PatternMatching, TestTwoMatchingsOneCorrect)
{
// Pattern
ade::Graph pg;
{
GMat in1, in2;
GMat n = cv::gapi::bitwise_not(in1);
GMat e = cv::gapi::erode3x3(in1);
GMat d = cv::gapi::dilate3x3(in2);
GMat out = cv::gapi::merge3(n, e, d);
matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(out));
}
// Test
ade::Graph tg;
GMat in1, in2;
GMat n = cv::gapi::bitwise_not(in1);
GMat e = cv::gapi::erode3x3(in2);
GMat d = cv::gapi::dilate3x3(in2);
GMat mrg = cv::gapi::merge3(n, e, d);
GMat i, sqi;
std::tie(i, sqi) = cv::gapi::integral(mrg);
GMat n1 = cv::gapi::bitwise_not(i);
GMat e1 = cv::gapi::erode3x3(i);
GMat d1 = cv::gapi::dilate3x3(sqi);
GMat out = cv::gapi::merge3(n1, e1, d1);
matching_test::initGModel(tg, cv::GIn(in1, in2), cv::GOut(out));
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_TRUE(match.ok());
auto nodes = match.nodes();
EXPECT_EQ(10u, nodes.size());
const auto i_nh = cv::gimpl::GModel::dataNodeOf(tgm, i);
const auto sqi_nh = cv::gimpl::GModel::dataNodeOf(tgm, sqi);
const auto n1_nh = cv::gimpl::GModel::dataNodeOf(tgm, n1);
const auto e1_nh = cv::gimpl::GModel::dataNodeOf(tgm, e1);
const auto d1_nh = cv::gimpl::GModel::dataNodeOf(tgm, d1);
const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out);
const auto n_op_nh = cv::gimpl::GModel::producerOf(tgm, n1_nh);
const auto e_op_nh = cv::gimpl::GModel::producerOf(tgm, e1_nh);
const auto d_op_nh = cv::gimpl::GModel::producerOf(tgm, d1_nh);
const auto m_op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh);
EXPECT_EQ(matching_test::S({i_nh, sqi_nh, n1_nh, e1_nh, d1_nh, out_nh,
n_op_nh, e_op_nh, d_op_nh, m_op_nh}), nodes);
EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, n_op_nh));
EXPECT_EQ(cv::gapi::imgproc::GErode::id(), matching_test::opName(tgm, e_op_nh));
EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, d_op_nh));
EXPECT_EQ(cv::gapi::core::GMerge3::id(), matching_test::opName(tgm, m_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, i_nh, n_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, i_nh, e_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, sqi_nh, d_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, n1_nh, m_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, e1_nh, m_op_nh));
EXPECT_TRUE(matching_test::isConsumedBy(tgm, d1_nh, m_op_nh));
EXPECT_EQ(1u, n1_nh->outEdges().size());
EXPECT_EQ(1u, e1_nh->outEdges().size());
EXPECT_EQ(1u, d1_nh->outEdges().size());
EXPECT_EQ(matching_test::S({n_op_nh, e_op_nh, d_op_nh}), match.startOps());
EXPECT_EQ(matching_test::S{m_op_nh}, match.finishOps());
EXPECT_EQ(matching_test::V({i_nh, sqi_nh}), match.protoIns());
EXPECT_EQ(matching_test::V{out_nh}, match.protoOuts());}
TEST(PatternMatching, CheckNoMatch)
{
// Pattern
ade::Graph pg;
{
GMat in;
GMat tmp = cv::gapi::filter2D(in, -1, {});
GMat out = cv::gapi::filter2D(tmp, -1, {});
matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out));
}
// Test
ade::Graph tg;
{
GMat in;
GMat tmp1 = cv::gapi::erode3x3(in);
GMat out = cv::gapi::dilate3x3(tmp1);
matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out));
}
// Pattern Matching
cv::gimpl::GModel::Graph pgm(pg);
cv::gimpl::GModel::Graph tgm(tg);
cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg);
// Inspecting results:
EXPECT_FALSE(match.ok());
}
TEST(PatternMatching, adeSmokeTest)
{
ade::Graph g;
ade::NodeHandle src = g.createNode();
ade::NodeHandle dst = g.createNode();
g.link(src, dst);
g.link(src, dst);
EXPECT_EQ(2u, dst->inNodes().size());
}
} // namespace opencv_test

View File

@@ -0,0 +1,649 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "../test_precomp.hpp"
#include <stdexcept>
#include <opencv2/gapi/gtransform.hpp>
#include <opencv2/gapi/cpu/core.hpp>
#include <opencv2/gapi/cpu/imgproc.hpp>
#include "compiler/gmodel.hpp"
#include "compiler/gmodel_priv.hpp"
#include "api/gcomputation_priv.hpp"
#include "compiler/gcompiler.hpp"
#include "compiler/gmodelbuilder.hpp"
#include "compiler/passes/passes.hpp"
#include "compiler/passes/pattern_matching.hpp"
#include "../common/gapi_tests_common.hpp"
#include "logger.hpp"
namespace opencv_test
{
// --------------------------------------------------------------------------------------
// Accuracy integration tests (GComputation-level)
namespace {
// FIXME: replace listener with something better (e.g. check graph via GModel?)
// custom "listener" to check what kernels are called within the test
struct KernelListener { std::map<std::string, size_t> counts; };
KernelListener& getListener() {
static KernelListener l;
return l;
}
using CompCreator = std::function<cv::GComputation()>;
using CompileArgsCreator = std::function<cv::GCompileArgs()>;
using Verifier = std::function<void(KernelListener)>;
} // anonymous namespace
// Custom kernels && transformations below:
G_TYPED_KERNEL(MyNV12toBGR, <GMat(GMat, GMat)>, "test.my_nv12_to_bgr") {
static GMatDesc outMeta(GMatDesc in_y, GMatDesc in_uv) {
return cv::gapi::imgproc::GNV12toBGR::outMeta(in_y, in_uv);
}
};
GAPI_OCV_KERNEL(MyNV12toBGRImpl, MyNV12toBGR)
{
static void run(const cv::Mat& in_y, const cv::Mat& in_uv, cv::Mat &out)
{
getListener().counts[MyNV12toBGR::id()]++;
cv::cvtColorTwoPlane(in_y, in_uv, out, cv::COLOR_YUV2BGR_NV12);
}
};
G_TYPED_KERNEL(MyPlanarResize, <GMatP(GMatP, Size, int)>, "test.my_planar_resize") {
static GMatDesc outMeta(GMatDesc in, Size sz, int interp) {
return cv::gapi::core::GResizeP::outMeta(in, sz, interp);
}
};
GAPI_OCV_KERNEL(MyPlanarResizeImpl, MyPlanarResize) {
static void run(const cv::Mat& in, cv::Size out_sz, int interp, cv::Mat &out)
{
getListener().counts[MyPlanarResize::id()]++;
int inH = in.rows / 3;
int inW = in.cols;
int outH = out.rows / 3;
int outW = out.cols;
for (int i = 0; i < 3; i++) {
auto in_plane = in(cv::Rect(0, i*inH, inW, inH));
auto out_plane = out(cv::Rect(0, i*outH, outW, outH));
cv::resize(in_plane, out_plane, out_sz, 0, 0, interp);
}
}
};
G_TYPED_KERNEL(MyInterleavedResize, <GMat(GMat, Size, int)>, "test.my_interleaved_resize") {
static GMatDesc outMeta(GMatDesc in, Size sz, int interp) {
return cv::gapi::core::GResize::outMeta(in, sz, 0.0, 0.0, interp);
}
};
GAPI_OCV_KERNEL(MyInterleavedResizeImpl, MyInterleavedResize) {
static void run(const cv::Mat& in, cv::Size out_sz, int interp, cv::Mat &out)
{
getListener().counts[MyInterleavedResize::id()]++;
cv::resize(in, out, out_sz, 0.0, 0.0, interp);
}
};
G_TYPED_KERNEL(MyToNCHW, <GMatP(GMat)>, "test.my_to_nchw") {
static GMatDesc outMeta(GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
GAPI_Assert(in.planar == false);
return in.asPlanar();
}
};
GAPI_OCV_KERNEL(MyToNCHWImpl, MyToNCHW) {
static void run(const cv::Mat& in, cv::Mat& out)
{
getListener().counts[MyToNCHW::id()]++;
auto sz = in.size();
auto w = sz.width;
auto h = sz.height;
cv::Mat ins[3] = {};
cv::split(in, ins);
for (int i = 0; i < 3; i++) {
auto in_plane = ins[i];
auto out_plane = out(cv::Rect(0, i*h, w, h));
in_plane.copyTo(out_plane);
}
}
};
using GMat4 = std::tuple<GMat, GMat, GMat, GMat>;
G_TYPED_KERNEL_M(MySplit4, <GMat4(GMat)>, "test.my_split4") {
static std::tuple<GMatDesc, GMatDesc, GMatDesc, GMatDesc> outMeta(GMatDesc in) {
const auto out_depth = in.depth;
const auto out_desc = in.withType(out_depth, 1);
return std::make_tuple(out_desc, out_desc, out_desc, out_desc);
}
};
GAPI_OCV_KERNEL(MySplit4Impl, MySplit4) {
static void run(const cv::Mat& in, cv::Mat& out1, cv::Mat& out2, cv::Mat& out3, cv::Mat& out4)
{
getListener().counts[MySplit4::id()]++;
cv::Mat outs[] = { out1, out2, out3, out4 };
cv::split(in, outs);
}
};
GAPI_TRANSFORM(NV12Transform, <cv::GMat(cv::GMat, cv::GMat)>, "test.nv12_transform")
{
static cv::GMat pattern(const cv::GMat& y, const cv::GMat& uv)
{
GMat out = cv::gapi::NV12toBGR(y, uv);
return out;
}
static cv::GMat substitute(const cv::GMat& y, const cv::GMat& uv)
{
GMat out = MyNV12toBGR::on(y, uv);
return out;
}
};
GAPI_TRANSFORM(ResizeTransform, <cv::GMat(cv::GMat)>, "3 x Resize -> Interleaved Resize")
{
static cv::GMat pattern(const cv::GMat& in)
{
GMat b, g, r;
std::tie(b, g, r) = cv::gapi::split3(in);
const auto resize = std::bind(&cv::gapi::resize, std::placeholders::_1,
cv::Size(100, 100), 0, 0, cv::INTER_AREA);
return cv::gapi::merge3(resize(b), resize(g), resize(r));
}
static cv::GMat substitute(const cv::GMat& in)
{
return MyInterleavedResize::on(in, cv::Size(100, 100), cv::INTER_AREA);
}
};
GAPI_TRANSFORM(ResizeTransformToCustom, <cv::GMat(cv::GMat)>, "Resize -> Custom Resize")
{
static cv::GMat pattern(const cv::GMat& in)
{
return cv::gapi::resize(in, cv::Size(100, 100), 0, 0, cv::INTER_AREA);
}
static cv::GMat substitute(const cv::GMat& in)
{
return MyInterleavedResize::on(in, cv::Size(100, 100), cv::INTER_AREA);
}
};
GAPI_TRANSFORM(ChainTransform1, <GMatP(GMat)>, "Resize + toNCHW -> toNCHW + PlanarResize")
{
static GMatP pattern(const cv::GMat& in)
{
return MyToNCHW::on(cv::gapi::resize(in, cv::Size(60, 60)));
}
static GMatP substitute(const cv::GMat& in)
{
return MyPlanarResize::on(MyToNCHW::on(in), cv::Size(60, 60), cv::INTER_LINEAR);
}
};
GAPI_TRANSFORM(ChainTransform2, <GMatP(GMat, GMat)>, "NV12toBGR + toNCHW -> NV12toBGRp")
{
static GMatP pattern(const GMat& y, const GMat& uv)
{
return MyToNCHW::on(MyNV12toBGR::on(y, uv));
}
static GMatP substitute(const GMat& y, const GMat& uv)
{
return cv::gapi::NV12toBGRp(y, uv);
}
};
GAPI_TRANSFORM(Split4Transform, <GMat4(GMat)>, "Split4 -> Custom Split4")
{
static GMat4 pattern(const GMat& in)
{
return cv::gapi::split4(in);
}
static GMat4 substitute(const GMat& in)
{
return MySplit4::on(in);
}
};
GAPI_TRANSFORM(Split4Merge3Transform, <GMat(GMat)>, "Split4 + Merge3 -> Custom Split4 + Merge3")
{
static GMat pattern(const GMat& in)
{
GMat tmp1, tmp2, tmp3, unused;
std::tie(tmp1, tmp2, tmp3, unused) = cv::gapi::split4(in);
return cv::gapi::merge3(tmp1, tmp2, tmp3);
}
static GMat substitute(const GMat& in)
{
GMat tmp1, tmp2, tmp3, unused;
std::tie(tmp1, tmp2, tmp3, unused) = MySplit4::on(in);
return cv::gapi::merge3(tmp1, tmp2, tmp3);
}
};
GAPI_TRANSFORM(Merge4Split4Transform, <GMat4(GMat, GMat, GMat, GMat)>,
"Merge4 + Split4 -> Merge4 + Custom Split4")
{
static GMat4 pattern(const GMat& in1, const GMat& in2, const GMat& in3,
const GMat& in4)
{
return cv::gapi::split4(cv::gapi::merge4(in1, in2, in3, in4));
}
static GMat4 substitute(const GMat& in1, const GMat& in2, const GMat& in3,
const GMat& in4)
{
return MySplit4::on(cv::gapi::merge4(in1, in2, in3, in4));
}
};
// --------------------------------------------------------------------------------------
// Integration tests
TEST(PatternMatchingIntegrationBasic, OneTransformationApplied)
{
cv::Size in_sz(640, 480);
cv::Mat input(in_sz, CV_8UC3);
cv::randu(input, cv::Scalar::all(0), cv::Scalar::all(100));
cv::Mat orig_graph_output, transformed_graph_output;
auto orig_args = cv::compile_args();
auto transform_args = cv::compile_args(
cv::gapi::kernels<MyInterleavedResizeImpl, ResizeTransform>());
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
const auto make_computation = [] () {
GMat in;
GMat b, g, r;
std::tie(b, g, r) = cv::gapi::split3(in);
const auto resize = std::bind(&cv::gapi::resize, std::placeholders::_1,
cv::Size(100, 100), 0, 0, cv::INTER_AREA);
GMat out = cv::gapi::merge3(resize(b), resize(g), resize(r));
return cv::GComputation(cv::GIn(in), cv::GOut(out));
};
{
// Run original graph
auto mainC = make_computation();
mainC.apply(cv::gin(input), cv::gout(orig_graph_output), std::move(orig_args));
}
// Generate transformed graph (passing transformations via compile args)
auto mainC = make_computation(); // get new copy with new Priv
mainC.apply(cv::gin(input), cv::gout(transformed_graph_output), std::move(transform_args));
// Compare
ASSERT_TRUE(AbsExact()(orig_graph_output, transformed_graph_output));
// Custom verification via listener
ASSERT_EQ(1u, listener.counts.size());
// called in transformed graph:
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyInterleavedResize::id()));
ASSERT_EQ(1u, listener.counts.at(MyInterleavedResize::id()));
}
TEST(PatternMatchingIntegrationBasic, SameTransformationAppliedSeveralTimes)
{
cv::Size in_sz(640, 480);
cv::Mat input(in_sz, CV_8UC3);
cv::randu(input, cv::Scalar::all(0), cv::Scalar::all(100));
cv::Mat orig_graph_output, transformed_graph_output;
auto orig_args = cv::compile_args();
auto transform_args = cv::compile_args(
cv::gapi::kernels<MyInterleavedResizeImpl, ResizeTransformToCustom>());
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
const auto make_computation = [] () {
GMat in;
GMat b, g, r;
std::tie(b, g, r) = cv::gapi::split3(in);
const auto resize = std::bind(&cv::gapi::resize, std::placeholders::_1,
cv::Size(100, 100), 0, 0, cv::INTER_AREA);
GMat out = cv::gapi::merge3(resize(b), resize(g), resize(r));
return cv::GComputation(cv::GIn(in), cv::GOut(out));
};
{
// Run original graph
auto mainC = make_computation();
mainC.apply(cv::gin(input), cv::gout(orig_graph_output), std::move(orig_args));
}
// Generate transformed graph (passing transformations via compile args)
auto mainC = make_computation(); // get new copy with new Priv
mainC.apply(cv::gin(input), cv::gout(transformed_graph_output), std::move(transform_args));
// Compare
ASSERT_TRUE(AbsExact()(orig_graph_output, transformed_graph_output));
// Custom verification via listener
ASSERT_EQ(1u, listener.counts.size());
// called in transformed graph:
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyInterleavedResize::id()));
ASSERT_EQ(3u, listener.counts.at(MyInterleavedResize::id()));
}
TEST(PatternMatchingIntegrationBasic, OneNV12toBGRTransformationApplied)
{
cv::Size in_sz(640, 480);
cv::Mat y(in_sz, CV_8UC1), uv(cv::Size(in_sz.width / 2, in_sz.height / 2), CV_8UC2);
cv::randu(y, cv::Scalar::all(0), cv::Scalar::all(100));
cv::randu(uv, cv::Scalar::all(100), cv::Scalar::all(200));
cv::Mat orig_graph_output, transformed_graph_output;
auto orig_args = cv::compile_args();
auto transform_args = cv::compile_args(cv::gapi::kernels<MyNV12toBGRImpl, NV12Transform>());
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
const auto make_computation = [] () {
GMat in1, in2;
GMat bgr = cv::gapi::NV12toBGR(in1, in2);
GMat out = cv::gapi::resize(bgr, cv::Size(100, 100));
return cv::GComputation(cv::GIn(in1, in2), cv::GOut(out));
};
{
// Run original graph
auto mainC = make_computation();
mainC.apply(cv::gin(y, uv), cv::gout(orig_graph_output), std::move(orig_args));
}
// Generate transformed graph (passing transformations via compile args)
auto mainC = make_computation(); // get new copy with new Priv
mainC.apply(cv::gin(y, uv), cv::gout(transformed_graph_output), std::move(transform_args));
// Compare
ASSERT_TRUE(AbsExact()(orig_graph_output, transformed_graph_output));
// Custom verification via listener
ASSERT_EQ(1u, listener.counts.size());
// called in transformed graph:
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyNV12toBGR::id()));
ASSERT_EQ(1u, listener.counts.at(MyNV12toBGR::id()));
}
TEST(PatternMatchingIntegrationBasic, TwoTransformationsApplied)
{
cv::Size in_sz(640, 480);
cv::Mat y(in_sz, CV_8UC1), uv(cv::Size(in_sz.width / 2, in_sz.height / 2), CV_8UC2);
cv::randu(y, cv::Scalar::all(0), cv::Scalar::all(100));
cv::randu(uv, cv::Scalar::all(100), cv::Scalar::all(200));
cv::Mat orig_graph_output, transformed_graph_output;
auto orig_args = cv::compile_args();
auto transform_args = cv::compile_args(
cv::gapi::kernels<MyNV12toBGRImpl, MyInterleavedResizeImpl, ResizeTransform,
NV12Transform>()); // compile args with transformations
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
const auto make_computation = [] () {
GMat in1, in2;
GMat bgr = cv::gapi::NV12toBGR(in1, in2);
GMat b, g, r;
std::tie(b, g, r) = cv::gapi::split3(bgr);
const auto resize = std::bind(&cv::gapi::resize, std::placeholders::_1,
cv::Size(100, 100), 0, 0, cv::INTER_AREA);
GMat tmp1 = cv::gapi::resize(bgr, cv::Size(90, 90));
GMat tmp2 = cv::gapi::bitwise_not(cv::gapi::merge3(resize(b), resize(g), resize(r)));
GMat out = cv::gapi::resize(tmp1 + GScalar(10.0), cv::Size(100, 100)) + tmp2;
return cv::GComputation(cv::GIn(in1, in2), cv::GOut(out));
};
{
// Run original graph
auto mainC = make_computation();
mainC.apply(cv::gin(y, uv), cv::gout(orig_graph_output), std::move(orig_args));
}
// Generate transformed graph (passing transformations via compile args)
auto mainC = make_computation(); // get new copy with new Priv
mainC.apply(cv::gin(y, uv), cv::gout(transformed_graph_output), std::move(transform_args));
// Compare
ASSERT_TRUE(AbsExact()(orig_graph_output, transformed_graph_output));
// Custom verification via listener
ASSERT_EQ(2u, listener.counts.size());
// called in transformed graph:
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyNV12toBGR::id()));
ASSERT_EQ(1u, listener.counts.at(MyNV12toBGR::id()));
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyInterleavedResize::id()));
ASSERT_EQ(1u, listener.counts.at(MyInterleavedResize::id()));
}
struct PatternMatchingIntegrationE2E : testing::Test
{
cv::GComputation makeComputation() {
GMat in1, in2;
GMat bgr = MyNV12toBGR::on(in1, in2);
GMat resized = cv::gapi::resize(bgr, cv::Size(60, 60));
GMatP out = MyToNCHW::on(resized);
return cv::GComputation(cv::GIn(in1, in2), cv::GOut(out));
}
void runTest(cv::GCompileArgs&& transform_args) {
cv::Size in_sz(640, 480);
cv::Mat y(in_sz, CV_8UC1), uv(cv::Size(in_sz.width / 2, in_sz.height / 2), CV_8UC2);
cv::randu(y, cv::Scalar::all(0), cv::Scalar::all(100));
cv::randu(uv, cv::Scalar::all(100), cv::Scalar::all(200));
cv::Mat orig_graph_output, transformed_graph_output;
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
{
// Run original graph
auto mainC = makeComputation();
mainC.apply(cv::gin(y, uv), cv::gout(orig_graph_output),
cv::compile_args(cv::gapi::kernels<MyNV12toBGRImpl, MyToNCHWImpl>()));
}
// Generate transformed graph (passing transformations via compile args)
auto mainC = makeComputation(); // get new copy with new Priv
mainC.apply(cv::gin(y, uv), cv::gout(transformed_graph_output), std::move(transform_args));
// Compare
ASSERT_TRUE(AbsExact()(orig_graph_output, transformed_graph_output));
// Custom verification via listener
ASSERT_EQ(3u, listener.counts.size());
// called in original graph:
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyNV12toBGR::id()));
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyToNCHW::id()));
ASSERT_EQ(1u, listener.counts.at(MyNV12toBGR::id()));
ASSERT_EQ(1u, listener.counts.at(MyToNCHW::id()));
// called in transformed graph:
ASSERT_NE(listener.counts.cend(), listener.counts.find(MyPlanarResize::id()));
ASSERT_EQ(1u, listener.counts.at(MyPlanarResize::id()));
}
};
TEST_F(PatternMatchingIntegrationE2E, ChainTransformationsApplied)
{
runTest(cv::compile_args(
cv::gapi::kernels<MyPlanarResizeImpl, ChainTransform1, ChainTransform2>()));
}
TEST_F(PatternMatchingIntegrationE2E, ReversedChainTransformationsApplied)
{
runTest(cv::compile_args(
cv::gapi::kernels<ChainTransform2, MyPlanarResizeImpl, ChainTransform1>()));
}
struct PatternMatchingIntegrationUnusedNodes : testing::Test
{
cv::GComputation makeComputation() {
GMat in1, in2;
GMat bgr = cv::gapi::NV12toBGR(in1, in2);
GMat b1, g1, r1;
std::tie(b1, g1, r1) = cv::gapi::split3(bgr);
// FIXME: easier way to call split4??
GMat merged4 = cv::gapi::merge4(b1, g1, r1, b1);
GMat b2, g2, r2, unused;
std::tie(b2, g2, r2, unused) = cv::gapi::split4(merged4);
GMat out = cv::gapi::merge3(b2, g2, r2);
return cv::GComputation(cv::GIn(in1, in2), cv::GOut(out));
}
void runTest(cv::GCompileArgs&& transform_args) {
cv::Size in_sz(640, 480);
cv::Mat y(in_sz, CV_8UC1), uv(cv::Size(in_sz.width / 2, in_sz.height / 2), CV_8UC2);
cv::randu(y, cv::Scalar::all(0), cv::Scalar::all(100));
cv::randu(uv, cv::Scalar::all(100), cv::Scalar::all(200));
cv::Mat orig_graph_output, transformed_graph_output;
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
{
// Run original graph
auto mainC = makeComputation();
mainC.apply(cv::gin(y, uv), cv::gout(orig_graph_output),
cv::compile_args(cv::gapi::kernels<MyNV12toBGRImpl, MyToNCHWImpl>()));
}
// Generate transformed graph (passing transformations via compile args)
auto mainC = makeComputation(); // get new copy with new Priv
mainC.apply(cv::gin(y, uv), cv::gout(transformed_graph_output), std::move(transform_args));
// Compare
ASSERT_TRUE(AbsExact()(orig_graph_output, transformed_graph_output));
// Custom verification via listener
ASSERT_EQ(1u, listener.counts.size());
// called in transformed graph:
ASSERT_NE(listener.counts.cend(), listener.counts.find(MySplit4::id()));
ASSERT_EQ(1u, listener.counts.at(MySplit4::id()));
}
};
TEST_F(PatternMatchingIntegrationUnusedNodes, SingleOpTransformApplied)
{
runTest(cv::compile_args(cv::gapi::kernels<MySplit4Impl, Split4Transform>()));
}
// FIXME: enable once unused nodes are properly handled by Transformation API
TEST_F(PatternMatchingIntegrationUnusedNodes, DISABLED_TransformWithInternalUnusedNodeApplied)
{
runTest(cv::compile_args(cv::gapi::kernels<MySplit4Impl, Split4Merge3Transform>()));
}
TEST_F(PatternMatchingIntegrationUnusedNodes, TransformWithOutputUnusedNodeApplied)
{
runTest(cv::compile_args(cv::gapi::kernels<MySplit4Impl, Merge4Split4Transform>()));
}
// --------------------------------------------------------------------------------------
// Bad arg integration tests (GCompiler-level) - General
struct PatternMatchingIntegrationBadArgTests : testing::Test
{
cv::GComputation makeComputation() {
GMat in;
GMat a, b, c, d;
std::tie(a, b, c, d) = MySplit4::on(in); // using custom Split4 to check if it's called
GMat out = cv::gapi::merge3(a + b, cv::gapi::bitwise_not(c), d * cv::GScalar(2.0));
return cv::GComputation(cv::GIn(in), cv::GOut(out));
}
void runTest(cv::GCompileArgs&& transform_args) {
cv::Size in_sz(640, 480);
cv::Mat input(in_sz, CV_8UC4);
cv::randu(input, cv::Scalar::all(70), cv::Scalar::all(140));
cv::Mat output;
// Generate transformed graph (passing transformations via compile args)
auto mainC = makeComputation(); // get new copy with new Priv
ASSERT_NO_THROW(mainC.apply(cv::gin(input), cv::gout(output), std::move(transform_args)));
}
};
TEST_F(PatternMatchingIntegrationBadArgTests, NoTransformations)
{
auto transform_args = cv::compile_args(cv::gapi::kernels<MySplit4Impl>());
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
runTest(std::move(transform_args));
// Custom verification via listener
ASSERT_EQ(1u, listener.counts.size());
ASSERT_NE(listener.counts.cend(), listener.counts.find(MySplit4::id()));
ASSERT_EQ(1u, listener.counts.at(MySplit4::id()));
}
TEST_F(PatternMatchingIntegrationBadArgTests, WrongTransformation)
{
// Here Split4Transform::pattern is "looking for" cv::gapi::split4 but it's not used
auto transform_args = cv::compile_args(cv::gapi::kernels<MySplit4Impl, Split4Transform>());
auto& listener = getListener();
listener.counts.clear(); // clear counters before testing
runTest(std::move(transform_args));
// Custom verification via listener
ASSERT_EQ(1u, listener.counts.size());
ASSERT_NE(listener.counts.cend(), listener.counts.find(MySplit4::id()));
ASSERT_EQ(1u, listener.counts.at(MySplit4::id()));
}
// --------------------------------------------------------------------------------------
// Bad arg integration tests (GCompiler-level) - Endless Loops
GAPI_TRANSFORM(EndlessLoopTransform, <cv::GMat(cv::GMat)>, "pattern in substitute")
{
static cv::GMat pattern(const cv::GMat& in)
{
return cv::gapi::resize(in, cv::Size(100, 100), 0, 0, cv::INTER_LINEAR);
}
static cv::GMat substitute(const cv::GMat& in)
{
cv::GMat b, g, r;
std::tie(b, g, r) = cv::gapi::split3(in);
auto resize = std::bind(&cv::gapi::resize,
std::placeholders::_1, cv::Size(100, 100), 0, 0, cv::INTER_LINEAR);
cv::GMat out = cv::gapi::merge3(resize(b), resize(g), resize(r));
return out;
}
};
TEST(PatternMatchingIntegrationEndlessLoops, PatternInSubstituteInOneTransform)
{
cv::Size in_sz(640, 480);
cv::Mat input(in_sz, CV_8UC3);
cv::randu(input, cv::Scalar::all(0), cv::Scalar::all(100));
auto c = [] () {
GMat in;
GMat tmp = cv::gapi::resize(in, cv::Size(100, 100), 0, 0, cv::INTER_LINEAR);
GMat out = cv::gapi::bitwise_not(tmp);
return cv::GComputation(cv::GIn(in), cv::GOut(out));
}();
EXPECT_THROW(
cv::gimpl::GCompiler(c, cv::descr_of(cv::gin(input)),
cv::compile_args(cv::gapi::kernels<EndlessLoopTransform>())),
std::exception);
}
} // namespace opencv_test

View File

@@ -0,0 +1,232 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include "api/gcomputation_priv.hpp"
#include <opencv2/gapi/fluid/gfluidkernel.hpp>
#include <opencv2/gapi/fluid/core.hpp>
#include <opencv2/gapi/fluid/imgproc.hpp>
namespace opencv_test
{
TEST(GComputationCompile, NoRecompileWithSameMeta)
{
cv::GMat in;
cv::GComputation cc(in, in+in);
cv::Mat in_mat1 = cv::Mat::eye (32, 32, CV_8UC1);
cv::Mat in_mat2 = cv::Mat::zeros(32, 32, CV_8UC1);
cv::Mat out_mat;
cc.apply(in_mat1, out_mat);
auto comp1 = cc.priv().m_lastCompiled;
cc.apply(in_mat2, out_mat);
auto comp2 = cc.priv().m_lastCompiled;
// Both compiled objects are actually the same unique executable
EXPECT_EQ(&comp1.priv(), &comp2.priv());
}
TEST(GComputationCompile, NoRecompileWithWrongMeta)
{
cv::GMat in;
cv::GComputation cc(in, in+in);
cv::Mat in_mat1 = cv::Mat::eye (32, 32, CV_8UC1);
cv::Mat in_mat2 = cv::Mat::zeros(32, 32, CV_8UC1);
cv::Mat out_mat;
cc.apply(in_mat1, out_mat);
auto comp1 = cc.priv().m_lastCompiled;
EXPECT_THROW(cc.apply(cv::gin(cv::Scalar(128)), cv::gout(out_mat)), std::logic_error);
auto comp2 = cc.priv().m_lastCompiled;
// Both compiled objects are actually the same unique executable
EXPECT_EQ(&comp1.priv(), &comp2.priv());
}
TEST(GComputationCompile, RecompileWithDifferentMeta)
{
cv::GMat in;
cv::GComputation cc(in, in+in);
cv::Mat in_mat1 = cv::Mat::eye (32, 32, CV_8UC1);
cv::Mat in_mat2 = cv::Mat::zeros(64, 64, CV_32F);
cv::Mat out_mat;
cc.apply(in_mat1, out_mat);
auto comp1 = cc.priv().m_lastCompiled;
cc.apply(in_mat2, out_mat);
auto comp2 = cc.priv().m_lastCompiled;
// Both compiled objects are different
EXPECT_NE(&comp1.priv(), &comp2.priv());
}
TEST(GComputationCompile, FluidReshapeWithDifferentDims)
{
cv::GMat in;
cv::GComputation cc(in, in+in);
cv::Mat in_mat1 = cv::Mat::eye (32, 32, CV_8UC1);
cv::Mat in_mat2 = cv::Mat::zeros(64, 64, CV_8UC1);
cv::Mat out_mat;
cc.apply(in_mat1, out_mat, cv::compile_args(cv::gapi::core::fluid::kernels()));
auto comp1 = cc.priv().m_lastCompiled;
cc.apply(in_mat2, out_mat);
auto comp2 = cc.priv().m_lastCompiled;
// Both compiled objects are actually the same unique executable
EXPECT_EQ(&comp1.priv(), &comp2.priv());
}
TEST(GComputationCompile, FluidReshapeResizeDownScale)
{
cv::Size szOut(4, 4);
cv::GMat in;
cv::GComputation cc(in, cv::gapi::resize(in, szOut));
cv::Mat in_mat1( 8, 8, CV_8UC3);
cv::Mat in_mat2(16, 16, CV_8UC3);
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
cv::Mat out_mat1, out_mat2;
cc.apply(in_mat1, out_mat1, cv::compile_args(cv::gapi::core::fluid::kernels()));
auto comp1 = cc.priv().m_lastCompiled;
cc.apply(in_mat2, out_mat2);
auto comp2 = cc.priv().m_lastCompiled;
// Both compiled objects are actually the same unique executable
EXPECT_EQ(&comp1.priv(), &comp2.priv());
cv::Mat cv_out_mat1, cv_out_mat2;
cv::resize(in_mat1, cv_out_mat1, szOut);
cv::resize(in_mat2, cv_out_mat2, szOut);
EXPECT_EQ(0, cv::countNonZero(out_mat1 != cv_out_mat1));
EXPECT_EQ(0, cv::countNonZero(out_mat2 != cv_out_mat2));
}
TEST(GComputationCompile, FluidReshapeSwitchToUpscaleFromDownscale)
{
cv::Size szOut(4, 4);
cv::GMat in;
cv::GComputation cc(in, cv::gapi::resize(in, szOut));
cv::Mat in_mat1( 8, 8, CV_8UC3);
cv::Mat in_mat2( 2, 2, CV_8UC3);
cv::Mat in_mat3(16, 16, CV_8UC3);
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat3, cv::Scalar::all(0), cv::Scalar::all(255));
cv::Mat out_mat1, out_mat2, out_mat3;
cc.apply(in_mat1, out_mat1, cv::compile_args(cv::gapi::core::fluid::kernels()));
auto comp1 = cc.priv().m_lastCompiled;
cc.apply(in_mat2, out_mat2);
auto comp2 = cc.priv().m_lastCompiled;
cc.apply(in_mat3, out_mat3);
auto comp3 = cc.priv().m_lastCompiled;
EXPECT_EQ(&comp1.priv(), &comp2.priv());
EXPECT_EQ(&comp1.priv(), &comp3.priv());
cv::Mat cv_out_mat1, cv_out_mat2, cv_out_mat3;
cv::resize(in_mat1, cv_out_mat1, szOut);
cv::resize(in_mat2, cv_out_mat2, szOut);
cv::resize(in_mat3, cv_out_mat3, szOut);
EXPECT_EQ(0, cv::countNonZero(out_mat1 != cv_out_mat1));
EXPECT_EQ(0, cv::countNonZero(out_mat2 != cv_out_mat2));
EXPECT_EQ(0, cv::countNonZero(out_mat3 != cv_out_mat3));
}
TEST(GComputationCompile, ReshapeBlur)
{
cv::Size kernelSize{3, 3};
cv::GMat in;
cv::GComputation cc(in, cv::gapi::blur(in, kernelSize));
cv::Mat in_mat1( 8, 8, CV_8UC1);
cv::Mat in_mat2(16, 16, CV_8UC1);
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
cv::Mat out_mat1, out_mat2;
cc.apply(in_mat1, out_mat1, cv::compile_args(cv::gapi::imgproc::fluid::kernels()));
auto comp1 = cc.priv().m_lastCompiled;
cc.apply(in_mat2, out_mat2);
auto comp2 = cc.priv().m_lastCompiled;
// Both compiled objects are actually the same unique executable
EXPECT_EQ(&comp1.priv(), &comp2.priv());
cv::Mat cv_out_mat1, cv_out_mat2;
cv::blur(in_mat1, cv_out_mat1, kernelSize);
cv::blur(in_mat2, cv_out_mat2, kernelSize);
EXPECT_EQ(0, cv::countNonZero(out_mat1 != cv_out_mat1));
EXPECT_EQ(0, cv::countNonZero(out_mat2 != cv_out_mat2));
}
TEST(GComputationCompile, ReshapeRois)
{
cv::Size kernelSize{3, 3};
cv::Size szOut(8, 8);
cv::GMat in;
auto blurred = cv::gapi::blur(in, kernelSize);
cv::GComputation cc(in, cv::gapi::resize(blurred, szOut));
cv::Mat first_in_mat(8, 8, CV_8UC3);
cv::randn(first_in_mat, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::Mat first_out_mat;
auto fluidKernels = cv::gapi::combine(gapi::imgproc::fluid::kernels(),
gapi::core::fluid::kernels());
cc.apply(first_in_mat, first_out_mat, cv::compile_args(fluidKernels));
auto first_comp = cc.priv().m_lastCompiled;
constexpr int niter = 4;
for (int i = 0; i < niter; i++)
{
int width = 4 + 2*i;
int height = width;
cv::Mat in_mat(width, height, CV_8UC3);
cv::randn(in_mat, cv::Scalar::all(127), cv::Scalar::all(40.f));
cv::Mat out_mat = cv::Mat::zeros(szOut, CV_8UC3);
int x = 0;
int y = szOut.height * i / niter;
int roiW = szOut.width;
int roiH = szOut.height / niter;
cv::Rect roi{x, y, roiW, roiH};
cc.apply(in_mat, out_mat, cv::compile_args(cv::GFluidOutputRois{{to_own(roi)}}));
auto comp = cc.priv().m_lastCompiled;
EXPECT_EQ(&first_comp.priv(), &comp.priv());
cv::Mat blur_mat, cv_out_mat;
cv::blur(in_mat, blur_mat, kernelSize);
cv::resize(blur_mat, cv_out_mat, szOut);
EXPECT_EQ(0, cv::countNonZero(out_mat(roi) != cv_out_mat(roi)));
}
}
} // opencv_test

View File

@@ -0,0 +1,207 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
namespace opencv_test
{
typedef ::testing::Types<int, cv::Point, cv::Rect> VectorRef_Test_Types;
template<typename T> struct VectorRefT: public ::testing::Test { using Type = T; };
TYPED_TEST_CASE(VectorRefT, VectorRef_Test_Types);
TYPED_TEST(VectorRefT, Reset_Valid)
{
using T = typename TestFixture::Type;
cv::detail::VectorRefT<T> ref; // vector ref created empty
EXPECT_NO_THROW(ref.reset()); // 1st reset is OK (initializes)
EXPECT_NO_THROW(ref.reset()); // 2nd reset is also OK (resets)
}
TYPED_TEST(VectorRefT, Reset_Invalid)
{
using T = typename TestFixture::Type;
std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRefT<T> ref(vec); // RO_EXT (since reference is const)
EXPECT_ANY_THROW(ref.reset()); // data-bound vector ref can't be reset
}
TYPED_TEST(VectorRefT, ReadRef_External)
{
using T = typename TestFixture::Type;
const std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRefT<T> ref(vec); // RO_EXT (since reference is const)
auto &vref = ref.rref();
EXPECT_EQ(vec.data(), vref.data());
EXPECT_EQ(vec.size(), vref.size());
}
TYPED_TEST(VectorRefT, ReadRef_Internal)
{
using T = typename TestFixture::Type;
cv::detail::VectorRefT<T> ref;
ref.reset(); // RW_OWN (reset on empty ref)
auto &vref = ref.rref(); // read access is valid for RW_OWN
EXPECT_EQ(0u, vref.size()); // by default vector is empty
}
TYPED_TEST(VectorRefT, WriteRef_External)
{
using T = typename TestFixture::Type;
std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRefT<T> ref(vec); // RW_EXT (since reference is not const)
auto &vref = ref.wref(); // write access is valid with RW_EXT
EXPECT_EQ(vec.data(), vref.data());
EXPECT_EQ(vec.size(), vref.size());
}
TYPED_TEST(VectorRefT, WriteRef_Internal)
{
using T = typename TestFixture::Type;
cv::detail::VectorRefT<T> ref;
ref.reset(); // RW_OWN (reset on empty ref)
auto &vref = ref.wref(); // write access is valid for RW_OWN
EXPECT_EQ(0u, vref.size()); // empty vector by default
}
TYPED_TEST(VectorRefT, WriteToRO)
{
using T = typename TestFixture::Type;
const std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRefT<T> ref(vec); // RO_EXT (since reference is const)
EXPECT_ANY_THROW(ref.wref());
}
TYPED_TEST(VectorRefT, ReadAfterWrite)
{
using T = typename TestFixture::Type;
std::vector<T> vec; // Initial data holder (empty vector)
cv::detail::VectorRefT<T> writer(vec); // RW_EXT
const auto& ro_ref = vec;
cv::detail::VectorRefT<T> reader(ro_ref); // RO_EXT
EXPECT_EQ(0u, writer.wref().size()); // Check the initial state
EXPECT_EQ(0u, reader.rref().size());
writer.wref().emplace_back(); // Check that write is successful
EXPECT_EQ(1u, writer.wref().size());
EXPECT_EQ(1u, vec.size()); // Check that changes are reflected to the original container
EXPECT_EQ(1u, reader.rref().size()); // Check that changes are reflected to reader's view
EXPECT_EQ(T(), vec.at(0)); // Check the value (must be default-initialized)
EXPECT_EQ(T(), reader.rref().at(0));
EXPECT_EQ(T(), writer.wref().at(0));
}
template<typename T> struct VectorRefU: public ::testing::Test { using Type = T; };
TYPED_TEST_CASE(VectorRefU, VectorRef_Test_Types);
template<class T> struct custom_struct { T a; T b; };
TYPED_TEST(VectorRefU, Reset_Valid)
{
using T = typename TestFixture::Type;
cv::detail::VectorRef ref; // vector ref created empty
EXPECT_NO_THROW(ref.reset<T>()); // 1st reset is OK (initializes)
EXPECT_NO_THROW(ref.reset<T>()); // 2nd reset is also OK (resets)
EXPECT_ANY_THROW(ref.reset<custom_struct<T> >()); // type change is not allowed
}
TYPED_TEST(VectorRefU, Reset_Invalid)
{
using T = typename TestFixture::Type;
std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRef ref(vec); // RO_EXT (since reference is const)
EXPECT_ANY_THROW(ref.reset<T>()); // data-bound vector ref can't be reset
}
TYPED_TEST(VectorRefU, ReadRef_External)
{
using T = typename TestFixture::Type;
const std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRef ref(vec); // RO_EXT (since reference is const)
auto &vref = ref.rref<T>();
EXPECT_EQ(vec.data(), vref.data());
EXPECT_EQ(vec.size(), vref.size());
}
TYPED_TEST(VectorRefU, ReadRef_Internal)
{
using T = typename TestFixture::Type;
cv::detail::VectorRef ref;
ref.reset<T>(); // RW_OWN (reset on empty ref)
auto &vref = ref.rref<T>(); // read access is valid for RW_OWN
EXPECT_EQ(0u, vref.size()); // by default vector is empty
}
TYPED_TEST(VectorRefU, WriteRef_External)
{
using T = typename TestFixture::Type;
std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRef ref(vec); // RW_EXT (since reference is not const)
auto &vref = ref.wref<T>(); // write access is valid with RW_EXT
EXPECT_EQ(vec.data(), vref.data());
EXPECT_EQ(vec.size(), vref.size());
}
TYPED_TEST(VectorRefU, WriteRef_Internal)
{
using T = typename TestFixture::Type;
cv::detail::VectorRef ref;
ref.reset<T>(); // RW_OWN (reset on empty ref)
auto &vref = ref.wref<T>(); // write access is valid for RW_OWN
EXPECT_EQ(0u, vref.size()); // empty vector by default
}
TYPED_TEST(VectorRefU, WriteToRO)
{
using T = typename TestFixture::Type;
const std::vector<T> vec(42); // create a std::vector of 42 elements
cv::detail::VectorRef ref(vec); // RO_EXT (since reference is const)
EXPECT_ANY_THROW(ref.wref<T>());
}
TYPED_TEST(VectorRefU, ReadAfterWrite)
{
using T = typename TestFixture::Type;
std::vector<T> vec; // Initial data holder (empty vector)
cv::detail::VectorRef writer(vec); // RW_EXT
const auto& ro_ref = vec;
cv::detail::VectorRef reader(ro_ref); // RO_EXT
EXPECT_EQ(0u, writer.wref<T>().size()); // Check the initial state
EXPECT_EQ(0u, reader.rref<T>().size());
writer.wref<T>().emplace_back(); // Check that write is successful
EXPECT_EQ(1u, writer.wref<T>().size());
EXPECT_EQ(1u, vec.size()); // Check that changes are reflected to the original container
EXPECT_EQ(1u, reader.rref<T>().size()); // Check that changes are reflected to reader's view
EXPECT_EQ(T(), vec.at(0)); // Check the value (must be default-initialized)
EXPECT_EQ(T(), reader.rref<T>().at(0));
EXPECT_EQ(T(), writer.wref<T>().at(0));
}
TEST(VectorRefU, TypeCheck)
{
cv::detail::VectorRef ref;
ref.reset<int>(); // RW_OWN
EXPECT_ANY_THROW(ref.reset<char>());
EXPECT_ANY_THROW(ref.rref<char>());
EXPECT_ANY_THROW(ref.wref<char>());
}
} // namespace opencv_test

View File

@@ -0,0 +1,222 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <ade/graph.hpp>
#include "compiler/transactions.hpp"
namespace opencv_test
{
namespace
{
bool contains(const ade::Graph& graph, const ade::NodeHandle& node)
{
auto nodes = graph.nodes();
return nodes.end() != std::find(nodes.begin(), nodes.end(), node);
}
bool connected(const ade::NodeHandle& src_node, const ade::NodeHandle& dst_node)
{
auto nodes = src_node->outNodes();
return nodes.end() != std::find(nodes.begin(), nodes.end(), dst_node);
}
struct SimpleGraph
{
// ehs[0] ehs[1] ehs[2] ehs[3]
// nhs[0] -- > nhs[1] --> nhs[2] --> nhs[3] --> nhs[4]
enum { node_nums = 5 };
ade::Graph graph;
ade::NodeHandle fused_nh; /* For check that fusion node is connected to the
inputs of the prod and the outputs of the cons */
std::array<ade::NodeHandle, node_nums> nhs;
std::array<ade::EdgeHandle, node_nums - 1> ehs;
Change::List changes;
SimpleGraph()
{
nhs[0] = graph.createNode();
for (int i = 1; i < node_nums; ++i)
{
nhs[i ] = graph.createNode();
ehs[i - 1] = graph.link(nhs[i - 1], nhs[i]);
}
}
void fuse()
{
// nhs[0] --> fused_nh --> nhs[4]
fused_nh = graph.createNode();
changes.enqueue<Change::NodeCreated>(fused_nh);
changes.enqueue<Change::NewLink> (graph, nhs[0], fused_nh);
changes.enqueue<Change::DropLink>(graph, nhs[1], ehs[0]);
changes.enqueue<Change::NewLink> (graph, fused_nh, nhs[4]);
changes.enqueue<Change::DropLink>(graph, nhs[3], ehs[3]);
changes.enqueue<Change::DropLink>(graph, nhs[1], ehs[1]);
changes.enqueue<Change::DropLink>(graph, nhs[2], ehs[2]);
changes.enqueue<Change::DropNode>(nhs[1]);
changes.enqueue<Change::DropNode>(nhs[2]);
changes.enqueue<Change::DropNode>(nhs[3]);
}
void commit() { changes.commit(graph); }
void rollback() { changes.rollback(graph); }
};
struct Transactions: public ::testing::Test, public SimpleGraph {};
} // anonymous namespace
TEST_F(Transactions, NodeCreated_Create)
{
auto new_nh = graph.createNode();
Change::NodeCreated node_created(new_nh);
EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
EXPECT_TRUE(contains(graph, new_nh));
}
TEST_F(Transactions, NodeCreated_RollBack)
{
auto new_nh = graph.createNode();
Change::NodeCreated node_created(new_nh);
node_created.rollback(graph);
EXPECT_EQ(5u, static_cast<std::size_t>(graph.nodes().size()));
EXPECT_FALSE(contains(graph, new_nh));
}
TEST_F(Transactions, NodeCreated_Commit)
{
auto new_nh = graph.createNode();
Change::NodeCreated node_created(new_nh);
node_created.commit(graph);
EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
EXPECT_TRUE(contains(graph, new_nh));
}
TEST_F(Transactions, DropLink_Create)
{
Change::DropLink drop_link(graph, nhs[0], ehs[0]);
EXPECT_FALSE(connected(nhs[0], nhs[1]));
}
TEST_F(Transactions, DropLink_RollBack)
{
Change::DropLink drop_link(graph, nhs[0], ehs[0]);
drop_link.rollback(graph);
EXPECT_TRUE(connected(nhs[0], nhs[1]));
}
TEST_F(Transactions, DropLink_Commit)
{
Change::DropLink drop_link(graph, nhs[0], ehs[0]);
drop_link.commit(graph);
EXPECT_FALSE(connected(nhs[0], nhs[1]));
}
TEST_F(Transactions, NewLink_Create)
{
auto new_nh = graph.createNode();
Change::NewLink new_link(graph, new_nh, nhs[0]);
EXPECT_TRUE(connected(new_nh, nhs[0]));
}
TEST_F(Transactions, NewLink_RollBack)
{
auto new_nh = graph.createNode();
Change::NewLink new_link(graph, new_nh, nhs[0]);
new_link.rollback(graph);
EXPECT_FALSE(connected(new_nh, nhs[0]));
}
TEST_F(Transactions, NewLink_Commit)
{
auto new_nh = graph.createNode();
Change::NewLink new_link(graph, new_nh, nhs[0]);
new_link.commit(graph);
EXPECT_TRUE(connected(new_nh, nhs[0]));
}
TEST_F(Transactions, DropNode_Create)
{
auto new_nh = graph.createNode();
Change::DropNode drop_node(new_nh);
EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
EXPECT_TRUE(contains(graph, new_nh));
}
TEST_F(Transactions, DropNode_RollBack)
{
auto new_nh = graph.createNode();
Change::DropNode drop_node(new_nh);
drop_node.rollback(graph);
EXPECT_EQ(6u, static_cast<std::size_t>(graph.nodes().size()));
EXPECT_TRUE(contains(graph, new_nh));
}
TEST_F(Transactions, DropNode_Commit)
{
auto new_nh = graph.createNode();
Change::DropNode drop_node(new_nh);
drop_node.commit(graph);
EXPECT_EQ(5u, static_cast<std::size_t>(graph.nodes().size()));
EXPECT_FALSE(contains(graph, new_nh));
}
TEST_F(Transactions, Fusion_Commit)
{
namespace C = Change;
fuse();
commit();
EXPECT_EQ(3u, static_cast<std::size_t>(graph.nodes().size()));
EXPECT_TRUE(connected(nhs[0] , fused_nh));
EXPECT_TRUE(connected(fused_nh, nhs[4]));
}
TEST_F(Transactions, Fusion_RollBack)
{
namespace C = Change;
fuse();
rollback();
EXPECT_EQ(static_cast<std::size_t>(node_nums),
static_cast<std::size_t>(graph.nodes().size()));
EXPECT_FALSE(contains(graph, fused_nh));
for (int i = 0; i < static_cast<int>(node_nums) - 1; ++i)
{
EXPECT_TRUE(connected(nhs[i], nhs[i + 1]));
}
}
} // opencv_test

View File

@@ -0,0 +1,260 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include <opencv2/core/ocl.hpp>
#include <opencv2/core/ocl_genbase.hpp>
#include <opencv2/core/opencl/ocl_defs.hpp>
#ifdef HAVE_OPENCL
const char* opencl_symm7x7_src =
"#if BORDER_REPLICATE\n"
"#define GET_BORDER(elem) (elem)\n"
"#define SET_ALL(i, j) a0[i] = a0[j]; a1[i] = a1[j]; a2[i] = a2[j]; b[i] = b[j]; c0[i] = c0[j]; c1[i] = c1[j]; c2[i] = c2[j];\n"
"#else\n"
"#define GET_BORDER(elem) (BORDER_CONSTANT_VALUE)\n"
"#define SET_ALL(i, j) a0[i] = a1[i] = a2[i] = c0[i] = c1[i] = c2[i] = BORDER_CONSTANT_VALUE; b[i] = BORDER_CONSTANT_VALUE;\n"
"#endif\n"
"#define GET_A0(id, x, l_edge, a1) ((x) <= (l_edge + 2) ? GET_BORDER(a1) : (((const __global uchar*)(id))[-3]))\n"
"#define GET_A1(id, x, l_edge, a2) ((x) <= (l_edge + 1) ? GET_BORDER(a2) : (((const __global uchar*)(id))[-2]))\n"
"#define GET_A2(id, x, l_edge, b) ((x) <= (l_edge) ? GET_BORDER(b[0]) : (((const __global uchar*)(id))[-1]))\n"
"#define GET_C0(id, x, r_edge, b) ((x) >= (r_edge) ? GET_BORDER(b[8 - 1]) : (((const __global uchar*)(id))[8]))\n"
"#define GET_C1(id, x, r_edge, c0) ((x) >= (r_edge - 1) ? GET_BORDER(c0) : (((const __global uchar*)(id))[8 + 1]))\n"
"#define GET_C2(id, x, r_edge, c1) ((x) >= (r_edge - 2) ? GET_BORDER(c1) : (((const __global uchar*)(id))[8 + 2]))\n"
"__kernel void symm_7x7_test(\n"
"__global const uchar * srcptr,\n"
"int srcStep, int srcEndX, int srcEndY,\n"
"__global uchar * dstptr, int dstStep,\n"
"int rows, int cols,\n"
"int tile_y_coord,\n"
"__constant int * coeff)\n"
"{\n"
"int lEdge = 0, rEdge = cols - 8;\n"
"int x = (get_global_id(0) < cols/8) ? get_global_id(0) * 8: cols - 8;\n"
"int y = get_global_id(1);\n"
"int yd = min(3, tile_y_coord);\n"
"int dst_id = mad24(y, dstStep, x);\n"
"y+=yd;\n"
"int src_id = mad24(y, srcStep, x);\n"
"int y_limit = y + tile_y_coord;\n"
"y_limit-=yd;\n"
"const __global uchar* psrc = (const __global uchar*)(srcptr + src_id);\n"
"__global uchar* pdst = (__global uchar*)(dstptr + dst_id);\n"
"#define BSIZE (7)\n"
"float a0[BSIZE]; float a1[BSIZE]; float a2[BSIZE];\n"
"float8 b[BSIZE];\n"
"float c0[BSIZE]; float c1[BSIZE]; float c2[BSIZE];\n"
"b[3] = convert_float8(vload8(0, (const __global uchar*)psrc));\n"
"if( (y_limit <=2 ) || (y_limit >= srcEndY - 3) || (x >= rEdge-2) || (x <= lEdge + 2) )\n"
"{\n"
"a2[3] = GET_A2(psrc, x, lEdge, b[3]);\n"
"a1[3] = GET_A1(psrc, x, lEdge, a2[3]);\n"
"a0[3] = GET_A0(psrc, x, lEdge, a1[3]);\n"
"c0[3] = GET_C0(psrc, x, rEdge, b[3]);\n"
"c1[3] = GET_C1(psrc, x, rEdge, c0[3]);\n"
"c2[3] = GET_C2(psrc, x, rEdge, c1[3]);\n"
"if(y_limit > 0)\n"
"{\n"
"b[2] = convert_float8(vload8(0, (const __global uchar*)(psrc - srcStep)));\n"
"a2[2] = GET_A2(psrc - srcStep, x, lEdge, b[2]);\n"
"a1[2] = GET_A1(psrc - srcStep, x, lEdge, a2[2]);\n"
"a0[2] = GET_A0(psrc - srcStep, x, lEdge, a1[2]);\n"
"c0[2] = GET_C0(psrc - srcStep, x, rEdge, b[2]);\n"
"c1[2] = GET_C1(psrc - srcStep, x, rEdge, c0[2]);\n"
"c2[2] = GET_C2(psrc - srcStep, x, rEdge, c1[2]);\n"
"}\n"
"else\n"
"{\n"
"SET_ALL(2, 3);\n"
"}\n"
"if( y_limit > 1 )\n"
"{\n"
"b[1] = convert_float8(vload8(0, (const __global uchar*)(psrc - srcStep*2)));\n"
"a2[1] = GET_A2(psrc - srcStep*2, x, lEdge, b[1]);\n"
"a1[1] = GET_A1(psrc - srcStep*2, x, lEdge, a2[1]);\n"
"a0[1] = GET_A0(psrc - srcStep*2, x, lEdge, a1[1]);\n"
"c0[1] = GET_C0(psrc - srcStep*2, x, rEdge, b[1]);\n"
"c1[1] = GET_C1(psrc - srcStep*2, x, rEdge, c0[1]);\n"
"c2[1] = GET_C2(psrc - srcStep*2, x, rEdge, c1[1]);\n"
"}\n"
"else\n"
"{\n"
"SET_ALL(1, 2);\n"
"}\n"
"if( y_limit > 2 )\n"
"{\n"
"b[0] = convert_float8(vload8(0, (const __global uchar*)(psrc - srcStep*3)));\n"
"a2[0] = GET_A2(psrc - srcStep*3, x, lEdge, b[0]);\n"
"a1[0] = GET_A1(psrc - srcStep*3, x, lEdge, a2[0]);\n"
"a0[0] = GET_A0(psrc - srcStep*3, x, lEdge, a1[0]);\n"
"c0[0] = GET_C0(psrc - srcStep*3, x, rEdge, b[0]);\n"
"c1[0] = GET_C1(psrc - srcStep*3, x, rEdge, c0[0]);\n"
"c2[0] = GET_C2(psrc - srcStep*3, x, rEdge, c1[0]);\n"
"}\n"
"else\n"
"{\n"
"SET_ALL(0, 1);\n"
"}\n"
"if( y_limit < srcEndY - 1 )\n"
"{\n"
"b[4] = convert_float8(vload8(0, (const __global uchar*)(psrc + srcStep)));\n"
"a2[4] = GET_A2(psrc + srcStep, x, lEdge, b[4]);\n"
"a1[4] = GET_A1(psrc + srcStep, x, lEdge, a2[4]);\n"
"a0[4] = GET_A0(psrc + srcStep, x, lEdge, a1[4]);\n"
"c0[4] = GET_C0(psrc + srcStep, x, rEdge, b[4]);\n"
"c1[4] = GET_C1(psrc + srcStep, x, rEdge, c0[4]);\n"
"c2[4] = GET_C2(psrc + srcStep, x, rEdge, c1[4]);\n"
"}\n"
"else\n"
"{\n"
"SET_ALL(4, 3);\n"
"}\n"
"if( y_limit < srcEndY - 2 )\n"
"{\n"
"b[5] = convert_float8(vload8(0, (const __global uchar*)(psrc + srcStep*2)));\n"
"a2[5] = GET_A2(psrc + srcStep*2, x, lEdge, b[5]);\n"
"a1[5] = GET_A1(psrc + srcStep*2, x, lEdge, a2[5]);\n"
"a0[5] = GET_A0(psrc + srcStep*2, x, lEdge, a1[5]);\n"
"c0[5] = GET_C0(psrc + srcStep*2, x, rEdge, b[5]);\n"
"c1[5] = GET_C1(psrc + srcStep*2, x, rEdge, c0[5]);\n"
"c2[5] = GET_C2(psrc + srcStep*2, x, rEdge, c1[5]);\n"
"}\n"
"else\n"
"{\n"
"SET_ALL(5, 4);\n"
"}\n"
"if( y_limit < srcEndY - 3 )\n"
"{\n"
"b[6] = convert_float8(vload8(0, (const __global uchar*)(psrc + srcStep*3)));\n"
"a2[6] = GET_A2(psrc + srcStep*3, x, lEdge, b[6]);\n"
"a1[6] = GET_A1(psrc + srcStep*3, x, lEdge, a2[6]);\n"
"a0[6] = GET_A0(psrc + srcStep*3, x, lEdge, a1[6]);\n"
"c0[6] = GET_C0(psrc + srcStep*3, x, rEdge, b[6]);\n"
"c1[6] = GET_C1(psrc + srcStep*3, x, rEdge, c0[6]);\n"
"c2[6] = GET_C2(psrc + srcStep*3, x, rEdge, c1[6]);\n"
"}\n"
"else\n"
"{\n"
"SET_ALL(6, 5);\n"
"}\n"
"}\n"
"else\n"
"{\n"
"a2[3] = (((const __global uchar*)(psrc))[-1]);\n"
"a1[3] = (((const __global uchar*)(psrc))[-2]);\n"
"a0[3] = (((const __global uchar*)(psrc))[-3]);\n"
"c0[3] = (((const __global uchar*)(psrc))[8]);\n"
"c1[3] = (((const __global uchar*)(psrc))[8 + 1]);\n"
"c2[3] = (((const __global uchar*)(psrc))[8 + 2]);\n"
"b[2] = convert_float8(vload8(0, (const __global uchar*)(psrc - srcStep)));\n"
"a2[2] = (((const __global uchar*)(psrc - srcStep))[-1]);\n"
"a1[2] = (((const __global uchar*)(psrc - srcStep))[-2]);\n"
"a0[2] = (((const __global uchar*)(psrc - srcStep))[-3]);\n"
"c0[2] = (((const __global uchar*)(psrc - srcStep))[8]);\n"
"c1[2] = (((const __global uchar*)(psrc - srcStep))[8 + 1]);\n"
"c2[2] = (((const __global uchar*)(psrc - srcStep))[8 + 2]);\n"
"b[1] = convert_float8(vload8(0, (const __global uchar*)(psrc - srcStep*2)));\n"
"a2[1] = (((const __global uchar*)(psrc - srcStep*2))[-1]);\n"
"a1[1] = (((const __global uchar*)(psrc - srcStep*2))[-2]);\n"
"a0[1] = (((const __global uchar*)(psrc - srcStep*2))[-3]);\n"
"c0[1] = (((const __global uchar*)(psrc - srcStep*2))[8]);\n"
"c1[1] = (((const __global uchar*)(psrc - srcStep*2))[8 + 1]);\n"
"c2[1] = (((const __global uchar*)(psrc - srcStep*2))[8 + 2]);\n"
"b[0] = convert_float8(vload8(0, (const __global uchar*)(psrc - srcStep*3)));\n"
"a2[0] = (((const __global uchar*)(psrc - srcStep*3))[-1]);\n"
"a1[0] = (((const __global uchar*)(psrc - srcStep*3))[-2]);\n"
"a0[0] = (((const __global uchar*)(psrc - srcStep*3))[-3]);\n"
"c0[0] = (((const __global uchar*)(psrc - srcStep*3))[8]);\n"
"c1[0] = (((const __global uchar*)(psrc - srcStep*3))[8 + 1]);\n"
"c2[0] = (((const __global uchar*)(psrc - srcStep*3))[8 + 2]);\n"
"b[4] = convert_float8(vload8(0, (const __global uchar*)(psrc + srcStep)));\n"
"a2[4] = (((const __global uchar*)(psrc + srcStep))[-1]);\n"
"a1[4] = (((const __global uchar*)(psrc + srcStep))[-2]);\n"
"a0[4] = (((const __global uchar*)(psrc + srcStep))[-3]);\n"
"c0[4] = (((const __global uchar*)(psrc + srcStep))[8]);\n"
"c1[4] = (((const __global uchar*)(psrc + srcStep))[8 + 1]);\n"
"c2[4] = (((const __global uchar*)(psrc + srcStep))[8 + 2]);\n"
"b[5] = convert_float8(vload8(0, (const __global uchar*)(psrc + srcStep*2)));\n"
"a2[5] = (((const __global uchar*)(psrc + srcStep*2))[-1]);\n"
"a1[5] = (((const __global uchar*)(psrc + srcStep*2))[-2]);\n"
"a0[5] = (((const __global uchar*)(psrc + srcStep*2))[-3]);\n"
"c0[5] = (((const __global uchar*)(psrc + srcStep*2))[8]);\n"
"c1[5] = (((const __global uchar*)(psrc + srcStep*2))[8 + 1]);\n"
"c2[5] = (((const __global uchar*)(psrc + srcStep*2))[8 + 2]);\n"
"b[6] = convert_float8(vload8(0, (const __global uchar*)(psrc + srcStep*3)));\n"
"a2[6] = (((const __global uchar*)(psrc + srcStep*3))[-1]);\n"
"a1[6] = (((const __global uchar*)(psrc + srcStep*3))[-2]);\n"
"a0[6] = (((const __global uchar*)(psrc + srcStep*3))[-3]);\n"
"c0[6] = (((const __global uchar*)(psrc + srcStep*3))[8]);\n"
"c1[6] = (((const __global uchar*)(psrc + srcStep*3))[8 + 1]);\n"
"c2[6] = (((const __global uchar*)(psrc + srcStep*3))[8 + 2]);\n"
"}\n"
"float a0_sum[3]; float a1_sum[3]; float a2_sum[3];\n"
"float8 b_sum[3];\n"
"float c0_sum[3]; float c1_sum[3]; float c2_sum[3];\n"
"a0_sum[0] = a0[0] + a0[6];\n"
"a0_sum[1] = a0[1] + a0[5];\n"
"a0_sum[2] = a0[2] + a0[4];\n"
"a1_sum[0] = a1[0] + a1[6];\n"
"a1_sum[1] = a1[1] + a1[5];\n"
"a1_sum[2] = a1[2] + a1[4];\n"
"a2_sum[0] = a2[0] + a2[6];\n"
"a2_sum[1] = a2[1] + a2[5];\n"
"a2_sum[2] = a2[2] + a2[4];\n"
"c0_sum[0] = c0[0] + c0[6];\n"
"c0_sum[1] = c0[1] + c0[5];\n"
"c0_sum[2] = c0[2] + c0[4];\n"
"c1_sum[0] = c1[0] + c1[6];\n"
"c1_sum[1] = c1[1] + c1[5];\n"
"c1_sum[2] = c1[2] + c1[4];\n"
"c2_sum[0] = c2[0] + c2[6];\n"
"c2_sum[1] = c2[1] + c2[5];\n"
"c2_sum[2] = c2[2] + c2[4];\n"
"b_sum[0] = b[0] + b[6];\n"
"b_sum[1] = b[1] + b[5];\n"
"b_sum[2] = b[2] + b[4];\n"
"float8 A = b[3];\n"
"float8 intermediate = A * (float)coeff[0];\n"
"float8 B = b_sum[2] +\n"
"(float8)(a2[3], b[3].s0123, b[3].s456) +\n"
"(float8)(b[3].s123, b[3].s4567, c0[3]);\n"
"intermediate += B * (float)coeff[1];\n"
"float8 C = (float8)(a2_sum[2], b_sum[2].s0123, b_sum[2].s456) +\n"
"(float8)(b_sum[2].s123, b_sum[2].s4567, c0_sum[2]);\n"
"intermediate += C * (float)coeff[2];\n"
"float8 D = b_sum[1] +\n"
"(float8)(a1[3], a2[3], b[3].s0123, b[3].s45) +\n"
"(float8)(b[3].s23, b[3].s4567, c0[3], c1[3]);\n"
"intermediate += D * (float)coeff[3];\n"
"float8 E = (float8)(a2_sum[1], b_sum[1].s0123, b_sum[1].s456) +\n"
"(float8)( b_sum[1].s123, b_sum[1].s4567, c0_sum[1]) +\n"
"(float8)( a1_sum[2], a2_sum[2], b_sum[2].s0123, b_sum[2].s45) +\n"
"(float8)( b_sum[2].s23, b_sum[2].s4567, c0_sum[2], c1_sum[2]);\n"
"intermediate += E * (float)coeff[4];\n"
"float8 F = (float8)(a1_sum[1], a2_sum[1], b_sum[1].s0123, b_sum[1].s45) +\n"
"(float8)(b_sum[1].s23, b_sum[1].s4567, c0_sum[1], c1_sum[1]);\n"
"intermediate += F * (float)coeff[5];\n"
"float8 G = b_sum[0] +\n"
"(float8)(a0[3], a1[3], a2[3], b[3].s0123, b[3].s4) +\n"
"(float8)(b[3].s3, b[3].s4567, c0[3], c1[3], c2[3]);\n"
"intermediate += G * (float)coeff[6];\n"
"float8 H = (float8)(a2_sum[0], b_sum[0].s0123, b_sum[0].s456) +\n"
"(float8)(b_sum[0].s123, b_sum[0].s4567, c0_sum[0]) +\n"
"(float8)(a0_sum[2], a1_sum[2], a2_sum[2], b_sum[2].s0123, b_sum[2].s4) +\n"
"(float8)(b_sum[2].s3, b_sum[2].s4567, c0_sum[2], c1_sum[2], c2_sum[2]);\n"
"intermediate += H * (float)coeff[7];\n"
"float8 I = (float8)(a1_sum[0], a2_sum[0], b_sum[0].s0123, b_sum[0].s45) +\n"
"(float8)(b_sum[0].s23, b_sum[0].s4567, c0_sum[0], c1_sum[0]) +\n"
"(float8)(a0_sum[1], a1_sum[1], a2_sum[1], b_sum[1].s0123, b_sum[1].s4) +\n"
"(float8)(b_sum[1].s3, b_sum[1].s4567, c0_sum[1], c1_sum[1], c2_sum[1]);\n"
"intermediate += I * (float)coeff[8];\n"
"float8 J = (float8)(a0_sum[0], a1_sum[0], a2_sum[0], b_sum[0].s0123, b_sum[0].s4) +\n"
"(float8)(b_sum[0].s3, b_sum[0].s4567, c0_sum[0], c1_sum[0], c2_sum[0]);\n"
"intermediate += J * (float)coeff[9];\n"
"intermediate *= SCALE;\n"
"vstore8(convert_uchar8_sat(intermediate), 0, (__global uchar*)(pdst));\n"
"}\n"
;
#endif

View File

@@ -0,0 +1,197 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "../test_precomp.hpp"
#include <unordered_set>
#include <thread>
#include "executor/conc_queue.hpp"
namespace opencv_test
{
using namespace cv::gapi;
TEST(ConcQueue, PushPop)
{
own::concurrent_bounded_queue<int> q;
for (int i = 0; i < 100; i++)
{
q.push(i);
}
for (int i = 0; i < 100; i++)
{
int x;
q.pop(x);
EXPECT_EQ(x, i);
}
}
TEST(ConcQueue, TryPop)
{
own::concurrent_bounded_queue<int> q;
int x = 0;
EXPECT_FALSE(q.try_pop(x));
q.push(1);
EXPECT_TRUE(q.try_pop(x));
EXPECT_EQ(1, x);
}
TEST(ConcQueue, Clear)
{
own::concurrent_bounded_queue<int> q;
for (int i = 0; i < 10; i++)
{
q.push(i);
}
q.clear();
int x = 0;
EXPECT_FALSE(q.try_pop(x));
}
// In this test, every writer thread produce its own range of integer
// numbers, writing those to a shared queue.
//
// Every reader thread pops elements from the queue (until -1 is
// reached) and stores those in its own associated set.
//
// Finally, the master thread waits for completion of all other
// threads and verifies that all the necessary data is
// produced/obtained.
using StressParam = std::tuple<int // Num writer threads
,int // Num elements per writer
,int // Num reader threads
,std::size_t>; // Queue capacity
namespace
{
constexpr int STOP_SIGN = -1;
constexpr int BASE = 1000;
}
struct ConcQueue_: public ::testing::TestWithParam<StressParam>
{
using Q = own::concurrent_bounded_queue<int>;
using S = std::unordered_set<int>;
static void writer(int base, int writes, Q& q)
{
for (int i = 0; i < writes; i++)
{
q.push(base + i);
}
q.push(STOP_SIGN);
}
static void reader(Q& q, S& s)
{
int x = 0;
while (true)
{
q.pop(x);
if (x == STOP_SIGN) return;
s.insert(x);
}
}
};
TEST_P(ConcQueue_, Test)
{
int num_writers = 0;
int num_writes = 0;
int num_readers = 0;
std::size_t capacity = 0u;
std::tie(num_writers, num_writes, num_readers, capacity) = GetParam();
CV_Assert(num_writers < 20);
CV_Assert(num_writes < BASE);
Q q;
if (capacity)
{
// see below (2)
CV_Assert(static_cast<int>(capacity) > (num_writers - num_readers));
q.set_capacity(capacity);
}
// Start reader threads
std::vector<S> storage(num_readers);
std::vector<std::thread> readers;
for (S& s : storage)
{
readers.emplace_back(reader, std::ref(q), std::ref(s));
}
// Start writer threads, also pre-generate reference numbers
S reference;
std::vector<std::thread> writers;
for (int w = 0; w < num_writers; w++)
{
writers.emplace_back(writer, w*BASE, num_writes, std::ref(q));
for (int r = 0; r < num_writes; r++)
{
reference.insert(w*BASE + r);
}
}
// Every writer puts a STOP_SIGN at the end,
// There are three cases:
// 1) num_writers == num_readers
// every reader should get its own STOP_SIGN from any
// of the writers
//
// 2) num_writers > num_readers
// every reader will get a STOP_SIGN but there're more
// STOP_SIGNs may be pushed to the queue - and if this
// number exceeds capacity, writers block (to a deadlock).
// The latter situation must be avoided at parameters level.
// [a] Also not every data produced by writers will be consumed
// by a reader in this case. Master thread will read the rest
//
// 3) num_readers > num_writers
// in this case, some readers will stuck and will never get
// a STOP_SIGN. Master thread will push extra STOP_SIGNs to the
// queue.
// Solution to (2a)
S remnants;
if (num_writers > num_readers)
{
int extra = num_writers - num_readers;
while (extra)
{
int x = 0;
q.pop(x);
if (x == STOP_SIGN) extra--;
else remnants.insert(x);
}
}
// Solution to (3)
if (num_readers > num_writers)
{
int extra = num_readers - num_writers;
while (extra--) q.push(STOP_SIGN);
}
// Wait for completions
for (auto &t : readers) t.join();
for (auto &t : writers) t.join();
// Accumulate and validate the result
S result(remnants.begin(), remnants.end());
for (const auto &s : storage) result.insert(s.begin(), s.end());
EXPECT_EQ(reference, result);
}
INSTANTIATE_TEST_CASE_P(ConcQueueStress, ConcQueue_,
Combine( Values(1, 2, 4, 8, 16) // writers
, Values(1, 32, 96, 256) // writes
, Values(1, 2, 10) // readers
, Values(0u, 16u, 32u))); // capacity
} // namespace opencv_test

View File

@@ -0,0 +1,159 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <opencv2/gapi/own/types.hpp>
namespace opencv_test
{
TEST(Point, CreateEmpty)
{
cv::gapi::own::Point p;
EXPECT_EQ(0, p.x);
EXPECT_EQ(0, p.y);
}
TEST(Point, CreateWithParams)
{
cv::gapi::own::Point p = {1, 2};
EXPECT_EQ(1, p.x);
EXPECT_EQ(2, p.y);
}
TEST(Rect, CreateEmpty)
{
cv::gapi::own::Rect r;
EXPECT_EQ(0, r.x);
EXPECT_EQ(0, r.y);
EXPECT_EQ(0, r.width);
EXPECT_EQ(0, r.height);
}
TEST(Rect, CreateWithParams)
{
cv::gapi::own::Rect r(1, 2, 3, 4);
EXPECT_EQ(1, r.x);
EXPECT_EQ(2, r.y);
EXPECT_EQ(3, r.width);
EXPECT_EQ(4, r.height);
}
TEST(Rect, CompareEqual)
{
cv::gapi::own::Rect r1(1, 2, 3, 4);
cv::gapi::own::Rect r2(1, 2, 3, 4);
EXPECT_TRUE(r1 == r2);
}
TEST(Rect, CompareDefaultEqual)
{
cv::gapi::own::Rect r1;
cv::gapi::own::Rect r2;
EXPECT_TRUE(r1 == r2);
}
TEST(Rect, CompareNotEqual)
{
cv::gapi::own::Rect r1(1, 2, 3, 4);
cv::gapi::own::Rect r2;
EXPECT_TRUE(r1 != r2);
}
TEST(Rect, Intersection)
{
cv::gapi::own::Rect r1(2, 2, 3, 3);
cv::gapi::own::Rect r2(3, 1, 3, 3);
cv::gapi::own::Rect intersect = r1 & r2;
EXPECT_EQ(3, intersect.x);
EXPECT_EQ(2, intersect.y);
EXPECT_EQ(2, intersect.width);
EXPECT_EQ(2, intersect.height);
}
TEST(Rect, AssignIntersection)
{
cv::gapi::own::Rect r1(2, 2, 3, 3);
cv::gapi::own::Rect r2(3, 1, 3, 3);
r1 &= r2;
EXPECT_EQ(3, r1.x);
EXPECT_EQ(2, r1.y);
EXPECT_EQ(2, r1.width);
EXPECT_EQ(2, r1.height);
}
TEST(Size, CreateEmpty)
{
cv::gapi::own::Size s;
EXPECT_EQ(0, s.width);
EXPECT_EQ(0, s.height);
}
TEST(Size, CreateWithParams)
{
cv::gapi::own::Size s(640, 480);
EXPECT_EQ(640, s.width);
EXPECT_EQ(480, s.height);
}
TEST(Size, AdditionAssignment)
{
cv::gapi::own::Size s1(1, 2);
cv::gapi::own::Size s2(2, 3);
s1 += s2;
EXPECT_EQ(3, s1.width);
EXPECT_EQ(5, s1.height);
}
TEST(Size, CompareEqual)
{
cv::gapi::own::Size s1(1, 2);
cv::gapi::own::Size s2(1, 2);
EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2);
}
TEST(Size, CompareDefaultEqual)
{
cv::gapi::own::Size s1;
cv::gapi::own::Size s2;
EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2);
}
TEST(Size, CompareNotEqual)
{
cv::gapi::own::Size s1(1, 2);
cv::gapi::own::Size s2(3, 4);
EXPECT_FALSE(s1 == s2);
EXPECT_TRUE(s1 != s2);
}
} // opencv_test

View File

@@ -0,0 +1,591 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <opencv2/gapi/own/mat.hpp>
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
namespace opencv_test
{
using Mat = cv::gapi::own::Mat;
using Dims = std::vector<int>;
TEST(OwnMat, DefaultConstruction)
{
Mat m;
ASSERT_EQ(m.data, nullptr);
ASSERT_EQ(m.cols, 0);
ASSERT_EQ(m.rows, 0);
ASSERT_EQ(m.cols, 0);
ASSERT_EQ(m.type(), 0);
ASSERT_EQ(m.depth(), 0);
ASSERT_TRUE(m.dims.empty());
ASSERT_TRUE(m.empty());
}
TEST(OwnMat, Create)
{
auto size = cv::gapi::own::Size{32,16};
Mat m;
m.create(size, CV_8UC1);
ASSERT_NE(m.data, nullptr);
ASSERT_EQ((cv::gapi::own::Size{m.cols, m.rows}), size);
ASSERT_EQ(m.total(), static_cast<size_t>(size.height*size.width));
ASSERT_EQ(m.type(), CV_8UC1);
ASSERT_EQ(m.depth(), CV_8U);
ASSERT_EQ(m.channels(), 1);
ASSERT_EQ(m.elemSize(), sizeof(uint8_t));
ASSERT_EQ(m.step, sizeof(uint8_t) * m.cols);
ASSERT_TRUE(m.dims.empty());
ASSERT_FALSE(m.empty());
}
TEST(OwnMat, CreateND)
{
Dims dims = {1,1,32,32};
Mat m;
m.create(dims, CV_32F);
ASSERT_NE(nullptr , m.data );
ASSERT_EQ((cv::gapi::own::Size{0,0}), (cv::gapi::own::Size{m.cols, m.rows}));
ASSERT_EQ(static_cast<size_t>(dims[0]*dims[1]*dims[2]*dims[3]), m.total());
ASSERT_EQ(CV_32F , m.type() );
ASSERT_EQ(CV_32F , m.depth() );
ASSERT_EQ(-1 , m.channels());
ASSERT_EQ(sizeof(float) , m.elemSize());
ASSERT_EQ(0u , m.step );
ASSERT_EQ(dims , m.dims );
ASSERT_FALSE(m.empty());
}
TEST(OwnMat, CreateOverload)
{
auto size = cv::gapi::own::Size{32,16};
Mat m;
m.create(size.height,size.width, CV_8UC1);
ASSERT_NE(m.data, nullptr);
ASSERT_EQ((cv::Size{m.cols, m.rows}), size);
ASSERT_EQ(m.total(), static_cast<size_t>(size.height*size.width));
ASSERT_EQ(m.type(), CV_8UC1);
ASSERT_EQ(m.depth(), CV_8U);
ASSERT_EQ(m.channels(), 1);
ASSERT_EQ(m.elemSize(), sizeof(uint8_t));
ASSERT_EQ(m.step, sizeof(uint8_t) * m.cols);
ASSERT_TRUE(m.dims.empty());
ASSERT_FALSE(m.empty());
}
TEST(OwnMat, Create3chan)
{
auto size = cv::Size{32,16};
Mat m;
m.create(size, CV_8UC3);
ASSERT_NE(m.data, nullptr);
ASSERT_EQ((cv::Size{m.cols, m.rows}), size);
ASSERT_EQ(m.type(), CV_8UC3);
ASSERT_EQ(m.depth(), CV_8U);
ASSERT_EQ(m.channels(), 3);
ASSERT_EQ(m.elemSize(), 3 * sizeof(uint8_t));
ASSERT_EQ(m.step, 3* sizeof(uint8_t) * m.cols);
ASSERT_TRUE(m.dims.empty());
ASSERT_FALSE(m.empty());
}
struct NonEmptyMat {
cv::gapi::own::Size size{32,16};
Mat m;
NonEmptyMat() {
m.create(size, CV_8UC1);
}
};
struct OwnMatSharedSemantics : NonEmptyMat, ::testing::Test {};
namespace {
auto state_of = [](Mat const& mat) {
return std::make_tuple(
mat.data,
cv::Size{mat.cols, mat.rows},
mat.type(),
mat.depth(),
mat.channels(),
mat.dims,
mat.empty()
);
};
void ensure_mats_are_same(Mat const& copy, Mat const& m){
EXPECT_NE(copy.data, nullptr);
EXPECT_EQ(state_of(copy), state_of(m));
}
}
TEST_F(OwnMatSharedSemantics, CopyConstruction)
{
Mat copy(m);
ensure_mats_are_same(copy, m);
}
TEST_F(OwnMatSharedSemantics, CopyAssignment)
{
Mat copy;
copy = m;
ensure_mats_are_same(copy, m);
}
struct OwnMatMoveSemantics : NonEmptyMat, ::testing::Test {
Mat& moved_from = m;
decltype(state_of(moved_from)) initial_state = state_of(moved_from);
void ensure_state_moved_to(Mat const& moved_to)
{
EXPECT_EQ(state_of(moved_to), initial_state);
EXPECT_EQ(state_of(moved_from), state_of(Mat{}));
}
};
TEST_F(OwnMatMoveSemantics, MoveConstruction)
{
Mat moved_to(std::move(moved_from));
ensure_state_moved_to(moved_to);
}
TEST_F(OwnMatMoveSemantics, MoveAssignment)
{
Mat moved_to(std::move(moved_from));
ensure_state_moved_to(moved_to);
}
struct OwnMatNonOwningView : NonEmptyMat, ::testing::Test {
decltype(state_of(m)) initial_state = state_of(m);
void TearDown() override {
EXPECT_EQ(state_of(m), initial_state)<<"State of the source matrix changed?";
//ASAN should complain here if memory is freed here (e.g. by bug in non owning logic of own::Mat)
volatile uchar dummy = m.data[0];
cv::util::suppress_unused_warning(dummy);
}
};
TEST_F(OwnMatNonOwningView, Construction)
{
Mat non_owning_view(m.rows, m.cols, m.type(), static_cast<void*>(m.data));
ensure_mats_are_same(non_owning_view, m);
}
TEST_F(OwnMatNonOwningView, CopyConstruction)
{
Mat non_owning_view{m.rows, m.cols, m.type(), static_cast<void*>(m.data)};
Mat non_owning_view_copy = non_owning_view;
ensure_mats_are_same(non_owning_view_copy, m);
}
TEST_F(OwnMatNonOwningView, Assignment)
{
Mat non_owning_view{m.rows, m.cols, m.type(), static_cast<void*>(m.data)};
Mat non_owning_view_copy;
non_owning_view_copy = non_owning_view;
ensure_mats_are_same(non_owning_view_copy, m);
}
TEST(OwnMatConversion, WithStep)
{
constexpr int width = 8;
constexpr int height = 8;
constexpr int stepInPixels = 16;
std::array<int, height * stepInPixels> data;
for (size_t i = 0; i < data.size(); i++)
{
data[i] = static_cast<int>(i);
}
cv::Mat cvMat(cv::Size{width, height}, CV_32S, data.data(), stepInPixels * sizeof(int));
auto ownMat = to_own(cvMat);
auto cvMatFromOwn = cv::gapi::own::to_ocv(ownMat);
EXPECT_EQ(0, cv::countNonZero(cvMat != cvMatFromOwn))
<< cvMat << std::endl
<< (cvMat != cvMatFromOwn);
}
TEST(OwnMatConversion, WithND)
{
const Dims dims = {1,3,8,8};
std::vector<uint8_t> data(dims[0]*dims[1]*dims[2]*dims[3]);
for (size_t i = 0u; i < data.size(); i++)
{
data[i] = static_cast<uint8_t>(i);
}
cv::Mat cvMat(dims, CV_8U, data.data());
auto ownMat = to_own(cvMat);
auto cvMatFromOwn = cv::gapi::own::to_ocv(ownMat);
EXPECT_EQ(0, cv::norm(cvMat, cvMatFromOwn, NORM_INF))
<< cvMat << std::endl
<< (cvMat != cvMatFromOwn);
}
TEST(OwnMat, PtrWithStep)
{
constexpr int width = 8;
constexpr int height = 8;
constexpr int stepInPixels = 16;
std::array<int, height * stepInPixels> data;
for (size_t i = 0; i < data.size(); i++)
{
data[i] = static_cast<int>(i);
}
Mat mat(height, width, CV_32S, data.data(), stepInPixels * sizeof(int));
EXPECT_EQ(& data[0], reinterpret_cast<int*>(mat.ptr(0)));
EXPECT_EQ(& data[1], reinterpret_cast<int*>(mat.ptr(0, 1)));
EXPECT_EQ(& data[stepInPixels], reinterpret_cast<int*>(mat.ptr(1)));
EXPECT_EQ(& data[stepInPixels +1], reinterpret_cast<int*>(mat.ptr(1,1)));
auto const& cmat = mat;
EXPECT_EQ(& data[0], reinterpret_cast<const int*>(cmat.ptr(0)));
EXPECT_EQ(& data[1], reinterpret_cast<const int*>(cmat.ptr(0, 1)));
EXPECT_EQ(& data[stepInPixels], reinterpret_cast<const int*>(cmat.ptr(1)));
EXPECT_EQ(& data[stepInPixels +1], reinterpret_cast<const int*>(cmat.ptr(1,1)));
}
TEST(OwnMat, CopyToWithStep)
{
constexpr int width = 8;
constexpr int height = 8;
constexpr int stepInPixels = 16;
std::array<int, height * stepInPixels> data;
for (size_t i = 0; i < data.size(); i++)
{
data[i] = static_cast<int>(i);
}
Mat mat(height, width, CV_32S, data.data(), stepInPixels * sizeof(int));
Mat dst;
mat.copyTo(dst);
EXPECT_NE(mat.data, dst.data);
EXPECT_EQ(0, cv::countNonZero(to_ocv(mat) != to_ocv(dst)))
<< to_ocv(mat) << std::endl
<< (to_ocv(mat) != to_ocv(dst));
}
TEST(OwnMat, AssignNDtoRegular)
{
const auto sz = cv::gapi::own::Size{32,32};
const auto dims = Dims{1,3,224,224};
Mat a;
a.create(sz, CV_8U);
const auto *old_ptr = a.data;
ASSERT_NE(nullptr , a.data);
ASSERT_EQ(sz , (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(sz.width*sz.height), a.total());
ASSERT_EQ(CV_8U , a.type());
ASSERT_EQ(CV_8U , a.depth());
ASSERT_EQ(1 , a.channels());
ASSERT_EQ(sizeof(uint8_t), a.elemSize());
ASSERT_EQ(static_cast<size_t>(sz.width), a.step);
ASSERT_TRUE(a.dims.empty());
Mat b;
b.create(dims, CV_32F);
a = b;
ASSERT_NE(nullptr , a.data);
ASSERT_NE(old_ptr , a.data);
ASSERT_EQ((cv::gapi::own::Size{0,0}), (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(dims[0]*dims[1]*dims[2]*dims[3]), a.total());
ASSERT_EQ(CV_32F , a.type());
ASSERT_EQ(CV_32F , a.depth());
ASSERT_EQ(-1 , a.channels());
ASSERT_EQ(sizeof(float), a.elemSize());
ASSERT_EQ(0u , a.step);
ASSERT_EQ(dims , a.dims);
}
TEST(OwnMat, AssignRegularToND)
{
const auto sz = cv::gapi::own::Size{32,32};
const auto dims = Dims{1,3,224,224};
Mat a;
a.create(dims, CV_32F);
const auto *old_ptr = a.data;
ASSERT_NE(nullptr , a.data);
ASSERT_EQ((cv::gapi::own::Size{0,0}), (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(dims[0]*dims[1]*dims[2]*dims[3]), a.total());
ASSERT_EQ(CV_32F , a.type());
ASSERT_EQ(CV_32F , a.depth());
ASSERT_EQ(-1 , a.channels());
ASSERT_EQ(sizeof(float), a.elemSize());
ASSERT_EQ(0u , a.step);
ASSERT_EQ(dims , a.dims);
Mat b;
b.create(sz, CV_8U);
a = b;
ASSERT_NE(nullptr , a.data);
ASSERT_NE(old_ptr , a.data);
ASSERT_EQ(sz , (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(sz.width*sz.height), a.total());
ASSERT_EQ(CV_8U , a.type());
ASSERT_EQ(CV_8U , a.depth());
ASSERT_EQ(1 , a.channels());
ASSERT_EQ(sizeof(uint8_t), a.elemSize());
ASSERT_EQ(static_cast<size_t>(sz.width), a.step);
ASSERT_TRUE(a.dims.empty());
}
TEST(OwnMat, CopyNDtoRegular)
{
const auto sz = cv::gapi::own::Size{32,32};
const auto dims = Dims{1,3,224,224};
Mat a;
a.create(sz, CV_8U);
const auto *old_ptr = a.data;
ASSERT_NE(nullptr , a.data);
ASSERT_EQ(sz , (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(sz.width*sz.height), a.total());
ASSERT_EQ(CV_8U , a.type());
ASSERT_EQ(CV_8U , a.depth());
ASSERT_EQ(1 , a.channels());
ASSERT_EQ(sizeof(uint8_t), a.elemSize());
ASSERT_EQ(static_cast<size_t>(sz.width), a.step);
ASSERT_TRUE(a.dims.empty());
Mat b;
b.create(dims, CV_32F);
b.copyTo(a);
ASSERT_NE(nullptr , a.data);
ASSERT_NE(old_ptr , a.data);
ASSERT_NE(b.data , a.data);
ASSERT_EQ((cv::gapi::own::Size{0,0}), (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(dims[0]*dims[1]*dims[2]*dims[3]), a.total());
ASSERT_EQ(CV_32F , a.type());
ASSERT_EQ(CV_32F , a.depth());
ASSERT_EQ(-1 , a.channels());
ASSERT_EQ(sizeof(float), a.elemSize());
ASSERT_EQ(0u , a.step);
ASSERT_EQ(dims , a.dims);
}
TEST(OwnMat, CopyRegularToND)
{
const auto sz = cv::gapi::own::Size{32,32};
const auto dims = Dims{1,3,224,224};
Mat a;
a.create(dims, CV_32F);
const auto *old_ptr = a.data;
ASSERT_NE(nullptr , a.data);
ASSERT_EQ((cv::gapi::own::Size{0,0}), (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(dims[0]*dims[1]*dims[2]*dims[3]), a.total());
ASSERT_EQ(CV_32F , a.type());
ASSERT_EQ(CV_32F , a.depth());
ASSERT_EQ(-1 , a.channels());
ASSERT_EQ(sizeof(float), a.elemSize());
ASSERT_EQ(0u , a.step);
ASSERT_EQ(dims , a.dims);
Mat b;
b.create(sz, CV_8U);
b.copyTo(a);
ASSERT_NE(nullptr , a.data);
ASSERT_NE(old_ptr , a.data);
ASSERT_NE(b.data , a.data);
ASSERT_EQ(sz , (cv::gapi::own::Size{a.cols, a.rows}));
ASSERT_EQ(static_cast<size_t>(sz.width*sz.height), a.total());
ASSERT_EQ(CV_8U , a.type());
ASSERT_EQ(CV_8U , a.depth());
ASSERT_EQ(1 , a.channels());
ASSERT_EQ(sizeof(uint8_t), a.elemSize());
ASSERT_EQ(static_cast<size_t>(sz.width), a.step);
ASSERT_TRUE(a.dims.empty());
}
TEST(OwnMat, ScalarAssign32SC1)
{
constexpr int width = 8;
constexpr int height = 8;
constexpr int stepInPixels = 16;
std::array<int, height * stepInPixels> data;
for (size_t i = 0; i < data.size(); i++)
{
data[i] = static_cast<int>(i);
}
Mat mat(height, width, CV_32S, data.data(), stepInPixels * sizeof(data[0]));
mat = cv::gapi::own::Scalar{-1};
std::array<int, height * stepInPixels> expected;
for (size_t row = 0; row < height; row++)
{
for (size_t col = 0; col < stepInPixels; col++)
{
auto index = row*stepInPixels + col;
expected[index] = col < width ? -1 : static_cast<int>(index);
}
}
auto cmp_result_mat = (cv::Mat{height, stepInPixels, CV_32S, data.data()} != cv::Mat{height, stepInPixels, CV_32S, expected.data()});
EXPECT_EQ(0, cv::countNonZero(cmp_result_mat))
<< cmp_result_mat << std::endl;
}
TEST(OwnMat, ScalarAssign8UC1)
{
constexpr int width = 8;
constexpr int height = 8;
constexpr int stepInPixels = 16;
std::array<uchar, height * stepInPixels> data;
for (size_t i = 0; i < data.size(); i++)
{
data[i] = static_cast<uchar>(i);
}
Mat mat(height, width, CV_8U, data.data(), stepInPixels * sizeof(data[0]));
mat = cv::gapi::own::Scalar{-1};
std::array<uchar, height * stepInPixels> expected;
for (size_t row = 0; row < height; row++)
{
for (size_t col = 0; col < stepInPixels; col++)
{
auto index = row*stepInPixels + col;
expected[index] = col < width ? cv::saturate_cast<uchar>(-1) : static_cast<uchar>(index);
}
}
auto cmp_result_mat = (cv::Mat{height, stepInPixels, CV_8U, data.data()} != cv::Mat{height, stepInPixels, CV_8U, expected.data()});
EXPECT_EQ(0, cv::countNonZero(cmp_result_mat))
<< cmp_result_mat << std::endl;
}
TEST(OwnMat, ScalarAssignND)
{
std::vector<int> dims = {1,1000};
Mat m;
m.create(dims, CV_32F);
m = cv::gapi::own::Scalar{-1};
const float *ptr = reinterpret_cast<float*>(m.data);
for (auto i = 0u; i < m.total(); i++) {
EXPECT_EQ(-1.f, ptr[i]);
}
}
TEST(OwnMat, ScalarAssign8UC3)
{
constexpr auto cv_type = CV_8SC3;
constexpr int channels = 3;
constexpr int width = 8;
constexpr int height = 8;
constexpr int stepInPixels = 16;
std::array<schar, height * stepInPixels * channels> data;
for (size_t i = 0; i < data.size(); i+= channels)
{
data[i + 0] = static_cast<schar>(10 * i + 0);
data[i + 1] = static_cast<schar>(10 * i + 1);
data[i + 2] = static_cast<schar>(10 * i + 2);
}
Mat mat(height, width, cv_type, data.data(), channels * stepInPixels * sizeof(data[0]));
mat = cv::gapi::own::Scalar{-10, -11, -12};
std::array<schar, data.size()> expected;
for (size_t row = 0; row < height; row++)
{
for (size_t col = 0; col < stepInPixels; col++)
{
int index = static_cast<int>(channels * (row*stepInPixels + col));
expected[index + 0] = static_cast<schar>(col < width ? -10 : 10 * index + 0);
expected[index + 1] = static_cast<schar>(col < width ? -11 : 10 * index + 1);
expected[index + 2] = static_cast<schar>(col < width ? -12 : 10 * index + 2);
}
}
auto cmp_result_mat = (cv::Mat{height, stepInPixels, cv_type, data.data()} != cv::Mat{height, stepInPixels, cv_type, expected.data()});
EXPECT_EQ(0, cv::countNonZero(cmp_result_mat))
<< cmp_result_mat << std::endl
<< "data : " << std::endl
<< cv::Mat{height, stepInPixels, cv_type, data.data()} << std::endl
<< "expected : " << std::endl
<< cv::Mat{height, stepInPixels, cv_type, expected.data()} << std::endl;
}
TEST(OwnMat, ROIView)
{
constexpr int width = 8;
constexpr int height = 8;
constexpr int stepInPixels = 16;
std::array<uchar, height * stepInPixels> data;
for (size_t i = 0; i < data.size(); i++)
{
data[i] = static_cast<uchar>(i);
}
// std::cout<<cv::Mat{height, stepInPixels, CV_8U, data.data()}<<std::endl;
std::array<uchar, 4 * 4> expected;
for (size_t row = 0; row < 4; row++)
{
for (size_t col = 0; col < 4; col++)
{
expected[row*4 +col] = static_cast<uchar>(stepInPixels * (2 + row) + 2 + col);
}
}
Mat mat(height, width, CV_8U, data.data(), stepInPixels * sizeof(data[0]));
Mat roi_view (mat, cv::gapi::own::Rect{2,2,4,4});
// std::cout<<cv::Mat{4, 4, CV_8U, expected.data()}<<std::endl;
//
auto expected_cv_mat = cv::Mat{4, 4, CV_8U, expected.data()};
auto cmp_result_mat = (to_ocv(roi_view) != expected_cv_mat);
EXPECT_EQ(0, cv::countNonZero(cmp_result_mat))
<< cmp_result_mat << std::endl
<< to_ocv(roi_view) << std::endl
<< expected_cv_mat << std::endl;
}
} // namespace opencv_test

View File

@@ -0,0 +1,44 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <opencv2/gapi/own/scalar.hpp>
namespace opencv_test
{
TEST(Scalar, CreateEmpty)
{
cv::gapi::own::Scalar s;
for (int i = 0; i < 4; ++i)
{
EXPECT_EQ(s[i], 0.0);
}
}
TEST(Scalar, CreateFromVal)
{
cv::gapi::own::Scalar s(5.0);
EXPECT_EQ(s[0], 5.0);
EXPECT_EQ(s[1], 0.0);
EXPECT_EQ(s[2], 0.0);
EXPECT_EQ(s[3], 0.0);
}
TEST(Scalar, CreateFromVals)
{
cv::gapi::own::Scalar s(5.3, 3.3, 4.1, -2.0);
EXPECT_EQ(s[0], 5.3);
EXPECT_EQ(s[1], 3.3);
EXPECT_EQ(s[2], 4.1);
EXPECT_EQ(s[3], -2.0);
}
} // namespace opencv_test

View File

@@ -0,0 +1,73 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#ifdef HAVE_FREETYPE
#include <random>
#include <opencv2/core/utils/configuration.private.hpp>
#include "api/ft_render.hpp"
namespace opencv_test
{
static std::string getFontPath()
{
static std::string path = cv::utils::getConfigurationParameterString("OPENCV_TEST_FREETYPE_FONT_PATH",
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc");
return path;
}
inline void RunTest(const std::string& font,
size_t num_iters,
size_t lower_char_code,
size_t upper_char_code)
{
cv::gapi::wip::draw::FTTextRender ftpr(font);
std::mt19937 gen{std::random_device()()};
std::uniform_int_distribution<int> dist(lower_char_code, upper_char_code);
std::uniform_int_distribution<int> dist_size(2, 200);
for (size_t i = 0; i < num_iters; ++i)
{
size_t text_size = dist_size(gen);
std::wstring text;
for (size_t j = 0; j < text_size; ++j)
{
wchar_t c = dist(gen);
text += c;
}
int fh = dist_size(gen);
int baseline = 0;
cv::Size size;
ASSERT_NO_THROW(size = ftpr.getTextSize(text, fh, &baseline));
cv::Mat bmp(size, CV_8UC1, cv::Scalar::all(0));
cv::Point org(0, bmp.rows - baseline);
ASSERT_NO_THROW(ftpr.putText(bmp, text, org, fh));
}
}
TEST(FTTextRenderTest, Smoke_Test_Ascii)
{
RunTest(getFontPath(), 2000, 32, 126);
}
TEST(FTTextRenderTest, Smoke_Test_Unicode)
{
RunTest(getFontPath(), 2000, 20320, 30000);
}
} // namespace opencv_test
#endif // HAVE_FREETYPE

View File

@@ -0,0 +1,561 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#ifdef HAVE_FREETYPE
#include <codecvt>
#endif // HAVE_FREETYPE
#include "../test_precomp.hpp"
#include "../common/gapi_render_tests.hpp"
#include "api/render_priv.hpp"
namespace opencv_test
{
#ifdef HAVE_FREETYPE
GAPI_RENDER_TEST_FIXTURES(OCVTestFTexts, FIXTURE_API(std::wstring, cv::Point, int, cv::Scalar), 4, text, org, fh, color)
#endif // HAVE_FREETYPE
GAPI_RENDER_TEST_FIXTURES(OCVTestTexts, FIXTURE_API(std::string, cv::Point, int, double, cv::Scalar, int, int, bool), 8, text, org, ff, fs, color, thick, lt, blo)
GAPI_RENDER_TEST_FIXTURES(OCVTestRects, FIXTURE_API(cv::Rect, cv::Scalar, int, int, int), 5, rect, color, thick, lt, shift)
GAPI_RENDER_TEST_FIXTURES(OCVTestCircles, FIXTURE_API(cv::Point, int, cv::Scalar, int, int, int), 6, center, radius, color, thick, lt, shift)
GAPI_RENDER_TEST_FIXTURES(OCVTestLines, FIXTURE_API(cv::Point, cv::Point, cv::Scalar, int, int, int), 6, pt1, pt2, color, thick, lt, shift)
GAPI_RENDER_TEST_FIXTURES(OCVTestMosaics, FIXTURE_API(cv::Rect, int, int), 3, mos, cellsz, decim)
GAPI_RENDER_TEST_FIXTURES(OCVTestImages, FIXTURE_API(cv::Rect, cv::Scalar, double), 3, rect, color, transparency)
GAPI_RENDER_TEST_FIXTURES(OCVTestPolylines, FIXTURE_API(Points, cv::Scalar, int, int, int), 5, points, color, thick, lt, shift)
TEST_P(RenderBGROCVTestTexts, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Text{text, org, ff, fs, color, thick, lt, blo});
cv::gapi::wip::draw::render(gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
cv::putText(ref_mat, text, org, ff, fs, color, thick, lt, blo);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(gapi_mat, ref_mat));
}
}
TEST_P(RenderNV12OCVTestTexts, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Text{text, org, ff, fs, color, thick, lt, blo});
cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
// NV12 -> YUV
cv::Mat yuv;
cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
cv::putText(yuv, text, org, ff, fs, cvtBGRToYUVC(color), thick, lt, blo);
// YUV -> NV12
cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(y_gapi_mat, y_ref_mat));
EXPECT_EQ(0, cv::norm(uv_gapi_mat, uv_ref_mat));
}
}
# ifdef HAVE_FREETYPE
TEST_P(RenderBGROCVTestFTexts, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::FText{text, org, fh, color});
EXPECT_NO_THROW(cv::gapi::wip::draw::render(gapi_mat, prims,
cv::compile_args(cv::gapi::wip::draw::freetype_font{
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
})));
}
TEST_P(RenderNV12OCVTestFTexts, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::FText{text, org, fh, color});
EXPECT_NO_THROW(cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims,
cv::compile_args(cv::gapi::wip::draw::freetype_font{
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
})));
}
static std::wstring to_wstring(const char* bytes)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
return converter.from_bytes(bytes);
}
TEST(RenderFText, FontsNotPassedToCompileArgs)
{
cv::Mat in_mat(640, 480, CV_8UC3, cv::Scalar::all(0));
std::wstring text = to_wstring("\xe4\xbd\xa0\xe5\xa5\xbd");
cv::Point org(100, 100);
int fh = 60;
cv::Scalar color(200, 100, 25);
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::FText{text, org, fh, color});
EXPECT_ANY_THROW(cv::gapi::wip::draw::render(in_mat, prims));
}
#endif // HAVE_FREETYPE
TEST_P(RenderBGROCVTestRects, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, shift});
cv::gapi::wip::draw::render(gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
cv::rectangle(ref_mat, rect, color, thick, lt, shift);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(gapi_mat, ref_mat));
}
}
TEST_P(RenderNV12OCVTestRects, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, shift});
cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
// NV12 -> YUV
cv::Mat yuv;
cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
cv::rectangle(yuv, rect, cvtBGRToYUVC(color), thick, lt, shift);
// YUV -> NV12
cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(y_gapi_mat, y_ref_mat));
EXPECT_EQ(0, cv::norm(uv_gapi_mat, uv_ref_mat));
}
}
TEST_P(RenderBGROCVTestCircles, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Circle{center, radius, color, thick, lt, shift});
cv::gapi::wip::draw::render(gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
cv::circle(ref_mat, center, radius, color, thick, lt, shift);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(gapi_mat, ref_mat));
}
}
TEST_P(RenderNV12OCVTestCircles, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Circle{center, radius, color, thick, lt, shift});
cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
// NV12 -> YUV
cv::Mat yuv;
cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
cv::circle(yuv, center, radius, cvtBGRToYUVC(color), thick, lt, shift);
// YUV -> NV12
cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(y_gapi_mat, y_ref_mat));
EXPECT_EQ(0, cv::norm(uv_gapi_mat, uv_ref_mat));
}
}
TEST_P(RenderBGROCVTestLines, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Line{pt1, pt2, color, thick, lt, shift});
cv::gapi::wip::draw::render(gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
cv::line(ref_mat, pt1, pt2, color, thick, lt, shift);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(gapi_mat, ref_mat));
}
}
TEST_P(RenderNV12OCVTestLines, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Line{pt1, pt2, color, thick, lt, shift});
cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
// NV12 -> YUV
cv::Mat yuv;
cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
cv::line(yuv, pt1, pt2, cvtBGRToYUVC(color), thick, lt, shift);
// YUV -> NV12
cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(y_gapi_mat, y_ref_mat));
EXPECT_EQ(0, cv::norm(uv_gapi_mat, uv_ref_mat));
}
}
TEST_P(RenderBGROCVTestMosaics, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Mosaic{mos, cellsz, decim});
cv::gapi::wip::draw::render(gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
drawMosaicRef(ref_mat, mos, cellsz);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(gapi_mat, ref_mat));
}
}
TEST_P(RenderNV12OCVTestMosaics, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Mosaic{mos, cellsz, decim});
cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
// NV12 -> YUV
cv::Mat yuv;
cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
drawMosaicRef(yuv, mos, cellsz);
// YUV -> NV12
cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(y_gapi_mat, y_ref_mat));
EXPECT_EQ(0, cv::norm(uv_gapi_mat, uv_ref_mat));
}
}
TEST_P(RenderBGROCVTestImages, AccuracyTest)
{
cv::Mat img(rect.size(), CV_8UC3, color);
cv::Mat alpha(rect.size(), CV_32FC1, transparency);
auto tl = rect.tl();
cv::Point org = {tl.x, tl.y + rect.size().height};
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Image{org, img, alpha});
cv::gapi::wip::draw::render(gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
blendImageRef(ref_mat, org, img, alpha);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(gapi_mat, ref_mat));
}
}
TEST_P(RenderNV12OCVTestImages, AccuracyTest)
{
cv::Mat img(rect.size(), CV_8UC3, color);
cv::Mat alpha(rect.size(), CV_32FC1, transparency);
auto tl = rect.tl();
cv::Point org = {tl.x, tl.y + rect.size().height};
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Image{org, img, alpha});
cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
// NV12 -> YUV
cv::Mat yuv;
cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
cv::Mat yuv_img;
cv::cvtColor(img, yuv_img, cv::COLOR_BGR2YUV);
blendImageRef(yuv, org, yuv_img, alpha);
// YUV -> NV12
cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(y_gapi_mat, y_ref_mat));
EXPECT_EQ(0, cv::norm(uv_gapi_mat, uv_ref_mat));
}
}
TEST_P(RenderBGROCVTestPolylines, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Poly{points, color, thick, lt, shift});
cv::gapi::wip::draw::render(gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
std::vector<std::vector<cv::Point>> array_points{points};
cv::fillPoly(ref_mat, array_points, color, lt, shift);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(gapi_mat, ref_mat));
}
}
TEST_P(RenderNV12OCVTestPolylines, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
cv::gapi::wip::draw::Prims prims;
prims.emplace_back(cv::gapi::wip::draw::Poly{points, color, thick, lt, shift});
cv::gapi::wip::draw::render(y_gapi_mat, uv_gapi_mat, prims);
// OpenCV code //////////////////////////////////////////////////////////////
{
// NV12 -> YUV
cv::Mat yuv;
cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
std::vector<std::vector<cv::Point>> pp{points};
cv::fillPoly(yuv, pp, cvtBGRToYUVC(color), lt, shift);
// YUV -> NV12
cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::norm(y_gapi_mat, y_ref_mat));
EXPECT_EQ(0, cv::norm(uv_gapi_mat, uv_ref_mat));
}
}
// FIXME avoid code duplicate for NV12 and BGR cases
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestRectsImpl, RenderBGROCVTestRects,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Rect(100, 100, 200, 200)),
Values(cv::Scalar(100, 50, 150)),
Values(2),
Values(LINE_8),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestRectsImpl, RenderNV12OCVTestRects,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Rect(100, 100, 200, 200)),
Values(cv::Scalar(100, 50, 150)),
Values(2),
Values(LINE_8),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestCirclesImpl, RenderBGROCVTestCircles,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Point(100, 100)),
Values(10),
Values(cv::Scalar(100, 50, 150)),
Values(2),
Values(LINE_8),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestCirclesImpl, RenderNV12OCVTestCircles,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Point(100, 100)),
Values(10),
Values(cv::Scalar(100, 50, 150)),
Values(2),
Values(LINE_8),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestLinesImpl, RenderBGROCVTestLines,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Point(100, 100)),
Values(cv::Point(200, 200)),
Values(cv::Scalar(100, 50, 150)),
Values(2),
Values(LINE_8),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestLinesImpl, RenderNV12OCVTestLines,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Point(100, 100)),
Values(cv::Point(200, 200)),
Values(cv::Scalar(100, 50, 150)),
Values(2),
Values(LINE_8),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestTextsImpl, RenderBGROCVTestTexts,
Combine(Values(cv::Size(1280, 720)),
Values("SomeText"),
Values(cv::Point(200, 200)),
Values(FONT_HERSHEY_SIMPLEX),
Values(2.0),
Values(cv::Scalar(0, 255, 0)),
Values(2),
Values(LINE_8),
Values(false)));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestTextsImpl, RenderNV12OCVTestTexts,
Combine(Values(cv::Size(1280, 720)),
Values("SomeText"),
Values(cv::Point(200, 200)),
Values(FONT_HERSHEY_SIMPLEX),
Values(2.0),
Values(cv::Scalar(0, 255, 0)),
Values(2),
Values(LINE_8),
Values(false)));
#ifdef HAVE_FREETYPE
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestFTextsImpl, RenderBGROCVTestFTexts,
Combine(Values(cv::Size(1280, 720)),
Values(to_wstring("\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c"),
to_wstring("\xe3\x80\xa4\xe3\x80\xa5\xe3\x80\xa6\xe3\x80\xa7\xe3\x80\xa8\xe3\x80\x85\xe3\x80\x86")),
Values(cv::Point(200, 200)),
Values(64),
Values(cv::Scalar(0, 255, 0))));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestFTextsImpl, RenderNV12OCVTestFTexts,
Combine(Values(cv::Size(1280, 720)),
Values(to_wstring("\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c"),
to_wstring("\xe3\x80\xa4\xe3\x80\xa5\xe3\x80\xa6\xe3\x80\xa7\xe3\x80\xa8\xe3\x80\x85\xe3\x80\x86")),
Values(cv::Point(200, 200)),
Values(64),
Values(cv::Scalar(0, 255, 0))));
#endif // HAVE_FREETYPE
// FIXME Implement a macros to instantiate the tests because BGR and NV12 have the same parameters
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestMosaicsImpl, RenderBGROCVTestMosaics,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Rect(100, 100, 200, 200), // Normal case
cv::Rect(-50, -50, 200, 200), // Intersection with left-top corner
cv::Rect(-50, 100, 200, 200), // Intersection with left side
cv::Rect(-50, 600, 200, 200), // Intersection with left-bottom corner
cv::Rect(100, 600, 200, 200), // Intersection with bottom side
cv::Rect(1200, 700, 200, 200), // Intersection with right-bottom corner
cv::Rect(1200, 400, 200, 200), // Intersection with right side
cv::Rect(1200, -50, 200, 200), // Intersection with right-top corner
cv::Rect(500, -50, 200, 200), // Intersection with top side
cv::Rect(-100, 300, 1480, 300), // From left to right side with intersection
cv::Rect(5000, 2000, 100, 100), // Outside image
cv::Rect(-300, -300, 3000, 3000), // Cover all image
cv::Rect(100, 100, -500, -500)), // Negative width and height
Values(25),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestMosaicsImpl, RenderNV12OCVTestMosaics,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Rect(100, 100, 200, 200), // Normal case
cv::Rect(-50, -50, 200, 200), // Intersection with left-top corner
cv::Rect(-50, 100, 200, 200), // Intersection with left side
cv::Rect(-50, 600, 200, 200), // Intersection with left-bottom corner
cv::Rect(100, 600, 200, 200), // Intersection with bottom side
cv::Rect(1200, 700, 200, 200), // Intersection with right-bottom corner
cv::Rect(1200, 400, 200, 200), // Intersection with right side
cv::Rect(1200, -50, 200, 200), // Intersection with right-top corner
cv::Rect(500, -50, 200, 200), // Intersection with top side
cv::Rect(-100, 300, 1480, 300), // From left to right side with intersection
cv::Rect(5000, 2000, 100, 100), // Outside image
cv::Rect(-300, -300, 3000, 3000), // Cover all image
cv::Rect(100, 100, -500, -500)), // Negative width and height
Values(25),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestImagesImpl, RenderBGROCVTestImages,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Rect(100, 100, 200, 200)),
Values(cv::Scalar(100, 150, 60)),
Values(1.0)));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestImagesImpl, RenderNV12OCVTestImages,
Combine(Values(cv::Size(1280, 720)),
Values(cv::Rect(100, 100, 200, 200)),
Values(cv::Scalar(100, 150, 60)),
Values(1.0)));
INSTANTIATE_TEST_CASE_P(RenderBGROCVTestPolylinesImpl, RenderBGROCVTestPolylines,
Combine(Values(cv::Size(1280, 720)),
Values(std::vector<cv::Point>{{100, 100}, {200, 200}, {150, 300}, {400, 150}}),
Values(cv::Scalar(100, 150, 60)),
Values(2),
Values(LINE_8),
Values(0)));
INSTANTIATE_TEST_CASE_P(RenderNV12OCVTestPolylinesImpl, RenderNV12OCVTestPolylines,
Combine(Values(cv::Size(1280, 720)),
Values(std::vector<cv::Point>{{100, 100}, {200, 200}, {150, 300}, {400, 150}}),
Values(cv::Scalar(100, 150, 60)),
Values(2),
Values(LINE_8),
Values(0)));
}

View File

@@ -0,0 +1,978 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "../test_precomp.hpp"
#include <opencv2/gapi/cpu/core.hpp>
#include <opencv2/gapi/cpu/imgproc.hpp>
#include <opencv2/gapi/fluid/core.hpp>
#include <opencv2/gapi/fluid/imgproc.hpp>
#include <opencv2/gapi/fluid/gfluidkernel.hpp>
#include <opencv2/gapi/ocl/core.hpp>
#include <opencv2/gapi/ocl/imgproc.hpp>
#include <opencv2/gapi/streaming/cap.hpp>
namespace opencv_test
{
namespace
{
void initTestDataPath()
{
#ifndef WINRT
static bool initialized = false;
if (!initialized)
{
// Since G-API has no own test data (yet), it is taken from the common space
const char* testDataPath = getenv("OPENCV_TEST_DATA_PATH");
GAPI_Assert(testDataPath != nullptr);
cvtest::addDataSearchPath(testDataPath);
initialized = true;
}
#endif // WINRT
}
enum class KernelPackage: int
{
OCV,
OCV_FLUID,
OCL,
OCL_FLUID,
};
std::ostream& operator<< (std::ostream &os, const KernelPackage &e)
{
switch (e)
{
#define _C(X) case KernelPackage::X: os << #X; break
_C(OCV);
_C(OCV_FLUID);
_C(OCL);
_C(OCL_FLUID);
#undef _C
default: GAPI_Assert(false);
}
return os;
}
struct GAPI_Streaming: public ::testing::TestWithParam<KernelPackage> {
GAPI_Streaming() { initTestDataPath(); }
cv::gapi::GKernelPackage getKernelPackage()
{
using namespace cv::gapi;
switch (GetParam())
{
case KernelPackage::OCV:
return cv::gapi::combine(core::cpu::kernels(),
imgproc::cpu::kernels());
break;
case KernelPackage::OCV_FLUID:
return cv::gapi::combine(core::cpu::kernels(),
imgproc::cpu::kernels(),
core::fluid::kernels());
break;
// FIXME: OpenCL backend seem to work fine with Streaming
// however the results are not very bit exact with CPU
// It may be a problem but may be just implementation innacuracy.
// Need to customize the comparison function in tests where OpenCL
// is involved.
case KernelPackage::OCL:
return cv::gapi::combine(core::ocl::kernels(),
imgproc::ocl::kernels());
break;
case KernelPackage::OCL_FLUID:
return cv::gapi::combine(core::ocl::kernels(),
imgproc::ocl::kernels(),
core::fluid::kernels());
break;
}
throw std::logic_error("Unknown package");
}
};
} // anonymous namespace
TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat)
{
// This graph models the following use-case:
// Canny here is used as some "feature detector"
//
// Island/device layout may be different given the contents
// of the passed kernel package.
//
// The expectation is that we get as much islands in the
// graph as backends the GKernelPackage contains.
//
// [Capture] --> Crop --> Resize --> Canny --> [out]
const auto crop_rc = cv::Rect(13, 75, 377, 269);
const auto resample_sz = cv::Size(224, 224);
const auto thr_lo = 64.;
const auto thr_hi = 192.;
cv::GMat in;
auto roi = cv::gapi::crop(in, crop_rc);
auto res = cv::gapi::resize(roi, resample_sz);
auto out = cv::gapi::Canny(res, thr_lo, thr_hi);
cv::GComputation c(in, out);
// Input data
cv::Mat in_mat = cv::imread(findDataFile("cv/edgefilter/kodim23.png"));
cv::Mat out_mat_gapi;
// OpenCV reference image
cv::Mat out_mat_ocv;
{
cv::Mat tmp;
cv::resize(in_mat(crop_rc), tmp, resample_sz);
cv::Canny(tmp, out_mat_ocv, thr_lo, thr_hi);
}
// Compilation & testing
auto ccomp = c.compileStreaming(cv::descr_of(in_mat),
cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
EXPECT_TRUE(ccomp);
EXPECT_FALSE(ccomp.running());
ccomp.setSource(cv::gin(in_mat));
ccomp.start();
EXPECT_TRUE(ccomp.running());
// Fetch the result 15 times
for (int i = 0; i < 15; i++) {
// With constant inputs, the stream is endless so
// the blocking pull() should never return `false`.
EXPECT_TRUE(ccomp.pull(cv::gout(out_mat_gapi)));
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
}
EXPECT_TRUE(ccomp.running());
ccomp.stop();
EXPECT_FALSE(ccomp.running());
}
TEST_P(GAPI_Streaming, SmokeTest_VideoInput_GMat)
{
const auto crop_rc = cv::Rect(13, 75, 377, 269);
const auto resample_sz = cv::Size(224, 224);
const auto thr_lo = 64.;
const auto thr_hi = 192.;
cv::GMat in;
auto roi = cv::gapi::crop(in, crop_rc);
auto res = cv::gapi::resize(roi, resample_sz);
auto out = cv::gapi::Canny(res, thr_lo, thr_hi);
cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in), out));
// OpenCV reference image code
auto opencv_ref = [&](const cv::Mat &in_mat, cv::Mat &out_mat) {
cv::Mat tmp;
cv::resize(in_mat(crop_rc), tmp, resample_sz);
cv::Canny(tmp, out_mat, thr_lo, thr_hi);
};
// Compilation & testing
auto ccomp = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
EXPECT_TRUE(ccomp);
EXPECT_FALSE(ccomp.running());
ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi")));
ccomp.start();
EXPECT_TRUE(ccomp.running());
// Process the full video
cv::Mat in_mat_gapi, out_mat_gapi;
std::size_t frames = 0u;
while (ccomp.pull(cv::gout(in_mat_gapi, out_mat_gapi))) {
frames++;
cv::Mat out_mat_ocv;
opencv_ref(in_mat_gapi, out_mat_ocv);
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
}
EXPECT_LT(0u, frames);
EXPECT_FALSE(ccomp.running());
// Stop can be called at any time (even if the pipeline is not running)
ccomp.stop();
EXPECT_FALSE(ccomp.running());
}
TEST_P(GAPI_Streaming, Regression_CompileTimeScalar)
{
// There was a bug with compile-time GScalars. Compile-time
// GScalars generate their own DATA nodes at GModel/GIslandModel
// level, resulting in an extra link at the GIslandModel level, so
// GStreamingExecutor automatically assigned an input queue to
// such edges. Since there were no in-graph producer for that
// data, no data were pushed to such queue what lead to a
// deadlock.
cv::GMat in;
cv::GMat tmp = cv::gapi::copy(in);
for (int i = 0; i < 3; i++) {
tmp = tmp & cv::gapi::blur(in, cv::Size(3,3));
}
cv::GComputation c(cv::GIn(in), cv::GOut(tmp, tmp + 1));
auto ccomp = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,512}},
cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
cv::Mat in_mat = cv::imread(findDataFile("cv/edgefilter/kodim23.png"));
cv::Mat out_mat1, out_mat2;
// Fetch the result 15 times
ccomp.setSource(cv::gin(in_mat));
ccomp.start();
for (int i = 0; i < 15; i++) {
EXPECT_TRUE(ccomp.pull(cv::gout(out_mat1, out_mat2)));
}
ccomp.stop();
}
TEST_P(GAPI_Streaming, SmokeTest_StartRestart)
{
cv::GMat in;
auto res = cv::gapi::resize(in, cv::Size{300,200});
auto out = cv::gapi::Canny(res, 95, 220);
cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in), out));
auto ccomp = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
EXPECT_TRUE(ccomp);
EXPECT_FALSE(ccomp.running());
// Run 1
std::size_t num_frames1 = 0u;
ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi")));
ccomp.start();
EXPECT_TRUE(ccomp.running());
cv::Mat out1, out2;
while (ccomp.pull(cv::gout(out1, out2))) num_frames1++;
EXPECT_FALSE(ccomp.running());
// Run 2
std::size_t num_frames2 = 0u;
ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi")));
ccomp.start();
EXPECT_TRUE(ccomp.running());
while (ccomp.pull(cv::gout(out1, out2))) num_frames2++;
EXPECT_FALSE(ccomp.running());
EXPECT_LT(0u, num_frames1);
EXPECT_LT(0u, num_frames2);
EXPECT_EQ(num_frames1, num_frames2);
}
TEST_P(GAPI_Streaming, SmokeTest_VideoConstSource_NoHang)
{
// A video source is a finite one, while const source is not.
// Check that pipeline completes when a video source completes.
auto refc = cv::GComputation([](){
cv::GMat in;
return cv::GComputation(in, cv::gapi::copy(in));
}).compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
refc.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi")));
refc.start();
std::size_t ref_frames = 0u;
cv::Mat tmp;
while (refc.pull(cv::gout(tmp))) ref_frames++;
EXPECT_EQ(100u, ref_frames);
cv::GMat in;
cv::GMat in2;
cv::GMat roi = cv::gapi::crop(in2, cv::Rect{1,1,256,256});
cv::GMat blr = cv::gapi::blur(roi, cv::Size(3,3));
cv::GMat out = blr - in;
auto testc = cv::GComputation(cv::GIn(in, in2), cv::GOut(out))
.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{256,256}},
cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
cv::Mat in_const = cv::Mat::eye(cv::Size(256,256), CV_8UC3);
testc.setSource(cv::gin(in_const,
gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi"))));
testc.start();
std::size_t test_frames = 0u;
while (testc.pull(cv::gout(tmp))) test_frames++;
EXPECT_EQ(ref_frames, test_frames);
}
TEST_P(GAPI_Streaming, SmokeTest_AutoMeta)
{
cv::GMat in;
cv::GMat in2;
cv::GMat roi = cv::gapi::crop(in2, cv::Rect{1,1,256,256});
cv::GMat blr = cv::gapi::blur(roi, cv::Size(3,3));
cv::GMat out = blr - in;
auto testc = cv::GComputation(cv::GIn(in, in2), cv::GOut(out))
.compileStreaming(cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
cv::Mat in_const = cv::Mat::eye(cv::Size(256,256), CV_8UC3);
cv::Mat tmp;
// Test with one video source
auto in_src = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi"));
testc.setSource(cv::gin(in_const, in_src));
testc.start();
std::size_t test_frames = 0u;
while (testc.pull(cv::gout(tmp))) test_frames++;
EXPECT_EQ(100u, test_frames);
// Now test with another one
in_src = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/1920x1080.avi"));
testc.setSource(cv::gin(in_const, in_src));
testc.start();
test_frames = 0u;
while (testc.pull(cv::gout(tmp))) test_frames++;
EXPECT_EQ(165u, test_frames);
}
TEST_P(GAPI_Streaming, SmokeTest_AutoMeta_2xConstMat)
{
cv::GMat in;
cv::GMat in2;
cv::GMat roi = cv::gapi::crop(in2, cv::Rect{1,1,256,256});
cv::GMat blr = cv::gapi::blur(roi, cv::Size(3,3));
cv::GMat out = blr - in;
auto testc = cv::GComputation(cv::GIn(in, in2), cv::GOut(out))
.compileStreaming(cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
cv::Mat in_const = cv::Mat::eye(cv::Size(256,256), CV_8UC3);
cv::Mat tmp;
// Test with first image
auto in_src = cv::imread(findDataFile("cv/edgefilter/statue.png"));
testc.setSource(cv::gin(in_const, in_src));
testc.start();
ASSERT_TRUE(testc.pull(cv::gout(tmp)));
testc.stop();
// Now test with second image
in_src = cv::imread(findDataFile("cv/edgefilter/kodim23.png"));
testc.setSource(cv::gin(in_const, in_src));
testc.start();
ASSERT_TRUE(testc.pull(cv::gout(tmp)));
testc.stop();
}
TEST_P(GAPI_Streaming, SmokeTest_AutoMeta_VideoScalar)
{
cv::GMat in_m;
cv::GScalar in_s;
cv::GMat out_m = in_m * in_s;
auto testc = cv::GComputation(cv::GIn(in_m, in_s), cv::GOut(out_m))
.compileStreaming(cv::compile_args(cv::gapi::use_only{getKernelPackage()}));
cv::Mat tmp;
// Test with one video source and scalar
auto in_src = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi"));
testc.setSource(cv::gin(in_src, cv::Scalar{1.25}));
testc.start();
std::size_t test_frames = 0u;
while (testc.pull(cv::gout(tmp))) test_frames++;
EXPECT_EQ(100u, test_frames);
// Now test with another one video source and scalar
in_src = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/1920x1080.avi"));
testc.setSource(cv::gin(in_src, cv::Scalar{0.75}));
testc.start();
test_frames = 0u;
while (testc.pull(cv::gout(tmp))) test_frames++;
EXPECT_EQ(165u, test_frames);
}
INSTANTIATE_TEST_CASE_P(TestStreaming, GAPI_Streaming,
Values( KernelPackage::OCV
//, KernelPackage::OCL // FIXME: Fails bit-exactness check, maybe relax it?
, KernelPackage::OCV_FLUID
//, KernelPackage::OCL // FIXME: Fails bit-exactness check, maybe relax it?
));
namespace TypesTest
{
G_API_OP(SumV, <cv::GArray<int>(cv::GMat)>, "test.gapi.sumv") {
static cv::GArrayDesc outMeta(const cv::GMatDesc &) {
return cv::empty_array_desc();
}
};
G_API_OP(AddV, <cv::GMat(cv::GMat,cv::GArray<int>)>, "test.gapi.addv") {
static cv::GMatDesc outMeta(const cv::GMatDesc &in, const cv::GArrayDesc &) {
return in;
}
};
GAPI_OCV_KERNEL(OCVSumV, SumV) {
static void run(const cv::Mat &in, std::vector<int> &out) {
CV_Assert(in.depth() == CV_8U);
const auto length = in.cols * in.channels();
out.resize(length);
const uchar *ptr = in.ptr(0);
for (int c = 0; c < length; c++) {
out[c] = ptr[c];
}
for (int r = 1; r < in.rows; r++) {
ptr = in.ptr(r);
for (int c = 0; c < length; c++) {
out[c] += ptr[c];
}
}
}
};
GAPI_OCV_KERNEL(OCVAddV, AddV) {
static void run(const cv::Mat &in, const std::vector<int> &inv, cv::Mat &out) {
CV_Assert(in.depth() == CV_8U);
const auto length = in.cols * in.channels();
CV_Assert(length == static_cast<int>(inv.size()));
for (int r = 0; r < in.rows; r++) {
const uchar *in_ptr = in.ptr(r);
uchar *out_ptr = out.ptr(r);
for (int c = 0; c < length; c++) {
out_ptr[c] = cv::saturate_cast<uchar>(in_ptr[c] + inv[c]);
}
}
}
};
GAPI_FLUID_KERNEL(FluidAddV, AddV, false) {
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in,
const std::vector<int> &inv,
cv::gapi::fluid::Buffer &out) {
const uchar *in_ptr = in.InLineB(0);
uchar *out_ptr = out.OutLineB(0);
const auto length = in.meta().size.width * in.meta().chan;
CV_Assert(length == static_cast<int>(inv.size()));
for (int c = 0; c < length; c++) {
out_ptr[c] = cv::saturate_cast<uchar>(in_ptr[c] + inv[c]);
}
}
};
} // namespace TypesTest
TEST_P(GAPI_Streaming, SmokeTest_AutoMeta_VideoArray)
{
cv::GMat in_m;
cv::GArray<int> in_v;
cv::GMat out_m = TypesTest::AddV::on(in_m, in_v) - in_m;
// Run pipeline
auto testc = cv::GComputation(cv::GIn(in_m, in_v), cv::GOut(out_m))
.compileStreaming(cv::compile_args(cv::gapi::kernels<TypesTest::OCVAddV>()));
cv::Mat tmp;
// Test with one video source and vector
auto in_src = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi"));
std::vector<int> first_in_vec(768*3, 1);
testc.setSource(cv::gin(in_src, first_in_vec));
testc.start();
std::size_t test_frames = 0u;
while (testc.pull(cv::gout(tmp))) test_frames++;
EXPECT_EQ(100u, test_frames);
// Now test with another one
in_src = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/1920x1080.avi"));
std::vector<int> second_in_vec(1920*3, 1);
testc.setSource(cv::gin(in_src, second_in_vec));
testc.start();
test_frames = 0u;
while (testc.pull(cv::gout(tmp))) test_frames++;
EXPECT_EQ(165u, test_frames);
}
TEST(GAPI_Streaming_Types, InputScalar)
{
// This test verifies if Streaming works with Scalar data @ input.
cv::GMat in_m;
cv::GScalar in_s;
cv::GMat out_m = in_m * in_s;
cv::GComputation c(cv::GIn(in_m, in_s), cv::GOut(out_m));
// Input data
cv::Mat in_mat = cv::Mat::eye(256, 256, CV_8UC1);
cv::Scalar in_scl = 32;
// Run pipeline
auto sc = c.compileStreaming(cv::descr_of(in_mat), cv::descr_of(in_scl));
sc.setSource(cv::gin(in_mat, in_scl));
sc.start();
for (int i = 0; i < 10; i++)
{
cv::Mat out;
EXPECT_TRUE(sc.pull(cv::gout(out)));
EXPECT_EQ(0., cv::norm(out, in_mat.mul(in_scl), cv::NORM_INF));
}
}
TEST(GAPI_Streaming_Types, InputVector)
{
// This test verifies if Streaming works with Vector data @ input.
cv::GMat in_m;
cv::GArray<int> in_v;
cv::GMat out_m = TypesTest::AddV::on(in_m, in_v) - in_m;
cv::GComputation c(cv::GIn(in_m, in_v), cv::GOut(out_m));
// Input data
cv::Mat in_mat = cv::Mat::eye(256, 256, CV_8UC1);
std::vector<int> in_vec;
TypesTest::OCVSumV::run(in_mat, in_vec);
EXPECT_EQ(std::vector<int>(256,1), in_vec); // self-sanity-check
auto opencv_ref = [&](const cv::Mat &in, const std::vector<int> &inv, cv::Mat &out) {
cv::Mat tmp = in_mat.clone(); // allocate the same amount of memory as graph does
TypesTest::OCVAddV::run(in, inv, tmp);
out = tmp - in;
};
// Run pipeline
auto sc = c.compileStreaming(cv::descr_of(in_mat),
cv::descr_of(in_vec),
cv::compile_args(cv::gapi::kernels<TypesTest::OCVAddV>()));
sc.setSource(cv::gin(in_mat, in_vec));
sc.start();
for (int i = 0; i < 10; i++)
{
cv::Mat out_mat;
EXPECT_TRUE(sc.pull(cv::gout(out_mat)));
cv::Mat ref_mat;
opencv_ref(in_mat, in_vec, ref_mat);
EXPECT_EQ(0., cv::norm(ref_mat, out_mat, cv::NORM_INF));
}
}
TEST(GAPI_Streaming_Types, XChangeScalar)
{
// This test verifies if Streaming works when pipeline steps
// (islands) exchange Scalar data.
initTestDataPath();
cv::GMat in;
cv::GScalar m = cv::gapi::mean(in);
cv::GMat tmp = cv::gapi::convertTo(in, CV_32F) - m;
cv::GMat out = cv::gapi::blur(tmp, cv::Size(3,3));
cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in),
cv::gapi::convertTo(out, CV_8U)));
auto ocv_ref = [](const cv::Mat &in_mat, cv::Mat &out_mat) {
cv::Scalar ocv_m = cv::mean(in_mat);
cv::Mat ocv_tmp;
in_mat.convertTo(ocv_tmp, CV_32F);
ocv_tmp -= ocv_m;
cv::blur(ocv_tmp, ocv_tmp, cv::Size(3,3));
ocv_tmp.convertTo(out_mat, CV_8U);
};
// Here we want mean & convertTo run on OCV
// and subC & blur3x3 on Fluid.
// FIXME: With the current API it looks quite awful:
auto ocv_kernels = cv::gapi::core::cpu::kernels(); // convertTo
ocv_kernels.remove<cv::gapi::core::GSubC>();
auto fluid_kernels = cv::gapi::combine(cv::gapi::core::fluid::kernels(), // subC
cv::gapi::imgproc::fluid::kernels()); // box3x3
fluid_kernels.remove<cv::gapi::core::GConvertTo>();
fluid_kernels.remove<cv::gapi::core::GMean>();
// FIXME: Now
// - fluid kernels take over ocv kernels (including Copy, SubC, & Box3x3)
// - selected kernels (which were removed from the fluid package) remain in OCV
// (ConvertTo + some others)
// FIXME: This is completely awful. User should easily pick up specific kernels
// to an empty kernel package to craft his own but not do it via exclusion.
// Need to expose kernel declarations to public headers to enable kernels<..>()
// on user side.
auto kernels = cv::gapi::combine(ocv_kernels, fluid_kernels);
// Compile streaming pipeline
auto sc = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::compile_args(cv::gapi::use_only{kernels}));
sc.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi")));
sc.start();
cv::Mat in_frame;
cv::Mat out_mat_gapi;
cv::Mat out_mat_ref;
std::size_t num_frames = 0u;
while (sc.pull(cv::gout(in_frame, out_mat_gapi))) {
num_frames++;
ocv_ref(in_frame, out_mat_ref);
EXPECT_EQ(0., cv::norm(out_mat_gapi, out_mat_ref, cv::NORM_INF));
}
EXPECT_LT(0u, num_frames);
}
TEST(GAPI_Streaming_Types, XChangeVector)
{
// This test verifies if Streaming works when pipeline steps
// (islands) exchange Vector data.
initTestDataPath();
cv::GMat in1, in2;
cv::GMat in = cv::gapi::crop(in1, cv::Rect{0,0,576,576});
cv::GScalar m = cv::gapi::mean(in);
cv::GArray<int> s = TypesTest::SumV::on(in2); // (in2 = eye, so s = [1,0,0,1,..])
cv::GMat out = TypesTest::AddV::on(in - m, s);
cv::GComputation c(cv::GIn(in1, in2), cv::GOut(cv::gapi::copy(in), out));
auto ocv_ref = [](const cv::Mat &in_mat1, const cv::Mat &in_mat2, cv::Mat &out_mat) {
cv::Mat in_roi = in_mat1(cv::Rect{0,0,576,576});
cv::Scalar ocv_m = cv::mean(in_roi);
std::vector<int> ocv_v;
TypesTest::OCVSumV::run(in_mat2, ocv_v);
out_mat.create(cv::Size(576,576), CV_8UC3);
cv::Mat in_tmp = in_roi - ocv_m;
TypesTest::OCVAddV::run(in_tmp, ocv_v, out_mat);
};
// Let crop/mean/sumV be calculated via OCV,
// and AddV/subC be calculated via Fluid
auto ocv_kernels = cv::gapi::core::cpu::kernels();
ocv_kernels.remove<cv::gapi::core::GSubC>();
ocv_kernels.include<TypesTest::OCVSumV>();
auto fluid_kernels = cv::gapi::core::fluid::kernels();
fluid_kernels.include<TypesTest::FluidAddV>();
// Here OCV takes precedense over Fluid, with SubC & SumV remaining
// in Fluid.
auto kernels = cv::gapi::combine(fluid_kernels, ocv_kernels);
// Compile streaming pipeline
cv::Mat in_eye = cv::Mat::eye(cv::Size(576, 576), CV_8UC3);
auto sc = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::GMatDesc{CV_8U,3,cv::Size{576,576}},
cv::compile_args(cv::gapi::use_only{kernels}));
sc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi")),
in_eye));
sc.start();
cv::Mat in_frame;
cv::Mat out_mat_gapi;
cv::Mat out_mat_ref;
std::size_t num_frames = 0u;
while (sc.pull(cv::gout(in_frame, out_mat_gapi))) {
num_frames++;
ocv_ref(in_frame, in_eye, out_mat_ref);
EXPECT_EQ(0., cv::norm(out_mat_gapi, out_mat_ref, cv::NORM_INF));
}
EXPECT_LT(0u, num_frames);
}
TEST(GAPI_Streaming_Types, OutputScalar)
{
// This test verifies if Streaming works when pipeline
// produces scalar data only
initTestDataPath();
cv::GMat in;
cv::GScalar out = cv::gapi::mean(in);
auto sc = cv::GComputation(cv::GIn(in), cv::GOut(out))
.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}});
const auto video_path = findDataFile("cv/video/768x576.avi");
sc.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(video_path));
sc.start();
cv::VideoCapture cap;
cap.open(video_path);
cv::Mat tmp;
cv::Scalar out_scl;
std::size_t num_frames = 0u;
while (sc.pull(cv::gout(out_scl)))
{
num_frames++;
cap >> tmp;
cv::Scalar out_ref = cv::mean(tmp);
EXPECT_EQ(out_ref, out_scl);
}
EXPECT_LT(0u, num_frames);
}
TEST(GAPI_Streaming_Types, OutputVector)
{
// This test verifies if Streaming works when pipeline
// produces vector data only
initTestDataPath();
auto pkg = cv::gapi::kernels<TypesTest::OCVSumV>();
cv::GMat in1, in2;
cv::GMat roi = cv::gapi::crop(in2, cv::Rect(3,3,256,256));
cv::GArray<int> out = TypesTest::SumV::on(cv::gapi::mul(roi, in1));
auto sc = cv::GComputation(cv::GIn(in1, in2), cv::GOut(out))
.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{256,256}},
cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::compile_args(pkg));
auto ocv_ref = [](const cv::Mat &ocv_in1,
const cv::Mat &ocv_in2,
std::vector<int> &ocv_out) {
auto ocv_roi = ocv_in2(cv::Rect{3,3,256,256});
TypesTest::OCVSumV::run(ocv_roi.mul(ocv_in1), ocv_out);
};
cv::Mat in_eye = cv::Mat::eye(cv::Size(256, 256), CV_8UC3);
const auto video_path = findDataFile("cv/video/768x576.avi");
sc.setSource(cv::gin(in_eye, gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(video_path)));
sc.start();
cv::VideoCapture cap;
cap.open(video_path);
cv::Mat tmp;
std::vector<int> ref_vec;
std::vector<int> out_vec;
std::size_t num_frames = 0u;
while (sc.pull(cv::gout(out_vec)))
{
num_frames++;
cap >> tmp;
ref_vec.clear();
ocv_ref(in_eye, tmp, ref_vec);
EXPECT_EQ(ref_vec, out_vec);
}
EXPECT_LT(0u, num_frames);
}
struct GAPI_Streaming_Unit: public ::testing::Test {
cv::Mat m;
cv::GComputation cc;
cv::GStreamingCompiled sc;
cv::GCompiled ref;
GAPI_Streaming_Unit()
: m(cv::Mat::ones(224,224,CV_8UC3))
, cc([]{
cv::GMat a, b;
cv::GMat c = a + b*2;
return cv::GComputation(cv::GIn(a, b), cv::GOut(c));
})
{
initTestDataPath();
const auto a_desc = cv::descr_of(m);
const auto b_desc = cv::descr_of(m);
sc = cc.compileStreaming(a_desc, b_desc);
ref = cc.compile(a_desc, b_desc);
}
};
TEST_F(GAPI_Streaming_Unit, TestTwoVideoSourcesFail)
{
const auto c_ptr = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi"));
auto c_desc = cv::GMatDesc{CV_8U,3,{768,576}};
auto m_desc = cv::descr_of(m);
sc = cc.compileStreaming(c_desc, m_desc);
EXPECT_NO_THROW(sc.setSource(cv::gin(c_ptr, m)));
sc = cc.compileStreaming(m_desc, c_desc);
EXPECT_NO_THROW(sc.setSource(cv::gin(m, c_ptr)));
sc = cc.compileStreaming(c_desc, c_desc);
EXPECT_ANY_THROW(sc.setSource(cv::gin(c_ptr, c_ptr)));
}
TEST_F(GAPI_Streaming_Unit, TestStartWithoutnSetSource)
{
EXPECT_ANY_THROW(sc.start());
}
TEST_F(GAPI_Streaming_Unit, TestStopWithoutStart1)
{
// It is ok!
EXPECT_NO_THROW(sc.stop());
}
TEST_F(GAPI_Streaming_Unit, TestStopWithoutStart2)
{
// It should be ok as well
sc.setSource(cv::gin(m, m));
EXPECT_NO_THROW(sc.stop());
}
TEST_F(GAPI_Streaming_Unit, StopStartStop)
{
cv::Mat out;
EXPECT_NO_THROW(sc.stop());
EXPECT_NO_THROW(sc.setSource(cv::gin(m, m)));
EXPECT_NO_THROW(sc.start());
std::size_t i = 0u;
while (i++ < 10u) {EXPECT_TRUE(sc.pull(cv::gout(out)));};
EXPECT_NO_THROW(sc.stop());
}
TEST_F(GAPI_Streaming_Unit, ImplicitStop)
{
EXPECT_NO_THROW(sc.setSource(cv::gin(m, m)));
EXPECT_NO_THROW(sc.start());
// No explicit stop here - pipeline stops successfully at the test exit
}
TEST_F(GAPI_Streaming_Unit, StartStopStart_NoSetSource)
{
EXPECT_NO_THROW(sc.setSource(cv::gin(m, m)));
EXPECT_NO_THROW(sc.start());
EXPECT_NO_THROW(sc.stop());
EXPECT_ANY_THROW(sc.start()); // Should fails since setSource was not called
}
TEST_F(GAPI_Streaming_Unit, StartStopStress_Const)
{
// Runs 100 times with no deadlock - assumed stable (robust) enough
for (int i = 0; i < 100; i++)
{
sc.stop();
sc.setSource(cv::gin(m, m));
sc.start();
cv::Mat out;
for (int j = 0; j < 5; j++) EXPECT_TRUE(sc.pull(cv::gout(out)));
}
}
TEST_F(GAPI_Streaming_Unit, StartStopStress_Video)
{
// Runs 100 times with no deadlock - assumed stable (robust) enough
sc = cc.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
cv::GMatDesc{CV_8U,3,cv::Size{768,576}});
m = cv::Mat::eye(cv::Size{768,576}, CV_8UC3);
for (int i = 0; i < 100; i++)
{
auto src = cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi"));
sc.stop();
sc.setSource(cv::gin(src, m));
sc.start();
cv::Mat out;
for (int j = 0; j < 5; j++) EXPECT_TRUE(sc.pull(cv::gout(out)));
}
}
TEST_F(GAPI_Streaming_Unit, PullNoStart)
{
sc.setSource(cv::gin(m, m));
cv::Mat out;
EXPECT_ANY_THROW(sc.pull(cv::gout(out)));
}
TEST_F(GAPI_Streaming_Unit, SetSource_Multi_BeforeStart)
{
cv::Mat eye = cv::Mat::eye (224, 224, CV_8UC3);
cv::Mat zrs = cv::Mat::zeros(224, 224, CV_8UC3);
// Call setSource two times, data specified last time
// should be actually processed.
sc.setSource(cv::gin(zrs, zrs));
sc.setSource(cv::gin(eye, eye));
// Run the pipeline, acquire result once
sc.start();
cv::Mat out, out_ref;
EXPECT_TRUE(sc.pull(cv::gout(out)));
sc.stop();
// Pipeline should process `eye` mat, not `zrs`
ref(cv::gin(eye, eye), cv::gout(out_ref));
EXPECT_EQ(0., cv::norm(out, out_ref, cv::NORM_INF));
}
TEST_F(GAPI_Streaming_Unit, SetSource_During_Execution)
{
cv::Mat zrs = cv::Mat::zeros(224, 224, CV_8UC3);
sc.setSource(cv::gin(m, m));
sc.start();
EXPECT_ANY_THROW(sc.setSource(cv::gin(zrs, zrs)));
EXPECT_ANY_THROW(sc.setSource(cv::gin(zrs, zrs)));
EXPECT_ANY_THROW(sc.setSource(cv::gin(zrs, zrs)));
sc.stop();
}
TEST_F(GAPI_Streaming_Unit, SetSource_After_Completion)
{
sc.setSource(cv::gin(m, m));
// Test pipeline with `m` input
sc.start();
cv::Mat out, out_ref;
EXPECT_TRUE(sc.pull(cv::gout(out)));
sc.stop();
// Test against ref
ref(cv::gin(m, m), cv::gout(out_ref));
EXPECT_EQ(0., cv::norm(out, out_ref, cv::NORM_INF));
// Now set another source
cv::Mat eye = cv::Mat::eye(224, 224, CV_8UC3);
sc.setSource(cv::gin(eye, m));
sc.start();
EXPECT_TRUE(sc.pull(cv::gout(out)));
sc.stop();
// Test against new ref
ref(cv::gin(eye, m), cv::gout(out_ref));
EXPECT_EQ(0., cv::norm(out, out_ref, cv::NORM_INF));
}
} // namespace opencv_test

View File

@@ -0,0 +1,12 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// FIXME: OpenCV license header
#include "test_precomp.hpp"
CV_TEST_MAIN("gapi")

View File

@@ -0,0 +1,31 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// FIXME: OpenCV header
#ifndef __OPENCV_GAPI_TEST_PRECOMP_HPP__
#define __OPENCV_GAPI_TEST_PRECOMP_HPP__
#include <cstdint>
#include <vector>
#include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/imgproc.hpp>
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/cpu/gcpukernel.hpp>
#include <opencv2/gapi/gpu/ggpukernel.hpp>
#include <opencv2/gapi/gpu/imgproc.hpp>
#include <opencv2/gapi/gpu/core.hpp>
#include <opencv2/gapi/gcompoundkernel.hpp>
#include <opencv2/gapi/operators.hpp>
#include <opencv2/gapi/fluid/imgproc.hpp>
#include <opencv2/gapi/fluid/core.hpp>
#include <opencv2/gapi/infer.hpp>
#endif // __OPENCV_GAPI_TEST_PRECOMP_HPP__

View File

@@ -0,0 +1,142 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <opencv2/gapi/util/any.hpp>
namespace opencv_test
{
TEST(Any, basic)
{
using namespace util;
any a(8);
auto casted_pointer = any_cast<int>(&a);
ASSERT_NE(nullptr, casted_pointer);
ASSERT_EQ(*casted_pointer, 8);
*casted_pointer = 7;
ASSERT_EQ(any_cast<int>(a), 7);
}
TEST(Any, any_cast_ref_throws_on_empty)
{
using namespace util;
any a;
ASSERT_THROW(util::any_cast<int>(a), bad_any_cast);
}
TEST(Any, copy)
{
using namespace util;
any a(8);
ASSERT_EQ(any_cast<int>(a), 8);
any b (a);
ASSERT_NE(nullptr, any_cast<int>(&b));
ASSERT_EQ(8 , any_cast<int>(b));
ASSERT_EQ(8 , any_cast<int>(a));
}
TEST(Any, copy_empty)
{
using namespace util;
any a;
ASSERT_EQ(nullptr, any_cast<int>(&a));
any b (a);
ASSERT_EQ(nullptr, any_cast<int>(&a));
ASSERT_EQ(nullptr, any_cast<int>(&b));
}
TEST(Any, move)
{
using namespace util;
any a(8);
ASSERT_EQ(any_cast<int>(a), 8);
any b (std::move(a));
ASSERT_NE(nullptr, any_cast<int>(&b));
ASSERT_EQ(8 , any_cast<int>(b));
ASSERT_EQ(nullptr, any_cast<int>(&a));
}
TEST(Any, swap)
{
using namespace util;
any a(8);
any b(7);
ASSERT_EQ(7, any_cast<int>(b));
ASSERT_EQ(8, any_cast<int>(a));
swap(a,b);
ASSERT_EQ(8, any_cast<int>(b));
ASSERT_EQ(7, any_cast<int>(a));
}
TEST(Any, move_assign)
{
using namespace util;
any a(8);
any b;
ASSERT_EQ(any_cast<int>(a), 8);
b = (std::move(a));
ASSERT_NE(nullptr, any_cast<int>(&b));
ASSERT_EQ(8 , any_cast<int>(b));
ASSERT_EQ(nullptr, any_cast<int>(&a));
}
TEST(Any, copy_assign)
{
using namespace util;
any a(8);
any b;
ASSERT_EQ(any_cast<int>(a), 8);
ASSERT_EQ(nullptr, any_cast<int>(&b));
b = a;
ASSERT_NE(nullptr, any_cast<int>(&b));
ASSERT_EQ(8 , any_cast<int>(b));
ASSERT_EQ(8 , any_cast<int>(a));
}
TEST(Any, get_ref_to_val_from_any)
{
using namespace util;
int x = 8;
any a(x);
int& casted_ref = any_cast<int>(a);
ASSERT_EQ(casted_ref, 8);
}
TEST(Any, update_val_via_ref)
{
using namespace util;
int x = 8;
any a(x);
int& casted_ref = any_cast<int>(a);
ASSERT_EQ(casted_ref, 8);
casted_ref = 7;
ASSERT_EQ(any_cast<int>(a), 7);
}
} // namespace opencv_test

View File

@@ -0,0 +1,175 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <opencv2/gapi/util/optional.hpp>
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
namespace opencv_test
{
TEST(Optional, EmptyCtor)
{
util::optional<int> o;
EXPECT_FALSE(o.has_value());
EXPECT_FALSE(static_cast<bool>(o));
}
TEST(Optional, ValueCTor)
{
util::optional<int> o(42);
EXPECT_TRUE(o.has_value());
EXPECT_TRUE(static_cast<bool>(o));
}
TEST(Optional, MoveCtr)
{
util::optional<std::string> os1(std::string("text"));
EXPECT_TRUE(os1.has_value());
util::optional<std::string> os2(std::move(os1));
EXPECT_FALSE(os1.has_value());
EXPECT_TRUE(os2.has_value());
EXPECT_EQ("text", os2.value());
}
TEST(Optional, EmptyThrows)
{
struct foo { int bar; };
util::optional<foo> om;
const util::optional<foo> oc;
int dummy;
EXPECT_THROW(dummy = om->bar, util::bad_optional_access);
EXPECT_THROW(dummy = oc->bar, util::bad_optional_access);
cv::util::suppress_unused_warning(dummy);
EXPECT_THROW(*om, util::bad_optional_access);
EXPECT_THROW(*oc, util::bad_optional_access);
EXPECT_THROW(om.value(), util::bad_optional_access);
EXPECT_THROW(oc.value(), util::bad_optional_access);
}
TEST(Optional, ValueNoThrow)
{
struct foo { int bar; };
util::optional<foo> om(foo{42});
const util::optional<foo> oc(foo{42});
int dummy;
EXPECT_NO_THROW(dummy = om->bar);
EXPECT_NO_THROW(dummy = oc->bar);
cv::util::suppress_unused_warning(dummy);
EXPECT_NO_THROW(*om);
EXPECT_NO_THROW(*oc);
EXPECT_NO_THROW(om.value());
EXPECT_NO_THROW(oc.value());
}
TEST(Optional, Value)
{
util::optional<int> oi(42);
struct foo { int bar; };
util::optional<foo> of(foo{42});
EXPECT_EQ(42, oi.value());
EXPECT_EQ(42, *oi);
EXPECT_EQ(42, of.value().bar);
EXPECT_EQ(42, of->bar);
}
TEST(Optional, Mutable)
{
util::optional<int> oi(42);
*oi = 43;
EXPECT_EQ(43, *oi);
struct foo { int bar; int baz; };
util::optional<foo> of(foo{11,22});
(*of).bar = 42;
EXPECT_EQ(42, of->bar);
EXPECT_EQ(22, of->baz);
of->baz = 33;
EXPECT_EQ(42, of->bar);
EXPECT_EQ(33, of->baz);
}
TEST(Optional, MoveAssign)
{
util::optional<int> e, i(42);
EXPECT_FALSE(e.has_value());
EXPECT_TRUE(i.has_value());
EXPECT_EQ(42, *i);
e = std::move(i);
EXPECT_TRUE(e.has_value());
EXPECT_FALSE(i.has_value());
EXPECT_EQ(42, *e);
}
TEST(Optional, CopyAssign)
{
util::optional<int> e;
const util::optional<int> i(42);
EXPECT_FALSE(e.has_value());
EXPECT_TRUE(i.has_value());
EXPECT_EQ(42, *i);
e = i;
EXPECT_TRUE(e.has_value());
EXPECT_TRUE(i.has_value());
EXPECT_EQ(42, *e);
EXPECT_EQ(42, *i);
}
TEST(Optional, ValueOr)
{
util::optional<int> e;
EXPECT_FALSE(e.has_value());
EXPECT_EQ(42, e.value_or(42));
EXPECT_EQ(42, e.value_or(42.1));
}
TEST(Optional, Swap)
{
util::optional<int> e, i(42);
EXPECT_FALSE(e.has_value());
EXPECT_TRUE(i.has_value());
EXPECT_EQ(42, *i);
e.swap(i);
EXPECT_TRUE(e.has_value());
EXPECT_FALSE(i.has_value());
EXPECT_EQ(42, *e);
}
TEST(Optional, Reset)
{
util::optional<int> i(42);
EXPECT_TRUE(i.has_value());
i.reset();
EXPECT_FALSE(i.has_value());
}
TEST(Optional, MakeOptional)
{
std::string s("text");
auto os = util::make_optional(s);
EXPECT_TRUE(os.has_value());
EXPECT_EQ(s, os.value());
}
} // namespace opencv_test

View File

@@ -0,0 +1,386 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
#include "../test_precomp.hpp"
#include <opencv2/gapi/util/variant.hpp>
#include <cstddef> //std::max_align_t
namespace opencv_test
{
namespace
{
typedef util::variant<int, std::string> TestVar;
typedef util::variant<int, float> TestVar2;
}
TEST(Variant, EmptyCTor)
{
util::variant<int> vi;
EXPECT_EQ(0, util::get<int>(vi));
util::variant<int, std::string> vis;
EXPECT_EQ(0, util::get<int>(vis));
util::variant<std::string> vs;
EXPECT_EQ("", util::get<std::string>(vs));
util::variant<std::string, int> vsi;
EXPECT_EQ("", util::get<std::string>(vsi));
}
TEST(Variant, ValueMoveCTor)
{
util::variant<int> vi(42);
EXPECT_EQ(0u, vi.index());
EXPECT_EQ(42, util::get<int>(vi));
util::variant<int, std::string> vis(2017);
EXPECT_EQ(0u, vis.index());
EXPECT_EQ(2017, util::get<int>(vis));
util::variant<int, std::string> vis2(std::string("2017"));
EXPECT_EQ(1u, vis2.index());
EXPECT_EQ("2017", util::get<std::string>(vis2));
util::variant<std::string> vs(std::string("2017"));
EXPECT_EQ(0u, vs.index());
EXPECT_EQ("2017", util::get<std::string>(vs));
util::variant<std::string, int> vsi(std::string("2017"));
EXPECT_EQ(0u, vsi.index());
EXPECT_EQ("2017", util::get<std::string>(vsi));
util::variant<std::string, int> vsi2(42);
EXPECT_EQ(1u, vsi2.index());
EXPECT_EQ(42, util::get<int>(vsi2));
}
TEST(Variant, ValueCopyCTor)
{
const int i42 = 42;
const int i17 = 2017;
const std::string s17 = "2017";
util::variant<int> vi(i42);
EXPECT_EQ(0u, vi.index());
EXPECT_EQ(i42, util::get<int>(vi));
util::variant<int, std::string> vis(i17);
EXPECT_EQ(0u, vis.index());
EXPECT_EQ(i17, util::get<int>(vis));
util::variant<int, std::string> vis2(s17);
EXPECT_EQ(1u, vis2.index());
EXPECT_EQ(s17, util::get<std::string>(vis2));
util::variant<std::string> vs(s17);
EXPECT_EQ(0u, vs.index());
EXPECT_EQ(s17, util::get<std::string>(vs));
util::variant<std::string, int> vsi(s17);
EXPECT_EQ(0u, vsi.index());
EXPECT_EQ(s17, util::get<std::string>(vsi));
util::variant<std::string, int> vsi2(i42);
EXPECT_EQ(1u, vsi2.index());
EXPECT_EQ(i42, util::get<int>(vsi2));
}
TEST(Variant, CopyMoveCTor)
{
const TestVar tvconst(std::string("42"));
TestVar tv = tvconst;
EXPECT_EQ( 1u, tv.index());
EXPECT_EQ("42", util::get<std::string>(tv));
TestVar tv2(TestVar(40+2));
EXPECT_EQ( 0u, tv2.index());
EXPECT_EQ( 42, util::get<int>(tv2));
}
TEST(Variant, Assign_Basic)
{
TestVar vis;
EXPECT_EQ(0u, vis.index());
EXPECT_EQ(0, util::get<int>(vis));
vis = 42;
EXPECT_EQ(0u, vis.index());
EXPECT_EQ(42, util::get<int>(vis));
}
TEST(Variant, Assign_ValueUpdate_SameType)
{
TestVar vis(42);
EXPECT_EQ(0u, vis.index());
EXPECT_EQ(42, util::get<int>(vis));
vis = 43;
EXPECT_EQ(0u, vis.index());
EXPECT_EQ(43, util::get<int>(vis));
}
TEST(Variant, Assign_ValueUpdate_DiffType)
{
TestVar vis(42);
EXPECT_EQ(0u, vis.index());
EXPECT_EQ(42, util::get<int>(vis));
vis = std::string("42");
EXPECT_EQ(1u, vis.index());
EXPECT_EQ("42", util::get<std::string>(vis));
}
TEST(Variant, Assign_ValueUpdate_Const)
{
TestVar va(42);
const TestVar vb(43);
EXPECT_EQ(0u, va.index());
EXPECT_EQ(42, util::get<int>(va));
EXPECT_EQ(0u, vb.index());
EXPECT_EQ(43, util::get<int>(vb));
va = vb;
EXPECT_EQ(0u, va.index());
EXPECT_EQ(43, util::get<int>(va));
}
TEST(Variant, Assign_ValueUpdate_Const_DiffType)
{
TestVar va(42);
const TestVar vb(std::string("42"));
EXPECT_EQ(0u, va.index());
EXPECT_EQ(42, util::get<int>(va));
EXPECT_EQ(1u, vb.index());
EXPECT_EQ("42", util::get<std::string>(vb));
va = vb;
EXPECT_EQ(1u, va.index());
EXPECT_EQ("42", util::get<std::string>(va));
}
TEST(Variant, Assign_Move)
{
TestVar va(42);
TestVar vb(std::string("42"));
TestVar vc(43);
EXPECT_EQ(0u, va.index());
EXPECT_EQ(42, util::get<int>(va));
EXPECT_EQ(1u, vb.index());
EXPECT_EQ("42", util::get<std::string>(vb));
EXPECT_EQ(0u, vc.index());
EXPECT_EQ(43, util::get<int>(vc));
va = std::move(vb);
EXPECT_EQ(1u, va.index());
EXPECT_EQ("42", util::get<std::string>(va));
va = std::move(vc);
EXPECT_EQ(0u, va.index());
EXPECT_EQ(43, util::get<int>(va));
}
TEST(Variant, Swap_SameIndex)
{
TestVar tv1(42);
TestVar tv2(43);
EXPECT_EQ(0u, tv1.index());
EXPECT_EQ(42, util::get<int>(tv1));
EXPECT_EQ(0u, tv2.index());
EXPECT_EQ(43, util::get<int>(tv2));
tv1.swap(tv2);
EXPECT_EQ(0u, tv1.index());
EXPECT_EQ(43, util::get<int>(tv1));
EXPECT_EQ(0u, tv2.index());
EXPECT_EQ(42, util::get<int>(tv2));
}
TEST(Variant, Swap_DiffIndex)
{
TestVar2 tv1(42);
TestVar2 tv2(3.14f);
EXPECT_EQ(0u, tv1.index());
EXPECT_EQ(42, util::get<int>(tv1));
EXPECT_EQ(1u, tv2.index());
EXPECT_EQ(3.14f, util::get<float>(tv2));
tv1.swap(tv2);
EXPECT_EQ(0u, tv2.index());
EXPECT_EQ(42, util::get<int>(tv2));
EXPECT_EQ(1u, tv1.index());
EXPECT_EQ(3.14f, util::get<float>(tv1));
}
TEST(Variant, Get)
{
const TestVar cv(42);
// Test const& get()
EXPECT_EQ(42, util::get<int>(cv));
EXPECT_THROW(util::get<std::string>(cv), util::bad_variant_access);
// Test &get
TestVar cv2(std::string("42"));
EXPECT_EQ("42", util::get<std::string>(cv2));
EXPECT_THROW(util::get<int>(cv2), util::bad_variant_access);
}
TEST(Variant, GetWrite)
{
util::variant<int, std::string> v(42);
EXPECT_EQ(42, util::get<int>(v));
util::get<int>(v) = 43;
EXPECT_EQ(43, util::get<int>(v));
}
TEST(Variant, NoDefaultCtor)
{
struct MyType
{
int m_a;
MyType() = delete;
};
// This code MUST compile
util::variant<int, MyType> var;
SUCCEED() << "Code compiled";
// At the same time, util::variant<MyType, ...> MUST NOT.
}
TEST(Variant, MonoState)
{
struct MyType
{
int m_a;
explicit MyType(int a) : m_a(a) {}
MyType() = delete;
};
util::variant<util::monostate, MyType> var;
EXPECT_EQ(0u, var.index());
var = MyType{42};
EXPECT_EQ(1u, var.index());
EXPECT_EQ(42, util::get<MyType>(var).m_a);
}
TEST(Variant, Eq)
{
TestVar v1(42), v2(std::string("42"));
TestVar v3(v1), v4(v2);
EXPECT_TRUE(v1 == v3);
EXPECT_TRUE(v2 == v4);
EXPECT_TRUE(v1 != v2);
EXPECT_TRUE(v3 != v4);
EXPECT_FALSE(v1 == v2);
EXPECT_FALSE(v3 == v4);
EXPECT_FALSE(v1 != v3);
EXPECT_FALSE(v2 != v4);
}
TEST(Variant, Eq_Monostate)
{
using TestVar3 = util::variant<util::monostate, int>;
TestVar3 v1;
TestVar3 v2(42);
EXPECT_NE(v1, v2);
v2 = util::monostate{};
EXPECT_EQ(v1, v2);
}
TEST(Variant, VectorOfVariants)
{
std::vector<TestVar> vv1(1024);
std::vector<TestVar> vv2(1024);
EXPECT_TRUE(vv1 == vv2);
std::vector<TestVar> vv3(2048, TestVar(std::string("42")));
// Just test chat the below code compiles:
// 1: internal copy of variants from one vector to another,
// with probable reallocation of 1st vector to host all elements
std::copy(vv1.begin(), vv1.end(), std::back_inserter(vv2));
EXPECT_EQ(2048u, vv2.size());
// 2: truncation of vector, with probable destruction of its tail memory
vv2.resize(1024);
EXPECT_EQ(1024u, vv2.size());
// 3. vector assignment, with overwriting underlying variants
vv2 = vv3;
EXPECT_EQ(2048u, vv2.size());
EXPECT_TRUE(vv2 == vv3);
}
TEST(Variant, HoldsAlternative)
{
TestVar v(42);
EXPECT_TRUE (util::holds_alternative<int> (v));
EXPECT_FALSE(util::holds_alternative<std::string>(v));
v = std::string("42");
EXPECT_FALSE(util::holds_alternative<int> (v));
EXPECT_TRUE (util::holds_alternative<std::string>(v));
}
TEST(Variant, Sizeof)
{
//variant has to store index of the contained type as well as the type itself
EXPECT_EQ(2 * sizeof(size_t), (sizeof(util::variant<int, char>)));
#if !defined(__GNUG__) || __GNUG__ >= 5
// GCC versions prior to 5.0 have limited C++11 support, e.g.
// no std::max_align_t defined
EXPECT_EQ((sizeof(std::max_align_t) + std::max(sizeof(size_t), alignof(std::max_align_t))), (sizeof(util::variant<std::max_align_t, char>)));
#endif
}
TEST(Variant, EXT_IndexOf)
{
struct MyType{};
class MyClass{};
using V = util::variant<util::monostate, int, double, char, float, MyType, MyClass>;
static_assert(0u == V::index_of<util::monostate>(), "Index is incorrect");
static_assert(1u == V::index_of<int >(), "Index is incorrect");
static_assert(2u == V::index_of<double >(), "Index is incorrect");
static_assert(3u == V::index_of<char >(), "Index is incorrect");
static_assert(4u == V::index_of<float >(), "Index is incorrect");
static_assert(5u == V::index_of<MyType >(), "Index is incorrect");
static_assert(6u == V::index_of<MyClass>(), "Index is incorrect");
}
} // namespace opencv_test