Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
e06efd53
Commit
e06efd53
authored
Aug 09, 2019
by
AsyaPronina
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
G-API: Added graph pattern matching routine and basic tests
parent
358d6995
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1632 additions
and
1 deletion
+1632
-1
CMakeLists.txt
modules/gapi/CMakeLists.txt
+1
-0
gmodel_priv.hpp
modules/gapi/src/compiler/gmodel_priv.hpp
+8
-0
pattern_matching.cpp
modules/gapi/src/compiler/passes/pattern_matching.cpp
+582
-0
pattern_matching.hpp
modules/gapi/src/compiler/passes/pattern_matching.hpp
+98
-0
gapi_core_tests_inl.hpp
modules/gapi/test/common/gapi_core_tests_inl.hpp
+1
-1
gapi_int_pattern_matching_test.cpp
...les/gapi/test/internal/gapi_int_pattern_matching_test.cpp
+942
-0
No files found.
modules/gapi/CMakeLists.txt
View file @
e06efd53
...
...
@@ -60,6 +60,7 @@ set(gapi_srcs
src/compiler/passes/meta.cpp
src/compiler/passes/kernels.cpp
src/compiler/passes/exec.cpp
src/compiler/passes/pattern_matching.cpp
# Executor
src/executor/gexecutor.cpp
...
...
modules/gapi/src/compiler/gmodel_priv.hpp
View file @
e06efd53
...
...
@@ -46,6 +46,14 @@ template<typename T> inline ade::NodeHandle dataNodeOf(const ConstLayoutGraph& g
return
detail
::
dataNodeOf
(
g
,
cv
::
gimpl
::
proto
::
origin_of
(
GProtoArg
{
t
}));
}
inline
ade
::
NodeHandle
producerOf
(
const
cv
::
gimpl
::
GModel
::
Graph
&
gm
,
ade
::
NodeHandle
dh
)
{
GAPI_Assert
(
gm
.
metadata
(
dh
).
get
<
NodeType
>
().
t
==
NodeType
::
DATA
);
auto
ins
=
dh
->
inNodes
();
return
ins
.
empty
()
?
ade
::
NodeHandle
{
}
:
*
ins
.
begin
();
}
}}}
#endif // OPENCV_GAPI_GMODEL_PRIV_HPP
modules/gapi/src/compiler/passes/pattern_matching.cpp
0 → 100644
View file @
e06efd53
// 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 <unordered_set>
#include "pattern_matching.hpp"
namespace
{
using
Graph
=
cv
::
gimpl
::
GModel
::
Graph
;
using
Metadata
=
typename
Graph
::
CMetadataT
;
using
VisitedMatchings
=
std
::
list
<
std
::
pair
<
ade
::
NodeHandle
,
ade
::
NodeHandle
>>
;
using
LabeledNodes
=
std
::
unordered_map
<
// reader node
ade
::
NodeHandle
// if the reader node above is:
// - DATA node: then vector is 1-element vector containing port number of
// the input edge
// - OP node: then vector is ports' vector of current connections between
// this node and an parent active DATA node
,
std
::
vector
<
std
::
size_t
>
,
ade
::
HandleHasher
<
ade
::
Node
>
>
;
using
MultipleMatchings
=
std
::
unordered_map
// pattern OP node
<
ade
::
NodeHandle
// nodes in the test graph which match to the pattern OP node above
,
std
::
vector
<
ade
::
NodeHandle
>
,
ade
::
HandleHasher
<
ade
::
Node
>
>
;
// Returns true if two DATA nodes are semantically and structurally identical:
// - both nodes have the same GShape
// - both nodes are produced by the same port numbers
// - both nodes have the same number of output edges
// (output edges' ports are not checked here)
//
// @param first - first node to compare
// @param firstPorts - a single element vector with first DATA node's producer output port
// @param firstMeta - metadata of first
// @param second - second node to compare
// @param secondPorts - a single element vector with second DATA node's producer output port
// @param secondMeta - metadata of second
bool
compareDataNodes
(
const
ade
::
NodeHandle
&
first
,
const
std
::
vector
<
std
::
size_t
>&
firstPorts
,
const
Metadata
&
firstMeta
,
const
ade
::
NodeHandle
&
second
,
const
std
::
vector
<
std
::
size_t
>&
secondPorts
,
const
Metadata
&
secondMeta
)
{
if
(
secondMeta
.
get
<
cv
::
gimpl
::
NodeType
>
().
t
!=
cv
::
gimpl
::
NodeType
::
DATA
)
{
throw
std
::
logic_error
(
"NodeType of passed node as second argument"
"shall be NodeType::DATA!"
);
}
if
(
firstMeta
.
get
<
cv
::
gimpl
::
Data
>
().
shape
!=
secondMeta
.
get
<
cv
::
gimpl
::
Data
>
().
shape
)
{
return
false
;
}
if
(
*
firstPorts
.
begin
()
!=
*
secondPorts
.
begin
())
{
return
false
;
}
const
auto
&
firstOutputEdges
=
first
->
outEdges
();
const
auto
&
secondOutputEdges
=
second
->
outEdges
();
if
(
firstOutputEdges
.
size
()
!=
secondOutputEdges
.
size
())
{
return
false
;
}
// FIXME: Because of new changes which introduce existence of unused DATA nodes
// check that first and second nodes have the same type of DATA::Storage.
return
true
;
};
// Returns true if two OP nodes semantically and structurally identical:
// - both nodes have the same kernel name
// - both nodes are produced by the same port numbers
// - if any of the nodes are in the array with visited matchings, then:
// first node is equal to found matching first argument and
// second node is equal to found matching second argument
//
// @param first - first node to compare
// @param firstPorts - ports' vector of current connections between first node and an parent active
// DATA node
// @param firstMeta - metadata of first
// @param second - second node to compare
// @param secondPorts - ports' vector of current connections between second node and an parent
// active DATA node
// @param secondMeta - metadata of second
// @param [out] isAlreadyVisited - set to true if first and second nodes have been already visited
bool
compareOpNodes
(
const
VisitedMatchings
&
matchedVisitedNodes
,
const
ade
::
NodeHandle
&
first
,
std
::
vector
<
std
::
size_t
>
firstPorts
,
const
Metadata
&
firstMeta
,
const
ade
::
NodeHandle
&
second
,
std
::
vector
<
std
::
size_t
>
secondPorts
,
const
Metadata
&
secondMeta
,
bool
&
isAlreadyVisited
)
{
if
(
secondMeta
.
get
<
cv
::
gimpl
::
NodeType
>
().
t
!=
cv
::
gimpl
::
NodeType
::
OP
)
{
throw
std
::
logic_error
(
"NodeType of passed node as second argument shall be NodeType::OP!"
);
}
// Assuming that if kernels names are the same then
// output DATA nodes counts from kernels are the same.
// Assuming that if kernels names are the same then
// input DATA nodes counts to kernels are the same.
if
(
firstMeta
.
get
<
cv
::
gimpl
::
Op
>
().
k
.
name
!=
secondMeta
.
get
<
cv
::
gimpl
::
Op
>
().
k
.
name
)
{
return
false
;
}
std
::
sort
(
firstPorts
.
begin
(),
firstPorts
.
end
());
std
::
sort
(
secondPorts
.
begin
(),
secondPorts
.
end
());
if
(
firstPorts
!=
secondPorts
)
{
return
false
;
}
// Shall work, but it is good to test on the cases where multiple start pattern OP nodes
// maps to the test's one.
auto
foundIt
=
std
::
find_if
(
matchedVisitedNodes
.
begin
(),
matchedVisitedNodes
.
end
(),
[
&
first
,
&
second
](
const
std
::
pair
<
ade
::
NodeHandle
,
ade
::
NodeHandle
>&
match
)
{
return
first
==
match
.
first
||
second
==
match
.
second
;
});
if
(
foundIt
!=
matchedVisitedNodes
.
end
())
{
if
(
first
!=
foundIt
->
first
||
second
!=
foundIt
->
second
)
{
return
false
;
}
isAlreadyVisited
=
true
;
}
return
true
;
};
// Retrieves and return sample from the cartesian product of candidates sets
VisitedMatchings
sampleFromProduct
(
std
::
size_t
sampleIdx
,
// index of the sample in the product
const
MultipleMatchings
&
candidatesSets
)
// map of nodes to sets
// of candidates
{
VisitedMatchings
matchingsSample
;
std
::
size_t
quo
=
sampleIdx
;
for
(
const
auto
&
setForNode
:
candidatesSets
)
{
// TODO: order is not determined: for ex., for last node.
// May be use ordered set and map to ensure order?
auto
size
=
setForNode
.
second
.
size
();
// The below code block decodes sampleIdx into a particular sample from cartesian product
// of candidates sets.
std
::
size_t
index
=
quo
%
size
;
quo
=
quo
/
size
;
const
auto
&
candidate
=
setForNode
.
second
[
index
];
matchingsSample
.
push_back
({
setForNode
.
first
,
candidate
});
}
return
matchingsSample
;
}
// Depending on type of the node retrieve port number (IN/OUT) of the edge entering this node.
std
::
size_t
labelOf
(
const
ade
::
NodeHandle
&
node
,
// reader node
const
ade
::
EdgeHandle
&
edge
,
// edge entering the reader node
const
Graph
&
graph
)
// graph containing node and edge
{
if
(
graph
.
metadata
(
node
).
get
<
cv
::
gimpl
::
NodeType
>
().
t
==
cv
::
gimpl
::
NodeType
::
OP
)
{
return
graph
.
metadata
(
edge
).
get
<
cv
::
gimpl
::
Input
>
().
port
;
}
else
{
return
graph
.
metadata
(
edge
).
get
<
cv
::
gimpl
::
Output
>
().
port
;
}
};
inline
bool
IS_STARTPOINT
(
const
ade
::
NodeHandle
&
nh
){
return
nh
->
inEdges
().
empty
();
}
inline
bool
IS_ENDPOINT
(
const
ade
::
NodeHandle
&
nh
){
// FIXME: Because of new changes which introduce existence of unused DATA nodes
// Try to rely on the nh Data::Storage::OUTPUT
return
nh
->
outEdges
().
empty
();
}
}
// Routine relies on the logic that 1 DATA node may have only 1 input edge.
cv
::
gimpl
::
SubgraphMatch
cv
::
gimpl
::
findMatches
(
const
cv
::
gimpl
::
GModel
::
Graph
&
patternGraph
,
const
cv
::
gimpl
::
GModel
::
Graph
&
testGraph
)
{
//TODO: Possibly, we may add N^2 check whether this graph may match or not at all.
// Check that all pattern OP nodes exist in computational graph.
//---------------------------------------------------------------
// Identify operations which start and end our pattern
SubgraphMatch
::
S
patternStartOpNodes
,
patternEndOpNodes
;
const
auto
&
patternInputDataNodes
=
patternGraph
.
metadata
().
get
<
cv
::
gimpl
::
Protocol
>
().
in_nhs
;
const
auto
&
patternOutputDataNodes
=
patternGraph
.
metadata
().
get
<
cv
::
gimpl
::
Protocol
>
().
out_nhs
;
for
(
const
auto
&
node
:
patternInputDataNodes
)
{
auto
opNodes
=
node
->
outNodes
();
patternStartOpNodes
.
insert
(
opNodes
.
begin
(),
opNodes
.
end
());
}
for
(
const
auto
&
node
:
patternOutputDataNodes
)
{
auto
opNodes
=
node
->
inNodes
();
// May be switched to patternEndOpNodes.insert(*opNodes.begin());
patternEndOpNodes
.
insert
(
opNodes
.
begin
(),
opNodes
.
end
());
}
std
::
unordered_map
<
ade
::
NodeHandle
,
// pattern OP node
std
::
vector
<
ade
::
NodeHandle
>
,
// nodes in the test graph which match
// to the pattern OP node
ade
::
HandleHasher
<
ade
::
Node
>>
allMatchingsForStartOpNodes
;
//Filling of allMatchingsForStartOpNodes
std
::
size_t
possibleStartPointsCount
=
1
;
// For every starting OP node of pattern identify matching candidates(there may be many)
// in test graph.
auto
testOpNodes
=
ade
::
util
::
filter
(
testGraph
.
nodes
(),
[
&
](
const
ade
::
NodeHandle
&
node
)
{
return
testGraph
.
metadata
(
node
).
get
<
cv
::
gimpl
::
NodeType
>
().
t
==
cv
::
gimpl
::
NodeType
::
OP
;
});
for
(
const
auto
&
patternStartOpNode
:
patternStartOpNodes
)
{
const
auto
&
patternOpMeta
=
patternGraph
.
metadata
(
patternStartOpNode
);
auto
&
possibleMatchings
=
allMatchingsForStartOpNodes
[
patternStartOpNode
];
std
::
copy_if
(
testOpNodes
.
begin
(),
testOpNodes
.
end
(),
std
::
back_inserter
(
possibleMatchings
),
[
&
](
const
ade
::
NodeHandle
&
testOpNode
)
{
const
auto
&
testOpMeta
=
testGraph
.
metadata
(
testOpNode
);
bool
stub
=
false
;
return
compareOpNodes
({
},
patternStartOpNode
,
{
},
patternOpMeta
,
testOpNode
,
{
},
testOpMeta
,
stub
);
});
if
(
possibleMatchings
.
size
()
==
0
)
{
// Pattern graph is not matched
return
SubgraphMatch
{
};
}
possibleStartPointsCount
*=
possibleMatchings
.
size
();
}
SubgraphMatch
::
M
subgraphStartOps
;
SubgraphMatch
::
M
subgraphEndOps
;
// FIXME: consider moving to S
std
::
list
<
ade
::
NodeHandle
>
subgraphInternals
;
// Structural matching first, semantic matching second.
// 'patternFound' means pattern is matched.
bool
patternFound
=
false
;
std
::
size_t
i
=
0
;
while
(
!
patternFound
&&
(
i
<
possibleStartPointsCount
))
{
subgraphStartOps
.
clear
();
subgraphEndOps
.
clear
();
subgraphInternals
.
clear
();
// List of the pairs representing matchings of pattern node to the test node.
VisitedMatchings
matchedVisitedNodes
;
// Cartesian product of candidate sets for start OP nodes gives set of samples
// as possible matchings for start OP nodes.
// Let allMatchingsForStartOpNodes looks like: x1 : [ y1 ]
// x2 : [ y2, y3 ]
// Cartesian product of two these candidates sets (for x1 and x2 pattern nodes
// correspondingly) produces two samples of matchings for x1, x2:
// [ (x1, y1), (x2, y2) ]
// [ (x1, y1), (x2, y3) ]
//
// Here we fill matchedVisitedNodes list with the next sample from the cartesian product
// of candidates sets.
// i is traversing full cartesian product of candidates sets.
matchedVisitedNodes
=
sampleFromProduct
(
i
,
allMatchingsForStartOpNodes
);
bool
stop
=
false
;
// matchIt is an iterator to a pair of pattern ade::NodeHandle to test's ade::nodeHandle.
auto
matchIt
=
matchedVisitedNodes
.
begin
();
std
::
size_t
size
=
matchedVisitedNodes
.
size
();
while
(
!
stop
)
{
// The following loop traverses through the current level of matchings.
// Every iteration we consider only one certain pair of matched nodes.
for
(
std
::
size_t
index
=
0u
;
index
<
size
&&
!
stop
;
++
index
,
++
matchIt
)
{
// Check if a given matchIt->first node is an pattern-ending OP node.
// If it is just remember it in a special map.
bool
cond1
=
std
::
find
(
patternEndOpNodes
.
begin
(),
patternEndOpNodes
.
end
(),
matchIt
->
first
)
!=
patternEndOpNodes
.
end
();
if
(
cond1
)
{
subgraphEndOps
[
matchIt
->
first
]
=
matchIt
->
second
;
}
// Check if a given matchIt->first node is an pattern-starting OP node.
// If it is just remember it in a special map.
bool
cond2
=
std
::
find
(
patternStartOpNodes
.
begin
(),
patternStartOpNodes
.
end
(),
matchIt
->
first
)
!=
patternStartOpNodes
.
end
();
if
(
cond2
)
{
subgraphStartOps
[
matchIt
->
first
]
=
matchIt
->
second
;
}
// If neither of conditions are true mark the test node as an internal one.
if
(
!
cond1
&&
!
cond2
)
{
subgraphInternals
.
push_back
(
matchIt
->
second
);
}
//-------------------------------------------------------------------------------
// Given the current pattern/test matching of nodes, traverse their descendants.
// For every descendant store the port of the edge connecting to it.
// NOTE: the nature of port number may vary: it may be either IN for OP nodes
// or OUT for DATA ones
LabeledNodes
patternOutputNodesLabeled
;
LabeledNodes
testOutputNodesLabeled
;
auto
patternOutputEdges
=
matchIt
->
first
->
outEdges
();
auto
testOutputEdges
=
matchIt
->
second
->
outEdges
();
for
(
const
auto
&
patternOutputEdge
:
patternOutputEdges
)
{
const
auto
&
dstNh
=
patternOutputEdge
->
dstNode
();
if
(
!
IS_ENDPOINT
(
dstNh
))
{
//Assuming that there is no case for the op node without output data nodes.
patternOutputNodesLabeled
[
dstNh
].
push_back
(
labelOf
(
dstNh
,
patternOutputEdge
,
patternGraph
));
}
}
for
(
const
auto
&
testOutputEdge
:
testOutputEdges
)
{
const
auto
&
dstNh
=
testOutputEdge
->
dstNode
();
testOutputNodesLabeled
[
dstNh
].
push_back
(
labelOf
(
dstNh
,
testOutputEdge
,
testGraph
));
}
//---------------------------------------------------------------------------------
// Traverse through labeled descendants of pattern node and for every descedant
// find a matching in labeled descendants of corresponding test node
for
(
const
auto
&
patternNode
:
patternOutputNodesLabeled
)
{
bool
isAlreadyVisited
=
false
;
const
auto
&
patternNodeMeta
=
patternGraph
.
metadata
(
patternNode
.
first
);
auto
testIt
=
std
::
find_if
(
testOutputNodesLabeled
.
begin
(),
testOutputNodesLabeled
.
end
(),
[
&
](
const
std
::
pair
<
const
ade
::
NodeHandle
,
std
::
vector
<
std
::
size_t
>>&
testNode
)
{
const
auto
&
testNodeMeta
=
testGraph
.
metadata
(
testNode
.
first
);
auto
patternNodeType
=
patternNodeMeta
.
get
<
cv
::
gimpl
::
NodeType
>
().
t
;
switch
(
patternNodeType
)
{
case
cv
:
:
gimpl
::
NodeType
::
DATA
:
return
compareDataNodes
(
patternNode
.
first
,
patternNode
.
second
,
patternNodeMeta
,
testNode
.
first
,
testNode
.
second
,
testNodeMeta
);
case
cv
:
:
gimpl
::
NodeType
::
OP
:
return
compareOpNodes
(
matchedVisitedNodes
,
patternNode
.
first
,
patternNode
.
second
,
patternNodeMeta
,
testNode
.
first
,
testNode
.
second
,
testNodeMeta
,
isAlreadyVisited
);
default
:
GAPI_Assert
(
false
&&
"Unsupported Node type!"
);
}
return
false
;
});
if
(
testIt
==
testOutputNodesLabeled
.
end
())
{
stop
=
true
;
break
;
}
// Update matchedVisitedNodes list with found pair of nodes if the pair
// has not been visited before.
if
(
!
isAlreadyVisited
)
{
matchedVisitedNodes
.
push_back
({
patternNode
.
first
,
testIt
->
first
});
}
}
// Loop traversed patternOutputNodesLabeled
}
// Loop traversed matchedVisitedNodes
// Suppose, pattern and test graphs' structures without input DATA nodes look like:
// Pattern graph Test graph
// op1 op2 t_op1 t_op2
// +-----+ +-----+ +-----+ +-----+
// v v v v v v v v
// d1 d2 d3 d4 t_d1 t_d2 t_d3 t_d4
// v v v v v v v v
// ... ... ... ... ... ... ... ...
// matchedVisitedNodes content before previous loop execution:
// op1 <--> t_op1, op2 <--> t_op2
// matchedVisitedNodes content after previous loop execution (extended with the next
// level of matchings):
// op1 <--> t_op1, op2 <--> t_op2 | d1 <--> t_d1, d2 <--> t_d2, d3 <--> t_d3, d4 <--> t_d4
// ^
// |
// matchIt
//
// matchIt iterator points to the first matching in next level if the next level exists.
// If there is no next level, matchIt == matchedVisitedNodes.end() and all pattern
// levels (except ones for IN/OUT data nodes) have been already processed, so,
// pattern subgraph is found.
if
(
!
stop
)
{
// Check if pattetn subgraph is found
if
(
matchIt
==
matchedVisitedNodes
.
end
())
{
// Found
stop
=
true
;
patternFound
=
true
;
}
// Update 'size' with the size of the new level of matchings
size
=
static_cast
<
std
::
size_t
>
(
std
::
distance
(
matchIt
,
matchedVisitedNodes
.
end
()));
}
}
if
(
!
patternFound
){
// Pattern subgraph is not matched.
// Switch to the next combination of starting points
++
i
;
continue
;
}
SubgraphMatch
::
M
inputApiMatch
;
SubgraphMatch
::
M
outputApiMatch
;
// Traversing current result for starting OPs
for
(
auto
it
=
subgraphStartOps
.
begin
();
it
!=
subgraphStartOps
.
end
()
&&
patternFound
;
++
it
)
{
const
auto
&
match
=
*
it
;
auto
patternInputEdges
=
match
.
first
->
inEdges
();
auto
testInputEdges
=
match
.
second
->
inEdges
();
SubgraphMatch
::
S
patternUniqInNodes
(
match
.
first
->
inNodes
().
begin
(),
match
.
first
->
inNodes
().
end
());
SubgraphMatch
::
S
testUniqInNodes
(
match
.
second
->
inNodes
().
begin
(),
match
.
second
->
inNodes
().
end
());
if
(
patternUniqInNodes
.
size
()
<
testUniqInNodes
.
size
())
{
inputApiMatch
.
clear
();
patternFound
=
false
;
break
;
}
// Else, patternInNodes.size() > testInNodes.size() is considered as valid case.
// Match pattern input DATA nodes with boundary matched test DATA nodes.
for
(
const
auto
&
patternInEdge
:
patternInputEdges
)
{
// Not all start OP nodes are located in the beginning of the pattern graph
// Start OP may have one input DATA node as an Protocol IN node and other
// input DATA nodes produced from another operations
if
(
!
IS_STARTPOINT
(
patternInEdge
->
srcNode
()))
{
continue
;
}
auto
patternInputPort
=
patternGraph
.
metadata
(
patternInEdge
).
get
<
cv
::
gimpl
::
Input
>
().
port
;
auto
matchedIt
=
std
::
find_if
(
testInputEdges
.
begin
(),
testInputEdges
.
end
(),
[
&
](
const
ade
::
EdgeHandle
&
testInEdge
)
->
bool
{
auto
testInputPort
=
testGraph
.
metadata
(
testInEdge
).
get
<
cv
::
gimpl
::
Input
>
().
port
;
if
(
patternInputPort
!=
testInputPort
)
{
return
false
;
}
auto
foundIt
=
inputApiMatch
.
find
(
patternInEdge
->
srcNode
());
if
(
foundIt
!=
inputApiMatch
.
end
())
{
if
(
testInEdge
->
srcNode
()
!=
foundIt
->
second
)
{
return
false
;
}
return
true
;
}
// Update inputApiMatch map only if the pair of nodes isn't in the map already
inputApiMatch
[
patternInEdge
->
srcNode
()]
=
testInEdge
->
srcNode
();
return
true
;
});
if
(
matchedIt
==
testInputEdges
.
end
())
{
inputApiMatch
.
clear
();
patternFound
=
false
;
break
;
}
}
// Loop traversed patternInputEdges
}
// Loop traversed sugraphStartOps
if
(
!
patternFound
)
{
// Pattern IN data nodes can not be matched.
// Switch to the next combination of starting points
++
i
;
continue
;
}
// Create vector with the correctly ordered IN data nodes in the test subgraph
std
::
vector
<
ade
::
NodeHandle
>
inputTestDataNodes
;
for
(
const
auto
&
patternInNode
:
patternInputDataNodes
)
{
inputTestDataNodes
.
push_back
(
inputApiMatch
[
patternInNode
]);
}
// Traversing current result for ending OPs
// There is an assumption that if the pattern subgraph is matched, then
// OUT data nodes shall be definitely matched
for
(
const
auto
&
match
:
subgraphEndOps
)
{
auto
patternOutputEdges
=
match
.
first
->
outEdges
();
auto
testOutputEdges
=
match
.
second
->
outEdges
();
GAPI_Assert
(
patternOutputEdges
.
size
()
==
testOutputEdges
.
size
()
&&
"Ending OP nodes are matched, so OPs' outputs count shall be the same!"
);
// Match pattern output DATA nodes with boundary matched test DATA nodes.
for
(
const
auto
&
patternOutEdge
:
patternOutputEdges
)
{
// Not all end OP nodes are located in the ending of the pattern graph
// End OP node may have one output DATA node as an Protocol OUT node and other
// output DATA nodes as input for another operations
if
(
!
IS_ENDPOINT
(
patternOutEdge
->
dstNode
()))
{
continue
;
}
auto
patternOutputPort
=
patternGraph
.
metadata
(
patternOutEdge
).
get
<
cv
::
gimpl
::
Output
>
().
port
;
auto
matchedIt
=
std
::
find_if
(
testOutputEdges
.
begin
(),
testOutputEdges
.
end
(),
[
&
](
const
ade
::
EdgeHandle
&
testOutEdge
)
->
bool
{
auto
testOutputPort
=
testGraph
.
metadata
(
testOutEdge
).
get
<
cv
::
gimpl
::
Output
>
().
port
;
if
(
patternOutputPort
!=
testOutputPort
)
{
return
false
;
}
outputApiMatch
[
patternOutEdge
->
dstNode
()]
=
testOutEdge
->
dstNode
();
return
true
;
});
GAPI_Assert
(
matchedIt
!=
testOutputEdges
.
end
()
&&
"There shall be a match for every OUT data node from ending OP node,"
"if ending OP node matches"
);
}
}
// Create vector with the correctly ordered OUT data nodes in the test subgraph
std
::
vector
<
ade
::
NodeHandle
>
outputTestDataNodes
;
for
(
const
auto
&
patternOutNode
:
patternOutputDataNodes
)
{
outputTestDataNodes
.
push_back
(
outputApiMatch
[
patternOutNode
]);
}
SubgraphMatch
subgraph
;
subgraph
.
inputDataNodes
=
std
::
move
(
inputApiMatch
);
subgraph
.
startOpNodes
=
std
::
move
(
subgraphStartOps
);
subgraph
.
internalLayers
=
std
::
move
(
subgraphInternals
);
subgraph
.
finishOpNodes
=
std
::
move
(
subgraphEndOps
);
subgraph
.
outputDataNodes
=
std
::
move
(
outputApiMatch
);
subgraph
.
inputTestDataNodes
=
std
::
move
(
inputTestDataNodes
);
subgraph
.
outputTestDataNodes
=
std
::
move
(
outputTestDataNodes
);
return
subgraph
;
}
return
SubgraphMatch
{
};
}
modules/gapi/src/compiler/passes/pattern_matching.hpp
0 → 100644
View file @
e06efd53
// 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
#ifndef OPENCV_GAPI_PATTERN_MATCHING_HPP
#define OPENCV_GAPI_PATTERN_MATCHING_HPP
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <list>
#include "compiler/gmodel.hpp"
namespace
cv
{
namespace
gimpl
{
struct
SubgraphMatch
{
using
M
=
std
::
unordered_map
<
ade
::
NodeHandle
// Pattern graph node
,
ade
::
NodeHandle
// Test graph node
,
ade
::
HandleHasher
<
ade
::
Node
>
>
;
using
S
=
std
::
unordered_set
<
ade
::
NodeHandle
,
ade
::
HandleHasher
<
ade
::
Node
>
>
;
M
inputDataNodes
;
M
startOpNodes
;
M
finishOpNodes
;
M
outputDataNodes
;
std
::
vector
<
ade
::
NodeHandle
>
inputTestDataNodes
;
std
::
vector
<
ade
::
NodeHandle
>
outputTestDataNodes
;
std
::
list
<
ade
::
NodeHandle
>
internalLayers
;
// FIXME: switch to operator bool() instead
bool
ok
()
const
{
return
!
inputDataNodes
.
empty
()
&&
!
startOpNodes
.
empty
()
&&
!
finishOpNodes
.
empty
()
&&
!
outputDataNodes
.
empty
()
&&
!
inputTestDataNodes
.
empty
()
&&
!
outputTestDataNodes
.
empty
();
}
S
nodes
()
const
{
S
allNodes
{};
allNodes
.
insert
(
inputTestDataNodes
.
begin
(),
inputTestDataNodes
.
end
());
for
(
const
auto
&
startOpMatch
:
startOpNodes
)
{
allNodes
.
insert
(
startOpMatch
.
second
);
}
for
(
const
auto
&
finishOpMatch
:
finishOpNodes
)
{
allNodes
.
insert
(
finishOpMatch
.
second
);
}
allNodes
.
insert
(
outputTestDataNodes
.
begin
(),
outputTestDataNodes
.
end
());
allNodes
.
insert
(
internalLayers
.
begin
(),
internalLayers
.
end
());
return
allNodes
;
}
S
startOps
()
{
S
sOps
;
for
(
const
auto
&
opMatch
:
startOpNodes
)
{
sOps
.
insert
(
opMatch
.
second
);
}
return
sOps
;
}
S
finishOps
()
{
S
fOps
;
for
(
const
auto
&
opMatch
:
finishOpNodes
)
{
fOps
.
insert
(
opMatch
.
second
);
}
return
fOps
;
}
std
::
vector
<
ade
::
NodeHandle
>
protoIns
()
{
return
inputTestDataNodes
;
}
std
::
vector
<
ade
::
NodeHandle
>
protoOuts
()
{
return
outputTestDataNodes
;
}
};
GAPI_EXPORTS
SubgraphMatch
findMatches
(
const
cv
::
gimpl
::
GModel
::
Graph
&
patternGraph
,
const
cv
::
gimpl
::
GModel
::
Graph
&
compGraph
);
}
//namespace gimpl
}
//namespace cv
#endif // OPENCV_GAPI_PATTERN_MATCHING_HPP
modules/gapi/test/common/gapi_core_tests_inl.hpp
View file @
e06efd53
...
...
@@ -14,7 +14,7 @@
namespace
opencv_test
{
TEST_P
(
MathOpTest
,
MatricesAccuracyTest
)
TEST_P
(
MathOpTest
,
MatricesAccuracyTest
)
{
// G-API code & corresponding OpenCV code ////////////////////////////////
cv
::
GMat
in1
,
in2
,
out
;
...
...
modules/gapi/test/internal/gapi_int_pattern_matching_test.cpp
0 → 100644
View file @
e06efd53
// 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 <stdexcept>
#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
<
ade
::
NodeHandle
>
;
using
S
=
std
::
unordered_set
<
ade
::
NodeHandle
,
ade
::
HandleHasher
<
ade
::
Node
>
>
;
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
(
cv
::
gimpl
::
GModel
::
Graph
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
(
cv
::
gimpl
::
GModel
::
Graph
gm
,
ade
::
NodeHandle
op_nh
)
{
return
gm
.
metadata
(
op_nh
).
get
<
cv
::
gimpl
::
Op
>
().
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
<
cv
::
gimpl
::
Protocol
>
().
in_nhs
;
auto
output_data_nhs
=
tgm
.
metadata
().
get
<
cv
::
gimpl
::
Protocol
>
().
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
,
TestPreprocSplit3
)
{
// 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
::
core
::
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
,
<
GMatP
(
GMat
)
>
,
"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
GMat
toNCHW
(
const
GMat
&
src
)
{
return
GToNCHW
::
on
(
src
);
}
TEST
(
PatternMatching
,
TestPreprocToNCHW
)
{
// Pattern
ade
::
Graph
pg
;
{
GMat
in
;
GMat
tmp
=
cv
::
gapi
::
resize
(
in
,
cv
::
Size
{
224
,
224
});
GMat
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
});
GMat
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
::
core
::
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
());
}
//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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment