Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate G-API module from main repo to opencv_contrib #3827

Merged
merged 5 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
440 changes: 440 additions & 0 deletions modules/gapi/CMakeLists.txt

Large diffs are not rendered by default.

51 changes: 51 additions & 0 deletions modules/gapi/cmake/DownloadADE.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
set(ade_src_dir "${OpenCV_BINARY_DIR}/3rdparty/ade")
set(ade_filename "v0.1.2e.zip")
set(ade_subdir "ade-0.1.2e")
set(ade_md5 "962ce79e0b95591f226431f7b5f152cd")
ocv_download(FILENAME ${ade_filename}
HASH ${ade_md5}
URL
"${OPENCV_ADE_URL}"
"$ENV{OPENCV_ADE_URL}"
"https://github.com/opencv/ade/archive/"
DESTINATION_DIR ${ade_src_dir}
ID ADE
STATUS res
UNPACK RELATIVE_URL)

if (NOT res)
return()
endif()

set(ADE_root "${ade_src_dir}/${ade_subdir}/sources/ade")
file(GLOB_RECURSE ADE_sources "${ADE_root}/source/*.cpp")
file(GLOB_RECURSE ADE_include "${ADE_root}/include/ade/*.hpp")
add_library(ade STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL}
${ADE_include}
${ADE_sources}
)

# https://github.com/opencv/ade/issues/32
if(CV_CLANG AND CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.1)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wdeprecated-copy)
endif()

target_include_directories(ade PUBLIC $<BUILD_INTERFACE:${ADE_root}/include>)
set_target_properties(ade PROPERTIES
POSITION_INDEPENDENT_CODE True
OUTPUT_NAME ade
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
COMPILE_PDB_NAME ade
COMPILE_PDB_NAME_DEBUG "ade${OPENCV_DEBUG_POSTFIX}"
ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH}
)

if(ENABLE_SOLUTION_FOLDERS)
set_target_properties(ade PROPERTIES FOLDER "3rdparty")
endif()

if(NOT BUILD_SHARED_LIBS)
ocv_install_target(ade EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev OPTIONAL)
endif()

ocv_install_3rdparty_licenses(ade "${ade_src_dir}/${ade_subdir}/LICENSE")
49 changes: 49 additions & 0 deletions modules/gapi/cmake/init.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
OCV_OPTION(WITH_ADE "Enable ADE framework (required for Graph API module)" ON)

OCV_OPTION(WITH_FREETYPE "Enable FreeType framework" OFF)
OCV_OPTION(WITH_PLAIDML "Include PlaidML2 support" OFF)
OCV_OPTION(WITH_OAK "Include OpenCV AI Kit support" OFF)

if(NOT WITH_ADE)
return()
endif()

if(ade_DIR)
# if ade_DIR is set, use ADE-supplied CMake script
# to set up variables to the prebuilt ADE
find_package(ade 0.1.0)
endif()

if(NOT TARGET ade)
# if ade_DIR is not set, try to use automatically
# downloaded one (if there any)
include("${CMAKE_CURRENT_LIST_DIR}/DownloadADE.cmake")
endif()

if(WITH_FREETYPE)
ocv_check_modules(FREETYPE freetype2)
if (FREETYPE_FOUND)
set(HAVE_FREETYPE TRUE)
endif()
endif()

if(WITH_PLAIDML)
find_package(PlaidML2 CONFIG QUIET)
if (PLAIDML_FOUND)
set(HAVE_PLAIDML TRUE)
endif()
endif()

if(WITH_GAPI_ONEVPL)
find_package(VPL)
if(VPL_FOUND)
set(HAVE_GAPI_ONEVPL TRUE)
endif()
endif()

if(WITH_OAK)
find_package(depthai QUIET)
if(depthai_FOUND)
set(HAVE_OAK TRUE)
endif()
endif()
62 changes: 62 additions & 0 deletions modules/gapi/cmake/standalone.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE "Release")
endif()

if (NOT TARGET ade )
find_package(ade 0.1.0 REQUIRED)
endif()

if (WITH_GAPI_ONEVPL)
find_package(VPL)
if(VPL_FOUND)
set(HAVE_GAPI_ONEVPL TRUE)
endif()
endif()

set(FLUID_TARGET fluid)
set(FLUID_ROOT "${CMAKE_CURRENT_LIST_DIR}/../")

