// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. // // Copyright (C) 2019 Intel Corporation #include "../test_precomp.hpp" #include #include "compiler/gmodel.hpp" #include "compiler/gmodel_priv.hpp" #include "api/gcomputation_priv.hpp" #include "compiler/gcompiler.hpp" #include "compiler/gmodelbuilder.hpp" #include "compiler/passes/passes.hpp" #include "compiler/passes/pattern_matching.hpp" #include "../common/gapi_tests_common.hpp" #include "logger.hpp" namespace opencv_test { namespace matching_test { namespace { using V = std::vector; using S = std::unordered_set< ade::NodeHandle , ade::HandleHasher >; void initGModel(ade::Graph& gr, cv::GProtoInputArgs&& in, cv::GProtoOutputArgs&& out) { cv::gimpl::GModel::Graph gm(gr); cv::gimpl::GModel::init(gm); auto proto_slots = cv::gimpl::GModelBuilder(gr) .put(in.m_args, out.m_args); cv::gimpl::Protocol p; std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots; gm.metadata().set(p); } bool isConsumedBy(const cv::gimpl::GModel::ConstGraph &gm, ade::NodeHandle data_nh, ade::NodeHandle op_nh) { auto oi = cv::gimpl::GModel::orderedInputs(gm, op_nh); return std::find(oi.begin(), oi.end(), data_nh) != oi.end(); } std::string opName(const cv::gimpl::GModel::ConstGraph &gm, ade::NodeHandle op_nh) { return gm.metadata(op_nh).get().k.name; } } } // matching_test TEST(PatternMatching, TestFuncDoesNotChangeTestGraph) { // Pattern ade::Graph pg; { GMat in; GMat out = cv::gapi::bitwise_not(in); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; GMat in; GMat out = cv::gapi::bitwise_not(in); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::findMatches(pg, tg); // Inspecting results: matching_test::S nodes{ tgm.nodes().begin(), tgm.nodes().end() }; const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in); const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out); auto input_data_nhs = tgm.metadata().get().in_nhs; auto output_data_nhs = tgm.metadata().get().out_nhs; EXPECT_EQ(1u, input_data_nhs.size()); EXPECT_EQ(1u, output_data_nhs.size()); EXPECT_EQ(in_nh, *input_data_nhs.begin()); EXPECT_EQ(out_nh, *output_data_nhs.begin()); EXPECT_EQ(0u, in_nh->inEdges().size()); EXPECT_EQ(0u, out_nh->outEdges().size()); EXPECT_EQ(1u, in_nh->outEdges().size()); EXPECT_EQ(1u, out_nh->inEdges().size()); const auto op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh); //bitwise_not EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh)); EXPECT_EQ(1u, op_nh->inEdges().size()); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh)); EXPECT_EQ(1u, op_nh->outEdges().size()); } TEST(PatternMatching, TestSimple1) { // Pattern ade::Graph pg; { GMat in; GMat out = cv::gapi::bitwise_not(in); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; GMat in; GMat out = cv::gapi::bitwise_not(in); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(3u, nodes.size()); const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in); const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out); const auto op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh); EXPECT_EQ(matching_test::S({in_nh, out_nh, op_nh}), nodes); EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh)); EXPECT_EQ(matching_test::S{op_nh}, match.startOps()); EXPECT_EQ(matching_test::S{op_nh}, match.finishOps()); EXPECT_EQ(matching_test::V{in_nh}, match.protoIns()); EXPECT_EQ(matching_test::V{out_nh}, match.protoOuts()); } TEST(PatternMatching, TestSimple2) { // Pattern ade::Graph pg; { GMat in; GMat out = cv::gapi::bitwise_not(in); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; GMat in; GMat tmp = cv::gapi::bitwise_not(in); GMat out = cv::gapi::blur(tmp, cv::Size(3, 3)); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(3u, nodes.size()); const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in); const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp); const auto op_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh); EXPECT_EQ(matching_test::S({in_nh, tmp_nh, op_nh}), nodes); EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh)); EXPECT_EQ(matching_test::S{op_nh}, match.startOps()); EXPECT_EQ(matching_test::S{op_nh}, match.finishOps()); EXPECT_EQ(matching_test::V{in_nh}, match.protoIns()); EXPECT_EQ(matching_test::V{tmp_nh}, match.protoOuts()); } TEST(PatternMatching, TestSimple3) { // Pattern ade::Graph pg; { GMat in; GMat out = cv::gapi::bitwise_not(in); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; GMat in; GMat tmp = cv::gapi::blur(in, cv::Size(3, 3)); GMat out = cv::gapi::bitwise_not(tmp); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(3u, nodes.size()); const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp); const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out); const auto op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh); EXPECT_EQ(matching_test::S({tmp_nh, out_nh, op_nh}), nodes); EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp_nh, op_nh)); EXPECT_EQ(matching_test::S{op_nh}, match.startOps()); EXPECT_EQ(matching_test::S{op_nh}, match.finishOps()); EXPECT_EQ(matching_test::V{tmp_nh}, match.protoIns()); EXPECT_EQ(matching_test::V{out_nh}, match.protoOuts()); } TEST(PatternMatching, TestMultiplePatternOuts) { // Pattern ade::Graph pg; { GMat in; GMat dx, dy; std::tie(dx, dy) = cv::gapi::SobelXY(in, -1, 1); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(dx, dy)); } // Test ade::Graph tg; GMat in; GMat dx, dy; std::tie(dx, dy) = cv::gapi::SobelXY(in, -1, 1); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(dx, dy)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(4u, nodes.size()); const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in); const auto dx_nh = cv::gimpl::GModel::dataNodeOf(tgm, dx); const auto dy_nh = cv::gimpl::GModel::dataNodeOf(tgm, dy); const auto op_nh = cv::gimpl::GModel::producerOf(tgm, dx_nh); EXPECT_EQ(op_nh, cv::gimpl::GModel::producerOf(tgm, dy_nh)); EXPECT_EQ(matching_test::S({in_nh, dx_nh, dy_nh, op_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GSobelXY::id(), matching_test::opName(tgm, op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh)); EXPECT_EQ(matching_test::S{op_nh}, match.startOps()); EXPECT_EQ(matching_test::S{op_nh}, match.finishOps()); EXPECT_EQ(matching_test::V{in_nh}, match.protoIns()); EXPECT_EQ(matching_test::V({dx_nh, dy_nh}), match.protoOuts()); } TEST(PatternMatching, TestPrepResizeSplit3) { // Pattern ade::Graph pg; { GMat in; GMat tmp = cv::gapi::resize(in, cv::Size{224, 224}); GMat b, g, r; std::tie(b, g, r) = cv::gapi::split3(tmp); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(b, g, r)); } // Test ade::Graph tg; GMat y, uv; GMat bgr = cv::gapi::NV12toBGR(y, uv); GMat tmp = cv::gapi::resize(bgr, cv::Size{224, 224}); GMat b, g, r; std::tie(b, g, r) = cv::gapi::split3(tmp); matching_test::initGModel(tg, cv::GIn(y, uv), cv::GOut(b, g, r)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(7u, nodes.size()); const auto bgr_nh = cv::gimpl::GModel::dataNodeOf(tgm, bgr); const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp); const auto b_nh = cv::gimpl::GModel::dataNodeOf(tgm, b); const auto g_nh = cv::gimpl::GModel::dataNodeOf(tgm, g); const auto r_nh = cv::gimpl::GModel::dataNodeOf(tgm, r); const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh); // 1st resize const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, b_nh); // 2nd split3 EXPECT_EQ(op2_nh, cv::gimpl::GModel::producerOf(tgm, g_nh)); EXPECT_EQ(op2_nh, cv::gimpl::GModel::producerOf(tgm, r_nh)); EXPECT_EQ(matching_test::S({bgr_nh, tmp_nh, b_nh, g_nh, r_nh, op1_nh, op2_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GResize::id(), matching_test::opName(tgm, op1_nh)); EXPECT_EQ(cv::gapi::core::GSplit3::id(), matching_test::opName(tgm, op2_nh)); EXPECT_EQ(1u, tmp_nh->outEdges().size()); EXPECT_TRUE(matching_test::isConsumedBy(tgm, bgr_nh, op1_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp_nh, op2_nh)); EXPECT_EQ(matching_test::S{ op1_nh }, match.startOps()); EXPECT_EQ(matching_test::S{ op2_nh }, match.finishOps()); EXPECT_EQ(matching_test::V{ bgr_nh }, match.protoIns()); EXPECT_EQ(matching_test::V({ b_nh, g_nh, r_nh }), match.protoOuts()); } G_TYPED_KERNEL(GToNCHW, , "test.toNCHW") { static GMatDesc outMeta(GMatDesc in) { GAPI_Assert(in.depth == CV_8U); GAPI_Assert(in.chan == 3); GAPI_Assert(in.planar == false); return in.asPlanar(); } }; static GMatP toNCHW(const GMat& src) { return GToNCHW::on(src); } TEST(PatternMatching, TestPrepResizeToNCHW) { // Pattern ade::Graph pg; { GMat in; GMat tmp = cv::gapi::resize(in, cv::Size{224, 224}); GMatP plr = toNCHW(tmp); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(plr)); } // Test ade::Graph tg; GMat y, uv; GMat bgr = cv::gapi::NV12toBGR(y, uv); GMat tmp = cv::gapi::resize(bgr, cv::Size{224, 224}); GMatP plr = toNCHW(tmp); matching_test::initGModel(tg, cv::GIn(y, uv), cv::GOut(plr)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(5u, nodes.size()); const auto bgr_nh = cv::gimpl::GModel::dataNodeOf(tgm, bgr); const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp); const auto plr_nh = cv::gimpl::GModel::dataNodeOf(tgm, plr); const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh); // 1st resize const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, plr_nh); // 2nd toNCHW EXPECT_EQ(matching_test::S({bgr_nh, tmp_nh, plr_nh, op1_nh, op2_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GResize::id(), matching_test::opName(tgm, op1_nh)); EXPECT_EQ(GToNCHW::id(), matching_test::opName(tgm, op2_nh)); EXPECT_EQ(1u, tmp_nh->outEdges().size()); EXPECT_TRUE(matching_test::isConsumedBy(tgm, bgr_nh, op1_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp_nh, op2_nh)); EXPECT_EQ(matching_test::S{ op1_nh }, match.startOps()); EXPECT_EQ(matching_test::S{ op2_nh }, match.finishOps()); EXPECT_EQ(matching_test::V{ bgr_nh }, match.protoIns()); EXPECT_EQ(matching_test::V{ plr_nh }, match.protoOuts()); } TEST(PatternMatching, TestPrepNV12toBGRToNCHW) { // Pattern ade::Graph pg; { GMat y, uv; GMat bgr = cv::gapi::NV12toBGR(y, uv); GMatP plr = toNCHW(bgr); matching_test::initGModel(pg, cv::GIn(y, uv), cv::GOut(plr)); } // Test ade::Graph tg; GMat y, uv; GMat bgr = cv::gapi::NV12toBGR(y, uv); GMatP plr = toNCHW(bgr); GMat rsz = cv::gapi::resizeP(plr, cv::Size{224, 224}); matching_test::initGModel(tg, cv::GIn(y, uv), cv::GOut(rsz)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(6u, nodes.size()); const auto y_nh = cv::gimpl::GModel::dataNodeOf(tgm, y); const auto uv_nh = cv::gimpl::GModel::dataNodeOf(tgm, uv); const auto bgr_nh = cv::gimpl::GModel::dataNodeOf(tgm, bgr); const auto plr_nh = cv::gimpl::GModel::dataNodeOf(tgm, plr); const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, bgr_nh); // 1st NV12toBGR const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, plr_nh); // 2nd toNCHW EXPECT_EQ(matching_test::S({y_nh, uv_nh, bgr_nh, plr_nh, op1_nh, op2_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GNV12toBGR::id(), matching_test::opName(tgm, op1_nh)); EXPECT_EQ(GToNCHW::id(), matching_test::opName(tgm, op2_nh)); EXPECT_EQ(1u, bgr_nh->outEdges().size()); EXPECT_TRUE(matching_test::isConsumedBy(tgm, y_nh, op1_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, uv_nh, op1_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, bgr_nh, op2_nh)); EXPECT_EQ(matching_test::S{ op1_nh }, match.startOps()); EXPECT_EQ(matching_test::S{ op2_nh }, match.finishOps()); EXPECT_EQ(matching_test::V({ y_nh, uv_nh }), match.protoIns()); EXPECT_EQ(matching_test::V{ plr_nh }, match.protoOuts()); } //FIXME: To switch from filter2d kernel (which shall be matched by params too) to another one TEST(PatternMatching, MatchChainInTheMiddle) { // Pattern ade::Graph pg; { GMat in; GMat tmp = cv::gapi::filter2D(in, -1, {}); GMat out = cv::gapi::filter2D(tmp, -1, {}); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; GMat in; GMat tmp1 = cv::gapi::erode3x3(in); GMat tmp2 = cv::gapi::filter2D(tmp1, -1, {}); GMat tmp3 = cv::gapi::filter2D(tmp2, -1, {}); GMat out = cv::gapi::dilate3x3(tmp3); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(5u, nodes.size()); const auto tmp1_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp1); const auto tmp2_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp2); const auto tmp3_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp3); const auto op1_nh = cv::gimpl::GModel::producerOf(tgm, tmp2_nh); // 1st filter2D const auto op2_nh = cv::gimpl::GModel::producerOf(tgm, tmp3_nh); // 2nd filter2D EXPECT_EQ(matching_test::S({tmp1_nh, tmp2_nh, tmp3_nh, op1_nh, op2_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GFilter2D::id(), matching_test::opName(tgm, op1_nh)); EXPECT_EQ(cv::gapi::imgproc::GFilter2D::id(), matching_test::opName(tgm, op2_nh)); EXPECT_EQ(1u, tmp2_nh->outEdges().size()); EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp1_nh, op1_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, tmp2_nh, op2_nh)); EXPECT_EQ(matching_test::S({op1_nh}), match.startOps()); EXPECT_EQ(matching_test::S({op2_nh}), match.finishOps()); EXPECT_EQ(matching_test::V{ tmp1_nh }, match.protoIns()); EXPECT_EQ(matching_test::V{ tmp3_nh }, match.protoOuts()); } TEST(PatternMatching, TestMultipleStartOps1) { // Pattern ade::Graph pg; { GMat in1, in2; GMat er = cv::gapi::erode3x3(in1); GMat dil = cv::gapi::dilate3x3(in2); GMat out = cv::gapi::add(er, dil); matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(out)); } // Test ade::Graph tg; GMat in1, in2, in3, in4, in5, in6; GMat er1 = cv::gapi::erode3x3(in1); GMat er2 = cv::gapi::erode3x3(in2); GMat er3 = cv::gapi::erode3x3(in3); GMat er4 = cv::gapi::erode3x3(in4); GMat dil1 = cv::gapi::dilate3x3(in5); GMat dil2 = cv::gapi::dilate3x3(in6); GMat out1 = cv::gapi::add(er1, er2); GMat out2 = cv::gapi::add(er3, dil2); matching_test::initGModel(tg, cv::GIn(in1, in2, in3, in4, in5, in6), cv::GOut(out1, out2, er4, dil1)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(8u, nodes.size()); const auto in3_nh = cv::gimpl::GModel::dataNodeOf(tgm, in3); const auto in6_nh = cv::gimpl::GModel::dataNodeOf(tgm, in6); const auto er3_nh = cv::gimpl::GModel::dataNodeOf(tgm, er3); const auto dil2_nh = cv::gimpl::GModel::dataNodeOf(tgm, dil2); const auto out2_nh = cv::gimpl::GModel::dataNodeOf(tgm, out2); const auto er_op_nh = cv::gimpl::GModel::producerOf(tgm, er3_nh); const auto dil_op_nh = cv::gimpl::GModel::producerOf(tgm, dil2_nh); const auto add_op_nh = cv::gimpl::GModel::producerOf(tgm, out2_nh); EXPECT_EQ(matching_test::S({in3_nh, in6_nh, er3_nh, dil2_nh, out2_nh, er_op_nh, dil_op_nh, add_op_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GErode::id(), matching_test::opName(tgm, er_op_nh)); EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, dil_op_nh)); EXPECT_EQ(cv::gapi::core::GAdd::id(), matching_test::opName(tgm, add_op_nh)); EXPECT_EQ(1u, er3_nh->outEdges().size()); EXPECT_EQ(1u, dil2_nh->outEdges().size()); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in3_nh, er_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in6_nh, dil_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, er3_nh, add_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, dil2_nh, add_op_nh)); EXPECT_EQ(matching_test::S({ er_op_nh, dil_op_nh }), match.startOps()); EXPECT_EQ(matching_test::S{ add_op_nh }, match.finishOps()); EXPECT_EQ(matching_test::V({ in3_nh, in6_nh }), match.protoIns()); EXPECT_EQ(matching_test::V{ out2_nh }, match.protoOuts()); } TEST(PatternMatching, TestMultipleStartOps2) { // Pattern ade::Graph pg; { GMat in1, in2; GMat er = cv::gapi::erode3x3(in1); GMat dil = cv::gapi::dilate3x3(in2); GMat out = cv::gapi::add(er, dil); matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(out)); } // Test ade::Graph tg; GMat in1, in2; GMat er = cv::gapi::erode3x3(in1); GMat dil1 = cv::gapi::dilate3x3(in2); GMat dil2 = cv::gapi::dilate3x3(dil1); GMat out = cv::gapi::add(er, dil2); matching_test::initGModel(tg, cv::GIn(in1, in2), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(8u, nodes.size()); const auto in1_nh = cv::gimpl::GModel::dataNodeOf(tgm, in1); const auto dil1_nh = cv::gimpl::GModel::dataNodeOf(tgm, dil1); const auto er_nh = cv::gimpl::GModel::dataNodeOf(tgm, er); const auto dil2_nh = cv::gimpl::GModel::dataNodeOf(tgm, dil2); const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out); const auto er_op_nh = cv::gimpl::GModel::producerOf(tgm, er_nh); const auto dil_op_nh = cv::gimpl::GModel::producerOf(tgm, dil2_nh); const auto add_op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh); EXPECT_EQ(matching_test::S({in1_nh, dil1_nh, er_nh, dil2_nh, out_nh, er_op_nh, dil_op_nh, add_op_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GErode::id(), matching_test::opName(tgm, er_op_nh)); EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, dil_op_nh)); EXPECT_EQ(cv::gapi::core::GAdd::id(), matching_test::opName(tgm, add_op_nh)); EXPECT_EQ(1u, er_nh->outEdges().size()); EXPECT_EQ(1u, dil2_nh->outEdges().size()); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in1_nh, er_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, dil1_nh, dil_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, er_nh, add_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, dil2_nh, add_op_nh)); EXPECT_EQ(matching_test::S({ er_op_nh, dil_op_nh }), match.startOps()); EXPECT_EQ(matching_test::S{ add_op_nh }, match.finishOps()); EXPECT_EQ(matching_test::V({ in1_nh, dil1_nh }), match.protoIns()); EXPECT_EQ(matching_test::V{ out_nh }, match.protoOuts()); } TEST(PatternMatching, TestInexactMatchOfInOutData) { // Pattern ade::Graph pg; { GMat in; GMat out = cv::gapi::dilate3x3(in); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; GMat in; GMat out1 = cv::gapi::erode3x3(in); GMat out2 = cv::gapi::boxFilter(in, -1, cv::Size(3, 3)); GMat tmp = cv::gapi::dilate3x3(in); GScalar out3 = cv::gapi::sum(tmp); GScalar out4 = cv::gapi::mean(tmp); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out1, out2, out3, out4)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(3u, nodes.size()); const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in); const auto tmp_nh = cv::gimpl::GModel::dataNodeOf(tgm, tmp); const auto op_nh = cv::gimpl::GModel::producerOf(tgm, tmp_nh); // dilate3x3 EXPECT_EQ(matching_test::S({in_nh, tmp_nh, op_nh}), nodes); EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, in_nh, op_nh)); EXPECT_EQ(matching_test::S{ op_nh }, match.startOps()); EXPECT_EQ(matching_test::S{ op_nh }, match.finishOps()); EXPECT_EQ(matching_test::V{ in_nh }, match.protoIns()); EXPECT_EQ(matching_test::V{ tmp_nh }, match.protoOuts()); EXPECT_GT(in_nh->outEdges().size(), 1u); EXPECT_GT(tmp_nh->outEdges().size(), 1u); } //FIXME: The start ops matching shall be reworked to more smarter way. // Start ops matching shall get rid of non valid matchings sample, // where two identical start ops in the pattern refer to the only one in the test. TEST(PatternMatching, TestManySameStartOpsAndHinge) { // Pattern ade::Graph pg; { GMat in1, in2, in3; GMat er1 = cv::gapi::erode3x3(in1); GMat er2 = cv::gapi::erode3x3(in2); GMat er3 = cv::gapi::erode3x3(in3); GMat mrg = cv::gapi::merge3(er1, er2, er3); matching_test::initGModel(pg, cv::GIn(in1, in2, in3), cv::GOut(mrg)); } // Test ade::Graph tg; GMat in1, in2, in3; GMat er1 = cv::gapi::erode3x3(in1); GMat er2 = cv::gapi::erode3x3(in2); GMat er3 = cv::gapi::erode3x3(in3); GMat mrg = cv::gapi::merge3(er1, er2, er3); matching_test::initGModel(tg, cv::GIn(in1, in2, in3), cv::GOut(mrg)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(11u, nodes.size()); EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()), nodes); } //FIXME: The start ops matching shall be reworked to more smarter way. // Start ops matching shall get rid of non valid matchings sample, // where two identical start ops in the pattern refer to the only one in the test. TEST(PatternMatching, TestManySameStartOpsAndHinge2) { // Pattern ade::Graph pg; { GMat in1, in2, in3; GMat er1 = cv::gapi::erode3x3(in1); GMat er2 = cv::gapi::erode3x3(in2); GMat er3 = cv::gapi::erode3x3(in3); GMat dil1 = cv::gapi::dilate3x3(er1); GMat dil2 = cv::gapi::dilate3x3(er2); GMat dil3 = cv::gapi::dilate3x3(er3); GMat mrg = cv::gapi::merge3(dil1, dil2, dil3); matching_test::initGModel(pg, cv::GIn(in1, in2, in3), cv::GOut(mrg)); } // Test ade::Graph tg; GMat in1, in2, in3; GMat er1 = cv::gapi::erode3x3(in1); GMat er2 = cv::gapi::erode3x3(in2); GMat er3 = cv::gapi::erode3x3(in3); GMat dil1 = cv::gapi::dilate3x3(er1); GMat dil2 = cv::gapi::dilate3x3(er2); GMat dil3 = cv::gapi::dilate3x3(er3); GMat mrg = cv::gapi::merge3(dil1, dil2, dil3); matching_test::initGModel(tg, cv::GIn(in1, in2, in3), cv::GOut(mrg)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(17u, nodes.size()); EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()), nodes); } //FIXME: The start ops matching shall be reworked to more smarter way. // Start ops matching shall get rid of non valid matchings sample, // where two identical start ops in the pattern refer to the only one in the test. TEST(PatternMatching, TestTwoChainsOnTheHingeIsomorphism) { // Pattern ade::Graph pg; { GMat in1, in2; GMat er1 = cv::gapi::erode3x3(in1); GMat er2 = cv::gapi::erode3x3(in2); GMat mdb = cv::gapi::medianBlur(er1, 3); GMat gb = cv::gapi::gaussianBlur(er2, cv::Size(5, 5), 0.12); GMat conc = cv::gapi::concatVert(mdb, gb); matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(conc)); } // Test ade::Graph tg; GMat in1, in2; GMat er1 = cv::gapi::erode3x3(in1); GMat er2 = cv::gapi::erode3x3(in2); GMat gb = cv::gapi::gaussianBlur(er1, cv::Size(5, 5), 0.12); GMat mdb = cv::gapi::medianBlur(er2, 3); GMat conc = cv::gapi::concatVert(mdb, gb); matching_test::initGModel(tg, cv::GIn(in1, in2), cv::GOut(conc)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(12u, nodes.size()); EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()), nodes); const auto in1_nh = cv::gimpl::GModel::dataNodeOf(tgm, in1); const auto in2_nh = cv::gimpl::GModel::dataNodeOf(tgm, in2); EXPECT_EQ(matching_test::V({ in2_nh, in1_nh }), match.protoIns()); } TEST(PatternMatching, TestPatternHasMoreInDataNodes) { // Pattern ade::Graph pg; { GMat in1, in2, in3; GMat out = cv::gapi::merge3(in1, in2, in3); matching_test::initGModel(pg, cv::GIn(in1, in2, in3), cv::GOut(out)); } // Test ade::Graph tg; GMat in; GMat out = cv::gapi::merge3(in, in, in); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(3u, nodes.size()); EXPECT_EQ(matching_test::S(tgm.nodes().begin(), tgm.nodes().end()), nodes); const auto in_nh = cv::gimpl::GModel::dataNodeOf(tgm, in); EXPECT_EQ(matching_test::V({ in_nh, in_nh, in_nh }), match.protoIns()); } TEST(PatternMatching, TestPatternHasFewerInDataNodes) { // Pattern ade::Graph pg; { GMat in; GMat out = cv::gapi::merge3(in, in, in); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; GMat in1, in2, in3; GMat out = cv::gapi::merge3(in1, in2, in3); matching_test::initGModel(tg, cv::GIn(in1, in2, in3), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_FALSE(match.ok()); } TEST(PatternMatching, TestTwoMatchingsOneCorrect) { // Pattern ade::Graph pg; { GMat in1, in2; GMat n = cv::gapi::bitwise_not(in1); GMat e = cv::gapi::erode3x3(in1); GMat d = cv::gapi::dilate3x3(in2); GMat out = cv::gapi::merge3(n, e, d); matching_test::initGModel(pg, cv::GIn(in1, in2), cv::GOut(out)); } // Test ade::Graph tg; GMat in1, in2; GMat n = cv::gapi::bitwise_not(in1); GMat e = cv::gapi::erode3x3(in2); GMat d = cv::gapi::dilate3x3(in2); GMat mrg = cv::gapi::merge3(n, e, d); GMat i, sqi; std::tie(i, sqi) = cv::gapi::integral(mrg); GMat n1 = cv::gapi::bitwise_not(i); GMat e1 = cv::gapi::erode3x3(i); GMat d1 = cv::gapi::dilate3x3(sqi); GMat out = cv::gapi::merge3(n1, e1, d1); matching_test::initGModel(tg, cv::GIn(in1, in2), cv::GOut(out)); // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_TRUE(match.ok()); auto nodes = match.nodes(); EXPECT_EQ(10u, nodes.size()); const auto i_nh = cv::gimpl::GModel::dataNodeOf(tgm, i); const auto sqi_nh = cv::gimpl::GModel::dataNodeOf(tgm, sqi); const auto n1_nh = cv::gimpl::GModel::dataNodeOf(tgm, n1); const auto e1_nh = cv::gimpl::GModel::dataNodeOf(tgm, e1); const auto d1_nh = cv::gimpl::GModel::dataNodeOf(tgm, d1); const auto out_nh = cv::gimpl::GModel::dataNodeOf(tgm, out); const auto n_op_nh = cv::gimpl::GModel::producerOf(tgm, n1_nh); const auto e_op_nh = cv::gimpl::GModel::producerOf(tgm, e1_nh); const auto d_op_nh = cv::gimpl::GModel::producerOf(tgm, d1_nh); const auto m_op_nh = cv::gimpl::GModel::producerOf(tgm, out_nh); EXPECT_EQ(matching_test::S({i_nh, sqi_nh, n1_nh, e1_nh, d1_nh, out_nh, n_op_nh, e_op_nh, d_op_nh, m_op_nh}), nodes); EXPECT_EQ(cv::gapi::core::GNot::id(), matching_test::opName(tgm, n_op_nh)); EXPECT_EQ(cv::gapi::imgproc::GErode::id(), matching_test::opName(tgm, e_op_nh)); EXPECT_EQ(cv::gapi::imgproc::GDilate::id(), matching_test::opName(tgm, d_op_nh)); EXPECT_EQ(cv::gapi::core::GMerge3::id(), matching_test::opName(tgm, m_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, i_nh, n_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, i_nh, e_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, sqi_nh, d_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, n1_nh, m_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, e1_nh, m_op_nh)); EXPECT_TRUE(matching_test::isConsumedBy(tgm, d1_nh, m_op_nh)); EXPECT_EQ(1u, n1_nh->outEdges().size()); EXPECT_EQ(1u, e1_nh->outEdges().size()); EXPECT_EQ(1u, d1_nh->outEdges().size()); EXPECT_EQ(matching_test::S({n_op_nh, e_op_nh, d_op_nh}), match.startOps()); EXPECT_EQ(matching_test::S{m_op_nh}, match.finishOps()); EXPECT_EQ(matching_test::V({i_nh, sqi_nh}), match.protoIns()); EXPECT_EQ(matching_test::V{out_nh}, match.protoOuts());} TEST(PatternMatching, CheckNoMatch) { // Pattern ade::Graph pg; { GMat in; GMat tmp = cv::gapi::filter2D(in, -1, {}); GMat out = cv::gapi::filter2D(tmp, -1, {}); matching_test::initGModel(pg, cv::GIn(in), cv::GOut(out)); } // Test ade::Graph tg; { GMat in; GMat tmp1 = cv::gapi::erode3x3(in); GMat out = cv::gapi::dilate3x3(tmp1); matching_test::initGModel(tg, cv::GIn(in), cv::GOut(out)); } // Pattern Matching cv::gimpl::GModel::Graph pgm(pg); cv::gimpl::GModel::Graph tgm(tg); cv::gimpl::SubgraphMatch match = cv::gimpl::findMatches(pg, tg); // Inspecting results: EXPECT_FALSE(match.ok()); } TEST(PatternMatching, adeSmokeTest) { ade::Graph g; ade::NodeHandle src = g.createNode(); ade::NodeHandle dst = g.createNode(); g.link(src, dst); g.link(src, dst); EXPECT_EQ(2u, dst->inNodes().size()); } } // namespace opencv_test