mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 12:40:05 +08:00
Merge pull request #14402 from rgarnov:gapi_planar_mats
This commit is contained in:
commit
7b8ce63730
@ -46,6 +46,10 @@ private:
|
||||
std::shared_ptr<GOrigin> m_priv;
|
||||
};
|
||||
|
||||
namespace gapi { namespace own {
|
||||
class Mat;
|
||||
}}//gapi::own
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@ -58,10 +62,16 @@ struct GAPI_EXPORTS GMatDesc
|
||||
int depth;
|
||||
int chan;
|
||||
cv::gapi::own::Size size; // NB.: no multi-dimensional cases covered yet
|
||||
bool planar;
|
||||
|
||||
GMatDesc(int d, int c, cv::gapi::own::Size s, bool p = false)
|
||||
: depth(d), chan(c), size(s), planar(p) {}
|
||||
|
||||
GMatDesc() : GMatDesc(-1, -1, {-1,-1}) {}
|
||||
|
||||
inline bool operator== (const GMatDesc &rhs) const
|
||||
{
|
||||
return depth == rhs.depth && chan == rhs.chan && size == rhs.size;
|
||||
return depth == rhs.depth && chan == rhs.chan && size == rhs.size && planar == rhs.planar;
|
||||
}
|
||||
|
||||
inline bool operator!= (const GMatDesc &rhs) const
|
||||
@ -69,6 +79,12 @@ struct GAPI_EXPORTS GMatDesc
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
// Checks if the passed mat can be described by this descriptor
|
||||
// (it handles the case when
|
||||
// 1-channel mat can be reinterpreted as is (1-channel mat)
|
||||
// and as a 3-channel planar mat with height divided by 3)
|
||||
bool canDescribe(const cv::gapi::own::Mat& mat) const;
|
||||
|
||||
// Meta combinator: return a new GMatDesc which differs in size by delta
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
// FIXME: a better name?
|
||||
@ -88,6 +104,8 @@ struct GAPI_EXPORTS GMatDesc
|
||||
{
|
||||
return withSize(to_own(sz));
|
||||
}
|
||||
|
||||
bool canDescribe(const cv::Mat& mat) const;
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
// Meta combinator: return a new GMatDesc which differs in size by delta
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
@ -125,6 +143,43 @@ struct GAPI_EXPORTS GMatDesc
|
||||
desc.chan = dchan;
|
||||
return desc;
|
||||
}
|
||||
|
||||
// Meta combinator: return a new GMatDesc with planar flag set
|
||||
// (no size changes are performed, only channel interpretation is changed
|
||||
// (interleaved -> planar)
|
||||
GMatDesc asPlanar() const
|
||||
{
|
||||
GAPI_Assert(planar == false);
|
||||
GMatDesc desc(*this);
|
||||
desc.planar = true;
|
||||
return desc;
|
||||
}
|
||||
|
||||
// Meta combinator: return a new GMatDesc
|
||||
// reinterpreting 1-channel input as planar image
|
||||
// (size height is divided by plane number)
|
||||
GMatDesc asPlanar(int planes) const
|
||||
{
|
||||
GAPI_Assert(planar == false);
|
||||
GAPI_Assert(chan == 1);
|
||||
GAPI_Assert(planes > 1);
|
||||
GAPI_Assert(size.height % planes == 0);
|
||||
GMatDesc desc(*this);
|
||||
desc.size.height /= planes;
|
||||
desc.chan = planes;
|
||||
return desc.asPlanar();
|
||||
}
|
||||
|
||||
// Meta combinator: return a new GMatDesc with planar flag set to false
|
||||
// (no size changes are performed, only channel interpretation is changed
|
||||
// (planar -> interleaved)
|
||||
GMatDesc asInterleaved() const
|
||||
{
|
||||
GAPI_Assert(planar == true);
|
||||
GMatDesc desc(*this);
|
||||
desc.planar = false;
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
|
||||
static inline GMatDesc empty_gmat_desc() { return GMatDesc{-1,-1,{-1,-1}}; }
|
||||
@ -138,7 +193,6 @@ GAPI_EXPORTS GMatDesc descr_of(const cv::UMat &mat);
|
||||
/** @} */
|
||||
|
||||
namespace gapi { namespace own {
|
||||
class Mat;
|
||||
GAPI_EXPORTS GMatDesc descr_of(const Mat &mat);
|
||||
}}//gapi::own
|
||||
|
||||
|
@ -112,8 +112,16 @@ GMetaArgs GAPI_EXPORTS descr_of(const GRunArgs &args);
|
||||
|
||||
// Transform run-time operation result argument into metadata extracted from that argument
|
||||
// Used to compare the metadata, which generated at compile time with the metadata result operation in run time
|
||||
GMetaArg GAPI_EXPORTS descr_of(const GRunArgP& argp);
|
||||
GMetaArg GAPI_EXPORTS descr_of(const GRunArgP& argp);
|
||||
|
||||
// Checks if run-time computation argument can be described by metadata
|
||||
bool GAPI_EXPORTS can_describe(const GMetaArg& meta, const GRunArg& arg);
|
||||
bool GAPI_EXPORTS can_describe(const GMetaArgs& metas, const GRunArgs& args);
|
||||
|
||||
// Checks if run-time computation result argument can be described by metadata.
|
||||
// Used to check if the metadata generated at compile time
|
||||
// coincides with output arguments passed to computation in cpu and ocl backends
|
||||
bool GAPI_EXPORTS can_describe(const GMetaArg& meta, const GRunArgP& argp);
|
||||
|
||||
} // namespace cv
|
||||
|
||||
|
@ -79,6 +79,7 @@ namespace detail
|
||||
template<typename T> struct GTypeOf;
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
template<> struct GTypeOf<cv::Mat> { using type = cv::GMat; };
|
||||
template<> struct GTypeOf<cv::UMat> { using type = cv::GMat; };
|
||||
template<> struct GTypeOf<cv::Scalar> { using type = cv::GScalar; };
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
template<> struct GTypeOf<cv::gapi::own::Mat> { using type = cv::GMat; };
|
||||
|
@ -349,5 +349,24 @@ void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg, bool is_umat)
|
||||
}
|
||||
|
||||
} // namespace magazine
|
||||
|
||||
void createMat(const cv::GMatDesc desc, cv::gapi::own::Mat& mat)
|
||||
{
|
||||
const auto type = desc.planar ? desc.depth : CV_MAKETYPE(desc.depth, desc.chan);
|
||||
const auto size = desc.planar ? cv::gapi::own::Size{desc.size.width, desc.size.height*desc.chan}
|
||||
: desc.size;
|
||||
mat.create(size, type);
|
||||
}
|
||||
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
void createMat(const cv::GMatDesc desc, cv::Mat& mat)
|
||||
{
|
||||
const auto type = desc.planar ? desc.depth : CV_MAKETYPE(desc.depth, desc.chan);
|
||||
const auto size = desc.planar ? cv::Size{desc.size.width, desc.size.height*desc.chan}
|
||||
: cv::gapi::own::to_ocv(desc.size);
|
||||
mat.create(size, type);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gimpl
|
||||
} // namespace cv
|
||||
|
@ -99,9 +99,32 @@ std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc)
|
||||
break;
|
||||
}
|
||||
|
||||
os << "C" << desc.chan << " ";
|
||||
os << "C" << desc.chan;
|
||||
if (desc.planar) os << "p";
|
||||
os << " ";
|
||||
os << desc.size.width << "x" << desc.size.height;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<typename M> inline bool canDescribeHelper(const GMatDesc& desc, const M& mat)
|
||||
{
|
||||
const auto mat_desc = desc.planar ? descr_of(mat).asPlanar(desc.chan) : descr_of(mat);
|
||||
return desc == mat_desc;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
bool GMatDesc::canDescribe(const cv::gapi::own::Mat& mat) const
|
||||
{
|
||||
return canDescribeHelper(*this, mat);
|
||||
}
|
||||
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
bool GMatDesc::canDescribe(const cv::Mat& mat) const
|
||||
{
|
||||
return canDescribeHelper(*this, mat);
|
||||
}
|
||||
#endif
|
||||
|
||||
}// namespace cv
|
||||
|
@ -132,6 +132,51 @@ cv::GMetaArg cv::descr_of(const cv::GRunArgP &argp)
|
||||
}
|
||||
}
|
||||
|
||||
bool cv::can_describe(const GMetaArg& meta, const GRunArgP& argp)
|
||||
{
|
||||
switch (argp.index())
|
||||
{
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
case GRunArgP::index_of<cv::Mat*>(): return util::holds_alternative<GMatDesc>(meta) &&
|
||||
util::get<GMatDesc>(meta).canDescribe(*util::get<cv::Mat*>(argp));
|
||||
case GRunArgP::index_of<cv::UMat*>(): return meta == GMetaArg(descr_of(*util::get<cv::UMat*>(argp)));
|
||||
case GRunArgP::index_of<cv::Scalar*>(): return meta == GMetaArg(descr_of(*util::get<cv::Scalar*>(argp)));
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
case GRunArgP::index_of<cv::gapi::own::Mat*>(): return util::holds_alternative<GMatDesc>(meta) &&
|
||||
util::get<GMatDesc>(meta).canDescribe(*util::get<cv::gapi::own::Mat*>(argp));
|
||||
case GRunArgP::index_of<cv::gapi::own::Scalar*>(): return meta == GMetaArg(descr_of(*util::get<cv::gapi::own::Scalar*>(argp)));
|
||||
case GRunArgP::index_of<cv::detail::VectorRef>(): return meta == GMetaArg(util::get<cv::detail::VectorRef>(argp).descr_of());
|
||||
default: util::throw_error(std::logic_error("Unsupported GRunArgP type"));
|
||||
}
|
||||
}
|
||||
|
||||
bool cv::can_describe(const GMetaArg& meta, const GRunArg& arg)
|
||||
{
|
||||
switch (arg.index())
|
||||
{
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
case GRunArg::index_of<cv::Mat>(): return util::holds_alternative<GMatDesc>(meta) &&
|
||||
util::get<GMatDesc>(meta).canDescribe(util::get<cv::Mat>(arg));
|
||||
case GRunArg::index_of<cv::UMat>(): return meta == cv::GMetaArg(descr_of(util::get<cv::UMat>(arg)));
|
||||
case GRunArg::index_of<cv::Scalar>(): return meta == cv::GMetaArg(descr_of(util::get<cv::Scalar>(arg)));
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
case GRunArg::index_of<cv::gapi::own::Mat>(): return util::holds_alternative<GMatDesc>(meta) &&
|
||||
util::get<GMatDesc>(meta).canDescribe(util::get<cv::gapi::own::Mat>(arg));
|
||||
case GRunArg::index_of<cv::gapi::own::Scalar>(): return meta == cv::GMetaArg(descr_of(util::get<cv::gapi::own::Scalar>(arg)));
|
||||
case GRunArg::index_of<cv::detail::VectorRef>(): return meta == cv::GMetaArg(util::get<cv::detail::VectorRef>(arg).descr_of());
|
||||
default: util::throw_error(std::logic_error("Unsupported GRunArg type"));
|
||||
}
|
||||
}
|
||||
|
||||
bool cv::can_describe(const GMetaArgs &metas, const GRunArgs &args)
|
||||
{
|
||||
return metas.size() == args.size() &&
|
||||
std::equal(metas.begin(), metas.end(), args.begin(),
|
||||
[](const GMetaArg& meta, const GRunArg& arg) {
|
||||
return can_describe(meta, arg);
|
||||
});
|
||||
}
|
||||
|
||||
namespace cv {
|
||||
std::ostream& operator<<(std::ostream& os, const cv::GMetaArg &arg)
|
||||
{
|
||||
|
@ -99,7 +99,10 @@ inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args)
|
||||
return cv::util::optional<T>();
|
||||
}
|
||||
|
||||
|
||||
void createMat(const cv::GMatDesc desc, cv::gapi::own::Mat& mat);
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
void createMat(const cv::GMatDesc desc, cv::Mat& mat);
|
||||
#endif
|
||||
|
||||
}} // cv::gimpl
|
||||
|
||||
|
@ -101,8 +101,8 @@ cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
|
||||
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)
|
||||
{
|
||||
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
|
||||
const auto type = CV_MAKETYPE(mat_desc.depth, mat_desc.chan);
|
||||
m_res.slot<cv::gapi::own::Mat>()[desc.rc].create(mat_desc.size, type);
|
||||
auto& mat = m_res.slot<cv::gapi::own::Mat>()[desc.rc];
|
||||
createMat(mat_desc, mat);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -207,14 +207,16 @@ void cv::gimpl::GCPUExecutable::run(std::vector<InObj> &&input_objs,
|
||||
//As Kernels are forbidden to allocate memory for (Mat) outputs,
|
||||
//this code seems redundant, at least for Mats
|
||||
//FIXME: unify with cv::detail::ensure_out_mats_not_reallocated
|
||||
//FIXME: when it's done, remove can_describe(const GMetaArg&, const GRunArgP&)
|
||||
//and descr_of(const cv::GRunArgP &argp)
|
||||
for (const auto &out_it : ade::util::indexed(op_info.expected_out_metas))
|
||||
{
|
||||
const auto out_index = ade::util::index(out_it);
|
||||
const auto expected_meta = ade::util::value(out_it);
|
||||
const auto out_meta = descr_of(context.m_results[out_index]);
|
||||
|
||||
if (expected_meta != out_meta)
|
||||
if (!can_describe(expected_meta, context.m_results[out_index]))
|
||||
{
|
||||
const auto out_meta = descr_of(context.m_results[out_index]);
|
||||
util::throw_error
|
||||
(std::logic_error
|
||||
("Output meta doesn't "
|
||||
|
@ -101,8 +101,8 @@ cv::gimpl::GOCLExecutable::GOCLExecutable(const ade::Graph &g,
|
||||
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)
|
||||
{
|
||||
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
|
||||
const auto type = CV_MAKETYPE(mat_desc.depth, mat_desc.chan);
|
||||
m_res.slot<cv::UMat>()[desc.rc].create(mat_desc.size.height, mat_desc.size.width, type);
|
||||
auto& mat = m_res.slot<cv::gapi::own::Mat>()[desc.rc];
|
||||
createMat(mat_desc, mat);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -208,10 +208,10 @@ void cv::gimpl::GOCLExecutable::run(std::vector<InObj> &&input_objs,
|
||||
{
|
||||
const auto out_index = ade::util::index(out_it);
|
||||
const auto expected_meta = ade::util::value(out_it);
|
||||
const auto out_meta = descr_of(context.m_results[out_index]);
|
||||
|
||||
if (expected_meta != out_meta)
|
||||
if (!can_describe(expected_meta, context.m_results[out_index]))
|
||||
{
|
||||
const auto out_meta = descr_of(context.m_results[out_index]);
|
||||
util::throw_error
|
||||
(std::logic_error
|
||||
("Output meta doesn't "
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include <ade/graph.hpp>
|
||||
|
||||
#include "opencv2/gapi/gproto.hpp" // descr_of
|
||||
#include "opencv2/gapi/gproto.hpp" // can_describe
|
||||
#include "opencv2/gapi/gcompiled.hpp"
|
||||
|
||||
#include "compiler/gcompiled_priv.hpp"
|
||||
@ -50,11 +50,10 @@ const cv::GMetaArgs& cv::GCompiled::Priv::outMetas() const
|
||||
|
||||
void cv::GCompiled::Priv::checkArgs(const cv::gimpl::GRuntimeArgs &args) const
|
||||
{
|
||||
const auto runtime_metas = descr_of(args.inObjs);
|
||||
if (runtime_metas != m_metas)
|
||||
if (!can_describe(m_metas, args.inObjs))
|
||||
{
|
||||
util::throw_error(std::logic_error("This object was compiled "
|
||||
"for different metadata!"));
|
||||
util::throw_error(std::logic_error("This object was compiled "
|
||||
"for different metadata!"));
|
||||
// FIXME: Add details on what is actually wrong
|
||||
}
|
||||
}
|
||||
|
@ -99,8 +99,8 @@ void cv::gimpl::GExecutor::initResource(const ade::NodeHandle &orig_nh)
|
||||
case GShape::GMAT:
|
||||
{
|
||||
const auto desc = util::get<cv::GMatDesc>(d.meta);
|
||||
const auto type = CV_MAKETYPE(desc.depth, desc.chan);
|
||||
m_res.slot<cv::gapi::own::Mat>()[d.rc].create(desc.size, type);
|
||||
auto& mat = m_res.slot<cv::gapi::own::Mat>()[d.rc];
|
||||
createMat(desc, mat);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -152,21 +152,17 @@ void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
|
||||
{
|
||||
using cv::util::get;
|
||||
const auto desc = get<cv::GMatDesc>(d.meta);
|
||||
const auto type = CV_MAKETYPE(desc.depth, desc.chan);
|
||||
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
// Building as part of OpenCV - follow OpenCV behavior
|
||||
// if output buffer is not enough to hold the result, reallocate it
|
||||
auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
|
||||
out_mat.create(cv::gapi::own::to_ocv(desc.size), type);
|
||||
createMat(desc, out_mat);
|
||||
#else
|
||||
// Building standalone - output buffer should always exist,
|
||||
// and _exact_ match our inferred metadata
|
||||
auto& out_mat = *get<cv::gapi::own::Mat*>(args.outObjs.at(index));
|
||||
GAPI_Assert( out_mat.type() == type
|
||||
&& out_mat.data != nullptr
|
||||
&& out_mat.rows == desc.size.height
|
||||
&& out_mat.cols == desc.size.width)
|
||||
GAPI_Assert(out_mat.data != nullptr &&
|
||||
desc.canDescribe(out_mat))
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
}
|
||||
}
|
||||
|
@ -236,4 +236,70 @@ TEST(GAPI_MetaDesc, Typed_Compile_MatchMetaType_Mixed)
|
||||
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
|
||||
|
211
modules/gapi/test/gapi_planar_test.cpp
Normal file
211
modules/gapi/test/gapi_planar_test.cpp
Normal file
@ -0,0 +1,211 @@
|
||||
// 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, <GMat(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, <GMat(GMat,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(GNV12toRGB, <GMat(GMat,GMat)>, "test.nv12torgb") {
|
||||
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
|
||||
return NV12toRGBoutMeta(inY, inUV);
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GNV12toRGBp, <GMat(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::GMat 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
|
@ -133,4 +133,69 @@ TEST(GMetaArg, Can_Get_Metas_From_Output_Run_Args)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user