Pre-processing: Adding DivC and SubC kernels. (#5364)

* [PP] FLuid level tests for mean value preprocessing

* PP] Fluid operations for mean value preprocessing

* * Relaxed tolerance and fix for issue.

* * Fix for issue.

* * Applied comments.

Co-authored-by: Anton Potapov <anton.potapov@intel.com>
This commit is contained in:
Anna Khakimova 2021-04-29 13:38:28 +03:00 committed by GitHub
parent 768aec9d92
commit b1a4a73328
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 308 additions and 20 deletions

View File

@ -2461,6 +2461,58 @@ GAPI_FLUID_KERNEL(FConvertDepth, ConvertDepth, false) {
}
};
namespace {
template <typename src_t, typename dst_t>
void sub(const uint8_t* src, uint8_t* dst, const int width, double c) {
const auto *in = reinterpret_cast<const src_t *>(src);
auto *out = reinterpret_cast<dst_t *>(dst);
for (int i = 0; i < width; i++) {
out[i] = saturate_cast<dst_t>(in[i] - c);
}
}
template <typename src_t, typename dst_t>
void div(const uint8_t* src, uint8_t* dst, const int width, double c) {
const auto *in = reinterpret_cast<const src_t *>(src);
auto *out = reinterpret_cast<dst_t *>(dst);
for (int i = 0; i < width; i++) {
out[i] = saturate_cast<dst_t>(in[i] / c);
}
}
} // namespace
GAPI_FLUID_KERNEL(FSubC, GSubC, false) {
static const int Window = 1;
static void run(const cv::gapi::fluid::View& src, const cv::Scalar &scalar, int depth, cv::gapi::fluid::Buffer& dst) {
GAPI_Assert(src.meta().depth == CV_32F && src.meta().chan == 1);
const auto *in = src.InLineB(0);
auto *out = dst.OutLineB();
auto const width = dst.length();
sub<float, float>(in, out, width, scalar[0]);
}
};
GAPI_FLUID_KERNEL(FDivC, GDivC, false) {
static const int Window = 1;
static void run(const cv::gapi::fluid::View &src, const cv::Scalar &scalar, double _scale, int /*dtype*/,
cv::gapi::fluid::Buffer &dst) {
GAPI_Assert(src.meta().depth == CV_32F && src.meta().chan == 1);
const auto *in = src.InLineB(0);
auto *out = dst.OutLineB();
auto const width = dst.length();
div<float, float>(in, out, width, scalar[0]);
}
};
} // namespace kernels
//----------------------------------------------------------------------
@ -2488,6 +2540,8 @@ cv::gapi::GKernelPackage preprocKernels() {
, FNV12toRGB
, FI420toRGB
, FConvertDepth
, FSubC
, FDivC
>();
}

View File

@ -152,8 +152,17 @@ namespace gapi {
}
};
G_TYPED_KERNEL(GSubC, <cv::GMat(cv::GMat, cv::GScalar, int)>, "com.intel.ie.math.subC") {
static cv::GMatDesc outMeta(cv::GMatDesc a, cv::GScalarDesc, int ddepth) {
return a.withDepth(ddepth);
}
};
G_TYPED_KERNEL(GDivC, <cv::GMat(cv::GMat, cv::GScalar, double, int)>, "com.intel.ie.math.divC") {
static cv::GMatDesc outMeta(cv::GMatDesc a, cv::GScalarDesc, double, int ddepth) {
return a.withDepth(ddepth);
}
};
cv::gapi::GKernelPackage preprocKernels();
} // namespace gapi

View File

@ -57,6 +57,8 @@ template<> inline uint8_t saturate_cast(uint16_t x) {
std::max(static_cast<uint16_t>(lim::min()), x));
}
template<> inline uint8_t saturate_cast(float x) { return saturate_cast<uint8_t>(static_cast<int>(std::rint(x))); }
template<> inline float saturate_cast(double x) { return x; }
//------------------------------------------------------------------------------
constexpr static const int ONE = 1 << 15;

View File