file(GLOB FLUID_includes "${FLUID_ROOT}/include/opencv2/*.hpp"
"${FLUID_ROOT}/include/opencv2/gapi/g*.hpp"
"${FLUID_ROOT}/include/opencv2/gapi/util/*.hpp"
"${FLUID_ROOT}/include/opencv2/gapi/own/*.hpp"
"${FLUID_ROOT}/include/opencv2/gapi/fluid/*.hpp")
file(GLOB FLUID_sources "${FLUID_ROOT}/src/api/g*.cpp"
"${FLUID_ROOT}/src/api/rmat.cpp"
"${FLUID_ROOT}/src/api/media.cpp"
"${FLUID_ROOT}/src/compiler/*.cpp"
"${FLUID_ROOT}/src/compiler/passes/*.cpp"
"${FLUID_ROOT}/src/executor/*.cpp"
"${FLUID_ROOT}/src/backends/fluid/*.cpp"
"${FLUID_ROOT}/src/backends/streaming/*.cpp"
"${FLUID_ROOT}/src/backends/common/*.cpp")

add_library(${FLUID_TARGET} STATIC ${FLUID_includes} ${FLUID_sources})

target_include_directories(${FLUID_TARGET}
PUBLIC $<BUILD_INTERFACE:${FLUID_ROOT}/include>
PRIVATE ${FLUID_ROOT}/src)

target_compile_definitions(${FLUID_TARGET} PUBLIC GAPI_STANDALONE
# This preprocessor definition resolves symbol clash when
# standalone fluid meets gapi ocv module in one application
PUBLIC cv=fluidcv)

set_target_properties(${FLUID_TARGET} PROPERTIES POSITION_INDEPENDENT_CODE True)
set_property(TARGET ${FLUID_TARGET} PROPERTY CXX_STANDARD 11)

if(MSVC)
target_compile_options(${FLUID_TARGET} PUBLIC "/wd4251")
target_compile_options(${FLUID_TARGET} PUBLIC "/wd4275")
target_compile_definitions(${FLUID_TARGET} PRIVATE _CRT_SECURE_NO_DEPRECATE)
# Disable obsollete warning C4503 popping up on MSVC <<2017
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4503?view=vs-2019
set_target_properties(${FLUID_TARGET} PROPERTIES COMPILE_FLAGS "/wd4503")
endif()

target_link_libraries(${FLUID_TARGET} PRIVATE ade)

