1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 23:33:05 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2023-06-01 09:37:38 +03:00
565 changed files with 84396 additions and 17589 deletions
+6
View File
@@ -24,6 +24,12 @@ add_library(ade STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL}
${ADE_include}
${ADE_sources}
)
# https://github.com/opencv/ade/issues/32
if(CV_CLANG AND CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.1)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wdeprecated-copy)
endif()
target_include_directories(ade PUBLIC $<BUILD_INTERFACE:${ADE_root}/include>)
set_target_properties(ade PROPERTIES
POSITION_INDEPENDENT_CODE True
@@ -13,7 +13,7 @@
namespace cv { namespace gapi { namespace imgproc { namespace fluid {
GAPI_EXPORTS GKernelPackage kernels();
GAPI_EXPORTS_W GKernelPackage kernels();
}}}}
@@ -414,8 +414,8 @@ namespace cv {
class GAPI_EXPORTS_W_SIMPLE GKernelPackage;
namespace gapi {
GAPI_EXPORTS cv::GKernelPackage combine(const cv::GKernelPackage &lhs,
const cv::GKernelPackage &rhs);
GAPI_EXPORTS_W cv::GKernelPackage combine(const cv::GKernelPackage &lhs,
const cv::GKernelPackage &rhs);
/// @private
class GFunctor
@@ -513,7 +513,7 @@ namespace gapi {
*
* @return a number of kernels in the package
*/
std::size_t size() const;
GAPI_WRAP std::size_t size() const;
/**
* @brief Returns vector of transformations included in the package
@@ -717,6 +717,8 @@ namespace gapi {
{
return combine(a, combine(b, rest...));
}
// NB(DM): Variadic-arg version in Python may require the same
// approach as used in GComputation::compile/apply.
/** \addtogroup gapi_compile_args
* @{
@@ -26,6 +26,13 @@ public:
GAPI_WRAP
PyParams(const std::string& tag, const std::string& model_path);
GAPI_WRAP
PyParams& cfgMeanStd(const std::string &layer_name,
const cv::Scalar &m,
const cv::Scalar &s);
GAPI_WRAP
PyParams& cfgNormalize(const std::string &layer_name, bool flag);
GBackend backend() const;
std::string tag() const;
cv::util::any params() const;
@@ -242,7 +242,7 @@ public:
@param cfg Map of pairs: (config parameter name, config parameter value).
@return reference to this parameter structure.
*/
Params& pluginConfig(const IEConfig& cfg) {
Params& pluginConfig(const IEConfig& cfg) {
desc.config = cfg;
return *this;
}
@@ -70,6 +70,14 @@ struct ParamDesc {
std::vector<std::string> names_to_remap; //!< Names of output layers that will be processed in PostProc function.
bool is_generic;
// TODO: Needs to modify the rest of ParamDesc accordingly to support
// both generic and non-generic options without duplication
// (as it was done for the OV IE backend)
// These values are pushed into the respective vector<> fields above
// when the generic infer parameters are unpacked (see GONNXBackendImpl::unpackKernel)
std::unordered_map<std::string, std::pair<cv::Scalar, cv::Scalar> > generic_mstd;
std::unordered_map<std::string, bool> generic_norm;
};
} // namespace detail
@@ -298,7 +306,17 @@ public:
@param model_path path to model file (.onnx file).
*/
Params(const std::string& tag, const std::string& model_path)
: desc{model_path, 0u, 0u, {}, {}, {}, {}, {}, {}, {}, {}, {}, true}, m_tag(tag) {}
: desc{model_path, 0u, 0u, {}, {}, {}, {}, {}, {}, {}, {}, {}, true, {}, {} }, m_tag(tag) {}
void cfgMeanStdDev(const std::string &layer,
const cv::Scalar &m,
const cv::Scalar &s) {
desc.generic_mstd[layer] = std::make_pair(m, s);
}
void cfgNormalize(const std::string &layer, bool flag) {
desc.generic_norm[layer] = flag;
}
// BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::onnx::backend(); }
@@ -31,6 +31,7 @@ namespace cv {
using Size = gapi::own::Size;
using Point = gapi::own::Point;
using Point2f = gapi::own::Point2f;
using Point3f = gapi::own::Point3f;
using Scalar = gapi::own::Scalar;
using Mat = gapi::own::Mat;
} // namespace cv
@@ -43,6 +43,17 @@ public:
float y = 0.f;
};
class Point3f
{
public:
Point3f() = default;
Point3f(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
float x = 0.f;
float y = 0.f;
float z = 0.f;
};
class Rect
{
public:
+11 -17
View File
@@ -664,7 +664,6 @@ static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
cv::GRunArgs outs;
try
{
int in_idx = 0;
// NB: Doesn't increase reference counter (false),
// because PyObject already have ownership.
// In case exception decrement reference counter.
@@ -697,7 +696,6 @@ static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
util::throw_error(std::logic_error("GFrame isn't supported for custom operation"));
break;
}
++in_idx;
}
if (ctx.m_state.has_value())
@@ -787,15 +785,14 @@ static void unpackMetasToTuple(const cv::GMetaArgs& meta,
}
}
static cv::GArg setup_py(cv::detail::PyObjectHolder setup,
const cv::GMetaArgs& meta,
const cv::GArgs& gargs)
static cv::GArg run_py_setup(cv::detail::PyObjectHolder setup,
const cv::GMetaArgs &meta,
const cv::GArgs &gargs)
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
cv::GArg out;
cv::GArg state;
try
{
// NB: Doesn't increase reference counter (false),
@@ -803,23 +800,20 @@ static cv::GArg setup_py(cv::detail::PyObjectHolder setup,
// In case exception decrement reference counter.
cv::detail::PyObjectHolder args(PyTuple_New(meta.size()), false);
unpackMetasToTuple(meta, gargs, args);
// NB: Take an onwership because this state is "Python" type so it will be wrapped as-is
// into cv::GArg and stored in GPythonBackend. Object without ownership can't
// be dealocated outside this function.
cv::detail::PyObjectHolder result(PyObject_CallObject(setup.get(), args.get()), true);
PyObject *py_kernel_state = PyObject_CallObject(setup.get(), args.get());
if (PyErr_Occurred())
{
PyErr_PrintEx(0);
PyErr_Clear();
throw std::logic_error("Python kernel failed with error!");
throw std::logic_error("Python kernel setup failed with error!");
}
// NB: In fact it's impossible situation, because errors were handled above.
GAPI_Assert(result.get() && "Python kernel returned NULL!");
GAPI_Assert(py_kernel_state && "Python kernel setup returned NULL!");
if (!pyopencv_to(result.get(), out, ArgInfo("arg", false)))
if (!pyopencv_to(py_kernel_state, state, ArgInfo("arg", false)))
{
util::throw_error(std::logic_error("Unsupported output meta type"));
util::throw_error(std::logic_error("Failed to convert python state"));
}
}
catch (...)
@@ -828,7 +822,7 @@ static cv::GArg setup_py(cv::detail::PyObjectHolder setup,
throw;
}
PyGILState_Release(gstate);
return out;
return state;
}
static GMetaArg get_meta_arg(PyObject* obj)
@@ -949,7 +943,7 @@ static PyObject* pyopencv_cv_gapi_kernels(PyObject* , PyObject* py_args, PyObjec
gapi::python::GPythonFunctor f(
id.c_str(), std::bind(run_py_meta, cv::detail::PyObjectHolder{out_meta}, _1, _2),
std::bind(run_py_kernel, cv::detail::PyObjectHolder{run}, _1),
std::bind(setup_py, cv::detail::PyObjectHolder{setup}, _1, _2));
std::bind(run_py_setup, cv::detail::PyObjectHolder{setup}, _1, _2));
pkg.include(f);
}
else
@@ -14,21 +14,14 @@ try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
CLASSIFICATION_MODEL_PATH = "onnx_models/vision/classification/squeezenet/model/squeezenet1.0-9.onnx"
testdata_required = bool(os.environ.get('OPENCV_DNN_TEST_REQUIRE_TESTDATA', False))
CLASSIFICATION_MODEL_PATH = "vision/classification/squeezenet/model/squeezenet1.0-9.onnx"
class test_gapi_infer(NewOpenCVTests):
def find_dnn_file(self, filename, required=None):
if not required:
required = testdata_required
return self.find_file(filename, [os.environ.get('OPENCV_DNN_TEST_DATA_PATH', os.getcwd()),
os.environ['OPENCV_TEST_DATA_PATH']],
required=required)
def find_dnn_file(self, filename):
return self.find_file(filename, [os.environ.get('OPENCV_GAPI_ONNX_MODEL_PATH')], False)
def test_onnx_classification(self):
model_path = self.find_dnn_file(CLASSIFICATION_MODEL_PATH)
if model_path is None:
raise unittest.SkipTest("Missing DNN test file")
@@ -45,6 +38,7 @@ try:
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
net = cv.gapi.onnx.params("squeeze-net", model_path)
net.cfgNormalize("data_0", False)
try:
out_gapi = comp.apply(cv.gin(in_mat), cv.gapi.compile_args(cv.gapi.networks(net)))
except cv.error as err:
@@ -0,0 +1,48 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
class gapi_kernels_test(NewOpenCVTests):
def test_fluid_core_package(self):
fluid_core = cv.gapi.core.fluid.kernels()
self.assertLess(0, fluid_core.size())
def test_fluid_imgproc_package(self):
fluid_imgproc = cv.gapi.imgproc.fluid.kernels()
self.assertLess(0, fluid_imgproc.size())
def test_combine(self):
fluid_core = cv.gapi.core.fluid.kernels()
fluid_imgproc = cv.gapi.imgproc.fluid.kernels()
fluid = cv.gapi.combine(fluid_core, fluid_imgproc)
self.assertEqual(fluid_core.size() + fluid_imgproc.size(), fluid.size())
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()
@@ -24,7 +24,7 @@ try:
in_types=[cv.GOpaque.Int],
out_types=[cv.GOpaque.Int])
class GStatefulCounter:
"""Accumulate state counter on every call"""
"""Accumulates state counter on every call"""
@staticmethod
def outMeta(desc):
@@ -45,6 +45,22 @@ try:
return state.counter
class SumState:
def __init__(self):
self.sum = 0
@cv.gapi.op('stateful_sum',
in_types=[cv.GOpaque.Int, cv.GOpaque.Int],
out_types=[cv.GOpaque.Int])
class GStatefulSum:
"""Accumulates sum on every call"""
@staticmethod
def outMeta(lhs_desc, rhs_desc):
return cv.empty_gopaque_desc()
class gapi_sample_pipelines(NewOpenCVTests):
def test_stateful_kernel_single_instance(self):
g_in = cv.GOpaque.Int()
@@ -124,6 +140,64 @@ try:
cc.stop()
def test_stateful_multiple_inputs(self):
@cv.gapi.kernel(GStatefulSum)
class GStatefulSumImpl:
"""Implementation for GStatefulCounter operation."""
@staticmethod
def setup(lhs_desc, rhs_desc):
return SumState()
@staticmethod
def run(lhs, rhs, state):
state.sum+= lhs + rhs
return state.sum
g_in1 = cv.GOpaque.Int()
g_in2 = cv.GOpaque.Int()
g_out = GStatefulSum.on(g_in1, g_in2)
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
pkg = cv.gapi.kernels(GStatefulSumImpl)
lhs_list = [1, 10, 15]
rhs_list = [2, 14, 32]
ref_out = 0
for lhs, rhs in zip(lhs_list, rhs_list):
ref_out += lhs + rhs
gapi_out = comp.apply(cv.gin(lhs, rhs), cv.gapi.compile_args(pkg))
self.assertEqual(ref_out, gapi_out)
def test_stateful_multiple_inputs_throw(self):
@cv.gapi.kernel(GStatefulSum)
class GStatefulSumImplIncorrect:
"""Incorrect implementation for GStatefulCounter operation."""
# NB: setup methods is intentionally
# incorrect - accepts one meta arg instead of two
@staticmethod
def setup(desc):
return SumState()
@staticmethod
def run(lhs, rhs, state):
state.sum+= lhs + rhs
return state.sum
g_in1 = cv.GOpaque.Int()
g_in2 = cv.GOpaque.Int()
g_out = GStatefulSum.on(g_in1, g_in2)
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
pkg = cv.gapi.kernels(GStatefulSumImplIncorrect)
with self.assertRaises(Exception): comp.apply(cv.gin(42, 42),
args=cv.gapi.compile_args(pkg))
except unittest.SkipTest as e:
message = str(e)
@@ -17,7 +17,7 @@ try:
@cv.gapi.op('custom.delay', in_types=[cv.GMat], out_types=[cv.GMat])
class GDelay:
"""Delay for 10 ms."""
"""Delay for 50 ms."""
@staticmethod
def outMeta(desc):
@@ -30,7 +30,7 @@ try:
@staticmethod
def run(img):
time.sleep(0.01)
time.sleep(0.05)
return img
@@ -289,8 +289,7 @@ try:
ccomp.start()
# Assert
max_num_frames = 10
proc_num_frames = 0
max_num_frames = 50
out_counter = 0
desync_out_counter = 0
@@ -307,12 +306,11 @@ try:
else:
none_counter += 1
proc_num_frames += 1
if proc_num_frames == max_num_frames:
if out_counter == max_num_frames:
ccomp.stop()
break
self.assertLess(0, proc_num_frames)
self.assertLess(0, out_counter)
self.assertLess(desync_out_counter, out_counter)
self.assertLess(0, none_counter)
@@ -35,6 +35,22 @@ static AppMode strToAppMode(const std::string& mode_str) {
}
}
enum class WaitMode {
BUSY,
SLEEP
};
static WaitMode strToWaitMode(const std::string& mode_str) {
if (mode_str == "sleep") {
return WaitMode::SLEEP;
} else if (mode_str == "busy") {
return WaitMode::BUSY;
} else {
throw std::logic_error("Unsupported wait mode: " + mode_str +
"\nPlease chose between: busy (default) and sleep");
}
}
template <typename T>
T read(const cv::FileNode& node) {
return static_cast<T>(node);
@@ -401,7 +417,12 @@ int main(int argc, char* argv[]) {
if (app_mode == AppMode::BENCHMARK) {
latency = 0.0;
}
auto src = std::make_shared<DummySource>(latency, output, drop_frames);
const auto wait_mode =
strToWaitMode(readOpt<std::string>(src_fn["wait_mode"]).value_or("busy"));
auto wait_strategy = (wait_mode == WaitMode::SLEEP) ? utils::sleep : utils::busyWait;
auto src = std::make_shared<DummySource>(
utils::double_ms_t{latency}, output, drop_frames, std::move(wait_strategy));
builder.setSource(src_name, src);
}
@@ -446,7 +467,7 @@ int main(int argc, char* argv[]) {
// NB: Pipeline mode from config takes priority over cmd.
auto pl_mode = cfg_pl_mode.has_value()
? strToPLMode(cfg_pl_mode.value()) : cmd_pl_mode;
// NB: Using drop_frames with streaming pipelines will follow to
// NB: Using drop_frames with streaming pipelines will lead to
// incorrect performance results.
if (drop_frames && pl_mode == PLMode::STREAMING) {
throw std::logic_error(
@@ -12,26 +12,36 @@
class DummySource final: public cv::gapi::wip::IStreamSource {
public:
using WaitStrategy = std::function<void(std::chrono::microseconds)>;
using Ptr = std::shared_ptr<DummySource>;
DummySource(const double latency,
using ts_t = std::chrono::microseconds;
template <typename DurationT>
DummySource(const DurationT latency,
const OutputDescr& output,
const bool drop_frames);
const bool drop_frames,
WaitStrategy&& wait);
bool pull(cv::gapi::wip::Data& data) override;
cv::GMetaArg descr_of() const override;
double latency() const { return m_latency; };
private:
double m_latency;
cv::Mat m_mat;
bool m_drop_frames;
double m_next_tick_ts = -1;
int64_t m_curr_seq_id = 0;
int64_t m_latency;
cv::Mat m_mat;
bool m_drop_frames;
int64_t m_next_tick_ts = -1;
int64_t m_curr_seq_id = 0;
WaitStrategy m_wait;
};
DummySource::DummySource(const double latency,
template <typename DurationT>
DummySource::DummySource(const DurationT latency,
const OutputDescr& output,
const bool drop_frames)
: m_latency(latency), m_drop_frames(drop_frames) {
const bool drop_frames,
WaitStrategy&& wait)
: m_latency(std::chrono::duration_cast<ts_t>(latency).count()),
m_drop_frames(drop_frames),
m_wait(std::move(wait)) {
utils::createNDMat(m_mat, output.dims, output.precision);
utils::generateRandom(m_mat);
}
@@ -42,10 +52,10 @@ bool DummySource::pull(cv::gapi::wip::Data& data) {
// NB: Wait m_latency before return the first frame.
if (m_next_tick_ts == -1) {
m_next_tick_ts = utils::timestamp<milliseconds>() + m_latency;
m_next_tick_ts = utils::timestamp<ts_t>() + m_latency;
}
int64_t curr_ts = utils::timestamp<milliseconds>();
int64_t curr_ts = utils::timestamp<ts_t>();
if (curr_ts < m_next_tick_ts) {
/*
* curr_ts
@@ -57,8 +67,8 @@ bool DummySource::pull(cv::gapi::wip::Data& data) {
*
* NB: New frame will be produced at the m_next_tick_ts point.
*/
utils::sleep(m_next_tick_ts - curr_ts);
} else {
m_wait(ts_t{m_next_tick_ts - curr_ts});
} else if (m_latency != 0) {
/*
* curr_ts
* +1 +2 |
@@ -66,29 +76,28 @@ bool DummySource::pull(cv::gapi::wip::Data& data) {
* ^ ^
* m_next_tick_ts ------------->
*
*
* NB: Shift m_next_tick_ts to the nearest tick before curr_ts and
* update current seq_id correspondingly.
*
* if drop_frames is enabled, wait for the next tick, otherwise
* return last written frame (+2 at the picture above) immediately.
*/
// NB: Count how many frames have been produced since last pull (m_next_tick_ts).
int64_t num_frames =
static_cast<int64_t>((curr_ts - m_next_tick_ts) / m_latency);
m_curr_seq_id += num_frames;
// NB: Shift m_next_tick_ts to the nearest tick before curr_ts.
m_next_tick_ts += num_frames * m_latency;
// NB: if drop_frames is enabled, update current seq_id and wait for the next tick, otherwise
// return last written frame (+2 at the picture above) immediately.
if (m_drop_frames) {
// NB: Shift tick to the next frame.
m_next_tick_ts += m_latency;
++m_curr_seq_id;
utils::sleep(m_next_tick_ts - curr_ts);
// NB: Wait for the next frame.
m_wait(ts_t{m_next_tick_ts - curr_ts});
// NB: Drop already produced frames + update seq_id for the current.
m_curr_seq_id += num_frames + 1;
}
}
// NB: Just increase reference counter not to release mat memory
// after assigning it to the data.
cv::Mat mat = m_mat;
data.meta[meta_tag::timestamp] = utils::timestamp<milliseconds>();
data.meta[meta_tag::timestamp] = utils::timestamp<ts_t>();
data.meta[meta_tag::seq_id] = m_curr_seq_id++;
data = mat;
m_next_tick_ts += m_latency;
@@ -6,34 +6,39 @@
struct PerfReport {
std::string name;
double avg_latency = 0.0;
int64_t min_latency = 0;
int64_t max_latency = 0;
int64_t first_latency = 0;
double min_latency = 0.0;
double max_latency = 0.0;
double first_latency = 0.0;
double throughput = 0.0;
int64_t elapsed = 0;
int64_t warmup_time = 0;
double elapsed = 0.0;
double warmup_time = 0.0;
int64_t num_late_frames = 0;
std::vector<int64_t> latencies;
std::vector<double> latencies;
std::vector<int64_t> seq_ids;
std::string toStr(bool expanded = false) const;
};
std::string PerfReport::toStr(bool expand) const {
const auto to_double_str = [](double val) {
std::stringstream ss;
ss << std::fixed << std::setprecision(3) << val;
return ss.str();
};
std::stringstream ss;
ss << name << ": \n"
<< " Warm up time: " << warmup_time << " ms\n"
<< " Execution time: " << elapsed << " ms\n"
<< " Frames: " << num_late_frames << "/" << latencies.size() << " (late/all)\n"
<< " Latency:\n"
<< " first: " << first_latency << " ms\n"
<< " min: " << min_latency << " ms\n"
<< " max: " << max_latency << " ms\n"
<< " avg: " << std::fixed << std::setprecision(3) << avg_latency << " ms\n"
<< " Throughput: " << std::fixed << std::setprecision(3) << throughput << " FPS";
ss << name << ": warm-up: " << to_double_str(warmup_time)
<< " ms, execution time: " << to_double_str(elapsed)
<< " ms, throughput: " << to_double_str(throughput)
<< " FPS, latency: first: " << to_double_str(first_latency)
<< " ms, min: " << to_double_str(min_latency)
<< " ms, avg: " << to_double_str(avg_latency)
<< " ms, max: " << to_double_str(max_latency)
<< " ms, frames: " << num_late_frames << "/" << seq_ids.back()+1 << " (dropped/all)";
if (expand) {
for (size_t i = 0; i < latencies.size(); ++i) {
ss << "\nFrame:" << i << "\nLatency: "
<< latencies[i] << " ms";
<< to_double_str(latencies[i]) << " ms";
}
}
@@ -70,10 +75,12 @@ public:
virtual ~Pipeline() = default;
protected:
virtual void _compile() = 0;
virtual int64_t run_iter() = 0;
virtual void init() {};
virtual void deinit() {};
virtual void _compile() = 0;
virtual void run_iter() = 0;
virtual void init() {};
virtual void deinit() {};
void prepareOutputs();
std::string m_name;
cv::GComputation m_comp;
@@ -82,6 +89,11 @@ protected:
cv::GCompileArgs m_args;
size_t m_num_outputs;
PerfReport m_perf;
cv::GRunArgsP m_pipeline_outputs;
std::vector<cv::Mat> m_out_mats;
int64_t m_start_ts;
int64_t m_seq_id;
};
Pipeline::Pipeline(std::string&& name,
@@ -101,42 +113,82 @@ Pipeline::Pipeline(std::string&& name,
void Pipeline::compile() {
m_perf.warmup_time =
utils::measure<std::chrono::milliseconds>([this]() {
utils::measure<utils::double_ms_t>([this]() {
_compile();
});
}
void Pipeline::prepareOutputs() {
// NB: N-2 buffers + timestamp + seq_id.
m_out_mats.resize(m_num_outputs - 2);
for (auto& m : m_out_mats) {
m_pipeline_outputs += cv::gout(m);
}
m_pipeline_outputs += cv::gout(m_start_ts);
m_pipeline_outputs += cv::gout(m_seq_id);
}
void Pipeline::run() {
using namespace std::chrono;
// NB: Allocate outputs for execution
prepareOutputs();
// NB: Warm-up iteration invalidates source state
// so need to copy it
auto orig_src = m_src;
auto copy_src = std::make_shared<DummySource>(*m_src);
// NB: Use copy for warm-up iteration
m_src = copy_src;
// NB: Warm-up iteration
init();
run_iter();
deinit();
// NB: Calculate first latency
m_perf.first_latency = utils::double_ms_t{
microseconds{utils::timestamp<microseconds>() - m_start_ts}}.count();
// NB: Now use original source
m_src = orig_src;
// NB: Start measuring execution
init();
auto start = high_resolution_clock::now();
m_stop_criterion->start();
while (true) {
m_perf.latencies.push_back(run_iter());
m_perf.elapsed = duration_cast<milliseconds>(high_resolution_clock::now() - start).count();
run_iter();
const auto latency = utils::double_ms_t{
microseconds{utils::timestamp<microseconds>() - m_start_ts}}.count();
m_perf.latencies.push_back(latency);
m_perf.seq_ids.push_back(m_seq_id);
m_stop_criterion->iter();
if (m_stop_criterion->done()) {
m_perf.elapsed = duration_cast<utils::double_ms_t>(
high_resolution_clock::now() - start).count();
deinit();
break;
}
}
m_perf.avg_latency = utils::avg(m_perf.latencies);
m_perf.min_latency = utils::min(m_perf.latencies);
m_perf.max_latency = utils::max(m_perf.latencies);
m_perf.first_latency = m_perf.latencies[0];
m_perf.avg_latency = utils::avg(m_perf.latencies);
m_perf.min_latency = utils::min(m_perf.latencies);
m_perf.max_latency = utils::max(m_perf.latencies);
// NB: Count how many executions don't fit into camera latency interval.
m_perf.num_late_frames =
std::count_if(m_perf.latencies.begin(), m_perf.latencies.end(),
[this](int64_t latency) {
return static_cast<double>(latency) > m_src->latency();
});
// NB: Count the number of dropped frames
int64_t prev_seq_id = m_perf.seq_ids[0];
for (size_t i = 1; i < m_perf.seq_ids.size(); ++i) {
m_perf.num_late_frames += m_perf.seq_ids[i] - prev_seq_id - 1;
prev_seq_id = m_perf.seq_ids[i];
}
m_perf.throughput =
(m_perf.latencies.size() / static_cast<double>(m_perf.elapsed)) * 1000;
m_perf.throughput = (m_perf.latencies.size() / m_perf.elapsed) * 1000;
}
const PerfReport& Pipeline::report() const {
@@ -155,13 +207,6 @@ private:
}
virtual void init() override {
using namespace std::chrono;
// NB: N-1 buffers + timestamp.
m_out_mats.resize(m_num_outputs - 1);
for (auto& m : m_out_mats) {
m_pipeline_outputs += cv::gout(m);
}
m_pipeline_outputs += cv::gout(m_start_ts);
m_compiled.setSource(m_src);
m_compiled.start();
}
@@ -170,15 +215,11 @@ private:
m_compiled.stop();
}
virtual int64_t run_iter() override {
virtual void run_iter() override {
m_compiled.pull(cv::GRunArgsP{m_pipeline_outputs});
return utils::timestamp<std::chrono::milliseconds>() - m_start_ts;
}
cv::GStreamingCompiled m_compiled;
cv::GRunArgsP m_pipeline_outputs;
std::vector<cv::Mat> m_out_mats;
int64_t m_start_ts;
};
class RegularPipeline : public Pipeline {
@@ -192,26 +233,13 @@ private:
cv::GCompileArgs(m_args));
}
virtual void init() override {
m_out_mats.resize(m_num_outputs);
for (auto& m : m_out_mats) {
m_pipeline_outputs += cv::gout(m);
}
virtual void run_iter() override {
cv::gapi::wip::Data data;
m_src->pull(data);
m_compiled({data}, cv::GRunArgsP{m_pipeline_outputs});
}
virtual int64_t run_iter() override {
using namespace std::chrono;
cv::gapi::wip::Data d;
m_src->pull(d);
auto in_mat = cv::util::get<cv::Mat>(d);
return utils::measure<milliseconds>([&]{
m_compiled(cv::gin(in_mat), cv::GRunArgsP{m_pipeline_outputs});
});
}
cv::GCompiled m_compiled;
cv::GRunArgsP m_pipeline_outputs;
std::vector<cv::Mat> m_out_mats;
cv::GCompiled m_compiled;
};
enum class PLMode {
@@ -163,13 +163,10 @@ struct DummyCall {
cv::Mat& out_mat,
DummyState& state) {
using namespace std::chrono;
double total = 0;
auto start = high_resolution_clock::now();
auto start_ts = utils::timestamp<utils::double_ms_t>();
state.mat.copyTo(out_mat);
while (total < time) {
total = duration_cast<duration<double, std::milli>>(
high_resolution_clock::now() - start).count();
}
auto elapsed = utils::timestamp<utils::double_ms_t>() - start_ts;
utils::busyWait(duration_cast<microseconds>(utils::double_ms_t{time-elapsed}));
}
};
@@ -656,16 +653,16 @@ Pipeline::Ptr PipelineBuilder::construct() {
}
GAPI_Assert(m_state->stop_criterion);
if (m_state->mode == PLMode::STREAMING) {
GAPI_Assert(graph_inputs.size() == 1);
GAPI_Assert(cv::util::holds_alternative<cv::GMat>(graph_inputs[0]));
// FIXME: Handle GFrame when NV12 comes.
const auto& graph_input = cv::util::get<cv::GMat>(graph_inputs[0]);
// NB: In case streaming mode need to expose timestamp in order to
// calculate performance metrics.
graph_outputs.emplace_back(
cv::gapi::streaming::timestamp(graph_input).strip());
GAPI_Assert(graph_inputs.size() == 1);
GAPI_Assert(cv::util::holds_alternative<cv::GMat>(graph_inputs[0]));
// FIXME: Handle GFrame when NV12 comes.
const auto& graph_input = cv::util::get<cv::GMat>(graph_inputs[0]);
graph_outputs.emplace_back(
cv::gapi::streaming::timestamp(graph_input).strip());
graph_outputs.emplace_back(
cv::gapi::streaming::seq_id(graph_input).strip());
if (m_state->mode == PLMode::STREAMING) {
return std::make_shared<StreamingPipeline>(std::move(m_state->name),
cv::GComputation(
cv::GProtoInputArgs{graph_inputs},
@@ -17,6 +17,8 @@ struct OutputDescr {
namespace utils {
using double_ms_t = std::chrono::duration<double, std::milli>;
inline void createNDMat(cv::Mat& mat, const std::vector<int>& dims, int depth) {
GAPI_Assert(!dims.empty());
mat.create(dims, depth);
@@ -50,10 +52,8 @@ inline void generateRandom(cv::Mat& out) {
}
}
inline void sleep(double ms) {
inline void sleep(std::chrono::microseconds delay) {
#if defined(_WIN32)
// NB: It takes portions of 100 nanoseconds.
int64_t ns_units = static_cast<int64_t>(ms * 1e4);
// FIXME: Wrap it to RAII and instance only once.
HANDLE timer = CreateWaitableTimer(NULL, true, NULL);
if (!timer) {
@@ -61,7 +61,12 @@ inline void sleep(double ms) {
}
LARGE_INTEGER li;
li.QuadPart = -ns_units;
using ns_t = std::chrono::nanoseconds;
using ns_100_t = std::chrono::duration<ns_t::rep,
std::ratio_multiply<std::ratio<100>, ns_t::period>>;
// NB: QuadPart takes portions of 100 nanoseconds.
li.QuadPart = -std::chrono::duration_cast<ns_100_t>(delay).count();
if(!SetWaitableTimer(timer, &li, 0, NULL, NULL, false)){
CloseHandle(timer);
throw std::logic_error("Failed to set timer");
@@ -72,8 +77,7 @@ inline void sleep(double ms) {
}
CloseHandle(timer);
#else
using namespace std::chrono;
std::this_thread::sleep_for(duration<double, std::milli>(ms));
std::this_thread::sleep_for(delay);
#endif
}
@@ -93,6 +97,16 @@ typename duration_t::rep timestamp() {
return duration_cast<duration_t>(now.time_since_epoch()).count();
}
inline void busyWait(std::chrono::microseconds delay) {
auto start_ts = timestamp<std::chrono::microseconds>();
auto end_ts = start_ts;
auto time_to_wait = delay.count();
while (end_ts - start_ts < time_to_wait) {
end_ts = timestamp<std::chrono::microseconds>();
}
}
template <typename K, typename V>
void mergeMapWith(std::map<K, V>& target, const std::map<K, V>& second) {
for (auto&& item : second) {
+47 -15
View File
@@ -456,6 +456,7 @@ public:
cv::gimpl::GIslandExecutable::IOutput & output,
const cv::GArgs & args,
const std::vector<cv::gimpl::RcDesc> & outs,
cv::GRunArg::Meta && meta,
std::vector<cv::gimpl::GIslandExecutable::InObj> && input_objs,
std::vector<cv::gimpl::GIslandExecutable::OutObj> && output_objs);
@@ -477,9 +478,8 @@ public:
const cv::Mat& inMat (std::size_t input) const;
const cv::MediaFrame& inFrame(std::size_t input) const;
const cv::GRunArg& input (std::size_t idx) const;
cv::GRunArgP output (std::size_t idx);
cv::Mat& outMatR(std::size_t idx);
cv::GRunArgP output (std::size_t idx);
cv::Mat& outMatR(std::size_t idx);
const IEUnit &uu;
cv::gimpl::GIslandExecutable::IOutput &out;
@@ -491,6 +491,8 @@ public:
// To store exception appeared in callback.
std::exception_ptr eptr;
const cv::GRunArg::Meta& getMeta() { return m_meta; };
using req_key_t = void*;
cv::MediaFrame* prepareKeepAliveFrameSlot(req_key_t key);
size_t releaseKeepAliveFrame(req_key_t key);
@@ -499,6 +501,9 @@ private:
cv::GArg packArg(const cv::GArg &arg);
// To propagate accumulated meta from all inputs to output.
cv::GRunArg::Meta m_meta;
// To store input/output data from frames
std::vector<cv::gimpl::GIslandExecutable::InObj> m_input_objs;
std::vector<cv::gimpl::GIslandExecutable::OutObj> m_output_objs;
@@ -525,9 +530,11 @@ IECallContext::IECallContext(const IEUnit &
cv::gimpl::GIslandExecutable::IOutput & output,
const cv::GArgs & args,
const std::vector<cv::gimpl::RcDesc> & outs,
cv::GRunArg::Meta && meta,
std::vector<cv::gimpl::GIslandExecutable::InObj> && input_objs,
std::vector<cv::gimpl::GIslandExecutable::OutObj> && output_objs)
: uu(unit), out(output), m_input_objs(std::move(input_objs)), m_output_objs(std::move(output_objs))
: uu(unit), out(output), m_meta(std::move(meta)),
m_input_objs(std::move(input_objs)), m_output_objs(std::move(output_objs))
{
for (auto& it : m_input_objs) cv::gimpl::magazine::bindInArg (m_res, it.first, it.second);
for (auto& it : m_output_objs) cv::gimpl::magazine::bindOutArg(m_res, it.first, it.second);
@@ -575,10 +582,6 @@ cv::GRunArgP IECallContext::output(std::size_t idx) {
return m_output_objs[idx].second;
};
const cv::GRunArg& IECallContext::input(std::size_t idx) const {
return m_input_objs[idx].second;
}
cv::detail::VectorRef& IECallContext::outVecRef(std::size_t idx) {
return cv::util::get<cv::detail::VectorRef>(m_results.at(idx));
}
@@ -1062,6 +1065,12 @@ void cv::gimpl::ie::GIEExecutable::run(cv::gimpl::GIslandExecutable::IInput &in
GAPI_Assert(cv::util::holds_alternative<cv::GRunArgs>(in_msg));
const auto in_vector = cv::util::get<cv::GRunArgs>(in_msg);
// NB: Collect meta from all inputs.
cv::GRunArg::Meta stub_meta;
for (auto &&in_arg : in_vector)
{
stub_meta.insert(in_arg.meta.begin(), in_arg.meta.end());
}
// (1) Collect island inputs/outputs
input_objs.reserve(in_desc.size());
@@ -1084,7 +1093,7 @@ void cv::gimpl::ie::GIEExecutable::run(cv::gimpl::GIslandExecutable::IInput &in
const auto &op = m_gm.metadata(this_nh).get<Op>();
// (2) Create kernel context
auto ctx = std::make_shared<IECallContext>(uu, out, op.args, op.outs,
std::move(input_objs), std::move(output_objs));
std::move(stub_meta), std::move(input_objs), std::move(output_objs));
const auto &kk = giem.metadata(this_nh).get<IECallable>();
@@ -1096,6 +1105,7 @@ void cv::gimpl::ie::GIEExecutable::run(cv::gimpl::GIslandExecutable::IInput &in
for (auto i : ade::util::iota(ctx->uu.params.num_out))
{
auto output = ctx->output(i);
ctx->out.meta(output, ctx->getMeta());
ctx->out.post(std::move(output), eptr);
}
return;
@@ -1247,7 +1257,7 @@ static void PostOutputs(InferenceEngine::InferRequest &request,
IE::Blob::Ptr this_blob = request.GetBlob(ctx->uu.params.output_names[i]);
copyFromIE(this_blob, out_mat);
auto output = ctx->output(i);
ctx->out.meta(output, ctx->input(0).meta);
ctx->out.meta(output, ctx->getMeta());
ctx->out.post(std::move(output), ctx->eptr);
}
@@ -1314,7 +1324,7 @@ void PostOutputsList::operator()(InferenceEngine::InferRequest &req,
if (finished == size) {
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
auto output = ctx->output(i);
ctx->out.meta(output, ctx->input(0).meta);
ctx->out.meta(output, ctx->getMeta());
ctx->out.post(std::move(output), ctx->eptr);
}
}
@@ -1374,6 +1384,11 @@ struct Infer: public cv::detail::KernelTag {
}
}
for (auto &&p : uu.params.const_inputs) {
const auto ii = inputs.at(p.first);
ii->setPrecision(toIE(p.second.first.depth()));
}
// FIXME: This isn't the best place to call reshape function.
// Сorrect solution would be to do this in compile() method of network,
// but now input meta isn't passed to compile() method.
@@ -1474,7 +1489,8 @@ struct InferROI: public cv::detail::KernelTag {
// only in the loadNetwork case.
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
// 0th is ROI, 1st is input image
auto ii = uu.net.getInputsInfo().at(input_name);
auto inputs = uu.net.getInputsInfo();
auto ii = inputs.at(input_name);
configureInputInfo(ii, mm);
if (uu.params.layer_names_to_reshape.find(input_name) !=
uu.params.layer_names_to_reshape.end()) {
@@ -1496,6 +1512,11 @@ struct InferROI: public cv::detail::KernelTag {
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
.set_param(input_name, ii->getTensorDesc());
}
for (auto &&p : uu.params.const_inputs) {
inputs.at(p.first)->setPrecision(toIE(p.second.first.depth()));
}
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
@@ -1614,6 +1635,12 @@ struct InferList: public cv::detail::KernelTag {
if (!input_reshape_table.empty()) {
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
}
for (auto &&p : uu.params.const_inputs) {
const auto ii = inputs.at(p.first);
ii->setPrecision(toIE(p.second.first.depth()));
}
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
} else {
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
@@ -1642,7 +1669,7 @@ struct InferList: public cv::detail::KernelTag {
if (in_roi_vec.empty()) {
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
auto output = ctx->output(i);
ctx->out.meta(output, ctx->input(0).meta);
ctx->out.meta(output, ctx->getMeta());
ctx->out.post(std::move(output));
}
return;
@@ -1751,8 +1778,9 @@ struct InferList2: public cv::detail::KernelTag {
// NB: Configuring input precision and network reshape must be done
// only in the loadNetwork case.
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
auto inputs = uu.net.getInputsInfo();
// This is a cv::Rect -- configure the IE preprocessing
auto ii = uu.net.getInputsInfo().at(input_name);
auto ii = inputs.at(input_name);
configureInputInfo(ii, mm_0);
if (uu.params.layer_names_to_reshape.find(input_name) !=
uu.params.layer_names_to_reshape.end()) {
@@ -1762,6 +1790,10 @@ struct InferList2: public cv::detail::KernelTag {
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
}
for (auto &&p : uu.params.const_inputs) {
inputs.at(p.first)->setPrecision(toIE(p.second.first.depth()));
}
// FIXME: This isn't the best place to call reshape function.
// Сorrect solution would be to do this in compile() method of network,
// but now input meta isn't passed to compile() method.
@@ -1806,7 +1838,7 @@ struct InferList2: public cv::detail::KernelTag {
if (list_size == 0u) {
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
auto output = ctx->output(i);
ctx->out.meta(output, ctx->input(0).meta);
ctx->out.meta(output, ctx->getMeta());
ctx->out.post(std::move(output));
}
return;
@@ -8,6 +8,19 @@ cv::gapi::onnx::PyParams::PyParams(const std::string& tag,
const std::string& model_path)
: m_priv(std::make_shared<Params<cv::gapi::Generic>>(tag, model_path)) {}
cv::gapi::onnx::PyParams& cv::gapi::onnx::PyParams::cfgMeanStd(const std::string &layer_name,
const cv::Scalar &m,
const cv::Scalar &s) {
m_priv->cfgMeanStdDev(layer_name, m, s);
return *this;
}
cv::gapi::onnx::PyParams& cv::gapi::onnx::PyParams::cfgNormalize(const std::string &layer_name,
bool flag) {
m_priv->cfgNormalize(layer_name, flag);
return *this;
}
cv::gapi::GBackend cv::gapi::onnx::PyParams::backend() const {
return m_priv->backend();
}
+23 -15
View File
@@ -44,7 +44,8 @@ static std::string pdims(const std::vector<int64_t> &dims) {
struct TensorInfo {
TensorInfo() = default;
explicit TensorInfo(const Ort::TensorTypeAndShapeInfo& info)
explicit TensorInfo(const Ort::ConstTensorTypeAndShapeInfo &info)
: dims(info.GetShape())
, type(info.GetElementType())
, is_dynamic(ade::util::find(dims, -1) != dims.end()) {
@@ -283,6 +284,7 @@ inline void preprocess(const cv::Mat& src,
cv::resize(csc, rsz, cv::Size(new_w, new_h));
if (src.depth() == CV_8U && type == CV_32F) {
rsz.convertTo(pp, type, ti.normalize ? 1.f / 255 : 1.f);
if (ti.mstd.has_value()) {
pp -= ti.mstd->mean;
pp /= ti.mstd->stdev;
@@ -688,11 +690,10 @@ std::vector<TensorInfo> ONNXCompiled::getTensorInfo(TensorPosition pos) {
: this_session.GetOutputTypeInfo(i);
tensor_info.emplace_back(info.GetTensorTypeAndShapeInfo());
char *name_p = pos == INPUT
? this_session.GetInputName(i, allocator)
: this_session.GetOutputName(i, allocator);
tensor_info.back().name = name_p;
allocator.Free(name_p);
Ort::AllocatedStringPtr name_p = pos == INPUT
? this_session.GetInputNameAllocated(i, allocator)
: this_session.GetOutputNameAllocated(i, allocator);
tensor_info.back().name = std::string(name_p.get());
}
return tensor_info;
@@ -1143,24 +1144,31 @@ namespace {
if (pp.is_generic) {
auto& info = cv::util::any_cast<cv::detail::InOutInfo>(op.params);
for (const auto& a : info.in_names)
for (const auto& layer_name : info.in_names)
{
pp.input_names.push_back(a);
}
// Adding const input is necessary because the definition of input_names
// includes const input.
for (const auto& a : pp.const_inputs)
{
pp.input_names.push_back(a.first);
pp.input_names.push_back(layer_name);
if (!pp.generic_mstd.empty()) {
const auto &ms = pp.generic_mstd.at(layer_name);
pp.mean.push_back(ms.first);
pp.stdev.push_back(ms.second);
}
if (!pp.generic_norm.empty()) {
pp.normalize.push_back(pp.generic_norm.at(layer_name));
}
}
pp.num_in = info.in_names.size();
// Incorporate extra parameters associated with input layer names
// FIXME(DM): The current form assumes ALL input layers require
// this information, this is obviously not correct
for (const auto& a : info.out_names)
{
pp.output_names.push_back(a);
}
pp.num_out = info.out_names.size();
}
} // if(is_generic) -- note, the structure is already filled at the user
// end when a non-generic Params are used
gm.metadata(nh).set(ONNXUnit{pp});
gm.metadata(nh).set(ONNXCallable{ki.run});
@@ -829,7 +829,11 @@ TEST_P(Preproc4lpiTest, Test)
cv::cvtColor(in_mat, rgb_mat, cv::COLOR_YUV2RGB_NV12);
cv::resize(rgb_mat, out_mat_ocv, out_sz, 0, 0, interp);
#if defined(__arm__) || defined(__aarch64__)
EXPECT_GE(2, cvtest::norm(out_mat(roi), out_mat_ocv(roi), NORM_INF));
#else
EXPECT_EQ(0, cvtest::norm(out_mat(roi), out_mat_ocv(roi), NORM_INF));
#endif
}
INSTANTIATE_TEST_CASE_P(Fluid, Preproc4lpiTest,
@@ -332,9 +332,8 @@ public:
// Inputs Run params
std::vector<Ort::Value> in_tensors;
for(size_t i = 0; i < num_in; ++i) {
char* in_node_name_p = session.GetInputName(i, allocator);
in_node_names.emplace_back(in_node_name_p);
allocator.Free(in_node_name_p);
auto in_node_name_p = session.GetInputNameAllocated(i, allocator);
in_node_names.emplace_back(in_node_name_p.get());
in_node_dims = toORT(ins[i].size);
in_tensors.emplace_back(Ort::Value::CreateTensor<T>(memory_info,
const_cast<T*>(ins[i].ptr<T>()),
@@ -345,9 +344,8 @@ public:
// Outputs Run params
if (custom_out_names.empty()) {
for(size_t i = 0; i < num_out; ++i) {
char* out_node_name_p = session.GetOutputName(i, allocator);
out_node_names.emplace_back(out_node_name_p);
allocator.Free(out_node_name_p);
auto out_node_name_p = session.GetOutputNameAllocated(i, allocator);
out_node_names.emplace_back(out_node_name_p.get());
}
} else {
out_node_names = std::move(custom_out_names);
@@ -425,13 +423,17 @@ public:
cv::Rect(cv::Point{50, 100}, cv::Size{250, 360})
};
void preprocess(const cv::Mat& src, cv::Mat& dst) {
// FIXME(dm): There's too much "preprocess" routines in this file
// Only one must stay but better design it wisely (and later)
void preprocess(const cv::Mat& src, cv::Mat& dst, bool norm = true) {
const int new_h = 224;
const int new_w = 224;
cv::Mat tmp, cvt, rsz;
cv::resize(src, rsz, cv::Size(new_w, new_h));
rsz.convertTo(cvt, CV_32F, 1.f / 255);
tmp = (cvt - mean) / std;
rsz.convertTo(cvt, CV_32F, norm ? 1.f / 255 : 1.f);
tmp = norm
? (cvt - mean) / std
: cvt;
toCHW(tmp, dst);
dst = dst.reshape(1, {1, 3, new_h, new_w});
}
@@ -552,16 +554,16 @@ TEST_F(ONNXClassification, Infer)
in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
// ONNX_API code
cv::Mat processed_mat;
preprocess(in_mat, processed_mat);
preprocess(in_mat, processed_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(processed_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
cv::GMat in;
cv::GMat out = cv::gapi::infer<SqueezNet>(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(in_mat),
cv::gout(out_gapi.front()),
cv::compile_args(cv::gapi::networks(net)));
@@ -575,7 +577,7 @@ TEST_F(ONNXClassification, InferTensor)
in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
// Create tensor
cv::Mat tensor;
preprocess(in_mat, tensor);
preprocess(in_mat, tensor, false); // NO normalization for 1.0-9, see #23597
// ONNX_API code
infer<float>(tensor, out_onnx);
// G_API code
@@ -583,7 +585,9 @@ TEST_F(ONNXClassification, InferTensor)
cv::GMat in;
cv::GMat out = cv::gapi::infer<SqueezNet>(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path };
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(tensor),
cv::gout(out_gapi.front()),
cv::compile_args(cv::gapi::networks(net)));
@@ -598,7 +602,7 @@ TEST_F(ONNXClassification, InferROI)
const auto ROI = rois.at(0);
// ONNX_API code
cv::Mat roi_mat;
preprocess(in_mat(ROI), roi_mat);
preprocess(in_mat(ROI), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
@@ -606,9 +610,9 @@ TEST_F(ONNXClassification, InferROI)
cv::GOpaque<cv::Rect> rect;
cv::GMat out = cv::gapi::infer<SqueezNet>(rect, in);
cv::GComputation comp(cv::GIn(in, rect), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(in_mat, ROI),
cv::gout(out_gapi.front()),
cv::compile_args(cv::gapi::networks(net)));
@@ -623,7 +627,7 @@ TEST_F(ONNXClassification, InferROIList)
// ONNX_API code
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat(rois[i]), roi_mat);
preprocess(in_mat(rois[i]), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
}
// G_API code
@@ -634,7 +638,9 @@ TEST_F(ONNXClassification, InferROIList)
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(in_mat, rois),
cv::gout(out_gapi),
cv::compile_args(cv::gapi::networks(net)));
@@ -649,7 +655,7 @@ TEST_F(ONNXClassification, Infer2ROIList)
// ONNX_API code
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat(rois[i]), roi_mat);
preprocess(in_mat(rois[i]), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
}
// G_API code
@@ -660,7 +666,9 @@ TEST_F(ONNXClassification, Infer2ROIList)
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(in_mat, rois),
cv::gout(out_gapi),
cv::compile_args(cv::gapi::networks(net)));
@@ -749,7 +757,7 @@ TEST_F(ONNXMediaFrame, InferBGR)
in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
// ONNX_API code
cv::Mat processed_mat;
preprocess(in_mat, processed_mat);
preprocess(in_mat, processed_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(processed_mat, out_onnx);
// G_API code
auto frame = MediaFrame::Create<TestMediaBGR>(in_mat);
@@ -759,7 +767,9 @@ TEST_F(ONNXMediaFrame, InferBGR)
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(frame),
cv::gout(out_gapi.front()),
cv::compile_args(cv::gapi::networks(net)));
@@ -776,7 +786,7 @@ TEST_F(ONNXMediaFrame, InferYUV)
cv::Mat pp;
cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
cv::Mat processed_mat;
preprocess(pp, processed_mat);
preprocess(pp, processed_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(processed_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
@@ -785,7 +795,9 @@ TEST_F(ONNXMediaFrame, InferYUV)
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(frame),
cv::gout(out_gapi.front()),
cv::compile_args(cv::gapi::networks(net)));
@@ -800,7 +812,7 @@ TEST_F(ONNXMediaFrame, InferROIBGR)
auto frame = MediaFrame::Create<TestMediaBGR>(in_mat);
// ONNX_API code
cv::Mat roi_mat;
preprocess(in_mat(rois.front()), roi_mat);
preprocess(in_mat(rois.front()), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
@@ -810,7 +822,9 @@ TEST_F(ONNXMediaFrame, InferROIBGR)
cv::GComputation comp(cv::GIn(in, rect), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(frame, rois.front()),
cv::gout(out_gapi.front()),
cv::compile_args(cv::gapi::networks(net)));
@@ -827,7 +841,7 @@ TEST_F(ONNXMediaFrame, InferROIYUV)
cv::Mat pp;
cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
cv::Mat roi_mat;
preprocess(pp(rois.front()), roi_mat);
preprocess(pp(rois.front()), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
// G_API code
G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
@@ -837,7 +851,9 @@ TEST_F(ONNXMediaFrame, InferROIYUV)
cv::GComputation comp(cv::GIn(in, rect), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(frame, rois.front()),
cv::gout(out_gapi.front()),
cv::compile_args(cv::gapi::networks(net)));
@@ -853,7 +869,7 @@ TEST_F(ONNXMediaFrame, InferListBGR)
// ONNX_API code
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat(rois[i]), roi_mat);
preprocess(in_mat(rois[i]), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
}
// G_API code
@@ -864,7 +880,9 @@ TEST_F(ONNXMediaFrame, InferListBGR)
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(frame, rois),
cv::gout(out_gapi),
cv::compile_args(cv::gapi::networks(net)));
@@ -882,7 +900,7 @@ TEST_F(ONNXMediaFrame, InferListYUV)
cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(pp(rois[i]), roi_mat);
preprocess(pp(rois[i]), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
}
// G_API code
@@ -893,7 +911,9 @@ TEST_F(ONNXMediaFrame, InferListYUV)
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(frame, rois),
cv::gout(out_gapi),
cv::compile_args(cv::gapi::networks(net)));
@@ -935,7 +955,7 @@ TEST_F(ONNXMediaFrame, InferList2BGR)
// ONNX_API code
for (size_t i = 0; i < rois.size(); ++i) {
cv::Mat roi_mat;
preprocess(in_mat(rois[i]), roi_mat);
preprocess(in_mat(rois[i]), roi_mat, false); // NO normalization for 1.0-9, see #23597
infer<float>(roi_mat, out_onnx);
}
// G_API code
@@ -946,7 +966,9 @@ TEST_F(ONNXMediaFrame, InferList2BGR)
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
// NOTE: We have to normalize U8 tensor
// so cfgMeanStd() is here
auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
auto net = cv::gapi::onnx::Params<SqueezNet> {
model_path
}.cfgNormalize({false});
comp.apply(cv::gin(frame, rois),
cv::gout(out_gapi),
cv::compile_args(cv::gapi::networks(net)));
@@ -27,7 +27,7 @@ class GMockExecutable final: public cv::gimpl::GIslandExecutable
m_priv->m_reshape_counter++;
}
virtual void handleNewStream() override { }
virtual void run(std::vector<InObj>&&, std::vector<OutObj>&&) { }
virtual void run(std::vector<InObj>&&, std::vector<OutObj>&&) override { }
virtual bool allocatesOutputs() const override
{
return true;
@@ -190,7 +190,7 @@ public:
: cv::gapi::wip::GCaptureSource(pipeline) {
}
bool pull(cv::gapi::wip::Data& data) {
bool pull(cv::gapi::wip::Data& data) override {
if (cv::gapi::wip::GCaptureSource::pull(data)) {
data = cv::MediaFrame::Create<TestMediaBGR>(cv::util::get<cv::Mat>(data));
return true;
@@ -232,7 +232,7 @@ public:
: cv::gapi::wip::GCaptureSource(pipeline) {
}
bool pull(cv::gapi::wip::Data& data) {
bool pull(cv::gapi::wip::Data& data) override {
if (cv::gapi::wip::GCaptureSource::pull(data)) {
cv::Mat bgr = cv::util::get<cv::Mat>(data);
cv::Mat y, uv;
@@ -256,7 +256,7 @@ public:
: cv::gapi::wip::GCaptureSource(pipeline) {
}
bool pull(cv::gapi::wip::Data& data) {
bool pull(cv::gapi::wip::Data& data) override {
if (cv::gapi::wip::GCaptureSource::pull(data)) {
cv::Mat bgr = cv::util::get<cv::Mat>(data);
cv::Mat gray;
@@ -319,7 +319,7 @@ public:
return "InvalidSource sucessfuly failed!";
}
bool pull(cv::gapi::wip::Data& d) {
bool pull(cv::gapi::wip::Data& d) override {
++m_curr_frame_id;
if (m_curr_frame_id > m_num_frames) {
return false;