mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 06:26:29 +08:00
Merge pull request #20298 from mpashchenkov:mp/python-desync
G-API: Python. Desync. * Desync. GMat. * Alignment
This commit is contained in:
parent
050ea9762f
commit
05f1939b02
@ -71,6 +71,15 @@ using GOptRunArgP = util::variant<
|
|||||||
>;
|
>;
|
||||||
using GOptRunArgsP = std::vector<GOptRunArgP>;
|
using GOptRunArgsP = std::vector<GOptRunArgP>;
|
||||||
|
|
||||||
|
using GOptRunArg = util::variant<
|
||||||
|
optional<cv::Mat>,
|
||||||
|
optional<cv::RMat>,
|
||||||
|
optional<cv::Scalar>,
|
||||||
|
optional<cv::detail::VectorRef>,
|
||||||
|
optional<cv::detail::OpaqueRef>
|
||||||
|
>;
|
||||||
|
using GOptRunArgs = std::vector<GOptRunArg>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<typename T> inline GOptRunArgP wrap_opt_arg(optional<T>& arg) {
|
template<typename T> inline GOptRunArgP wrap_opt_arg(optional<T>& arg) {
|
||||||
@ -255,7 +264,7 @@ public:
|
|||||||
|
|
||||||
// NB: Used from python
|
// NB: Used from python
|
||||||
/// @private -- Exclude this function from OpenCV documentation
|
/// @private -- Exclude this function from OpenCV documentation
|
||||||
GAPI_WRAP std::tuple<bool, cv::GRunArgs> pull();
|
GAPI_WRAP std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> pull();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get some next available data from the pipeline.
|
* @brief Get some next available data from the pipeline.
|
||||||
|
@ -131,7 +131,8 @@ PyObject* pyopencv_from(const cv::detail::PyObjectHolder& v)
|
|||||||
template <>
|
template <>
|
||||||
PyObject* pyopencv_from(const cv::gapi::wip::draw::Prim& prim)
|
PyObject* pyopencv_from(const cv::gapi::wip::draw::Prim& prim)
|
||||||
{
|
{
|
||||||
switch (prim.index()) {
|
switch (prim.index())
|
||||||
|
{
|
||||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Rect>():
|
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Rect>():
|
||||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Rect>(prim));
|
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Rect>(prim));
|
||||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Text>():
|
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Text>():
|
||||||
@ -319,40 +320,69 @@ PyObject* pyopencv_from(const GRunArg& v)
|
|||||||
return pyopencv_from(util::get<cv::detail::OpaqueRef>(v));
|
return pyopencv_from(util::get<cv::detail::OpaqueRef>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs");
|
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs. Index of variant is unknown");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
PyObject* pyopencv_from(const cv::optional<T>& opt)
|
||||||
|
{
|
||||||
|
if (!opt.has_value())
|
||||||
|
{
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
return pyopencv_from(*opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
PyObject* pyopencv_from(const GOptRunArg& v)
|
||||||
|
{
|
||||||
|
switch (v.index())
|
||||||
|
{
|
||||||
|
case GOptRunArg::index_of<cv::optional<cv::Mat>>():
|
||||||
|
return pyopencv_from(util::get<cv::optional<cv::Mat>>(v));
|
||||||
|
|
||||||
|
case GOptRunArg::index_of<cv::optional<cv::Scalar>>():
|
||||||
|
return pyopencv_from(util::get<cv::optional<cv::Scalar>>(v));
|
||||||
|
|
||||||
|
case GOptRunArg::index_of<optional<cv::detail::VectorRef>>():
|
||||||
|
return pyopencv_from(util::get<optional<cv::detail::VectorRef>>(v));
|
||||||
|
|
||||||
|
case GOptRunArg::index_of<optional<cv::detail::OpaqueRef>>():
|
||||||
|
return pyopencv_from(util::get<optional<cv::detail::OpaqueRef>>(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Failed to unpack GOptRunArg. Index of variant is unknown");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
PyObject* pyopencv_from(const GRunArgs& value)
|
PyObject* pyopencv_from(const GRunArgs& value)
|
||||||
{
|
{
|
||||||
size_t i, n = value.size();
|
return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
|
||||||
|
}
|
||||||
|
|
||||||
// NB: It doesn't make sense to return list with a single element
|
template<>
|
||||||
if (n == 1)
|
PyObject* pyopencv_from(const GOptRunArgs& value)
|
||||||
|
{
|
||||||
|
return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: cv::variant should be wrapped once for all types.
|
||||||
|
template <>
|
||||||
|
PyObject* pyopencv_from(const cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>& v)
|
||||||
|
{
|
||||||
|
using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||||
|
switch (v.index())
|
||||||
{
|
{
|
||||||
PyObject* item = pyopencv_from(value[0]);
|
case RunArgs::index_of<cv::GRunArgs>():
|
||||||
if(!item)
|
return pyopencv_from(util::get<cv::GRunArgs>(v));
|
||||||
{
|
case RunArgs::index_of<cv::GOptRunArgs>():
|
||||||
return NULL;
|
return pyopencv_from(util::get<cv::GOptRunArgs>(v));
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* list = PyList_New(n);
|
PyErr_SetString(PyExc_TypeError, "Failed to recognize kind of RunArgs. Index of variant is unknown");
|
||||||
for(i = 0; i < n; ++i)
|
return NULL;
|
||||||
{
|
|
||||||
PyObject* item = pyopencv_from(value[i]);
|
|
||||||
if(!item)
|
|
||||||
{
|
|
||||||
Py_DECREF(list);
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
PyList_SetItem(list, i, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -634,7 +664,8 @@ static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
|
|||||||
cv::detail::PyObjectHolder result(
|
cv::detail::PyObjectHolder result(
|
||||||
PyObject_CallObject(kernel.get(), args.get()), false);
|
PyObject_CallObject(kernel.get(), args.get()), false);
|
||||||
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred())
|
||||||
|
{
|
||||||
PyErr_PrintEx(0);
|
PyErr_PrintEx(0);
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
throw std::logic_error("Python kernel failed with error!");
|
throw std::logic_error("Python kernel failed with error!");
|
||||||
@ -717,8 +748,9 @@ static cv::GMetaArgs get_meta_args(PyObject* tuple)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GMetaArgs run_py_meta(cv::detail::PyObjectHolder out_meta,
|
static GMetaArgs run_py_meta(cv::detail::PyObjectHolder out_meta,
|
||||||
const cv::GMetaArgs &meta,
|
const cv::GMetaArgs &meta,
|
||||||
const cv::GArgs &gargs) {
|
const cv::GArgs &gargs)
|
||||||
|
{
|
||||||
PyGILState_STATE gstate;
|
PyGILState_STATE gstate;
|
||||||
gstate = PyGILState_Ensure();
|
gstate = PyGILState_Ensure();
|
||||||
|
|
||||||
@ -760,7 +792,8 @@ static GMetaArgs run_py_meta(cv::detail::PyObjectHolder out_meta,
|
|||||||
cv::detail::PyObjectHolder result(
|
cv::detail::PyObjectHolder result(
|
||||||
PyObject_CallObject(out_meta.get(), args.get()), false);
|
PyObject_CallObject(out_meta.get(), args.get()), false);
|
||||||
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred())
|
||||||
|
{
|
||||||
PyErr_PrintEx(0);
|
PyErr_PrintEx(0);
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
throw std::logic_error("Python outMeta failed with error!");
|
throw std::logic_error("Python outMeta failed with error!");
|
||||||
@ -792,21 +825,24 @@ static PyObject* pyopencv_cv_gapi_kernels(PyObject* , PyObject* py_args, PyObjec
|
|||||||
PyObject* user_kernel = PyTuple_GetItem(py_args, i);
|
PyObject* user_kernel = PyTuple_GetItem(py_args, i);
|
||||||
|
|
||||||
PyObject* id_obj = PyObject_GetAttrString(user_kernel, "id");
|
PyObject* id_obj = PyObject_GetAttrString(user_kernel, "id");
|
||||||
if (!id_obj) {
|
if (!id_obj)
|
||||||
|
{
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"Python kernel should contain id, please use cv.gapi.kernel to define kernel");
|
"Python kernel should contain id, please use cv.gapi.kernel to define kernel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* out_meta = PyObject_GetAttrString(user_kernel, "outMeta");
|
PyObject* out_meta = PyObject_GetAttrString(user_kernel, "outMeta");
|
||||||
if (!out_meta) {
|
if (!out_meta)
|
||||||
|
{
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"Python kernel should contain outMeta, please use cv.gapi.kernel to define kernel");
|
"Python kernel should contain outMeta, please use cv.gapi.kernel to define kernel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* run = PyObject_GetAttrString(user_kernel, "run");
|
PyObject* run = PyObject_GetAttrString(user_kernel, "run");
|
||||||
if (!run) {
|
if (!run)
|
||||||
|
{
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"Python kernel should contain run, please use cv.gapi.kernel to define kernel");
|
"Python kernel should contain run, please use cv.gapi.kernel to define kernel");
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -951,9 +987,12 @@ struct PyOpenCV_Converter<cv::GArray<T>>
|
|||||||
if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
|
if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
|
||||||
{
|
{
|
||||||
auto& array = reinterpret_cast<pyopencv_GArrayT_t*>(obj)->v;
|
auto& array = reinterpret_cast<pyopencv_GArrayT_t*>(obj)->v;
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
value = cv::util::get<cv::GArray<T>>(array.arg());
|
value = cv::util::get<cv::GArray<T>>(array.arg());
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -974,9 +1013,12 @@ struct PyOpenCV_Converter<cv::GOpaque<T>>
|
|||||||
if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
|
if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
|
||||||
{
|
{
|
||||||
auto& opaque = reinterpret_cast<pyopencv_GOpaqueT_t*>(obj)->v;
|
auto& opaque = reinterpret_cast<pyopencv_GOpaqueT_t*>(obj)->v;
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
value = cv::util::get<cv::GOpaque<T>>(opaque.arg());
|
value = cv::util::get<cv::GOpaque<T>>(opaque.arg());
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -3,39 +3,40 @@
|
|||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
struct GAPI_EXPORTS_W_SIMPLE GCompileArg {
|
struct GAPI_EXPORTS_W_SIMPLE GCompileArg
|
||||||
GAPI_WRAP GCompileArg(gapi::GKernelPackage pkg);
|
{
|
||||||
GAPI_WRAP GCompileArg(gapi::GNetPackage pkg);
|
GAPI_WRAP GCompileArg(gapi::GKernelPackage pkg);
|
||||||
|
GAPI_WRAP GCompileArg(gapi::GNetPackage pkg);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GAPI_EXPORTS_W_SIMPLE GInferInputs
|
class GAPI_EXPORTS_W_SIMPLE GInferInputs
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GAPI_WRAP GInferInputs();
|
GAPI_WRAP GInferInputs();
|
||||||
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GMat& value);
|
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GMat& value);
|
||||||
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GFrame& value);
|
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GFrame& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GAPI_EXPORTS_W_SIMPLE GInferListInputs
|
class GAPI_EXPORTS_W_SIMPLE GInferListInputs
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GAPI_WRAP GInferListInputs();
|
GAPI_WRAP GInferListInputs();
|
||||||
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::GMat>& value);
|
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::GMat>& value);
|
||||||
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::Rect>& value);
|
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::Rect>& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
class GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GAPI_WRAP GInferOutputs();
|
GAPI_WRAP GInferOutputs();
|
||||||
GAPI_WRAP cv::GMat at(const std::string& name);
|
GAPI_WRAP cv::GMat at(const std::string& name);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GAPI_EXPORTS_W_SIMPLE GInferListOutputs
|
class GAPI_EXPORTS_W_SIMPLE GInferListOutputs
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GAPI_WRAP GInferListOutputs();
|
GAPI_WRAP GInferListOutputs();
|
||||||
GAPI_WRAP cv::GArray<cv::GMat> at(const std::string& name);
|
GAPI_WRAP cv::GArray<cv::GMat> at(const std::string& name);
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace gapi
|
namespace gapi
|
||||||
@ -69,11 +70,13 @@ namespace streaming
|
|||||||
cv::GOpaque<int64_t> GAPI_EXPORTS_W timestamp(cv::GMat);
|
cv::GOpaque<int64_t> GAPI_EXPORTS_W timestamp(cv::GMat);
|
||||||
cv::GOpaque<int64_t> GAPI_EXPORTS_W seqNo(cv::GMat);
|
cv::GOpaque<int64_t> GAPI_EXPORTS_W seqNo(cv::GMat);
|
||||||
cv::GOpaque<int64_t> GAPI_EXPORTS_W seq_id(cv::GMat);
|
cv::GOpaque<int64_t> GAPI_EXPORTS_W seq_id(cv::GMat);
|
||||||
|
|
||||||
|
GAPI_EXPORTS_W cv::GMat desync(const cv::GMat &g);
|
||||||
} // namespace streaming
|
} // namespace streaming
|
||||||
} // namespace gapi
|
} // namespace gapi
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::ie::PyParams params);
|
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::ie::PyParams params);
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
@ -5,16 +5,35 @@ import cv2 as cv
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
import time
|
||||||
|
|
||||||
from tests_common import NewOpenCVTests
|
from tests_common import NewOpenCVTests
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
if sys.version_info[:2] < (3, 0):
|
if sys.version_info[:2] < (3, 0):
|
||||||
raise unittest.SkipTest('Python 2.x is not supported')
|
raise unittest.SkipTest('Python 2.x is not supported')
|
||||||
|
|
||||||
|
|
||||||
|
@cv.gapi.op('custom.delay', in_types=[cv.GMat], out_types=[cv.GMat])
|
||||||
|
class GDelay:
|
||||||
|
"""Delay for 10 ms."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def outMeta(desc):
|
||||||
|
return desc
|
||||||
|
|
||||||
|
|
||||||
|
@cv.gapi.kernel(GDelay)
|
||||||
|
class GDelayImpl:
|
||||||
|
"""Implementation for GDelay operation."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def run(img):
|
||||||
|
time.sleep(0.01)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
class test_gapi_streaming(NewOpenCVTests):
|
class test_gapi_streaming(NewOpenCVTests):
|
||||||
|
|
||||||
def test_image_input(self):
|
def test_image_input(self):
|
||||||
@ -148,7 +167,7 @@ try:
|
|||||||
|
|
||||||
proc_num_frames += 1
|
proc_num_frames += 1
|
||||||
if proc_num_frames == max_num_frames:
|
if proc_num_frames == max_num_frames:
|
||||||
break;
|
break
|
||||||
|
|
||||||
|
|
||||||
def test_video_good_features_to_track(self):
|
def test_video_good_features_to_track(self):
|
||||||
@ -242,6 +261,51 @@ try:
|
|||||||
if curr_frame_number == max_num_frames:
|
if curr_frame_number == max_num_frames:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
def test_desync(self):
|
||||||
|
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||||
|
|
||||||
|
# G-API
|
||||||
|
g_in = cv.GMat()
|
||||||
|
g_out1 = cv.gapi.copy(g_in)
|
||||||
|
des = cv.gapi.streaming.desync(g_in)
|
||||||
|
g_out2 = GDelay.on(des)
|
||||||
|
|
||||||
|
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out1, g_out2))
|
||||||
|
|
||||||
|
kernels = cv.gapi.kernels(GDelayImpl)
|
||||||
|
ccomp = c.compileStreaming(args=cv.gapi.compile_args(kernels))
|
||||||
|
source = cv.gapi.wip.make_capture_src(path)
|
||||||
|
ccomp.setSource(cv.gin(source))
|
||||||
|
ccomp.start()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
max_num_frames = 10
|
||||||
|
proc_num_frames = 0
|
||||||
|
|
||||||
|
out_counter = 0
|
||||||
|
desync_out_counter = 0
|
||||||
|
none_counter = 0
|
||||||
|
while True:
|
||||||
|
has_frame, (out1, out2) = ccomp.pull()
|
||||||
|
if not has_frame:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not out1 is None:
|
||||||
|
out_counter += 1
|
||||||
|
if not out2 is None:
|
||||||
|
desync_out_counter += 1
|
||||||
|
else:
|
||||||
|
none_counter += 1
|
||||||
|
|
||||||
|
proc_num_frames += 1
|
||||||
|
if proc_num_frames == max_num_frames:
|
||||||
|
ccomp.stop()
|
||||||
|
break
|
||||||
|
|
||||||
|
self.assertLess(0, proc_num_frames)
|
||||||
|
self.assertLess(desync_out_counter, out_counter)
|
||||||
|
self.assertLess(0, none_counter)
|
||||||
|
|
||||||
|
|
||||||
except unittest.SkipTest as e:
|
except unittest.SkipTest as e:
|
||||||
|
|
||||||
|
@ -75,6 +75,11 @@ bool cv::GStreamingCompiled::Priv::pull(cv::GOptRunArgsP &&outs)
|
|||||||
return m_exec->pull(std::move(outs));
|
return m_exec->pull(std::move(outs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> cv::GStreamingCompiled::Priv::pull()
|
||||||
|
{
|
||||||
|
return m_exec->pull();
|
||||||
|
}
|
||||||
|
|
||||||
bool cv::GStreamingCompiled::Priv::try_pull(cv::GRunArgsP &&outs)
|
bool cv::GStreamingCompiled::Priv::try_pull(cv::GRunArgsP &&outs)
|
||||||
{
|
{
|
||||||
return m_exec->try_pull(std::move(outs));
|
return m_exec->try_pull(std::move(outs));
|
||||||
@ -123,18 +128,9 @@ bool cv::GStreamingCompiled::pull(cv::GRunArgsP &&outs)
|
|||||||
return m_priv->pull(std::move(outs));
|
return m_priv->pull(std::move(outs));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<bool, cv::GRunArgs> cv::GStreamingCompiled::pull()
|
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> cv::GStreamingCompiled::pull()
|
||||||
{
|
{
|
||||||
GRunArgs run_args;
|
return m_priv->pull();
|
||||||
GRunArgsP outs;
|
|
||||||
const auto& out_info = m_priv->outInfo();
|
|
||||||
run_args.reserve(out_info.size());
|
|
||||||
outs.reserve(out_info.size());
|
|
||||||
|
|
||||||
cv::detail::constructGraphOutputs(m_priv->outInfo(), run_args, outs);
|
|
||||||
|
|
||||||
bool is_over = m_priv->pull(std::move(outs));
|
|
||||||
return std::make_tuple(is_over, run_args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cv::GStreamingCompiled::pull(cv::GOptRunArgsP &&outs)
|
bool cv::GStreamingCompiled::pull(cv::GOptRunArgsP &&outs)
|
||||||
|
@ -46,6 +46,7 @@ public:
|
|||||||
void start();
|
void start();
|
||||||
bool pull(cv::GRunArgsP &&outs);
|
bool pull(cv::GRunArgsP &&outs);
|
||||||
bool pull(cv::GOptRunArgsP &&outs);
|
bool pull(cv::GOptRunArgsP &&outs);
|
||||||
|
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> pull();
|
||||||
bool try_pull(cv::GRunArgsP &&outs);
|
bool try_pull(cv::GRunArgsP &&outs);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
@ -1017,6 +1017,49 @@ void check_DesyncObjectConsumedByMultipleIslands(const cv::gimpl::GIslandModel::
|
|||||||
} // for(nodes)
|
} // for(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NB: Construct GRunArgsP based on passed info and store the memory in passed cv::GRunArgs.
|
||||||
|
// Needed for python bridge, because in case python user doesn't pass output arguments to apply.
|
||||||
|
void constructOptGraphOutputs(const cv::GTypesInfo &out_info,
|
||||||
|
cv::GOptRunArgs &args,
|
||||||
|
cv::GOptRunArgsP &outs)
|
||||||
|
{
|
||||||
|
for (auto&& info : out_info)
|
||||||
|
{
|
||||||
|
switch (info.shape)
|
||||||
|
{
|
||||||
|
case cv::GShape::GMAT:
|
||||||
|
{
|
||||||
|
args.emplace_back(cv::optional<cv::Mat>{});
|
||||||
|
outs.emplace_back(&cv::util::get<cv::optional<cv::Mat>>(args.back()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cv::GShape::GSCALAR:
|
||||||
|
{
|
||||||
|
args.emplace_back(cv::optional<cv::Scalar>{});
|
||||||
|
outs.emplace_back(&cv::util::get<cv::optional<cv::Scalar>>(args.back()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cv::GShape::GARRAY:
|
||||||
|
{
|
||||||
|
cv::detail::VectorRef ref;
|
||||||
|
cv::util::get<cv::detail::ConstructVec>(info.ctor)(ref);
|
||||||
|
args.emplace_back(cv::util::make_optional(std::move(ref)));
|
||||||
|
outs.emplace_back(wrap_opt_arg(cv::util::get<cv::optional<cv::detail::VectorRef>>(args.back())));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cv::GShape::GOPAQUE:
|
||||||
|
{
|
||||||
|
cv::detail::OpaqueRef ref;
|
||||||
|
cv::util::get<cv::detail::ConstructOpaque>(info.ctor)(ref);
|
||||||
|
args.emplace_back(cv::util::make_optional(std::move(ref)));
|
||||||
|
outs.emplace_back(wrap_opt_arg(cv::util::get<cv::optional<cv::detail::OpaqueRef>>(args.back())));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cv::util::throw_error(std::logic_error("Unsupported optional output shape for Python"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
class cv::gimpl::GStreamingExecutor::Synchronizer final {
|
class cv::gimpl::GStreamingExecutor::Synchronizer final {
|
||||||
@ -1320,6 +1363,16 @@ cv::gimpl::GStreamingExecutor::GStreamingExecutor(std::unique_ptr<ade::Graph> &&
|
|||||||
// per the same input frame, so the output traffic multiplies)
|
// per the same input frame, so the output traffic multiplies)
|
||||||
GAPI_Assert(m_collector_map.size() > 0u);
|
GAPI_Assert(m_collector_map.size() > 0u);
|
||||||
m_out_queue.set_capacity(queue_capacity * m_collector_map.size());
|
m_out_queue.set_capacity(queue_capacity * m_collector_map.size());
|
||||||
|
|
||||||
|
// FIXME: The code duplicates logic of collectGraphInfo()
|
||||||
|
cv::gimpl::GModel::ConstGraph cgr(*m_orig_graph);
|
||||||
|
auto meta = cgr.metadata().get<cv::gimpl::Protocol>().out_nhs;
|
||||||
|
out_info.reserve(meta.size());
|
||||||
|
|
||||||
|
ade::util::transform(meta, std::back_inserter(out_info), [&cgr](const ade::NodeHandle& nh) {
|
||||||
|
const auto& data = cgr.metadata(nh).get<cv::gimpl::Data>();
|
||||||
|
return cv::GTypeInfo{data.shape, data.kind, data.ctor};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::gimpl::GStreamingExecutor::~GStreamingExecutor()
|
cv::gimpl::GStreamingExecutor::~GStreamingExecutor()
|
||||||
@ -1653,6 +1706,31 @@ bool cv::gimpl::GStreamingExecutor::pull(cv::GOptRunArgsP &&outs)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> cv::gimpl::GStreamingExecutor::pull()
|
||||||
|
{
|
||||||
|
using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||||
|
bool is_over = false;
|
||||||
|
|
||||||
|
if (m_desync) {
|
||||||
|
GOptRunArgs opt_run_args;
|
||||||
|
GOptRunArgsP opt_outs;
|
||||||
|
opt_outs.reserve(out_info.size());
|
||||||
|
opt_run_args.reserve(out_info.size());
|
||||||
|
|
||||||
|
constructOptGraphOutputs(out_info, opt_run_args, opt_outs);
|
||||||
|
is_over = pull(std::move(opt_outs));
|
||||||
|
return std::make_tuple(is_over, RunArgs(opt_run_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
GRunArgs run_args;
|
||||||
|
GRunArgsP outs;
|
||||||
|
run_args.reserve(out_info.size());
|
||||||
|
outs.reserve(out_info.size());
|
||||||
|
|
||||||
|
constructGraphOutputs(out_info, run_args, outs);
|
||||||
|
is_over = pull(std::move(outs));
|
||||||
|
return std::make_tuple(is_over, RunArgs(run_args));
|
||||||
|
}
|
||||||
|
|
||||||
bool cv::gimpl::GStreamingExecutor::try_pull(cv::GRunArgsP &&outs)
|
bool cv::gimpl::GStreamingExecutor::try_pull(cv::GRunArgsP &&outs)
|
||||||
{
|
{
|
||||||
|
@ -195,6 +195,8 @@ protected:
|
|||||||
|
|
||||||
void wait_shutdown();
|
void wait_shutdown();
|
||||||
|
|
||||||
|
cv::GTypesInfo out_info;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model,
|
explicit GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model,
|
||||||
const cv::GCompileArgs &comp_args);
|
const cv::GCompileArgs &comp_args);
|
||||||
@ -203,6 +205,7 @@ public:
|
|||||||
void start();
|
void start();
|
||||||
bool pull(cv::GRunArgsP &&outs);
|
bool pull(cv::GRunArgsP &&outs);
|
||||||
bool pull(cv::GOptRunArgsP &&outs);
|
bool pull(cv::GOptRunArgsP &&outs);
|
||||||
|
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> pull();
|
||||||
bool try_pull(cv::GRunArgsP &&outs);
|
bool try_pull(cv::GRunArgsP &&outs);
|
||||||
void stop();
|
void stop();
|
||||||
bool running() const;
|
bool running() const;
|
||||||
|
@ -244,6 +244,35 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void checkPullOverload(const cv::Mat& ref,
|
||||||
|
const bool has_output,
|
||||||
|
cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>& args) {
|
||||||
|
EXPECT_TRUE(has_output);
|
||||||
|
using runArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||||
|
cv::Mat out_mat;
|
||||||
|
switch (args.index()) {
|
||||||
|
case runArgs::index_of<cv::GRunArgs>():
|
||||||
|
{
|
||||||
|
auto outputs = util::get<cv::GRunArgs>(args);
|
||||||
|
EXPECT_EQ(1u, outputs.size());
|
||||||
|
out_mat = cv::util::get<cv::Mat>(outputs[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case runArgs::index_of<cv::GOptRunArgs>():
|
||||||
|
{
|
||||||
|
auto outputs = util::get<cv::GOptRunArgs>(args);
|
||||||
|
EXPECT_EQ(1u, outputs.size());
|
||||||
|
auto opt_mat = cv::util::get<cv::optional<cv::Mat>>(outputs[0]);
|
||||||
|
ASSERT_TRUE(opt_mat.has_value());
|
||||||
|
out_mat = *opt_mat;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: GAPI_Assert(false && "Incorrect type of Args");
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(0., cv::norm(ref, out_mat, cv::NORM_INF));
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat)
|
TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat)
|
||||||
@ -1336,13 +1365,45 @@ TEST(Streaming, Python_Pull_Overload)
|
|||||||
|
|
||||||
bool has_output;
|
bool has_output;
|
||||||
cv::GRunArgs outputs;
|
cv::GRunArgs outputs;
|
||||||
std::tie(has_output, outputs) = ccomp.pull();
|
using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||||
|
RunArgs args;
|
||||||
|
|
||||||
EXPECT_TRUE(has_output);
|
std::tie(has_output, args) = ccomp.pull();
|
||||||
EXPECT_EQ(1u, outputs.size());
|
|
||||||
|
|
||||||
auto out_mat = cv::util::get<cv::Mat>(outputs[0]);
|
checkPullOverload(in_mat, has_output, args);
|
||||||
EXPECT_EQ(0., cv::norm(in_mat, out_mat, cv::NORM_INF));
|
|
||||||
|
ccomp.stop();
|
||||||
|
EXPECT_FALSE(ccomp.running());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(GAPI_Streaming_Desync, Python_Pull_Overload)
|
||||||
|
{
|
||||||
|
cv::GMat in;
|
||||||
|
cv::GMat out = cv::gapi::streaming::desync(in);
|
||||||
|
cv::GComputation c(in, out);
|
||||||
|
|
||||||
|
cv::Size sz(3,3);
|
||||||
|
cv::Mat in_mat(sz, CV_8UC3);
|
||||||
|
cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar(255));
|
||||||
|
|
||||||
|
auto ccomp = c.compileStreaming();
|
||||||
|
|
||||||
|
EXPECT_TRUE(ccomp);
|
||||||
|
EXPECT_FALSE(ccomp.running());
|
||||||
|
|
||||||
|
ccomp.setSource(cv::gin(in_mat));
|
||||||
|
|
||||||
|
ccomp.start();
|
||||||
|
EXPECT_TRUE(ccomp.running());
|
||||||
|
|
||||||
|
bool has_output;
|
||||||
|
cv::GRunArgs outputs;
|
||||||
|
using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||||
|
RunArgs args;
|
||||||
|
|
||||||
|
std::tie(has_output, args) = ccomp.pull();
|
||||||
|
|
||||||
|
checkPullOverload(in_mat, has_output, args);
|
||||||
|
|
||||||
ccomp.stop();
|
ccomp.stop();
|
||||||
EXPECT_FALSE(ccomp.running());
|
EXPECT_FALSE(ccomp.running());
|
||||||
@ -2132,9 +2193,17 @@ TEST(GAPI_Streaming, TestPythonAPI)
|
|||||||
|
|
||||||
bool is_over = false;
|
bool is_over = false;
|
||||||
cv::GRunArgs out_args;
|
cv::GRunArgs out_args;
|
||||||
|
using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||||
|
RunArgs args;
|
||||||
|
|
||||||
// NB: Used by python bridge
|
// NB: Used by python bridge
|
||||||
std::tie(is_over, out_args) = cc.pull();
|
std::tie(is_over, args) = cc.pull();
|
||||||
|
|
||||||
|
switch (args.index()) {
|
||||||
|
case RunArgs::index_of<cv::GRunArgs>():
|
||||||
|
out_args = util::get<cv::GRunArgs>(args); break;
|
||||||
|
default: GAPI_Assert(false && "Incorrect type of return value");
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_EQ(1u, out_args.size());
|
ASSERT_EQ(1u, out_args.size());
|
||||||
ASSERT_TRUE(cv::util::holds_alternative<cv::Mat>(out_args[0]));
|
ASSERT_TRUE(cv::util::holds_alternative<cv::Mat>(out_args[0]));
|
||||||
|
Loading…
Reference in New Issue
Block a user