mirror of
https://github.com/opencv/opencv.git
synced 2025-07-25 22:57:53 +08:00
Added reshape() functionality to CPU backend
This commit is contained in:
parent
a332509e02
commit
ecb30409f6
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018-2021 Intel Corporation
|
// Copyright (C) 2018-2022 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#include "precomp.hpp"
|
#include "precomp.hpp"
|
||||||
@ -88,7 +88,7 @@ cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
|
|||||||
{
|
{
|
||||||
case NodeType::OP:
|
case NodeType::OP:
|
||||||
{
|
{
|
||||||
m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)});
|
m_opNodes.push_back(nh);
|
||||||
|
|
||||||
// If kernel is stateful then prepare storage for its state.
|
// If kernel is stateful then prepare storage for its state.
|
||||||
GCPUKernel k = gcm.metadata(nh).get<CPUUnit>().k;
|
GCPUKernel k = gcm.metadata(nh).get<CPUUnit>().k;
|
||||||
@ -107,19 +107,12 @@ cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
|
|||||||
auto rc = RcDesc{desc.rc, desc.shape, desc.ctor};
|
auto rc = RcDesc{desc.rc, desc.shape, desc.ctor};
|
||||||
magazine::bindInArg(m_res, rc, m_gm.metadata(nh).get<ConstValue>().arg);
|
magazine::bindInArg(m_res, rc, m_gm.metadata(nh).get<ConstValue>().arg);
|
||||||
}
|
}
|
||||||
//preallocate internal Mats in advance
|
|
||||||
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)
|
|
||||||
{
|
|
||||||
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
|
|
||||||
auto& mat = m_res.slot<cv::Mat>()[desc.rc];
|
|
||||||
createMat(mat_desc, mat);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: util::throw_error(std::logic_error("Unsupported NodeType type"));
|
default: util::throw_error(std::logic_error("Unsupported NodeType type"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
makeReshape();
|
||||||
// For each stateful kernel call 'setup' user callback to initialize state.
|
// For each stateful kernel call 'setup' user callback to initialize state.
|
||||||
setupKernelStates();
|
setupKernelStates();
|
||||||
}
|
}
|
||||||
@ -176,8 +169,38 @@ void cv::gimpl::GCPUExecutable::setupKernelStates()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cv::gimpl::GCPUExecutable::makeReshape() {
|
||||||
|
// Prepare the execution script
|
||||||
|
m_script.clear();
|
||||||
|
for (auto &nh : m_opNodes) {
|
||||||
|
m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate internal mats
|
||||||
|
for (auto& nh : m_dataNodes) {
|
||||||
|
const auto& desc = m_gm.metadata(nh).get<Data>();
|
||||||
|
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT) {
|
||||||
|
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
|
||||||
|
auto& mat = m_res.slot<cv::Mat>()[desc.rc];
|
||||||
|
createMat(mat_desc, mat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cv::gimpl::GCPUExecutable::reshape(ade::Graph&, const GCompileArgs& args) {
|
||||||
|
m_compileArgs = args;
|
||||||
|
makeReshape();
|
||||||
|
// Signal to reset stateful kernels` state.
|
||||||
|
// There can be no handleNewStream() call to set this flag
|
||||||
|
// if user didn't call GCompiled`s prepareForNewStream()
|
||||||
|
m_newStreamStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
void cv::gimpl::GCPUExecutable::handleNewStream()
|
void cv::gimpl::GCPUExecutable::handleNewStream()
|
||||||
{
|
{
|
||||||
|
// Signal to reset stateful kernels` state.
|
||||||
|
// No need to call reshape() here since it'll
|
||||||
|
// be called automatically if input meta was changed
|
||||||
m_newStreamStarted = true;
|
m_newStreamStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018-2020 Intel Corporation
|
// Copyright (C) 2018-2022 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENCV_GAPI_GCPUBACKEND_HPP
|
#ifndef OPENCV_GAPI_GCPUBACKEND_HPP
|
||||||
@ -33,7 +33,7 @@ class GCPUExecutable final: public GIslandExecutable
|
|||||||
{
|
{
|
||||||
const ade::Graph &m_g;
|
const ade::Graph &m_g;
|
||||||
GModel::ConstGraph m_gm;
|
GModel::ConstGraph m_gm;
|
||||||
const cv::GCompileArgs m_compileArgs;
|
cv::GCompileArgs m_compileArgs;
|
||||||
|
|
||||||
struct OperationInfo
|
struct OperationInfo
|
||||||
{
|
{
|
||||||
@ -51,6 +51,7 @@ class GCPUExecutable final: public GIslandExecutable
|
|||||||
|
|
||||||
// List of all resources in graph (both internal and external)
|
// List of all resources in graph (both internal and external)
|
||||||
std::vector<ade::NodeHandle> m_dataNodes;
|
std::vector<ade::NodeHandle> m_dataNodes;
|
||||||
|
std::vector<ade::NodeHandle> m_opNodes;
|
||||||
|
|
||||||
// Actual data of all resources in graph (both internal and external)
|
// Actual data of all resources in graph (both internal and external)
|
||||||
Mag m_res;
|
Mag m_res;
|
||||||
@ -61,19 +62,15 @@ class GCPUExecutable final: public GIslandExecutable
|
|||||||
GArg packArg(const GArg &arg);
|
GArg packArg(const GArg &arg);
|
||||||
void setupKernelStates();
|
void setupKernelStates();
|
||||||
|
|
||||||
|
void makeReshape();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GCPUExecutable(const ade::Graph &graph,
|
GCPUExecutable(const ade::Graph &graph,
|
||||||
const cv::GCompileArgs &compileArgs,
|
const cv::GCompileArgs &compileArgs,
|
||||||
const std::vector<ade::NodeHandle> &nodes);
|
const std::vector<ade::NodeHandle> &nodes);
|
||||||
|
|
||||||
virtual inline bool canReshape() const override { return false; }
|
virtual inline bool canReshape() const override { return true; }
|
||||||
virtual inline void reshape(ade::Graph&, const GCompileArgs&) override
|
virtual void reshape(ade::Graph&, const GCompileArgs&) override;
|
||||||
{
|
|
||||||
// FIXME: CPU plugin is in fact reshapeable (as it was initially,
|
|
||||||
// even before outMeta() has been introduced), so this limitation
|
|
||||||
// should be dropped.
|
|
||||||
util::throw_error(std::logic_error("GCPUExecutable::reshape() should never be called"));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void handleNewStream() override;
|
virtual void handleNewStream() override;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018-2020 Intel Corporation
|
// Copyright (C) 2018-2022 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#include "precomp.hpp"
|
#include "precomp.hpp"
|
||||||
@ -954,7 +954,7 @@ namespace
|
|||||||
GFluidModel fg(graph);
|
GFluidModel fg(graph);
|
||||||
for (const auto& node : g.nodes())
|
for (const auto& node : g.nodes())
|
||||||
{
|
{
|
||||||
if (g.metadata(node).get<NodeType>().t == NodeType::DATA)
|
if (fg.metadata(node).contains<FluidData>())
|
||||||
{
|
{
|
||||||
auto& fd = fg.metadata(node).get<FluidData>();
|
auto& fd = fg.metadata(node).get<FluidData>();
|
||||||
fd.latency = 0;
|
fd.latency = 0;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2020 Intel Corporation
|
// Copyright (C) 2020-2022 Intel Corporation
|
||||||
|
|
||||||
#include "gapi_ocv_stateful_kernel_test_utils.hpp"
|
#include "gapi_ocv_stateful_kernel_test_utils.hpp"
|
||||||
#include <opencv2/gapi/cpu/core.hpp>
|
#include <opencv2/gapi/cpu/core.hpp>
|
||||||
@ -342,7 +342,79 @@ TEST(StatefulKernel, StateIsInitViaCompArgsInStreaming)
|
|||||||
// Allowing 5% difference of all pixels between G-API and reference OpenCV results
|
// Allowing 5% difference of all pixels between G-API and reference OpenCV results
|
||||||
testBackSubInStreaming(gapiBackSub, 5);
|
testBackSubInStreaming(gapiBackSub, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(StatefulKernel, StateIsChangedViaCompArgsOnReshape)
|
||||||
|
{
|
||||||
|
cv::GMat in;
|
||||||
|
cv::GComputation comp(in, GBackSub::on(in));
|
||||||
|
|
||||||
|
const auto pkg = cv::gapi::kernels<GOCVBackSub>();
|
||||||
|
|
||||||
|
// OpenCV reference substractor
|
||||||
|
auto pOCVBackSubKNN = createBackgroundSubtractorKNN();
|
||||||
|
auto pOCVBackSubMOG2 = createBackgroundSubtractorMOG2();
|
||||||
|
|
||||||
|
const auto run = [&](const std::string& videoPath, const std::string& method) {
|
||||||
|
auto path = findDataFile(videoPath);
|
||||||
|
cv::gapi::wip::IStreamSource::Ptr source;
|
||||||
|
try {
|
||||||
|
source = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path);
|
||||||
|
} catch(...) {
|
||||||
|
throw SkipTestException("Video file can not be opened");
|
||||||
|
}
|
||||||
|
cv::Mat inMat, gapiForeground, ocvForeground;
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
cv::gapi::wip::Data inData;
|
||||||
|
source->pull(inData);
|
||||||
|
inMat = cv::util::get<cv::Mat>(inData);
|
||||||
|
comp.apply(inMat, gapiForeground,
|
||||||
|
cv::compile_args(pkg, BackSubStateParams{method}));
|
||||||
|
|
||||||
|
if (method == "knn") {
|
||||||
|
pOCVBackSubKNN->apply(inMat, ocvForeground, -1);
|
||||||
|
// Allowing 1% difference among all pixels
|
||||||
|
compareBackSubResults(gapiForeground, ocvForeground, 1);
|
||||||
|
} else if (method == "mog2") {
|
||||||
|
pOCVBackSubMOG2->apply(inMat, ocvForeground, -1);
|
||||||
|
compareBackSubResults(gapiForeground, ocvForeground, 5);
|
||||||
|
} else {
|
||||||
|
CV_Assert(false && "Unknown BackSub method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
run("cv/video/768x576.avi", "knn");
|
||||||
|
run("cv/video/1920x1080.avi", "mog2");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST(StatefulKernel, StateIsAutoResetOnReshape)
|
||||||
|
{
|
||||||
|
cv::GMat in;
|
||||||
|
cv::GOpaque<bool> up_to_date = GIsStateUpToDate::on(in);
|
||||||
|
cv::GOpaque<int> calls_count = GCountCalls::on(in);
|
||||||
|
cv::GComputation comp(cv::GIn(in), cv::GOut(up_to_date, calls_count));
|
||||||
|
|
||||||
|
auto run = [&comp](const cv::Mat& in_mat) {
|
||||||
|
const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate, GOCVCountCalls>();
|
||||||
|
bool stateIsUpToDate = false;
|
||||||
|
int callsCount = 0;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
comp.apply(cv::gin(in_mat), cv::gout(stateIsUpToDate, callsCount),
|
||||||
|
cv::compile_args(pkg));
|
||||||
|
EXPECT_TRUE(stateIsUpToDate);
|
||||||
|
EXPECT_EQ(i+1, callsCount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cv::Mat in_mat1(32, 32, CV_8UC1);
|
||||||
|
run(in_mat1);
|
||||||
|
|
||||||
|
cv::Mat in_mat2(16, 16, CV_8UC1);
|
||||||
|
run(in_mat2);
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2022 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#include "../test_precomp.hpp"
|
#include "../test_precomp.hpp"
|
||||||
#include "../gapi_mock_kernels.hpp"
|
#include "../gapi_mock_kernels.hpp"
|
||||||
|
|
||||||
|
#include <opencv2/gapi/core.hpp>
|
||||||
|
|
||||||
namespace opencv_test
|
namespace opencv_test
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -294,6 +296,28 @@ TEST_F(GExecutorReshapeTest, ReshapeCallAllocate)
|
|||||||
EXPECT_EQ(1, island1.getReshapeCounter());
|
EXPECT_EQ(1, island1.getReshapeCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(GExecutorReshapeTest, CPUBackendIsReshapable)
|
||||||
|
{
|
||||||
|
comp = cv::GComputation([](){
|
||||||
|
cv::GMat in;
|
||||||
|
cv::GMat foo = I::Foo::on(in);
|
||||||
|
cv::GMat out = cv::gapi::bitwise_not(cv::gapi::bitwise_not(in));
|
||||||
|
return cv::GComputation(cv::GIn(in), cv::GOut(foo, out));
|
||||||
|
});
|
||||||
|
// NB: Initial state
|
||||||
|
EXPECT_EQ(0, island1.getReshapeCounter());
|
||||||
|
|
||||||
|
// NB: First compilation.
|
||||||
|
cv::Mat out_mat2;
|
||||||
|
comp.apply(cv::gin(in_mat1), cv::gout(out_mat, out_mat2), cv::compile_args(pkg));
|
||||||
|
EXPECT_EQ(0, island1.getReshapeCounter());
|
||||||
|
|
||||||
|
// NB: The entire graph is reshapable, so it won't be recompiled, but reshaped.
|
||||||
|
comp.apply(cv::gin(in_mat2), cv::gout(out_mat, out_mat2), cv::compile_args(pkg));
|
||||||
|
EXPECT_EQ(1, island1.getReshapeCounter());
|
||||||
|
EXPECT_EQ(0, cvtest::norm(out_mat2, in_mat2, NORM_INF));
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Add explicit tests on GMat/GScalar/GArray<T> being connectors
|
// FIXME: Add explicit tests on GMat/GScalar/GArray<T> being connectors
|
||||||
// between executed islands
|
// between executed islands
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user