Merge pull request #18387 from dmatveev:dm/slides_upd_44
Update G-API slides to OpenCV 4.4 * G-API: Updated slides to v4.4 (+ sample) * Slight formatting changes + Python API page * Some more updates to slides: - Added more info on 4.2 and 4.4 versions - Added explanation on Operations and their functional wrappers
This commit is contained in:
parent
e7f2af5fdb
commit
4dbb8ac4b2
@ -1,10 +1,10 @@
|
||||
#+TITLE: OpenCV 4.0 Graph API
|
||||
#+TITLE: OpenCV 4.4 Graph API
|
||||
#+AUTHOR: Dmitry Matveev\newline Intel Corporation
|
||||
#+OPTIONS: H:2 toc:t num:t
|
||||
#+LATEX_CLASS: beamer
|
||||
#+LATEX_CLASS_OPTIONS: [presentation]
|
||||
#+LATEX_HEADER: \usepackage{transparent} \usepackage{listings} \usepackage{pgfplots} \usepackage{mtheme.sty/beamerthememetropolis}
|
||||
#+LATEX_HEADER: \setbeamertemplate{frame footer}{OpenCV 4.0 G-API: Overview and programming by example}
|
||||
#+LATEX_HEADER: \setbeamertemplate{frame footer}{OpenCV 4.4 G-API: Overview and programming by example}
|
||||
#+BEAMER_HEADER: \subtitle{Overview and programming by example}
|
||||
#+BEAMER_HEADER: \titlegraphic{ \vspace*{3cm}\hspace*{5cm} {\transparent{0.2}\includegraphics[height=\textheight]{ocv_logo.eps}}}
|
||||
#+COLUMNS: %45ITEM %10BEAMER_ENV(Env) %10BEAMER_ACT(Act) %4BEAMER_COL(Col) %8BEAMER_OPT(Opt)
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
- OpenCV meets C++, ~cv::Mat~ replaces ~IplImage*~;
|
||||
|
||||
*** Version 3.0: -- Welcome Transparent API (T-API)
|
||||
*** Version 3.0 -- Welcome Transparent API (T-API)
|
||||
|
||||
- ~cv::UMat~ is introduced as a /transparent/ addition to
|
||||
~cv::Mat~;
|
||||
@ -32,7 +32,7 @@
|
||||
** OpenCV evolution in one slide (cont'd)
|
||||
# FIXME: Learn proper page-breaking!
|
||||
|
||||
*** Version 4.0: -- Welcome Graph API (G-API)
|
||||
*** Version 4.0 -- Welcome Graph API (G-API)
|
||||
|
||||
- A new separate module (not a full library rewrite);
|
||||
- A framework (or even a /meta/-framework);
|
||||
@ -45,6 +45,24 @@
|
||||
- Kernels can be written in unconstrained platform-native code;
|
||||
- Halide can serve as a backend (one of many).
|
||||
|
||||
** OpenCV evolution in one slide (cont'd)
|
||||
# FIXME: Learn proper page-breaking!
|
||||
|
||||
*** Version 4.2 -- New horizons
|
||||
|
||||
- Introduced in-graph inference via OpenVINO™ Toolkit;
|
||||
- Introduced video-oriented Streaming execution mode;
|
||||
- Extended focus from individual image processing to the full
|
||||
application pipeline optimization.
|
||||
|
||||
*** Version 4.4 -- More on video
|
||||
|
||||
- Introduced a notion of stateful kernels;
|
||||
- The road to object tracking, background subtraction, etc. in the
|
||||
graph;
|
||||
- Added more video-oriented operations (feature detection, Optical
|
||||
flow).
|
||||
|
||||
** Why G-API?
|
||||
|
||||
*** Why introduce a new execution model?
|
||||
@ -80,7 +98,7 @@
|
||||
- *Heterogeneity* gets extra benefits like:
|
||||
- Avoiding unnecessary data transfers;
|
||||
- Shadowing transfer costs with parallel host co-execution;
|
||||
- Increasing system throughput with frame-level pipelining.
|
||||
- Improving system throughput with frame-level pipelining.
|
||||
|
||||
* Programming with G-API
|
||||
|
||||
@ -96,7 +114,34 @@
|
||||
- What data objects are /inputs/ to the graph?
|
||||
- What are its /outputs/?
|
||||
|
||||
** A code is worth a thousand words
|
||||
** The code is worth a thousand words
|
||||
:PROPERTIES:
|
||||
:BEAMER_opt: shrink=42
|
||||
:END:
|
||||
|
||||
#+BEGIN_SRC C++
|
||||
#include <opencv2/gapi.hpp> // G-API framework header
|
||||
#include <opencv2/gapi/imgproc.hpp> // cv::gapi::blur()
|
||||
#include <opencv2/highgui.hpp> // cv::imread/imwrite
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 3) return 1;
|
||||
|
||||
cv::GMat in; // Express the graph:
|
||||
cv::GMat out = cv::gapi::blur(in, cv::Size(3,3)); // `out` is a result of `blur` of `in`
|
||||
|
||||
cv::Mat in_mat = cv::imread(argv[1]); // Get the real data
|
||||
cv::Mat out_mat; // Output buffer (may be empty)
|
||||
|
||||
cv::GComputation(cv::GIn(in), cv::GOut(out)) // Declare a graph from `in` to `out`
|
||||
.apply(cv::gin(in_mat), cv::gout(out_mat)); // ...and run it immediately
|
||||
|
||||
cv::imwrite(argv[2], out_mat); // Save the result
|
||||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
** The code is worth a thousand words
|
||||
:PROPERTIES:
|
||||
:BEAMER_opt: shrink=42
|
||||
:END:
|
||||
@ -161,7 +206,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
** A code is worth a thousand words (cont'd)
|
||||
** The code is worth a thousand words (cont'd)
|
||||
# FIXME: sections!!!
|
||||
|
||||
*** What we have just learned?
|
||||
@ -183,59 +228,82 @@ cv::GComputation(cv::GIn(...), cv::GOut(...))
|
||||
** On data objects
|
||||
|
||||
Graph *protocol* defines what arguments a computation was defined on
|
||||
(both inputs and outputs), and what are the *shapes* (or types) of
|
||||
those arguments:
|
||||
(both inputs and outputs), and what are the *shapes* (or types) of
|
||||
those arguments:
|
||||
|
||||
| *Shape* | *Argument* | Size |
|
||||
|-------------+------------------+-----------------------------|
|
||||
| ~GMat~ | ~Mat~ | Static; defined during |
|
||||
| | | graph compilation |
|
||||
|-------------+------------------+-----------------------------|
|
||||
| ~GScalar~ | ~Scalar~ | 4 x ~double~ |
|
||||
|-------------+------------------+-----------------------------|
|
||||
| ~GArray<T>~ | ~std::vector<T>~ | Dynamic; defined in runtime |
|
||||
| *Shape* | *Argument* | Size |
|
||||
|--------------+------------------+-----------------------------|
|
||||
| ~GMat~ | ~Mat~ | Static; defined during |
|
||||
| | | graph compilation |
|
||||
|--------------+------------------+-----------------------------|
|
||||
| ~GScalar~ | ~Scalar~ | 4 x ~double~ |
|
||||
|--------------+------------------+-----------------------------|
|
||||
| ~GArray<T>~ | ~std::vector<T>~ | Dynamic; defined in runtime |
|
||||
|--------------+------------------+-----------------------------|
|
||||
| ~GOpaque<T>~ | ~T~ | Static, ~sizeof(T)~ |
|
||||
|
||||
~GScalar~ may be value-initialized at construction time to allow
|
||||
expressions like ~GMat a = 2*(b + 1)~.
|
||||
|
||||
** Customization example
|
||||
** On operations and kernels
|
||||
:PROPERTIES:
|
||||
:BEAMER_opt: shrink=22
|
||||
:END:
|
||||
|
||||
*** Tuning the execution
|
||||
*** :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.45
|
||||
:END:
|
||||
|
||||
- Graph execution model is defined by kernels which are used;
|
||||
- Kernels can be specified in graph compilation arguments:
|
||||
#+LaTeX: {\footnotesize
|
||||
#+BEGIN_SRC C++
|
||||
#include <opencv2/gapi/fluid/core.hpp>
|
||||
#include <opencv2/gapi/fluid/imgproc.hpp>
|
||||
...
|
||||
auto pkg = gapi::combine(gapi::core::fluid::kernels(),
|
||||
gapi::imgproc::fluid::kernels(),
|
||||
cv::unite_policy::KEEP);
|
||||
sobel.apply(in_mat, out_mat, compile_args(pkg));
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
- OpenCL backend can be used in the same way;
|
||||
#+LaTeX: {\footnotesize
|
||||
- *NOTE*: ~cv::unite_policy~ has been removed in OpenCV 4.1.1.
|
||||
#+LaTeX: }
|
||||
- Graphs are built with *Operations* over virtual *Data*;
|
||||
- *Operations* define interfaces (literally);
|
||||
- *Kernels* are implementations to *Operations* (like in OOP);
|
||||
- An *Operation* is platform-agnostic, a *kernel* is not;
|
||||
- *Kernels* are implemented for *Backends*, the latter provide
|
||||
APIs to write kernels;
|
||||
- Users can /add/ their *own* operations and kernels,
|
||||
and also /redefine/ "standard" kernels their *own* way.
|
||||
|
||||
** Operations and Kernels
|
||||
*** :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.45
|
||||
:END:
|
||||
|
||||
*** Specifying a kernel package
|
||||
#+BEGIN_SRC dot :file "000-ops-kernels.eps" :cmdline "-Kdot -Teps"
|
||||
digraph G {
|
||||
node [shape=box];
|
||||
rankdir=BT;
|
||||
|
||||
- A *kernel* is an implementation of *operation* (= interface);
|
||||
- A *kernel package* hosts kernels that G-API should use;
|
||||
- Kernels are written for different *backends* and using their APIs;
|
||||
- Two kernel packages can be *merged* into a single one;
|
||||
- User can safely supply his *own kernels* to either /replace/ or
|
||||
/augment/ the default package.
|
||||
- Yes, even the standard kernels can be /overwritten/ by user from
|
||||
the outside!
|
||||
- *Heterogeneous* kernel package hosts kernels of different backends.
|
||||
Gr [label="Graph"];
|
||||
Op [label="Operation\nA"];
|
||||
{rank=same
|
||||
Impl1 [label="Kernel\nA:2"];
|
||||
Impl2 [label="Kernel\nA:1"];
|
||||
}
|
||||
|
||||
** Operations and Kernels (cont'd)
|
||||
# FIXME!!!
|
||||
Op -> Gr [dir=back, label="'consists of'"];
|
||||
Impl1 -> Op [];
|
||||
Impl2 -> Op [label="'is implemented by'"];
|
||||
|
||||
node [shape=note,style=dashed];
|
||||
{rank=same
|
||||
Op;
|
||||
CommentOp [label="Abstract:\ndeclared via\nG_API_OP()"];
|
||||
}
|
||||
{rank=same
|
||||
Comment1 [label="Platform:\ndefined with\nOpenCL backend"];
|
||||
Comment2 [label="Platform:\ndefined with\nOpenCV backend"];
|
||||
}
|
||||
|
||||
CommentOp -> Op [constraint=false, style=dashed, arrowhead=none];
|
||||
Comment1 -> Impl1 [style=dashed, arrowhead=none];
|
||||
Comment2 -> Impl2 [style=dashed, arrowhead=none];
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
** On operations and kernels (cont'd)
|
||||
|
||||
*** Defining an operation
|
||||
|
||||
@ -245,16 +313,43 @@ Graph *protocol* defines what arguments a computation was defined on
|
||||
- Metadata callback -- describe what is the output value format(s),
|
||||
given the input and arguments.
|
||||
- Use ~OpType::on(...)~ to use a new kernel ~OpType~ to construct graphs.
|
||||
|
||||
#+LaTeX: {\footnotesize
|
||||
#+BEGIN_SRC C++
|
||||
G_TYPED_KERNEL(GSqrt,<GMat(GMat)>,"org.opencv.core.math.sqrt") {
|
||||
G_API_OP(GSqrt,<GMat(GMat)>,"org.opencv.core.math.sqrt") {
|
||||
static GMatDesc outMeta(GMatDesc in) { return in; }
|
||||
};
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
|
||||
** Operations and Kernels (cont'd)
|
||||
# FIXME!!!
|
||||
** On operations and kernels (cont'd)
|
||||
|
||||
*** ~GSqrt~ vs. ~cv::gapi::sqrt()~
|
||||
|
||||
- How a *type* relates to a *functions* from the example?
|
||||
- These functions are just wrappers over ~::on~:
|
||||
#+LaTeX: {\scriptsize
|
||||
#+BEGIN_SRC C++
|
||||
G_API_OP(GSqrt,<GMat(GMat)>,"org.opencv.core.math.sqrt") {
|
||||
static GMatDesc outMeta(GMatDesc in) { return in; }
|
||||
};
|
||||
GMat gapi::sqrt(const GMat& src) { return GSqrt::on(src); }
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
- Why -- Doxygen, default parameters, 1:n mapping:
|
||||
#+LaTeX: {\scriptsize
|
||||
#+BEGIN_SRC C++
|
||||
cv::GMat custom::unsharpMask(const cv::GMat &src,
|
||||
const int sigma,
|
||||
const float strength) {
|
||||
cv::GMat blurred = cv::gapi::medianBlur(src, sigma);
|
||||
cv::GMat laplacian = cv::gapi::Laplacian(blurred, CV_8U);
|
||||
return (src - (laplacian * strength));
|
||||
}
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
|
||||
** On operations and kernels (cont'd)
|
||||
|
||||
*** Implementing an operation
|
||||
|
||||
@ -297,6 +392,467 @@ G_TYPED_KERNEL(GSqrt,<GMat(GMat)>,"org.opencv.core.math.sqrt") {
|
||||
- Note ~run~ changes signature but still is derived from the operation
|
||||
signature.
|
||||
|
||||
** Operations and Kernels (cont'd)
|
||||
|
||||
*** Specifying which kernels to use
|
||||
|
||||
- Graph execution model is defined by kernels which are available/used;
|
||||
- Kernels can be specified via the graph compilation arguments:
|
||||
#+LaTeX: {\footnotesize
|
||||
#+BEGIN_SRC C++
|
||||
#include <opencv2/gapi/fluid/core.hpp>
|
||||
#include <opencv2/gapi/fluid/imgproc.hpp>
|
||||
...
|
||||
auto pkg = cv::gapi::combine(cv::gapi::core::fluid::kernels(),
|
||||
cv::gapi::imgproc::fluid::kernels());
|
||||
sobel.apply(in_mat, out_mat, cv::compile_args(pkg));
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
- Users can combine kernels of different backends and G-API will partition
|
||||
the execution among those automatically.
|
||||
|
||||
** Heterogeneity in G-API
|
||||
:PROPERTIES:
|
||||
:BEAMER_opt: shrink=35
|
||||
:END:
|
||||
*** Automatic subgraph partitioning in G-API
|
||||
*** :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.18
|
||||
:END:
|
||||
|
||||
#+BEGIN_SRC dot :file "010-hetero-init.eps" :cmdline "-Kdot -Teps"
|
||||
digraph G {
|
||||
rankdir=TB;
|
||||
ranksep=0.3;
|
||||
|
||||
node [shape=box margin=0 height=0.25];
|
||||
A; B; C;
|
||||
|
||||
node [shape=ellipse];
|
||||
GMat0;
|
||||
GMat1;
|
||||
GMat2;
|
||||
GMat3;
|
||||
|
||||
GMat0 -> A -> GMat1 -> B -> GMat2;
|
||||
GMat2 -> C;
|
||||
GMat0 -> C -> GMat3
|
||||
|
||||
subgraph cluster {style=invis; A; GMat1; B; GMat2; C};
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
The initial graph: operations are not resolved yet.
|
||||
|
||||
*** :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.18
|
||||
:END:
|
||||
|
||||
#+BEGIN_SRC dot :file "011-hetero-homo.eps" :cmdline "-Kdot -Teps"
|
||||
digraph G {
|
||||
rankdir=TB;
|
||||
ranksep=0.3;
|
||||
|
||||
node [shape=box margin=0 height=0.25];
|
||||
A; B; C;
|
||||
|
||||
node [shape=ellipse];
|
||||
GMat0;
|
||||
GMat1;
|
||||
GMat2;
|
||||
GMat3;
|
||||
|
||||
GMat0 -> A -> GMat1 -> B -> GMat2;
|
||||
GMat2 -> C;
|
||||
GMat0 -> C -> GMat3
|
||||
|
||||
subgraph cluster {style=filled;color=azure2; A; GMat1; B; GMat2; C};
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
All operations are handled by the same backend.
|
||||
|
||||
*** :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.18
|
||||
:END:
|
||||
|
||||
#+BEGIN_SRC dot :file "012-hetero-a.eps" :cmdline "-Kdot -Teps"
|
||||
digraph G {
|
||||
rankdir=TB;
|
||||
ranksep=0.3;
|
||||
|
||||
node [shape=box margin=0 height=0.25];
|
||||
A; B; C;
|
||||
|
||||
node [shape=ellipse];
|
||||
GMat0;
|
||||
GMat1;
|
||||
GMat2;
|
||||
GMat3;
|
||||
|
||||
GMat0 -> A -> GMat1 -> B -> GMat2;
|
||||
GMat2 -> C;
|
||||
GMat0 -> C -> GMat3
|
||||
|
||||
subgraph cluster_1 {style=filled;color=azure2; A; GMat1; B; }
|
||||
subgraph cluster_2 {style=filled;color=ivory2; C};
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
~A~ & ~B~ are of backend ~1~, ~C~ is of backend ~2~.
|
||||
|
||||
*** :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.18
|
||||
:END:
|
||||
|
||||
#+BEGIN_SRC dot :file "013-hetero-b.eps" :cmdline "-Kdot -Teps"
|
||||
digraph G {
|
||||
rankdir=TB;
|
||||
ranksep=0.3;
|
||||
|
||||
node [shape=box margin=0 height=0.25];
|
||||
A; B; C;
|
||||
|
||||
node [shape=ellipse];
|
||||
GMat0;
|
||||
GMat1;
|
||||
GMat2;
|
||||
GMat3;
|
||||
|
||||
GMat0 -> A -> GMat1 -> B -> GMat2;
|
||||
GMat2 -> C;
|
||||
GMat0 -> C -> GMat3
|
||||
|
||||
subgraph cluster_1 {style=filled;color=azure2; A};
|
||||
subgraph cluster_2 {style=filled;color=ivory2; B};
|
||||
subgraph cluster_3 {style=filled;color=azure2; C};
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
~A~ & ~C~ are of backend ~1~, ~B~ is of backend ~2~.
|
||||
|
||||
** Heterogeneity in G-API
|
||||
|
||||
*** Heterogeneity summary
|
||||
|
||||
- G-API automatically partitions its graph in subgraphs (called "islands")
|
||||
based on the available kernels;
|
||||
- Adjacent kernels taken from the same backend are "fused" into the same
|
||||
"island";
|
||||
- G-API implements a two-level execution model:
|
||||
- Islands are executed at the top level by a G-API's *Executor*;
|
||||
- Island internals are run at the bottom level by its *Backend*;
|
||||
- G-API fully delegates the low-level execution and memory management to backends.
|
||||
|
||||
* Inference and Streaming
|
||||
|
||||
** Inference with G-API
|
||||
|
||||
*** In-graph inference example
|
||||
|
||||
- Starting with OpencV 4.2 (2019), G-API allows to integrate ~infer~
|
||||
operations into the graph:
|
||||
#+LaTeX: {\scriptsize
|
||||
#+BEGIN_SRC C++
|
||||
G_API_NET(ObjDetect, <cv::GMat(cv::GMat)>, "pdf.example.od");
|
||||
|
||||
cv::GMat in;
|
||||
cv::GMat blob = cv::gapi::infer<ObjDetect>(bgr);
|
||||
cv::GOpaque<cv::Size> size = cv::gapi::streaming::size(bgr);
|
||||
cv::GArray<cv::Rect> objs = cv::gapi::streaming::parseSSD(blob, size);
|
||||
cv::GComputation pipelne(cv::GIn(in), cv::GOut(objs));
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
- Starting with OpenCV 4.5 (2020), G-API will provide more streaming-
|
||||
and NN-oriented operations out of the box.
|
||||
|
||||
** Inference with G-API
|
||||
|
||||
*** What is the difference?
|
||||
|
||||
- ~ObjDetect~ is not an operation, ~cv::gapi::infer<T>~ is;
|
||||
- ~cv::gapi::infer<T>~ is a *generic* operation, where ~T=ObjDetect~ describes
|
||||
the calling convention:
|
||||
- How many inputs the network consumes,
|
||||
- How many outputs the network produces.
|
||||
- Inference data types are ~GMat~ only:
|
||||
- Representing an image, then preprocessed automatically;
|
||||
- Representing a blob (n-dimensional ~Mat~), then passed as-is.
|
||||
- Inference *backends* only need to implement a single generic operation ~infer~.
|
||||
|
||||
** Inference with G-API
|
||||
|
||||
*** But how does it run?
|
||||
|
||||
- Since ~infer~ is an *Operation*, backends may provide *Kernels* implenting it;
|
||||
- The only publicly available inference backend now is *OpenVINO™*:
|
||||
- Brings its ~infer~ kernel atop of the Inference Engine;
|
||||
- NN model data is passed through G-API compile arguments (like kernels);
|
||||
- Every NN backend provides its own structure to configure the network (like
|
||||
a kernel API).
|
||||
|
||||
** Inference with G-API
|
||||
|
||||
*** Passing OpenVINO™ parameters to G-API
|
||||
|
||||
- ~ObjDetect~ example:
|
||||
#+LaTeX: {\footnotesize
|
||||
#+BEGIN_SRC C++
|
||||
auto face_net = cv::gapi::ie::Params<ObjDetect> {
|
||||
face_xml_path, // path to the topology IR
|
||||
face_bin_path, // path to the topology weights
|
||||
face_device_string, // OpenVINO plugin (device) string
|
||||
};
|
||||
auto networks = cv::gapi::networks(face_net);
|
||||
pipeline.compile(.., cv::compile_args(..., networks));
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
- ~AgeGender~ requires binding Op's outputs to NN layers:
|
||||
#+LaTeX: {\footnotesize
|
||||
#+BEGIN_SRC C++
|
||||
auto age_net = cv::gapi::ie::Params<AgeGender> {
|
||||
...
|
||||
}.cfgOutputLayers({"age_conv3", "prob"}); // array<string,2> !
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
|
||||
** Streaming with G-API
|
||||
|
||||
#+BEGIN_SRC dot :file 020-fd-demo.eps :cmdline "-Kdot -Teps"
|
||||
digraph {
|
||||
rankdir=LR;
|
||||
node [shape=box];
|
||||
|
||||
cap [label=Capture];
|
||||
dec [label=Decode];
|
||||
res [label=Resize];
|
||||
cnn [label=Infer];
|
||||
vis [label=Visualize];
|
||||
|
||||
cap -> dec;
|
||||
dec -> res;
|
||||
res -> cnn;
|
||||
cnn -> vis;
|
||||
}
|
||||
#+END_SRC
|
||||
Anatomy of a regular video analytics application
|
||||
|
||||
** Streaming with G-API
|
||||
|
||||
#+BEGIN_SRC dot :file 021-fd-serial.eps :cmdline "-Kdot -Teps"
|
||||
digraph {
|
||||
node [shape=box margin=0 width=0.3 height=0.4]
|
||||
nodesep=0.2;
|
||||
rankdir=LR;
|
||||
|
||||
subgraph cluster0 {
|
||||
colorscheme=blues9
|
||||
pp [label="..." shape=plaintext];
|
||||
v0 [label=V];
|
||||
label="Frame N-1";
|
||||
color=7;
|
||||
}
|
||||
|
||||
subgraph cluster1 {
|
||||
colorscheme=blues9
|
||||
c1 [label=C];
|
||||
d1 [label=D];
|
||||
r1 [label=R];
|
||||
i1 [label=I];
|
||||
v1 [label=V];
|
||||
label="Frame N";
|
||||
color=6;
|
||||
}
|
||||
|
||||
subgraph cluster2 {
|
||||
colorscheme=blues9
|
||||
c2 [label=C];
|
||||
nn [label="..." shape=plaintext];
|
||||
label="Frame N+1";
|
||||
color=5;
|
||||
}
|
||||
|
||||
c1 -> d1 -> r1 -> i1 -> v1;
|
||||
|
||||
pp-> v0;
|
||||
v0 -> c1 [style=invis];
|
||||
v1 -> c2 [style=invis];
|
||||
c2 -> nn;
|
||||
}
|
||||
#+END_SRC
|
||||
Serial execution of the sample video analytics application
|
||||
|
||||
** Streaming with G-API
|
||||
:PROPERTIES:
|
||||
:BEAMER_opt: shrink
|
||||
:END:
|
||||
|
||||
#+BEGIN_SRC dot :file 022-fd-pipelined.eps :cmdline "-Kdot -Teps"
|
||||
digraph {
|
||||
nodesep=0.2;
|
||||
ranksep=0.2;
|
||||
node [margin=0 width=0.4 height=0.2];
|
||||
node [shape=plaintext]
|
||||
Camera [label="Camera:"];
|
||||
GPU [label="GPU:"];
|
||||
FPGA [label="FPGA:"];
|
||||
CPU [label="CPU:"];
|
||||
Time [label="Time:"];
|
||||
t6 [label="T6"];
|
||||
t7 [label="T7"];
|
||||
t8 [label="T8"];
|
||||
t9 [label="T9"];
|
||||
t10 [label="T10"];
|
||||
tnn [label="..."];
|
||||
|
||||
node [shape=box margin=0 width=0.4 height=0.4 colorscheme=blues9]
|
||||
node [color=9] V3;
|
||||
node [color=8] F4; V4;
|
||||
node [color=7] DR5; F5; V5;
|
||||
node [color=6] C6; DR6; F6; V6;
|
||||
node [color=5] C7; DR7; F7; V7;
|
||||
node [color=4] C8; DR8; F8;
|
||||
node [color=3] C9; DR9;
|
||||
node [color=2] C10;
|
||||
|
||||
{rank=same; rankdir=LR; Camera C6 C7 C8 C9 C10}
|
||||
Camera -> C6 -> C7 -> C8 -> C9 -> C10 [style=invis];
|
||||
|
||||
{rank=same; rankdir=LR; GPU DR5 DR6 DR7 DR8 DR9}
|
||||
GPU -> DR5 -> DR6 -> DR7 -> DR8 -> DR9 [style=invis];
|
||||
|
||||
C6 -> DR5 [style=invis];
|
||||
C6 -> DR6 [constraint=false];
|
||||
C7 -> DR7 [constraint=false];
|
||||
C8 -> DR8 [constraint=false];
|
||||
C9 -> DR9 [constraint=false];
|
||||
|
||||
{rank=same; rankdir=LR; FPGA F4 F5 F6 F7 F8}
|
||||
FPGA -> F4 -> F5 -> F6 -> F7 -> F8 [style=invis];
|
||||
|
||||
DR5 -> F4 [style=invis];
|
||||
DR5 -> F5 [constraint=false];
|
||||
DR6 -> F6 [constraint=false];
|
||||
DR7 -> F7 [constraint=false];
|
||||
DR8 -> F8 [constraint=false];
|
||||
|
||||
{rank=same; rankdir=LR; CPU V3 V4 V5 V6 V7}
|
||||
CPU -> V3 -> V4 -> V5 -> V6 -> V7 [style=invis];
|
||||
|
||||
F4 -> V3 [style=invis];
|
||||
F4 -> V4 [constraint=false];
|
||||
F5 -> V5 [constraint=false];
|
||||
F6 -> V6 [constraint=false];
|
||||
F7 -> V7 [constraint=false];
|
||||
|
||||
{rank=same; rankdir=LR; Time t6 t7 t8 t9 t10 tnn}
|
||||
Time -> t6 -> t7 -> t8 -> t9 -> t10 -> tnn [style=invis];
|
||||
|
||||
CPU -> Time [style=invis];
|
||||
V3 -> t6 [style=invis];
|
||||
V4 -> t7 [style=invis];
|
||||
V5 -> t8 [style=invis];
|
||||
V6 -> t9 [style=invis];
|
||||
V7 -> t10 [style=invis];
|
||||
}
|
||||
#+END_SRC
|
||||
Pipelined execution for the video analytics application
|
||||
|
||||
** Streaming with G-API: Example
|
||||
|
||||
**** Serial mode (4.0) :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.45
|
||||
:END:
|
||||
#+LaTeX: {\tiny
|
||||
#+BEGIN_SRC C++
|
||||
pipeline = cv::GComputation(...);
|
||||
|
||||
cv::VideoCapture cap(input);
|
||||
cv::Mat in_frame;
|
||||
std::vector<cv::Rect> out_faces;
|
||||
|
||||
while (cap.read(in_frame)) {
|
||||
pipeline.apply(cv::gin(in_frame),
|
||||
cv::gout(out_faces),
|
||||
cv::compile_args(kernels,
|
||||
networks));
|
||||
// Process results
|
||||
...
|
||||
}
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
|
||||
**** Streaming mode (since 4.2) :B_block:BMCOL:
|
||||
:PROPERTIES:
|
||||
:BEAMER_env: block
|
||||
:BEAMER_col: 0.45
|
||||
:END:
|
||||
#+LaTeX: {\tiny
|
||||
#+BEGIN_SRC C++
|
||||
pipeline = cv::GComputation(...);
|
||||
|
||||
auto in_src = cv::gapi::wip::make_src
|
||||
<cv::gapi::wip::GCaptureSource>(input)
|
||||
auto cc = pipeline.compileStreaming
|
||||
(cv::compile_args(kernels, networks))
|
||||
cc.setSource(cv::gin(in_src));
|
||||
cc.start();
|
||||
|
||||
std::vector<cv::Rect> out_faces;
|
||||
while (cc.pull(cv::gout(out_faces))) {
|
||||
// Process results
|
||||
...
|
||||
}
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
|
||||
**** More information
|
||||
|
||||
#+LaTeX: {\footnotesize
|
||||
https://opencv.org/hybrid-cv-dl-pipelines-with-opencv-4-4-g-api/
|
||||
#+LaTeX: }
|
||||
|
||||
* Latest features
|
||||
** Latest features
|
||||
*** Python API
|
||||
|
||||
- Initial Python3 binding is available now in ~master~ (future 4.5);
|
||||
- Only basic CV functionality is supported (~core~ & ~imgproc~ namespaces,
|
||||
selecting backends);
|
||||
- Adding more programmability, inference, and streaming is next.
|
||||
|
||||
** Latest features
|
||||
*** Python API
|
||||
|
||||
#+LaTeX: {\footnotesize
|
||||
#+BEGIN_SRC Python
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
sz = (1280, 720)
|
||||
in1 = np.random.randint(0, 100, sz).astype(np.uint8)
|
||||
in2 = np.random.randint(0, 100, sz).astype(np.uint8)
|
||||
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
g_out = cv.gapi.add(g_in1, g_in2)
|
||||
gr = cv.GComputation(g_in1, g_in2, g_out)
|
||||
|
||||
pkg = cv.gapi.core.fluid.kernels()
|
||||
out = gr.apply(in1, in2, args=cv.compile_args(pkg))
|
||||
#+END_SRC
|
||||
#+LaTeX: }
|
||||
|
||||
* Understanding the "G-Effect"
|
||||
|
||||
** Understanding the "G-Effect"
|
||||
@ -384,15 +940,22 @@ speed-up on QVGA taken as 1.0).
|
||||
* Resources on G-API
|
||||
|
||||
** Resources on G-API
|
||||
|
||||
:PROPERTIES:
|
||||
:BEAMER_opt: shrink
|
||||
:END:
|
||||
*** Repository
|
||||
|
||||
- https://github.com/opencv/opencv (see ~modules/gapi~)
|
||||
- Integral part of OpenCV starting version 4.0;
|
||||
|
||||
*** Article
|
||||
|
||||
- https://opencv.org/hybrid-cv-dl-pipelines-with-opencv-4-4-g-api/
|
||||
|
||||
*** Documentation
|
||||
|
||||
- https://docs.opencv.org/master/d0/d1e/gapi.html
|
||||
- A tutorial and a class reference are there as well.
|
||||
- https://docs.opencv.org/4.4.0/d0/d1e/gapi.html
|
||||
|
||||
*** Tutorials
|
||||
- https://docs.opencv.org/4.4.0/df/d7e/tutorial_table_of_content_gapi.html
|
||||
|
||||
* Thank you!
|
||||
|
||||
19
modules/gapi/samples/slides_blur_gapi.cpp
Normal file
19
modules/gapi/samples/slides_blur_gapi.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include <opencv2/gapi.hpp> // G-API framework header
|
||||
#include <opencv2/gapi/imgproc.hpp> // cv::gapi::blur()
|
||||
#include <opencv2/highgui.hpp> // cv::imread/imwrite
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 3) return 1;
|
||||
|
||||
cv::GMat in; // Express the graph:
|
||||
cv::GMat out = cv::gapi::blur(in, cv::Size(3,3)); // `out` is a result of `blur` of `in`
|
||||
|
||||
cv::Mat in_mat = cv::imread(argv[1]); // Get the real data
|
||||
cv::Mat out_mat; // Output buffer (may be empty)
|
||||
|
||||
cv::GComputation(cv::GIn(in), cv::GOut(out)) // Declare a graph from `in` to `out`
|
||||
.apply(cv::gin(in_mat), cv::gout(out_mat)); // ...and run it immediately
|
||||
|
||||
cv::imwrite(argv[2], out_mat); // Save the result
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user