@ -142,6 +142,7 @@ std::vector<test::Mat> to_test(std::vector<cv::Mat>& mats)
}
test::Rect to_test(cv::Rect& rect) { return {rect.x, rect.y, rect.width, rect.height}; }
test::Scalar to_test(cv::Scalar const& sc) { return {sc[0], sc[1], sc[2], sc[3]}; }
cv::ColorConversionCodes toCvtColorCode(InferenceEngine::ColorFormat in,
InferenceEngine::ColorFormat out) {
@ -678,6 +679,61 @@ TEST_P(ConvertDepthTestGAPI, AccuracyTest)
EXPECT_LE(cv::norm(out_mat_ocv, out_mat_gapi, cv::NORM_INF), tolerance);
}
}
TEST_P(DivCTestGAPI, AccuracyTest)
{
const auto params = GetParam();
const int in_depth = std::get<0>(params);
const int in_channels = std::get<1>(params);
const cv::Size sz = std::get<2>(params);
const cv::Scalar C = std::get<3>(params);
double tolerance = std::get<4>(params);
const int in_type = CV_MAKETYPE(in_depth,in_channels);
initMatrixRandU(in_type, sz, in_type);
// G-API code
DivCComputation cc(to_test(in_mat1), to_test(out_mat_gapi), to_test(C));
cc.warmUp();
// OpenCV code /////////////////////////////////////////////////////////////
{
out_mat_ocv = in_mat1 / C;
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_LE(cv::norm(out_mat_ocv, out_mat_gapi, cv::NORM_INF), tolerance);
}
}
TEST_P(SubCTestGAPI, AccuracyTest)
{
const auto params = GetParam();
const int in_depth = std::get<0>(params);
const int in_channels = std::get<1>(params);
const cv::Size sz = std::get<2>(params);
const cv::Scalar C = std::get<3>(params);
const double tolerance = std::get<4>(params);
const int in_type = CV_MAKETYPE(in_depth,in_channels);
initMatrixRandU(in_type, sz, in_type);
// G-API code
SubCComputation cc(to_test(in_mat1), to_test(out_mat_gapi), to_test(C));
cc.warmUp();
// OpenCV code /////////////////////////////////////////////////////////////
{
out_mat_ocv = in_mat1 - C;
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_LE(cv::norm(out_mat_ocv, out_mat_gapi, cv::NORM_INF), tolerance);
}
}
//----------------------------------------------------------------------
TEST_P(ResizeTestIE, AccuracyTest)
@ -1268,5 +1324,31 @@ TEST_P(PreprocTest, Performance)
out_layout_str.c_str(), out_size.width, out_size.height,
colorFormatToString(in_fmt).c_str(), colorFormatToString(out_fmt).c_str());
#endif // PERF_TEST
}
TEST_P(MeanValueGAPI, AccuracyTest)
{
const auto params = GetParam();
cv::Size sz = std::get<0>(params);
double tolerance = std::get<1>(params);
initMatrixRandU(CV_32FC1, sz, CV_32FC1);
const cv::Scalar mean = { 0.485, 0.456, 0.406 };
const cv::Scalar std = { 0.229, 0.224, 0.225 };
// G-API code
MeanValueSubtractComputation cc(to_test(in_mat1), to_test(out_mat_gapi), to_test(mean), to_test(std));
cc.warmUp();
// OpenCV code /////////////////////////////////////////////////////////////
{
out_mat_ocv = (in_mat1 - mean) / std;
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_LE(cv::norm(out_mat_ocv, out_mat_gapi, cv::NORM_INF), tolerance);
}
}

View File

@ -25,6 +25,18 @@ struct ConvertDepthTestGAPI: public TestParams<std::tuple<
cv::Size,
double>> // tolerance
{};
struct DivCTestGAPI: public TestParams<std::tuple<
int, // input matrix depth
int, // input matrix channels number
cv::Size,
cv::Scalar, // second operarnd
double>> // tolerance
{};
struct SubCTestGAPI : public DivCTestGAPI
{};
struct MeanValueGAPI: public TestParams<std::tuple<cv::Size, double>> {};
//------------------------------------------------------------------------------
struct ResizeTestIE: public testing::TestWithParam<std::tuple<int, int, std::pair<cv::Size, cv::Size>, double>> {};

View File

@ -183,6 +183,20 @@ INSTANTIATE_TEST_CASE_P(ConvertDepthFluid, ConvertDepthTestGAPI,
cv::Size( 320, 200)),
Values(1)));
INSTANTIATE_TEST_CASE_P(DivCFluid, DivCTestGAPI,
Combine(Values(CV_32F),
Values(1), //channels
Values(TEST_SIZES),
Values(cv::Scalar{0.229}),
Values(0)));
INSTANTIATE_TEST_CASE_P(SubCFluid, SubCTestGAPI,
Combine(Values(CV_32F),
Values(1), //channels
Values(TEST_SIZES),
Values(cv::Scalar{0.229}),
Values(0.00001)));
INSTANTIATE_TEST_CASE_P(ResizeRoiTestFluid, ResizeRoiTestGAPI,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::INTER_LINEAR),
@ -284,6 +298,10 @@ INSTANTIATE_TEST_CASE_P(Reorder_CHW2HWC, ColorConvertTestIE,
Values(TEST_SIZES),
Values(0)));
INSTANTIATE_TEST_CASE_P(MeanValueGAPI32F, MeanValueGAPI,
Combine(Values(TEST_SIZES),
Values(0.00001)));
//------------------------------------------------------------------------------
namespace IE = InferenceEngine;

