1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge pull request #25055 from dmatveev:dm/value_initialized_gmat

G-API: A quick value-initialization support GMat #25055

This PR enables `GMat` objects to be value-initialized in the same way as it was done for `GScalar`s (and, possibly, other types).

- Added some helper methods in backends to distinguish if a certain G-type value initialization is supported or not;
- Added tests, including negative.

Where it is needed:

- Further extension of the OVCV backend (#24379 - will be refreshed soon);
- Further experiments with DNN module;
- Further experiments with "G-API behind UMat" sort of aggregation.

In the current form, PR can be reviewed & merged (@TolyaTalamanov please have a look)

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Dmitry Matveev
2024-03-06 14:15:49 +00:00
committed by GitHub
parent 0e524ee95a
commit f174363f60
14 changed files with 208 additions and 13 deletions
+3
View File
@@ -80,6 +80,9 @@ bool cv::gapi::GBackend::Priv::allowsMerge(const cv::gimpl::GIslandModel::Graph
return true;
}
bool cv::gapi::GBackend::Priv::supportsConst(cv::GShape) const {
return false;
}
// GBackend public implementation //////////////////////////////////////////////
cv::gapi::GBackend::GBackend()
+8
View File
@@ -84,6 +84,14 @@ public:
const ade::NodeHandle &slot_nh,
const ade::NodeHandle &b_nh) const;
// Ask backend if it supports CONST_VAL data of the given shape or not.
// If the backend does support this data type, a Data node with such
// value can be fused into the backend's Island body.
// If the backend doesn't support this data type, a Data node won't
// be fused into the Islands's body -- will be marked as an in-graph
// input connection for this Island.
virtual bool supportsConst(cv::GShape shape) const;
virtual ~Priv() = default;
};
+7 -2
View File
@@ -191,8 +191,8 @@ void cv::GComputation::recompile(GMetaArgs&& in_metas, GCompileArgs &&args)
if (m_priv->m_lastMetas != in_metas)
{
if (m_priv->m_lastCompiled &&
m_priv->m_lastCompiled.canReshape() &&
formats_are_same(m_priv->m_lastMetas, in_metas))
m_priv->m_lastCompiled.canReshape() &&
formats_are_same(m_priv->m_lastMetas, in_metas))
{
m_priv->m_lastCompiled.reshape(in_metas, args);
}
@@ -203,6 +203,11 @@ void cv::GComputation::recompile(GMetaArgs&& in_metas, GCompileArgs &&args)
}
m_priv->m_lastMetas = in_metas;
}
else if (in_metas.size() == 0) {
// Happens when the graph is head-less (e.g. starts with const-vals only)
// always compile ad-hoc
m_priv->m_lastCompiled = compile(GMetaArgs(in_metas), std::move(args));
}
}
void cv::GComputation::apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args)
+4
View File
@@ -26,6 +26,10 @@ cv::GMat::GMat(const GNode &n, std::size_t out)
{
}
cv::GMat::GMat(cv::Mat m)
: m_priv(new GOrigin(GShape::GMAT, cv::gimpl::ConstVal(m))) {
}
cv::GOrigin& cv::GMat::priv()
{
return *m_priv;
+1
View File
@@ -80,6 +80,7 @@ cv::GRunArg cv::value_of(const cv::GOrigin &origin)
{
case GShape::GSCALAR: return GRunArg(util::get<cv::Scalar>(origin.value));
case GShape::GARRAY: return GRunArg(util::get<cv::detail::VectorRef>(origin.value));
case GShape::GMAT: return GRunArg(util::get<cv::Mat>(origin.value));
default: util::throw_error(std::logic_error("Unsupported shape for constant"));
}
}
@@ -65,6 +65,17 @@ namespace
{
return EPtr{new cv::gimpl::GCPUExecutable(graph, compileArgs, nodes)};
}
virtual bool supportsConst(cv::GShape shape) const override
{
// Supports all types of const values
return shape == cv::GShape::GOPAQUE
|| shape == cv::GShape::GSCALAR
|| shape == cv::GShape::GARRAY;
// yes, value-initialized GMats are not supported currently
// as in-island data -- compiler will lift these values to the
// GIslandModel's SLOT level (will be handled uniformly)
}
};
}
@@ -62,6 +62,17 @@ namespace
{
return EPtr{new cv::gimpl::GOCLExecutable(graph, nodes)};
}
virtual bool supportsConst(cv::GShape shape) const override
{
// Supports all types of const values
return shape == cv::GShape::GOPAQUE
|| shape == cv::GShape::GSCALAR
|| shape == cv::GShape::GARRAY;
// yes, value-initialized GMats are not supported currently
// as in-island data -- compiler will lift these values to the
// GIslandModel's SLOT level (will be handled uniformly)
}
};
}
+1
View File
@@ -24,6 +24,7 @@ namespace gimpl
< util::monostate
, cv::Scalar
, cv::detail::VectorRef
, cv::Mat
>;
struct RcDesc
+20 -4
View File
@@ -9,7 +9,7 @@
#include <string>
#include <list> // list
#include <iomanip> // setw, etc
#include <iomanip> // setw, etc
#include <fstream> // ofstream
#include <memory>
#include <functional>
@@ -85,7 +85,7 @@ namespace
const auto& backend = *src_g.metadata().get<ActiveBackends>().backends.cbegin();
const auto& proto = src_g.metadata().get<Protocol>();
GIsland::node_set all, in_ops, out_ops;
GIsland::node_set all, in_ops, out_ops, in_cvals;
all.insert(src_g.nodes().begin(), src_g.nodes().end());
@@ -99,7 +99,22 @@ namespace
all.erase(nh);
out_ops.insert(nh->inNodes().begin(), nh->inNodes().end());
}
for (const auto& nh : src_g.nodes())
{
if (src_g.metadata(nh).get<NodeType>().t == NodeType::DATA)
{
const auto &d = src_g.metadata(nh).get<Data>();
if (d.storage == Data::Storage::CONST_VAL
&& !backend.priv().supportsConst(d.shape)) {
// don't put this node into the island's graph - so the island
// executable don't need to handle value-initialized G-type manually.
// Still mark its readers as inputs
all.erase(nh);
in_cvals.insert(nh);
in_ops.insert(nh->outNodes().begin(), nh->outNodes().end());
}
}
}
auto isl = std::make_shared<GIsland>(backend,
std::move(all),
std::move(in_ops),
@@ -108,7 +123,8 @@ namespace
auto ih = GIslandModel::mkIslandNode(g, std::move(isl));
for (const auto& nh : proto.in_nhs)
for (const auto& nh : ade::util::chain(ade::util::toRange(proto.in_nhs),
ade::util::toRange(in_cvals)))
{
auto slot = GIslandModel::mkSlotNode(g, nh);
g.link(slot, ih);
+6
View File
@@ -208,6 +208,12 @@ void cv::gimpl::GExecutor::initResource(const ade::NodeHandle & nh, const ade::N
switch (d.shape)
{
case GShape::GMAT:
if (d.storage == Data::Storage::CONST_VAL)
{
auto rc = RcDesc{d.rc, d.shape, d.ctor};
magazine::bindInArgExec(m_res, rc, m_gm.metadata(orig_nh).get<ConstValue>().arg);
}
else
{
// Let island allocate it's outputs if it can,
// allocate cv::Mat and wrap it with RMat otherwise
@@ -175,7 +175,11 @@ void cv::gimpl::GThreadedExecutor::initResource(const ade::NodeHandle &nh, const
// to as it is bound externally (e.g. already in the m_state.mag)
switch (d.shape) {
case GShape::GMAT: {
case GShape::GMAT:
if (d.storage == Data::Storage::CONST_VAL) {
auto rc = RcDesc{d.rc, d.shape, d.ctor};
magazine::bindInArgExec(m_state.mag, rc, m_gm.metadata(orig_nh).get<ConstValue>().arg);
} else {
// Let island allocate it's outputs if it can,
// allocate cv::Mat and wrap it with RMat otherwise
GAPI_Assert(!nh->inNodes().empty());