if(WIN32)
# Required for htonl/ntohl on Windows
target_link_libraries(${FLUID_TARGET} PRIVATE wsock32 ws2_32)
endif()
125 changes: 125 additions & 0 deletions modules/gapi/doc/00-root.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Graph API {#gapi}

# Introduction {#gapi_root_intro}

OpenCV Graph API (or G-API) is a new OpenCV module targeted to make
regular image processing fast and portable. These two goals are
achieved by introducing a new graph-based model of execution.

G-API is a special module in OpenCV -- in contrast with the majority
of other main modules, this one acts as a framework rather than some
specific CV algorithm. G-API provides means to define CV operations,
construct graphs (in form of expressions) using it, and finally
implement and run the operations for a particular backend.

@note G-API is a new module and now is in active development. It's API
is volatile at the moment and there may be minor but
compatibility-breaking changes in the future.

# Contents

G-API documentation is organized into the following chapters:

- @subpage gapi_purposes

The motivation behind G-API and its goals.

- @subpage gapi_hld

General overview of G-API architecture and its major internal
components.

- @subpage gapi_kernel_api

Learn how to introduce new operations in G-API and implement it for
various backends.

- @subpage gapi_impl

Low-level implementation details of G-API, for those who want to
contribute.

- API Reference: functions and classes

- @subpage gapi_ref

Core G-API classes, data types, backends, etc.

- @subpage gapi_core

Core G-API operations - arithmetic, boolean, and other matrix
operations;

- @subpage gapi_imgproc

Image processing functions: color space conversions, various
filters, etc.

- @subpage gapi_video

Video processing functionality.

- @subpage gapi_draw

Drawing and composition functionality

# API Example {#gapi_example}

A very basic example of G-API pipeline is shown below:

@include modules/gapi/samples/api_example.cpp

<!-- TODO align this code with text using marks and itemized list -->

G-API is a separate OpenCV module so its header files have to be
included explicitly. The first four lines of `main()` create and
initialize OpenCV's standard video capture object, which fetches
video frames from either an attached camera or a specified file.

G-API pipeline is constructed next. In fact, it is a series of G-API
operation calls on cv::GMat data. The important aspect of G-API is
that this code block is just a declaration of actions, but not the
actions themselves. No processing happens at this point, G-API only
tracks which operations form pipeline and how it is connected. G-API
_Data objects_ (here it is cv::GMat) are used to connect operations
each other. `in` is an _empty_ cv::GMat signalling that it is a
beginning of computation.

After G-API code is written, it is captured into a call graph with
instantiation of cv::GComputation object. This object takes
input/output data references (in this example, `in` and `out`
cv::GMat objects, respectively) as parameters and reconstructs the
call graph based on all the data flow between `in` and `out`.

cv::GComputation is a thin object in sense that it just captures which
operations form up a computation. However, it can be used to execute
computations -- in the following processing loop, every captured frame (a
cv::Mat `input_frame`) is passed to cv::GComputation::apply().

![Example pipeline running on sample video 'vtest.avi'](pics/demo.jpg)

cv::GComputation::apply() is a polimorphic method which accepts a
variadic number of arguments. Since this computation is defined on one
input, one output, a special overload of cv::GComputation::apply() is
used to pass input data and get output data.

Internally, cv::GComputation::apply() compiles the captured graph for
the given input parameters and executes the compiled graph on data
immediately.

There is a number important concepts can be outlines with this example:
* Graph declaration and graph execution are distinct steps;
* Graph is built implicitly from a sequence of G-API expressions;
* G-API supports function-like calls -- e.g. cv::gapi::resize(), and
operators, e.g operator|() which is used to compute bitwise OR;
* G-API syntax aims to look pure: every operation call within a graph
yields a new result, thus forming a directed acyclic graph (DAG);
* Graph declaration is not bound to any data -- real data objects
(cv::Mat) come into picture after the graph is already declared.

<!-- FIXME: The above operator|() link links to MatExpr not GAPI -->

See [tutorials and porting examples](@ref tutorial_table_of_content_gapi)
to learn more on various G-API features and concepts.

<!-- TODO Add chapter on declaration, compilation, execution -->
76 changes: 76 additions & 0 deletions modules/gapi/doc/01-background.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Why Graph API? {#gapi_purposes}

# Motivation behind G-API {#gapi_intro_why}

G-API module brings graph-based model of execution to OpenCV. This
chapter briefly describes how this new model can help software
developers in two aspects: optimizing and porting image processing
algorithms.

## Optimizing with Graph API {#gapi_intro_opt}

Traditionally OpenCV provided a lot of stand-alone image processing
functions (see modules `core` and `imgproc`). Many of that functions
are well-optimized (e.g. vectorized for specific CPUs, parallel, etc)
but still the out-of-box optimization scope has been limited to a
single function only -- optimizing the whole algorithm built atop of that
functions was a responsibility of a programmer.

OpenCV 3.0 introduced _Transparent API_ (or _T-API_) which allowed to
offload OpenCV function calls transparently to OpenCL devices and save
on Host/Device data transfers with cv::UMat -- and it was a great step
forward. However, T-API is a dynamic API -- user code still remains
unconstrained and OpenCL kernels are enqueued in arbitrary order, thus
eliminating further pipeline-level optimization potential.

G-API brings implicit graph model to OpenCV 4.0. Graph model captures
all operations and its data dependencies in a pipeline and so provides
G-API framework with extra information to do pipeline-level
optimizations.

The cornerstone of graph-based optimizations is _Tiling_. Tiling
allows to break the processing into smaller parts and reorganize
operations to enable data parallelism, improve data locality, and save
memory footprint. Data locality is an especially important aspect of
software optimization due to diffent costs of memory access on modern
computer architectures -- the more data is reused in the first level
cache, the more efficient pipeline is.

Definitely the aforementioned techniques can be applied manually --
but it requires extra skills and knowledge of the target platform and
the algorithm implementation changes irrevocably -- becoming more
specific, less flexible, and harder to extend and maintain.

G-API takes this responsibility and complexity from user and does the
majority of the work by itself, keeping the algorithm code clean from
device or optimization details. This approach has its own limitations,
though, as graph model is a _constrained_ model and not every
algorithm can be represented as a graph, so the G-API scope is limited
only to regular image processing -- various filters, arithmetic,
binary operations, and well-defined geometrical transformations.

## Porting with Graph API {#gapi_intro_port}

The essence of G-API is declaring a sequence of operations to run, and
then executing that sequence. G-API is a constrained API, so it puts a
number of limitations on which operations can form a pipeline and
which data these operations may exchange each other.

This formalization in fact helps to make an algorithm portable. G-API
clearly separates operation _interfaces_ from its _implementations_.

One operation (_kernel_) may have multiple implementations even for a
single device (e.g., OpenCV-based "reference" implementation and a
tiled optimized implementation, both running on CPU). Graphs (or
_Computations_ in G-API terms) are built only using operation
interfaces, not implementations -- thus the same graph can be executed
on different devices (and, of course, using different optimization
techniques) with little-to-no changes in the graph itself.

G-API supports plugins (_Backends_) which aggregate logic and
intelligence on what is the best way to execute on a particular
platform. Once a pipeline is built with G-API, it can be parametrized
to use either of the backends (or a combination of it) and so a graph
can be ported easily to a new platform.

@sa @ref gapi_hld
Loading
Loading