View File

@ -12,8 +12,42 @@
struct FluidComputation::Priv
{
cv::GComputation m_c;
std::vector<cv::gapi::own::Mat> m_v_in;
cv::GRunArgs m_v_in;
std::vector<cv::gapi::own::Mat> m_v_out;
Priv(cv::GComputation && c, std::vector<cv::gapi::own::Mat>&& v_in, std::vector<cv::gapi::own::Mat>&& v_out)
: m_c(std::move(c)),
m_v_in(v_in.begin(), v_in.end()),
m_v_out(std::move(v_out))
{}
Priv(cv::GComputation && c, cv::gapi::own::Mat&& v_in, cv::gapi::own::Mat&& v_out)
: m_c(std::move(c)),
m_v_in{std::move(v_in)},
m_v_out{std::move(v_out)}
{}
Priv(cv::GComputation && c, cv::gapi::own::Mat&& v_in, std::vector<cv::gapi::own::Mat>&& v_out)
: m_c(std::move(c)),
m_v_in{std::move(v_in)},
m_v_out(std::move(v_out))
{}
Priv(cv::GComputation && c, cv::GRunArgs&& v_in, std::vector<cv::gapi::own::Mat>&& v_out)
: m_c(std::move(c)),
m_v_in(std::move(v_in)),
m_v_out(std::move(v_out))
{}
cv::GRunArgs ins() { return m_v_in;}
cv::GRunArgsP outs() {
cv::GRunArgsP call_outs;
for (auto &m : m_v_out) { call_outs.emplace_back(&m); }
return call_outs;
}
};
FluidComputation::FluidComputation(Priv *priv)
@ -27,19 +61,24 @@ namespace
void FluidComputation::warmUp(test::Rect roi)
{
if (roi.empty())
m_priv->m_c.apply(m_priv->m_v_in, m_priv->m_v_out, cv::compile_args(InferenceEngine::gapi::preprocKernels()));
else
m_priv->m_c.apply(m_priv->m_v_in, m_priv->m_v_out, cv::compile_args(InferenceEngine::gapi::preprocKernels(), cv::GFluidOutputRois{{to_own(roi)}}));
auto compile_args = roi.empty() ? cv::compile_args(InferenceEngine::gapi::preprocKernels())
: cv::compile_args(InferenceEngine::gapi::preprocKernels(),
cv::GFluidOutputRois{{to_own(roi)}});
m_priv->m_c.apply(m_priv->ins(), m_priv->outs(), std::move(compile_args));
}
void FluidComputation::apply()
{
m_priv->m_c.apply(m_priv->m_v_in, m_priv->m_v_out);
m_priv->m_c.apply(m_priv->ins(), m_priv->outs());
}
namespace
{
cv::gapi::own::Scalar to_own(test::Scalar const& s) {
return {s.v[0], s.v[1], s.v[2], s.v[3]};
}
cv::gapi::own::Mat to_own(test::Mat mat) {
return {mat.rows, mat.cols, mat.type, mat.data, mat.step};
}
@ -94,8 +133,8 @@ static cv::GComputation buildResizeComputation(test::Mat inMat, test::Mat outMat
FluidResizeComputation::FluidResizeComputation(test::Mat inMat, test::Mat outMat, int interp)
: FluidComputation(new Priv{buildResizeComputation(inMat, outMat, interp)
,{to_own(inMat)}
,{to_own(outMat)}
,to_own(inMat)
,to_own(outMat)
})
{}
@ -122,8 +161,8 @@ static cv::GComputation buildResizeRGB8UComputation(test::Mat inMat, test::Mat o
FluidResizeRGB8UComputation::FluidResizeRGB8UComputation(test::Mat inMat, test::Mat outMat, int interp)
: FluidComputation(new Priv{buildResizeRGB8UComputation(inMat, outMat, interp)
,{to_own(inMat)}
,{to_own(outMat)}
,to_own(inMat)
,to_own(outMat)
})
{}
@ -144,7 +183,7 @@ static cv::GComputation buildSplitComputation(int planes)
FluidSplitComputation::FluidSplitComputation(test::Mat inMat, std::vector<test::Mat> outMats)
: FluidComputation(new Priv{buildSplitComputation(outMats.size())
,{to_own(inMat)}
,to_own(inMat)
,to_own(outMats)
})
{}
@ -158,8 +197,8 @@ static cv::GComputation buildChanToPlaneComputation(int chan)
FluidChanToPlaneComputation::FluidChanToPlaneComputation(test::Mat inMat, test::Mat outMat, int chan)
: FluidComputation(new Priv{buildChanToPlaneComputation(chan)
,{to_own(inMat)}
,{to_own(outMat)}
,to_own(inMat)
,to_own(outMat)
})
{}
@ -216,12 +255,60 @@ FluidI420toRGBComputation::FluidI420toRGBComputation(test::Mat inMat_y, test::Ma
ConvertDepthComputation::ConvertDepthComputation(test::Mat inMat, test::Mat outMat, int depth)
: FluidComputation(new Priv{ [depth]()-> cv::GComputation {
cv::GMat in;
cv::GMat out = InferenceEngine::gapi::ConvertDepth::on(in, depth);
return cv::GComputation(cv::GIn(in), cv::GOut(out));
}()
, {to_own(inMat)}
, {to_own(outMat)}
cv::GMat in;
cv::GMat out = InferenceEngine::gapi::ConvertDepth::on(in, depth);
return cv::GComputation(cv::GIn(in), cv::GOut(out));
}()
, to_own(inMat)
, to_own(outMat)
})
{}
DivCComputation::DivCComputation(test::Mat inMat, test::Mat outMat, test::Scalar const& c)
: FluidComputation(new Priv{ []()-> cv::GComputation {
cv::GMat in;
cv::GScalar C;
cv::GMat out = in / C;
return cv::GComputation(cv::GIn(in, C), cv::GOut(out));
}()
, cv::GRunArgs{cv::GRunArg{to_own(inMat)}, cv::GRunArg{to_own(c)}}
, {to_own(outMat)}
})
{}
SubCComputation::SubCComputation(test::Mat inMat, test::Mat outMat, test::Scalar const& c)
: FluidComputation(new Priv{ []()-> cv::GComputation{
cv::GMat in;
cv::GScalar C;
cv::GMat out = in - C;
return cv::GComputation(cv::GIn(in, C), cv::GOut(out));
}()
, cv::GRunArgs{cv::GRunArg{to_own(inMat)}, cv::GRunArg{to_own(c)}}
, {to_own(outMat)}
})
{}
MeanValueSubtractComputation::MeanValueSubtractComputation(test::Mat inMat, test::Mat outMat, test::Scalar const& mean, test::Scalar const& std)
: FluidComputation(new Priv{ []()-> cv::GComputation{
cv::GMat in;
cv::GScalar _mean;
cv::GScalar _std;
cv::GMat out = (in - _mean) / _std;
return cv::GComputation(cv::GIn(in, _mean, _std), cv::GOut(out));
}()
, cv::GRunArgs{cv::GRunArg{to_own(inMat)}, cv::GRunArg{to_own(mean)}, cv::GRunArg{to_own(std)}}
, {to_own(outMat)}
})
{}
namespace cv {
cv::GMat operator-(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return InferenceEngine::gapi::GSubC::on(lhs, rhs, -1);
}
cv::GMat operator/(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return InferenceEngine::gapi::GDivC::on(lhs, rhs, 1.0, -1);
}
}

View File

@ -9,6 +9,7 @@
#include <memory>
#include <vector>
#include <array>
#if defined(_WIN32)
#ifdef IMPLEMENT_FLUID_COMPUTATION_API
@ -43,6 +44,11 @@ struct Rect{
return width == 0 && height == 0;
};
};
struct Scalar
{
std::array<double, 4> v;
};
}
class FLUID_COMPUTATION_VISIBILITY FluidComputation
@ -104,4 +110,22 @@ public:
ConvertDepthComputation(test::Mat inMat, test::Mat outMat, int depth);
};
class FLUID_COMPUTATION_VISIBILITY DivCComputation : public FluidComputation
{
public:
DivCComputation(test::Mat inMat, test::Mat outMat, test::Scalar const& c);
};
class FLUID_COMPUTATION_VISIBILITY SubCComputation : public FluidComputation
{
public:
SubCComputation(test::Mat inMat, test::Mat outMat, test::Scalar const& c);
};
class FLUID_COMPUTATION_VISIBILITY MeanValueSubtractComputation : public FluidComputation
{
public:
MeanValueSubtractComputation(test::Mat inMat, test::Mat outMat, test::Scalar const& mean, test::Scalar const& std);
};
#endif // FLUID_TEST_COMPUTATIONS_HPP