Compare commits

...

10 Commits

Author SHA1 Message Date
Maxim Kurin
d56d921409 [Hetero] Update pre processing info (#4127)
* [Hetero] Update layout in inputs info

* Azure CI: set testdata branch for Mac

Co-authored-by: Alexander Zhogov <alexander.zhogov@intel.com>
2021-02-11 16:00:03 +03:00
Mikhail Kozlov
e17f43922e [Compile-tool] Fix write output blob for Windows to release (#4132)
* Fix write output blob for Windows.

* Refactoring

* Azure CI: set testdata branch for Mac

Co-authored-by: Alexander Zhogov <alexander.zhogov@intel.com>
2021-02-11 15:59:42 +03:00
Artemy Skrebkov
aa23fbb9d3 Update benchmark_app to pass precision and layout via command line (#4167)
* Move processing ins and outs into samples/common

    - To re-use it in compile_tool and benchmark_app

* Extract common into samples_utils lib

    - To re-use it in samples and tools

* Move processLayout into samples_utils

* Clean up

* Enable warning as errors for samples_utils

* Cannot set precision or layout for compiled network

* Remove layout setting for benchmark_app

  - It requires further discussion

* Fix compilation of samples

* Fix one more sample

* Fix windows build

* Update README.md

* One more fix for windows

* Fix OpenVino ONNX CI build

* More build fixes

* Move os and vpu common into utils

* Fix build for myriad tools

* Fix windows build

* Export gflags
2021-02-11 15:53:19 +03:00
azhogov
8690aac494 Azure CI: Remove fake ONNX CI 2021-02-10 17:51:32 +03:00
azhogov
783af1e5ae Azure CI: Sync with master 2021-02-10 17:34:19 +03:00
Andrey Somsikov
8396e6473e Switch to OpenCV 4.5.1 (#4006) 2021-01-27 11:09:51 +03:00
Alexander Perepelkin
1eeaad3c82 Fix virtual inheritance for class PadLayerTest (#3914) 2021-01-20 15:17:29 +03:00
Dmitry Budnikov
c4ac476d2a fluid update (#3625) 2020-12-16 12:11:02 +03:00
Mikhail Kozlov
ed6e329774 Rename KMB to VPUX (#3591) 2020-12-15 06:59:55 +03:00
Nikita Kudriavtsev
fb1536f2be [IE VPUX][cherry pick #3001] Part of changes: Visitor API deserialization for ops from opset1 (#3558) 2020-12-11 18:06:58 +03:00
237 changed files with 18923 additions and 2016 deletions

View File

@@ -4,13 +4,13 @@ jobs:
timeoutInMinutes: 90
pool:
name: LIN_VMSS_VENV_F8S_WU2
name: LIN_VMSS_VENV_F16S_WU2
variables:
system.debug: true
VSTS_HTTP_RETRY: 5
VSTS_HTTP_TIMEOUT: 200
WORKERS_NUMBER: 8
WORKERS_NUMBER: 16
BUILD_TYPE: Release
REPO_DIR: $(Build.Repository.LocalPath)
WORK_DIR: $(Pipeline.Workspace)/_w
@@ -22,11 +22,10 @@ jobs:
curl -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2019-06-01"
whoami
uname -a
which python3
python3 --version
which java
java -version
gcc --version
echo Python3 info ; which python3 ; python3 --version
echo Python info ; which python ; python --version
echo Java info ; which java ; java -version
echo gcc info ; which gcc ; gcc --version
lsb_release
env
cat /proc/cpuinfo
@@ -35,6 +34,7 @@ jobs:
vmstat -s
df
lsblk -o NAME,HCTL,SIZE,MOUNTPOINT | grep -i "sd"
free -h
displayName: 'System info'
- script: |

View File

@@ -1,95 +0,0 @@
jobs:
- job: nGraph_ONNX_Lin
# About 150% of total time
timeoutInMinutes: 60
pool:
name: LIN_VMSS_VENV_F8S_WU2
variables:
system.debug: true
VSTS_HTTP_RETRY: 5
VSTS_HTTP_TIMEOUT: 200
WORKERS_NUMBER: 8
BUILD_TYPE: Release
REPO_DIR: $(Build.Repository.LocalPath)
WORK_DIR: $(Pipeline.Workspace)/_w
BUILD_DIR: $(WORK_DIR)/build
BIN_DIR: $(REPO_DIR)/bin/intel64/$(BUILD_TYPE)
INSTALL_DIR: $(WORK_DIR)/install
steps:
- checkout: self
clean: true
lfs: false
submodules: recursive
path: openvino
- script: |
curl -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2019-06-01"
whoami
uname -a
which python3
python3 --version
gcc --version
lsb_release
env
cat /proc/cpuinfo
cat /proc/meminfo
vmstat -s
df
displayName: 'System info'
- script: |
rm -rf $(WORK_DIR) ; mkdir $(WORK_DIR)
displayName: 'Make dir'
- script: |
sudo apt --assume-yes install libusb-1.0-0-dev
python3 -m pip install -r ./inference-engine/ie_bridges/python/requirements.txt
# For running Python API tests
python3 -m pip install -r ./inference-engine/ie_bridges/python/src/requirements-dev.txt
displayName: 'Install dependencies'
enabled: false
- script: |
wget https://github.com/ninja-build/ninja/releases/download/v1.10.0/ninja-linux.zip
unzip ninja-linux.zip
sudo cp -v ninja /usr/local/bin/
workingDirectory: $(WORK_DIR)
displayName: 'Install Ninja'
enabled: false
- task: CMake@1
inputs:
# CMake must get Python 3.x version by default
cmakeArgs: -GNinja -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DENABLE_VPU=OFF -DENABLE_GNA=OFF -DENABLE_OPENCV=OFF -DENABLE_CPPLINT=OFF -DENABLE_TESTS=OFF -DENABLE_BEH_TESTS=OFF -DENABLE_FUNCTIONAL_TESTS=OFF -DENABLE_MKL_DNN=ON -DENABLE_CLDNN=OFF -DENABLE_PROFILING_ITT=OFF -DENABLE_SAMPLES=OFF -DENABLE_SPEECH_DEMO=OFF -DENABLE_PYTHON=ON -DPYTHON_EXECUTABLE=/usr/bin/python3.6 -DNGRAPH_ONNX_IMPORT_ENABLE=ON -DNGRAPH_INTERPRETER_ENABLE=ON -DNGRAPH_DEBUG_ENABLE=OFF -DNGRAPH_DYNAMIC_COMPONENTS_ENABLE=ON -DCMAKE_INSTALL_PREFIX=$(INSTALL_DIR) $(REPO_DIR)
workingDirectory: $(BUILD_DIR)
enabled: false
- script: ninja
workingDirectory: $(BUILD_DIR)
displayName: 'Build'
enabled: false
- script: make install
workingDirectory: $(BUILD_DIR)
displayName: 'Install'
enabled: false
- script: |
ls -alR $(REPO_DIR)/bin/
ls -alR $(INSTALL_DIR)
displayName: 'List files'
enabled: false
- script: docker build --tag=openvino-onnx-ci-image --file=$(REPO_DIR)/.ci/openvino-onnx/Dockerfile .
workingDirectory: $(BUILD_DIR)
displayName: 'Docker build'
enabled: false
- script: docker run --name openvino-onnx-ci-container openvino-onnx-ci-image
workingDirectory: $(BUILD_DIR)
displayName: 'Docker run tests'
enabled: false

View File

@@ -111,7 +111,7 @@ jobs:
continueOnError: false
- script: |
git clone https://github.com/openvinotoolkit/testdata.git
git clone --single-branch --branch releases/2021/2 https://github.com/openvinotoolkit/testdata.git
workingDirectory: $(WORK_DIR)
displayName: 'Clone testdata'

View File

@@ -53,16 +53,11 @@ jobs:
displayName: 'Install dependencies'
- script: |
certutil -urlcache -split -f https://incredibuilddiag1wu2.blob.core.windows.net/incredibuild/IBSetupConsole_9_5_0.exe IBSetupConsole_9_5_0.exe
call IBSetupConsole_9_5_0.exe /Install /Components=Agent,oneuse /Coordinator=11.1.0.4 /AGENT:OPENFIREWALL=ON /AGENT:AUTOSELECTPORTS=ON /ADDTOPATH=ON /AGENT:INSTALLADDINS=OFF
certutil -urlcache -split -f https://incredibuilddiag1wu2.blob.core.windows.net/incredibuild/install_ib_console.bat install_ib_console.bat
call install_ib_console.bat
workingDirectory: $(WORK_DIR)
displayName: 'Install IncrediBuild'
- script: |
echo Stop IncrediBuild_Agent && net stop IncrediBuild_Agent
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Xoreax\IncrediBuild\Builder /f /v LastEnabled /d 0 && echo Start IncrediBuild_Agent && net start IncrediBuild_Agent
displayName: 'Start IncrediBuild'
- script: |
set PATH=$(WORK_DIR)\ninja-win;%PATH%
call "$(MSVS_VARS_PATH)" && cmake -GNinja -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DENABLE_TESTS=ON -DCMAKE_C_COMPILER:PATH="$(MSVC_COMPILER_PATH)" -DCMAKE_CXX_COMPILER:PATH="$(MSVC_COMPILER_PATH)" $(REPO_DIR)
@@ -78,6 +73,7 @@ jobs:
- script: echo Stop IncrediBuild_Agent && net stop IncrediBuild_Agent
displayName: Stop IncrediBuild
continueOnError: true
- script: dir $(REPO_DIR)\bin\ /s
displayName: 'List files'
@@ -149,7 +145,7 @@ jobs:
# Add for gtest-parallel, it hangs now (CVS-33386)
#python $(BUILD_DIR)\gtest-parallel\gtest-parallel $(BIN_DIR)\MklDnnFunctionalTests --workers=$(WORKERS_NUMBER) --dump_json_test_results=MklDnnFunctionalTests.json --gtest_filter=*smoke* -- --gtest_print_time=1
- script: |
set PATH=$(REPO_DIR)\inference-engine\temp\tbb\bin;$(REPO_DIR)\inference-engine\temp\opencv_4.5.0\opencv\bin;%PATH%
set PATH=$(REPO_DIR)\inference-engine\temp\tbb\bin;$(REPO_DIR)\inference-engine\temp\opencv_4.5.1\opencv\bin;%PATH%
set DATA_PATH=$(BUILD_DIR)\testdata
set MODELS_PATH=$(BUILD_DIR)\testdata
$(BIN_DIR)\MklDnnFunctionalTests --gtest_filter=*smoke* --gtest_print_time=1 --gtest_output=xml:TEST-MklDnnFunctionalTests.xml
@@ -157,7 +153,7 @@ jobs:
continueOnError: false
- script: |
set PATH=$(REPO_DIR)\inference-engine\temp\tbb\bin;$(REPO_DIR)\inference-engine\temp\opencv_4.5.0\opencv\bin;%PATH%
set PATH=$(REPO_DIR)\inference-engine\temp\tbb\bin;$(REPO_DIR)\inference-engine\temp\opencv_4.5.1\opencv\bin;%PATH%
set DATA_PATH=$(BUILD_DIR)\testdata
set MODELS_PATH=$(BUILD_DIR)\testdata
$(BIN_DIR)\InferenceEngineCAPITests --gtest_output=xml:TEST-InferenceEngineCAPITests.xml

View File

@@ -180,6 +180,8 @@ endif()
#
ie_developer_export_targets(format_reader)
ie_developer_export_targets(ie_samples_utils)
ie_developer_export_targets(gflags)
ie_developer_export_targets(${NGRAPH_LIBRARIES})
# for Template plugin

View File

@@ -181,8 +181,8 @@ endif ()
if (ENABLE_OPENCV)
reset_deps_cache(OpenCV_DIR)
set(OPENCV_VERSION "4.5.0")
set(OPENCV_BUILD "36")
set(OPENCV_VERSION "4.5.1")
set(OPENCV_BUILD "044")
set(OPENCV_BUILD_YOCTO "337")
if (AARCH64)

View File

@@ -137,6 +137,10 @@ else()
find_package(InferenceEngine 2.1 REQUIRED)
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/common/utils")
add_subdirectory(common/utils)
endif()
# format reader must be added after find_package(InferenceEngine) to get
# exactly the same OpenCV_DIR path which was used for the InferenceEngine build
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/common/format_reader")

View File

@@ -8,5 +8,6 @@ file (GLOB HDR ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
ie_add_sample(NAME benchmark_app
SOURCES ${SRC}
HEADERS ${HDR}
DEPENDENCIES format_reader
DEPENDENCIES format_reader ie_samples_utils
OPENCV_DEPENDENCIES imgcodecs)

View File

@@ -95,6 +95,9 @@ Options:
-nthreads "<integer>" Optional. Number of threads to use for inference on the CPU (including HETERO and MULTI cases).
-enforcebf16 Optional. Enforcing of floating point operations execution in bfloat16 precision on platforms with native bfloat16 support. By default, this key sets "true" on platforms with native bfloat16 support and "false" for other platforms. Use "-enforcebf16=false" to disable this feature.
-pin "YES"/"NO"/"NUMA" Optional. Enable threads->cores ("YES", default), threads->(NUMA)nodes ("NUMA") or completely disable ("NO") CPU threads pinning for CPU-involved inference.
-ip "U8"/"FP16"/"FP32" Optional. Specifies precision for all input layers of the network.
-op "U8"/"FP16"/"FP32" Optional. Specifies precision for all output layers of the network.
-iop Optional. Specifies precision for input and output layers by name. Example: -iop "input:FP16, output:FP16". Notice that quotes are required. Overwrites precision from ip and op options for specified layers.
Statistics dumping options:

View File

@@ -103,6 +103,19 @@ static const char shape_message[] = "Optional. Set shape for input. For example,
// @brief message for quantization bits
static const char gna_qb_message[] = "Optional. Weight bits for quantization: 8 or 16 (default)";
// TODO: duplicate options from compile_tool
static constexpr char inputs_precision_message[] =
"Optional. Specifies precision for all input layers of the network.";
static constexpr char outputs_precision_message[] =
"Optional. Specifies precision for all output layers of the network.";
static constexpr char iop_message[] =
"Optional. Specifies precision for input and output layers by name.\n"
" Example: -iop \"input:FP16, output:FP16\".\n"
" Notice that quotes are required.\n"
" Overwrites precision from ip and op options for specified layers.";
/// @brief Define flag for showing help message <br>
DEFINE_bool(h, false, help_message);
@@ -190,6 +203,18 @@ DEFINE_string(shape, "", shape_message);
/// @brief Define flag for quantization bits (default 16)
DEFINE_int32(qb, 16, gna_qb_message);
/// @brief Specify precision for all input layers of the network
DEFINE_string(ip, "", inputs_precision_message);
/// @brief Specify precision for all ouput layers of the network
DEFINE_string(op, "", outputs_precision_message);
/// @brief Specify precision for input and output layers by name.\n"
/// Example: -iop \"input:FP16, output:FP16\".\n"
/// Notice that quotes are required.\n"
/// Overwrites layout from ip and op options for specified layers.";
DEFINE_string(iop, "", iop_message);
/**
* @brief This function show a help message
*/
@@ -228,4 +253,7 @@ static void showUsage() {
std::cout << " -load_config " << load_config_message << std::endl;
#endif
std::cout << " -qb " << gna_qb_message << std::endl;
std::cout << " -ip <value> " << inputs_precision_message << std::endl;
std::cout << " -op <value> " << outputs_precision_message << std::endl;
std::cout << " -iop \"<value>\" " << iop_message << std::endl;
}

View File

@@ -67,6 +67,14 @@ bool ParseAndCheckCommandLine(int argc, char *argv[]) {
throw std::logic_error("only " + std::string(detailedCntReport) + " report type is supported for MULTI device");
}
bool isNetworkCompiled = fileExt(FLAGS_m) == "blob";
bool isPrecisionSet = !(FLAGS_ip.empty() && FLAGS_op.empty() && FLAGS_iop.empty());
if (isNetworkCompiled && isPrecisionSet) {
std::string err = std::string("Cannot set precision for a compiled network. ") +
std::string("Please re-compile your network with required precision using compile_tool");
throw std::logic_error(err);
}
return true;
}
@@ -376,6 +384,10 @@ int main(int argc, char *argv[]) {
item.second->setPrecision(Precision::U8);
}
}
processPrecision(cnnNetwork, FLAGS_ip, FLAGS_op, FLAGS_iop);
printInputAndOutputsInfo(cnnNetwork);
// ----------------- 7. Loading the model to the device --------------------------------------------------------
next_step();
startTime = Time::now();

View File

@@ -5,4 +5,4 @@
ie_add_sample(NAME classification_sample_async
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
HEADERS classification_sample_async.h
DEPENDENCIES format_reader)
DEPENDENCIES format_reader ie_samples_utils)

View File

@@ -25,7 +25,7 @@ find_package(OpenCV COMPONENTS imgcodecs videoio imgproc QUIET)
if(NOT OpenCV_FOUND)
message(WARNING "OPENCV is disabled or not found, " ${TARGET_NAME} " will be built without OPENCV support")
else()
target_link_libraries(${TARGET_NAME} PRIVATE ${OpenCV_LIBRARIES})
target_link_libraries(${TARGET_NAME} PRIVATE ${OpenCV_LIBRARIES} ie_samples_utils)
if(UNIX AND NOT APPLE)
# Workaround issue that rpath-link is missing for PRIVATE dependencies
# Fixed in cmake 3.16.0 https://gitlab.kitware.com/cmake/cmake/issues/19556

View File

@@ -1,87 +0,0 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
/**
* @brief a header file with common samples functionality
* @file args_helper.hpp
*/
#pragma once
#include <string>
#include <vector>
#include <gflags/gflags.h>
#include <iostream>
#include <sys/stat.h>
#include <samples/slog.hpp>
#ifdef _WIN32
#include <os/windows/w_dirent.h>
#else
#include <dirent.h>
#endif
/**
* @brief This function checks input args and existence of specified files in a given folder
* @param arg path to a file to be checked for existence
* @return files updated vector of verified input files
*/
void readInputFilesArguments(std::vector<std::string> &files, const std::string& arg) {
struct stat sb;
if (stat(arg.c_str(), &sb) != 0) {
slog::warn << "File " << arg << " cannot be opened!" << slog::endl;
return;
}
if (S_ISDIR(sb.st_mode)) {
DIR *dp;
dp = opendir(arg.c_str());
if (dp == nullptr) {
slog::warn << "Directory " << arg << " cannot be opened!" << slog::endl;
return;
}
struct dirent *ep;
while (nullptr != (ep = readdir(dp))) {
std::string fileName = ep->d_name;
if (fileName == "." || fileName == "..") continue;
files.push_back(arg + "/" + ep->d_name);
}
closedir(dp);
} else {
files.push_back(arg);
}
if (files.size() < 20) {
slog::info << "Files were added: " << files.size() << slog::endl;
for (std::string filePath : files) {
slog::info << " " << filePath << slog::endl;
}
} else {
slog::info << "Files were added: " << files.size() << ". Too many to display each of them." << slog::endl;
}
}
/**
* @brief This function find -i/--images key in input args
* It's necessary to process multiple values for single key
* @return files updated vector of verified input files
*/
void parseInputFilesArguments(std::vector<std::string> &files) {
std::vector<std::string> args = gflags::GetArgvs();
bool readArguments = false;
for (size_t i = 0; i < args.size(); i++) {
if (args.at(i) == "-i" || args.at(i) == "--images") {
readArguments = true;
continue;
}
if (!readArguments) {
continue;
}
if (args.at(i).c_str()[0] == '-') {
break;
}
readInputFilesArguments(files, args.at(i));
}
}

View File

@@ -0,0 +1,19 @@
# Copyright (C) Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
set(TARGET_NAME "ie_samples_utils")
file(GLOB_RECURSE SOURCES "*.cpp" "*.hpp")
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})
add_library(${TARGET_NAME} STATIC ${SOURCES})
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "src")
target_include_directories(${TARGET_NAME}
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(${TARGET_NAME}
PUBLIC
IE::inference_engine
gflags)

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
/**
* @brief a header file with common samples functionality
* @file args_helper.hpp
*/
#pragma once
#include <string>
#include <vector>
#include <inference_engine.hpp>
/**
* @brief This function checks input args and existence of specified files in a given folder
* @param arg path to a file to be checked for existence
* @return files updated vector of verified input files
*/
void readInputFilesArguments(std::vector<std::string> &files, const std::string& arg);
/**
* @brief This function find -i/--images key in input args
* It's necessary to process multiple values for single key
* @return files updated vector of verified input files
*/
void parseInputFilesArguments(std::vector<std::string> &files);
void processPrecision(InferenceEngine::CNNNetwork& network, const std::string &ip, const std::string &op, const std::string &iop);
void processLayout(InferenceEngine::CNNNetwork& network, const std::string& il, const std::string& ol, const std::string& iol);
void printInputAndOutputsInfo(const InferenceEngine::CNNNetwork& network);

View File

@@ -6,6 +6,8 @@
* @brief a header file with output classification results
* @file classification_results.hpp
*/
#pragma once
#include <string>
#include <vector>
#include <iostream>

View File

@@ -1129,3 +1129,13 @@ inline void showAvailableDevices() {
}
std::cout << std::endl;
}
/**
* @brief Parse text config file. The file must have the following format (with space a delimeter):
* CONFIG_NAME1 CONFIG_VALUE1
* CONFIG_NAME2 CONFIG_VALUE2
*
* @param configName - filename for a file with config options
* @param comment - lines starting with symbol `comment` are skipped
*/
std::map<std::string, std::string> parseConfig(const std::string &configName, char comment = '#');

View File

@@ -0,0 +1,307 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "samples/args_helper.hpp"
#include <gflags/gflags.h>
#include <iostream>
#include <sys/stat.h>
#include <samples/slog.hpp>
#ifdef _WIN32
#include <samples/os/windows/w_dirent.h>
#else
#include <dirent.h>
#endif
void readInputFilesArguments(std::vector<std::string> &files, const std::string& arg) {
struct stat sb;
if (stat(arg.c_str(), &sb) != 0) {
slog::warn << "File " << arg << " cannot be opened!" << slog::endl;
return;
}
if (S_ISDIR(sb.st_mode)) {
DIR *dp;
dp = opendir(arg.c_str());
if (dp == nullptr) {
slog::warn << "Directory " << arg << " cannot be opened!" << slog::endl;
return;
}
struct dirent *ep;
while (nullptr != (ep = readdir(dp))) {
std::string fileName = ep->d_name;
if (fileName == "." || fileName == "..") continue;
files.push_back(arg + "/" + ep->d_name);
}
closedir(dp);
} else {
files.push_back(arg);
}
if (files.size() < 20) {
slog::info << "Files were added: " << files.size() << slog::endl;
for (std::string filePath : files) {
slog::info << " " << filePath << slog::endl;
}
} else {
slog::info << "Files were added: " << files.size() << ". Too many to display each of them." << slog::endl;
}
}
void parseInputFilesArguments(std::vector<std::string> &files) {
std::vector<std::string> args = gflags::GetArgvs();
bool readArguments = false;
for (size_t i = 0; i < args.size(); i++) {
if (args.at(i) == "-i" || args.at(i) == "--images") {
readArguments = true;
continue;
}
if (!readArguments) {
continue;
}
if (args.at(i).c_str()[0] == '-') {
break;
}
readInputFilesArguments(files, args.at(i));
}
}
namespace {
void splitStringList(const std::string& str, std::vector<std::string>& out, char delim) {
out.clear();
if (str.empty())
return;
std::istringstream istr(str);
std::string elem;
while (std::getline(istr, elem, delim)) {
if (elem.empty()) {
continue;
}
out.emplace_back(std::move(elem));
}
}
std::map<std::string, std::string> parseArgMap(std::string argMap) {
argMap.erase(std::remove_if(argMap.begin(), argMap.end(), ::isspace), argMap.end());
std::vector<std::string> pairs;
splitStringList(argMap, pairs, ',');
std::map<std::string, std::string> parsedMap;
for (auto&& pair : pairs) {
std::vector<std::string> keyValue;
splitStringList(pair, keyValue, ':');
if (keyValue.size() != 2) {
throw std::invalid_argument("Invalid key/value pair " + pair + ". Expected <layer_name>:<value>");
}
parsedMap[keyValue[0]] = keyValue[1];
}
return parsedMap;
}
using supported_precisions_t = std::unordered_map<std::string, InferenceEngine::Precision>;
InferenceEngine::Precision getPrecision(std::string value,
const supported_precisions_t& supported_precisions) {
std::transform(value.begin(), value.end(), value.begin(), ::toupper);
const auto precision = supported_precisions.find(value);
if (precision == supported_precisions.end()) {
throw std::logic_error("\"" + value + "\"" + " is not a valid precision");
}
return precision->second;
}
InferenceEngine::Precision getPrecision(const std::string& value) {
static const supported_precisions_t supported_precisions = {
{ "FP32", InferenceEngine::Precision::FP32 },
{ "FP16", InferenceEngine::Precision::FP16 },
{ "BF16", InferenceEngine::Precision::BF16 },
{ "U64", InferenceEngine::Precision::U64 },
{ "I64", InferenceEngine::Precision::I64 },
{ "U32", InferenceEngine::Precision::U32 },
{ "I32", InferenceEngine::Precision::I32 },
{ "U16", InferenceEngine::Precision::U16 },
{ "I16", InferenceEngine::Precision::I16 },
{ "U8", InferenceEngine::Precision::U8 },
{ "I8", InferenceEngine::Precision::I8 },
{ "BOOL", InferenceEngine::Precision::BOOL },
};
return getPrecision(value, supported_precisions);
}
void setPrecisions(const InferenceEngine::CNNNetwork& network, const std::string &iop) {
const auto user_precisions_map = parseArgMap(iop);
auto inputs = network.getInputsInfo();
auto outputs = network.getOutputsInfo();
for (auto&& item : user_precisions_map) {
const auto& layer_name = item.first;
const auto& user_precision = item.second;
const auto input = inputs.find(layer_name);
const auto output = outputs.find(layer_name);
if (input != inputs.end()) {
input->second->setPrecision(getPrecision(user_precision));
} else if (output != outputs.end()) {
output->second->setPrecision(getPrecision(user_precision));
} else {
throw std::logic_error(layer_name + " is not an input neither output");
}
}
}
} // namespace
void processPrecision(InferenceEngine::CNNNetwork& network, const std::string &ip, const std::string &op,
const std::string &iop) {
if (!ip.empty()) {
const auto user_precision = getPrecision(ip);
for (auto&& layer : network.getInputsInfo()) {
layer.second->setPrecision(user_precision);
}
}
if (!op.empty()) {
auto user_precision = getPrecision(op);
for (auto&& layer : network.getOutputsInfo()) {
layer.second->setPrecision(user_precision);
}
}
if (!iop.empty()) {
setPrecisions(network, iop);
}
}
namespace {
using supported_layouts_t = std::unordered_map<std::string, InferenceEngine::Layout>;
using matchLayoutToDims_t = std::unordered_map<size_t, size_t>;
InferenceEngine::Layout getLayout(std::string value,
const supported_layouts_t& supported_layouts) {
std::transform(value.begin(), value.end(), value.begin(), ::toupper);
const auto layout = supported_layouts.find(value);
if (layout == supported_layouts.end()) {
throw std::logic_error("\"" + value + "\"" + " is not a valid layout");
}
return layout->second;
}
InferenceEngine::Layout getLayout(const std::string& value) {
static const supported_layouts_t supported_layouts = {
{ "NCDHW", InferenceEngine::Layout::NCDHW },
{ "NDHWC", InferenceEngine::Layout::NDHWC },
{ "NCHW", InferenceEngine::Layout::NCHW },
{ "NHWC", InferenceEngine::Layout::NHWC },
{ "CHW", InferenceEngine::Layout::CHW },
{ "NC", InferenceEngine::Layout::NC },
{ "C", InferenceEngine::Layout::C },
};
return getLayout(value, supported_layouts);
}
bool isMatchLayoutToDims(InferenceEngine::Layout layout, size_t dimension) {
static const matchLayoutToDims_t matchLayoutToDims = {
{static_cast<size_t>(InferenceEngine::Layout::NCDHW), 5 },
{static_cast<size_t>(InferenceEngine::Layout::NDHWC), 5 },
{static_cast<size_t>(InferenceEngine::Layout::NCHW), 4 },
{static_cast<size_t>(InferenceEngine::Layout::NHWC), 4 },
{static_cast<size_t>(InferenceEngine::Layout::CHW), 3 },
{static_cast<size_t>(InferenceEngine::Layout::NC), 2 },
{static_cast<size_t>(InferenceEngine::Layout::C), 1 }
};
const auto dims = matchLayoutToDims.find(static_cast<size_t>(layout));
if (dims == matchLayoutToDims.end()) {
throw std::logic_error("Layout is not valid.");
}
return dimension == dims->second;
}
void setLayouts(const InferenceEngine::CNNNetwork& network, const std::string iol) {
const auto user_layouts_map = parseArgMap(iol);
auto inputs = network.getInputsInfo();
auto outputs = network.getOutputsInfo();
for (auto&& item : user_layouts_map) {
const auto& layer_name = item.first;
const auto& user_layout = getLayout(item.second);
const auto input = inputs.find(layer_name);
const auto output = outputs.find(layer_name);
if (input != inputs.end()) {
if (!isMatchLayoutToDims(user_layout, input->second->getTensorDesc().getDims().size())) {
throw std::logic_error(item.second + " layout is not applicable to " + layer_name);
}
input->second->setLayout(user_layout);
} else if (output != outputs.end()) {
if (!isMatchLayoutToDims(user_layout, output->second->getTensorDesc().getDims().size())) {
throw std::logic_error(item.second + " layout is not applicable to " + layer_name);
}
output->second->setLayout(user_layout);
} else {
throw std::logic_error(layer_name + " is not an input neither output");
}
}
}
} // namespace
void processLayout(InferenceEngine::CNNNetwork& network, const std::string& il, const std::string& ol, const std::string& iol) {
if (!il.empty()) {
const auto layout = getLayout(il);
for (auto&& layer : network.getInputsInfo()) {
if (isMatchLayoutToDims(layout, layer.second->getTensorDesc().getDims().size())) {
layer.second->setLayout(layout);
}
}
}
if (!ol.empty()) {
const auto layout = getLayout(ol);
for (auto&& layer : network.getOutputsInfo()) {
if (isMatchLayoutToDims(layout, layer.second->getTensorDesc().getDims().size())) {
layer.second->setLayout(layout);
}
}
}
if (!iol.empty()) {
setLayouts(network, iol);
}
}
void printInputAndOutputsInfo(const InferenceEngine::CNNNetwork& network) {
std::cout << "Network inputs:" << std::endl;
for (auto&& layer : network.getInputsInfo()) {
std::cout << " " << layer.first << " : " << layer.second->getPrecision() << " / " << layer.second->getLayout() << std::endl;
}
std::cout << "Network outputs:" << std::endl;
for (auto&& layer : network.getOutputsInfo()) {
std::cout << " " << layer.first << " : " << layer.second->getPrecision() << " / " << layer.second->getLayout() << std::endl;
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (C) Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "samples/common.hpp"
std::map<std::string, std::string> parseConfig(const std::string &configName, char comment) {
std::map<std::string, std::string> config = {};
std::ifstream file(configName);
if (!file.is_open()) {
return config;
}
std::string key, value;
while (file >> key >> value) {
if (key.empty() || key[0] == comment) {
continue;
}
config[key] = value;
}
return config;
}

View File

@@ -4,4 +4,5 @@
ie_add_sample(NAME hello_classification
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
DEPENDENCIES ie_samples_utils
OPENCV_DEPENDENCIES imgcodecs)

View File

@@ -3,4 +3,5 @@
#
ie_add_sample(NAME hello_nv12_input_classification
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp")
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
DEPENDENCIES ie_samples_utils)

View File

@@ -18,7 +18,7 @@
#include <sys/stat.h>
#ifdef _WIN32
#include <os/windows/w_dirent.h>
#include <samples/os/windows/w_dirent.h>
#else
#include <dirent.h>
#endif

View File

@@ -3,4 +3,5 @@
#
ie_add_sample(NAME hello_query_device
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp")
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
DEPENDENCIES ie_samples_utils)

View File

@@ -15,6 +15,7 @@
ie_add_sample(NAME hello_reshape_ssd
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/reshape_ssd_extension.hpp"
DEPENDENCIES ie_samples_utils
OPENCV_DEPENDENCIES imgcodecs)
find_package(ngraph REQUIRED)

View File

@@ -10,7 +10,7 @@ file (GLOB MAIN_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
ie_add_sample(NAME ngraph_function_creation_sample
SOURCES ${MAIN_SRC}
HEADERS ${MAIN_HEADERS}
DEPENDENCIES format_reader)
DEPENDENCIES format_reader ie_samples_utils)
find_package(ngraph REQUIRED)
target_link_libraries(${TARGET_NAME} PRIVATE ${NGRAPH_LIBRARIES})

View File

@@ -5,7 +5,7 @@
ie_add_sample(NAME object_detection_sample_ssd
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/object_detection_sample_ssd.h"
DEPENDENCIES format_reader)
DEPENDENCIES format_reader ie_samples_utils)
find_package(ngraph REQUIRED)
target_link_libraries(object_detection_sample_ssd PRIVATE ${NGRAPH_LIBRARIES})

View File

@@ -18,7 +18,6 @@
#include <samples/slog.hpp>
#include <samples/args_helper.hpp>
#include <vpu/vpu_tools_common.hpp>
#include <vpu/vpu_plugin_config.hpp>
#include "object_detection_sample_ssd.h"

View File

@@ -4,4 +4,5 @@
ie_add_sample(NAME speech_sample
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/speech_sample.hpp")
HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/speech_sample.hpp"
DEPENDENCIES ie_samples_utils)

View File

@@ -5,4 +5,4 @@
ie_add_sample(NAME style_transfer_sample
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/style_transfer_sample.h"
DEPENDENCIES format_reader)
DEPENDENCIES format_reader ie_samples_utils)

View File

@@ -652,6 +652,7 @@ void HeteroExecutableNetwork::InitNgraph(const InferenceEngine::ICNNNetwork& net
if (itClonedInput != clonedInputs.end() && nullptr != itClonedInput->second) {
itClonedInput->second->getPreProcess() = externalInput.second->getPreProcess();
itClonedInput->second->setPrecision(externalInput.second->getPrecision());
itClonedInput->second->setLayout(externalInput.second->getLayout());
}
}
isInputSubnetwork[id] = std::any_of(std::begin(subgraph._parameters),

View File

@@ -32,6 +32,7 @@ public:
const Output<Node>& end_token);
void validate_and_infer_types() override;
bool visit_attributes(AttributeVisitor& visitor) override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
};

View File

@@ -27,6 +27,7 @@ public:
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
void validate_and_infer_types() override;
bool visit_attributes(AttributeVisitor& visitor) override;
float get_alpha() const { return m_alpha; }
void set_alpha(float alpha) { m_alpha = alpha; }

View File

@@ -37,6 +37,8 @@ public:
void validate_and_infer_types() override;
bool visit_attributes(AttributeVisitor& visitor) override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;
InterpolateIEAttrs get_attrs() { return m_attrs; }

View File

@@ -63,3 +63,7 @@ void op::GatherTreeIE::validate_and_infer_types() {
const auto& step_ids_et = get_input_element_type(0);
set_output_type(0, step_ids_et, step_ids_rank);
}
bool ngraph::op::GatherTreeIE::visit_attributes(AttributeVisitor& visitor) {
return true;
}

View File

@@ -35,3 +35,7 @@ shared_ptr<Node> op::HardSigmoid_IE::clone_with_new_inputs(const OutputVector& n
check_new_args_count(this, new_args);
return make_shared<op::HardSigmoid_IE>(new_args.at(0), m_alpha, m_beta);
}
bool op::HardSigmoid_IE::visit_attributes(AttributeVisitor& visitor) {
return true;
}

View File

@@ -67,6 +67,16 @@ shared_ptr<Node> op::Interp::clone_with_new_inputs(const OutputVector& new_args)
return make_shared<Interp>(new_args.at(0), m_attrs);
}
bool op::Interp::visit_attributes(AttributeVisitor& visitor)
{
visitor.on_attribute("align_corners", m_attrs.align_corners);
visitor.on_attribute("width", m_attrs.width);
visitor.on_attribute("height", m_attrs.height);
visitor.on_attribute("pad_beg", m_attrs.pad_beg);
visitor.on_attribute("pad_end", m_attrs.pad_end);
return true;
}
constexpr NodeTypeInfo op::ResampleV2::type_info;
op::ResampleV2::ResampleV2(const Output<Node>& image, const Output<Node>& output_shape,

View File

@@ -28,7 +28,7 @@ typedef std::tuple<
namespace LayerTestsDefinitions {
class PadLayerTest : public testing::WithParamInterface<padLayerTestParamsSet>,
public LayerTestsUtils::LayerTestsCommon {
virtual public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(testing::TestParamInfo<padLayerTestParamsSet> obj);
@@ -36,4 +36,4 @@ protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions
} // namespace LayerTestsDefinitions

View File

@@ -11,7 +11,7 @@ const char DEVICE_GPU[] = "GPU";
const char DEVICE_HDDL[] = "HDDL";
const char DEVICE_FPGA[] = "FPGA";
const char DEVICE_MYRIAD[] = "MYRIAD";
const char DEVICE_KEEMBAY[] = "KMB";
const char DEVICE_KEEMBAY[] = "VPUX";
const char DEVICE_MULTI[] = "MULTI";
const char DEVICE_HETERO[] = "HETERO";

View File

@@ -29,7 +29,7 @@ function(add_helpers target_name)
# TODO: eliminate dependency on samples
target_include_directories(${target_name} PUBLIC
"${IE_MAIN_SOURCE_DIR}/samples/common/os/windows")
"${IE_MAIN_SOURCE_DIR}/samples/common/utils/include/samples/os/windows")
set_property(TARGET ${target_name} PROPERTY COMPILE_PDB_NAME ${target_name})

View File

@@ -1 +1 @@
d8947b3280c8644f9828fac2b36f5f5a
4cf15d9809d418afab0679189cd08d12

View File

@@ -38,6 +38,10 @@ if(MSVC)
endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") # don't add Clang here: issue should be investigated and fixed (workaround for Apple only)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wrange-loop-analysis) # https://github.com/opencv/opencv/issues/18928
endif()
file(GLOB gapi_ext_hdrs
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp"
@@ -49,6 +53,7 @@ file(GLOB gapi_ext_hdrs
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/ocl/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/render/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/s11n/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/plaidml/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp"
@@ -56,6 +61,7 @@ file(GLOB gapi_ext_hdrs
set(gapi_srcs
# Front-end part
src/api/grunarg.cpp
src/api/gorigin.cpp
src/api/gmat.cpp
src/api/garray.cpp
@@ -73,10 +79,12 @@ set(gapi_srcs
src/api/kernels_imgproc.cpp
src/api/kernels_video.cpp
src/api/kernels_nnparsers.cpp
src/api/kernels_streaming.cpp
src/api/render.cpp
src/api/render_ocv.cpp
src/api/ginfer.cpp
src/api/ft_render.cpp
src/api/media.cpp
src/api/rmat.cpp
# Compiler part
src/compiler/gmodel.cpp
@@ -95,9 +103,11 @@ set(gapi_srcs
src/compiler/passes/pattern_matching.cpp
src/compiler/passes/perform_substitution.cpp
src/compiler/passes/streaming.cpp
src/compiler/passes/intrin.cpp
# Executor
src/executor/gexecutor.cpp
src/executor/gtbbexecutor.cpp
src/executor/gstreamingexecutor.cpp
src/executor/gasync.cpp
@@ -127,21 +137,31 @@ set(gapi_srcs
src/backends/ie/giebackend.cpp
src/backends/ie/giebackend/giewrapper.cpp
# Render Backend.
src/backends/render/grenderocvbackend.cpp
src/backends/render/grenderocv.cpp
# ONNX backend
src/backends/onnx/gonnxbackend.cpp
#PlaidML Backend
# Render backend
src/backends/render/grenderocv.cpp
src/backends/render/ft_render.cpp
# PlaidML Backend
src/backends/plaidml/gplaidmlcore.cpp
src/backends/plaidml/gplaidmlbackend.cpp
# Compound
# Common backend code
src/backends/common/gmetabackend.cpp
src/backends/common/gcompoundbackend.cpp
src/backends/common/gcompoundkernel.cpp
# Serialization API and routines
src/api/s11n.cpp
src/backends/common/serialization.cpp
# Streaming backend
src/backends/streaming/gstreamingbackend.cpp
# Python bridge
src/backends/ie/bindings_ie.cpp
)
ocv_add_dispatched_file(backends/fluid/gfluidimgproc_func SSE4_1 AVX2)
@@ -180,6 +200,10 @@ if(TARGET opencv_test_gapi)
target_link_libraries(opencv_test_gapi PRIVATE ade)
endif()
if(HAVE_TBB AND TARGET opencv_test_gapi)
ocv_target_link_libraries(opencv_test_gapi PRIVATE tbb)
endif()
if(HAVE_FREETYPE)
ocv_target_compile_definitions(${the_module} PRIVATE -DHAVE_FREETYPE)
if(TARGET opencv_test_gapi)
@@ -198,10 +222,20 @@ if(HAVE_PLAIDML)
ocv_target_include_directories(${the_module} SYSTEM PRIVATE ${PLAIDML_INCLUDE_DIRS})
endif()
if(WIN32)
# Required for htonl/ntohl on Windows
ocv_target_link_libraries(${the_module} PRIVATE wsock32 ws2_32)
endif()
if(HAVE_ONNX)
ocv_target_link_libraries(${the_module} PRIVATE ${ONNX_LIBRARY})
ocv_target_compile_definitions(${the_module} PRIVATE HAVE_ONNX=1)
if(TARGET opencv_test_gapi)
ocv_target_compile_definitions(opencv_test_gapi PRIVATE HAVE_ONNX=1)
ocv_target_link_libraries(opencv_test_gapi PRIVATE ${ONNX_LIBRARY})
endif()
endif()
ocv_add_perf_tests()
ocv_add_samples()

View File

@@ -15,6 +15,8 @@ file(GLOB FLUID_includes "${FLUID_ROOT}/include/opencv2/*.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"

View File

@@ -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!

View File

@@ -24,10 +24,18 @@
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/gframe.hpp>
#include <opencv2/gapi/gcomputation.hpp>
#include <opencv2/gapi/gcompiled.hpp>
#include <opencv2/gapi/gtyped.hpp>
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/operators.hpp>
// Include these files here to avoid cyclic dependency between
// Desync & GKernel & GComputation & GStreamingCompiled.
#include <opencv2/gapi/streaming/desync.hpp>
#include <opencv2/gapi/streaming/format.hpp>
#endif // OPENCV_GAPI_HPP

View File

@@ -2,7 +2,7 @@
// 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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_CORE_HPP
@@ -26,6 +26,7 @@
@defgroup gapi_transform Graph API: Image and channel composition functions
@}
*/
namespace cv { namespace gapi {
namespace core {
using GMat2 = std::tuple<GMat,GMat>;
@@ -308,6 +309,13 @@ namespace core {
}
};
G_TYPED_KERNEL(GCountNonZero, <GOpaque<int>(GMat)>, "org.opencv.core.matrixop.countNonZero") {
static GOpaqueDesc outMeta(GMatDesc in) {
GAPI_Assert(in.chan == 1);
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GAddW, <GMat(GMat, double, GMat, double, double, int)>, "org.opencv.core.matrixop.addweighted") {
static GMatDesc outMeta(GMatDesc a, double, GMatDesc b, double, double, int ddepth) {
if (ddepth == -1)
@@ -502,18 +510,93 @@ namespace core {
}
};
G_TYPED_KERNEL(GSize, <GOpaque<Size>(GMat)>, "org.opencv.core.size") {
static GOpaqueDesc outMeta(const GMatDesc&) {
return empty_gopaque_desc();
G_TYPED_KERNEL(
GKMeansND,
<std::tuple<GOpaque<double>,GMat,GMat>(GMat,int,GMat,TermCriteria,int,KmeansFlags)>,
"org.opencv.core.kmeansND") {
static std::tuple<GOpaqueDesc,GMatDesc,GMatDesc>
outMeta(const GMatDesc& in, int K, const GMatDesc& bestLabels, const TermCriteria&, int,
KmeansFlags flags) {
GAPI_Assert(in.depth == CV_32F);
std::vector<int> amount_n_dim = detail::checkVector(in);
int amount = amount_n_dim[0], dim = amount_n_dim[1];
if (amount == -1) // Mat with height != 1, width != 1, channels != 1 given
{ // which means that kmeans will consider the following:
amount = in.size.height;
dim = in.size.width * in.chan;
}
// kmeans sets these labels' sizes when no bestLabels given:
GMatDesc out_labels(CV_32S, 1, Size{1, amount});
// kmeans always sets these centers' sizes:
GMatDesc centers (CV_32F, 1, Size{dim, K});
if (flags & KMEANS_USE_INITIAL_LABELS)
{
GAPI_Assert(bestLabels.depth == CV_32S);
int labels_amount = detail::checkVector(bestLabels, 1u);
GAPI_Assert(labels_amount == amount);
out_labels = bestLabels; // kmeans preserves bestLabels' sizes if given
}
return std::make_tuple(empty_gopaque_desc(), out_labels, centers);
}
};
G_TYPED_KERNEL(GSizeR, <GOpaque<Size>(GOpaque<Rect>)>, "org.opencv.core.sizeR") {
static GOpaqueDesc outMeta(const GOpaqueDesc&) {
return empty_gopaque_desc();
G_TYPED_KERNEL(
GKMeansNDNoInit,
<std::tuple<GOpaque<double>,GMat,GMat>(GMat,int,TermCriteria,int,KmeansFlags)>,
"org.opencv.core.kmeansNDNoInit") {
static std::tuple<GOpaqueDesc,GMatDesc,GMatDesc>
outMeta(const GMatDesc& in, int K, const TermCriteria&, int, KmeansFlags flags) {
GAPI_Assert( !(flags & KMEANS_USE_INITIAL_LABELS) );
GAPI_Assert(in.depth == CV_32F);
std::vector<int> amount_n_dim = detail::checkVector(in);
int amount = amount_n_dim[0], dim = amount_n_dim[1];
if (amount == -1) // Mat with height != 1, width != 1, channels != 1 given
{ // which means that kmeans will consider the following:
amount = in.size.height;
dim = in.size.width * in.chan;
}
GMatDesc out_labels(CV_32S, 1, Size{1, amount});
GMatDesc centers (CV_32F, 1, Size{dim, K});
return std::make_tuple(empty_gopaque_desc(), out_labels, centers);
}
};
}
G_TYPED_KERNEL(GKMeans2D, <std::tuple<GOpaque<double>,GArray<int>,GArray<Point2f>>
(GArray<Point2f>,int,GArray<int>,TermCriteria,int,KmeansFlags)>,
"org.opencv.core.kmeans2D") {
static std::tuple<GOpaqueDesc,GArrayDesc,GArrayDesc>
outMeta(const GArrayDesc&,int,const GArrayDesc&,const TermCriteria&,int,KmeansFlags) {
return std::make_tuple(empty_gopaque_desc(), empty_array_desc(), empty_array_desc());
}
};
G_TYPED_KERNEL(GKMeans3D, <std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>>
(GArray<Point3f>,int,GArray<int>,TermCriteria,int,KmeansFlags)>,
"org.opencv.core.kmeans3D") {
static std::tuple<GOpaqueDesc,GArrayDesc,GArrayDesc>
outMeta(const GArrayDesc&,int,const GArrayDesc&,const TermCriteria&,int,KmeansFlags) {
return std::make_tuple(empty_gopaque_desc(), empty_array_desc(), empty_array_desc());
}
};
} // namespace core
namespace streaming {
// Operations for Streaming (declared in this header for convenience)
G_TYPED_KERNEL(GSize, <GOpaque<Size>(GMat)>, "org.opencv.streaming.size") {
static GOpaqueDesc outMeta(const GMatDesc&) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GSizeR, <GOpaque<Size>(GOpaque<Rect>)>, "org.opencv.streaming.sizeR") {
static GOpaqueDesc outMeta(const GOpaqueDesc&) {
return empty_gopaque_desc();
}
};
} // namespace streaming
//! @addtogroup gapi_math
//! @{
@@ -755,6 +838,7 @@ Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref
@note Function textual ID is "org.opencv.core.math.mean"
@param src input matrix.
@sa countNonZero, min, max
*/
GAPI_EXPORTS_W GScalar mean(const GMat& src);
@@ -856,7 +940,7 @@ Supported input matrix data types are @ref CV_8UC1, @ref CV_16UC1, @ref CV_16SC1
@note Function textual ID is "org.opencv.core.pixelwise.compare.cmpGT"
@param src1 first input matrix.
@param src2 second input matrix/scalar of the same depth as first input matrix.
@sa min, max, threshold, cmpLE, cmpGE, cmpLS
@sa min, max, threshold, cmpLE, cmpGE, cmpLT
*/
GAPI_EXPORTS GMat cmpGT(const GMat& src1, const GMat& src2);
/** @overload
@@ -908,7 +992,7 @@ Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1,
@note Function textual ID is "org.opencv.core.pixelwise.compare.cmpGE"
@param src1 first input matrix.
@param src2 second input matrix/scalar of the same depth as first input matrix.
@sa min, max, threshold, cmpLE, cmpGT, cmpLS
@sa min, max, threshold, cmpLE, cmpGT, cmpLT
*/
GAPI_EXPORTS GMat cmpGE(const GMat& src1, const GMat& src2);
/** @overload
@@ -934,7 +1018,7 @@ Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1,
@note Function textual ID is "org.opencv.core.pixelwise.compare.cmpLE"
@param src1 first input matrix.
@param src2 second input matrix/scalar of the same depth as first input matrix.
@sa min, max, threshold, cmpGT, cmpGE, cmpLS
@sa min, max, threshold, cmpGT, cmpGE, cmpLT
*/
GAPI_EXPORTS GMat cmpLE(const GMat& src1, const GMat& src2);
/** @overload
@@ -1012,7 +1096,7 @@ Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref
*/
GAPI_EXPORTS GMat bitwise_and(const GMat& src1, const GMat& src2);
/** @overload
@note Function textual ID is "org.opencv.core.pixelwise.compare.bitwise_andS"
@note Function textual ID is "org.opencv.core.pixelwise.bitwise_andS"
@param src1 first input matrix.
@param src2 scalar, which will be per-lemenetly conjuncted with elements of src1.
*/
@@ -1036,7 +1120,7 @@ Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref
*/
GAPI_EXPORTS GMat bitwise_or(const GMat& src1, const GMat& src2);
/** @overload
@note Function textual ID is "org.opencv.core.pixelwise.compare.bitwise_orS"
@note Function textual ID is "org.opencv.core.pixelwise.bitwise_orS"
@param src1 first input matrix.
@param src2 scalar, which will be per-lemenetly disjuncted with elements of src1.
*/
@@ -1061,7 +1145,7 @@ Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref
*/
GAPI_EXPORTS GMat bitwise_xor(const GMat& src1, const GMat& src2);
/** @overload
@note Function textual ID is "org.opencv.core.pixelwise.compare.bitwise_xorS"
@note Function textual ID is "org.opencv.core.pixelwise.bitwise_xorS"
@param src1 first input matrix.
@param src2 scalar, for which per-lemenet "logical or" operation on elements of src1 will be performed.
*/
@@ -1121,7 +1205,7 @@ Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1,
@note Function textual ID is "org.opencv.core.matrixop.min"
@param src1 first input matrix.
@param src2 second input matrix of the same size and depth as src1.
@sa max, compareEqual, compareLess, compareLessEqual
@sa max, cmpEQ, cmpLT, cmpLE
*/
GAPI_EXPORTS GMat min(const GMat& src1, const GMat& src2);
@@ -1138,7 +1222,7 @@ Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref
@note Function textual ID is "org.opencv.core.matrixop.max"
@param src1 first input matrix.
@param src2 second input matrix of the same size and depth as src1.
@sa min, compare, compareEqual, compareGreater, compareGreaterEqual
@sa min, compare, cmpEQ, cmpGT, cmpGE
*/
GAPI_EXPORTS GMat max(const GMat& src1, const GMat& src2);
@@ -1184,10 +1268,23 @@ Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref
@note Function textual ID is "org.opencv.core.matrixop.sum"
@param src input matrix.
@sa min, max
@sa countNonZero, mean, min, max
*/
GAPI_EXPORTS GScalar sum(const GMat& src);
/** @brief Counts non-zero array elements.
The function returns the number of non-zero elements in src :
\f[\sum _{I: \; \texttt{src} (I) \ne0 } 1\f]
Supported matrix data types are @ref CV_8UC1, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
@note Function textual ID is "org.opencv.core.matrixop.countNonZero"
@param src input single-channel matrix.
@sa mean, min, max
*/
GAPI_EXPORTS GOpaque<int> countNonZero(const GMat& src);
/** @brief Calculates the weighted sum of two matrices.
The function addWeighted calculates the weighted sum of two matrices as follows:
@@ -1324,14 +1421,14 @@ Output matrix must be of the same size and depth as src.
types.
@param type thresholding type (see the cv::ThresholdTypes).
@sa min, max, cmpGT, cmpLE, cmpGE, cmpLS
@sa min, max, cmpGT, cmpLE, cmpGE, cmpLT
*/
GAPI_EXPORTS GMat threshold(const GMat& src, const GScalar& thresh, const GScalar& maxval, int type);
/** @overload
This function applicable for all threshold types except CV_THRESH_OTSU and CV_THRESH_TRIANGLE
@note Function textual ID is "org.opencv.core.matrixop.thresholdOT"
*/
GAPI_EXPORTS std::tuple<GMat, GScalar> threshold(const GMat& src, const GScalar& maxval, int type);
GAPI_EXPORTS_W std::tuple<GMat, GScalar> threshold(const GMat& src, const GScalar& maxval, int type);
/** @brief Applies a range-level threshold to each matrix element.
@@ -1411,41 +1508,77 @@ Output image size will have the size dsize, the depth of output is the same as o
*/
GAPI_EXPORTS GMatP resizeP(const GMatP& src, const Size& dsize, int interpolation = cv::INTER_LINEAR);
/** @brief Creates one 3-channel (4-channel) matrix out of 3(4) single-channel ones.
/** @brief Creates one 4-channel matrix out of 4 single-channel ones.
The function merges several matrices to make a single multi-channel matrix. That is, each
element of the output matrix will be a concatenation of the elements of the input matrices, where
elements of i-th input matrix are treated as mv[i].channels()-element vectors.
Input matrix must be of @ref CV_8UC3 (@ref CV_8UC4) type.
Output matrix must be of @ref CV_8UC4 type.
The function split3/split4 does the reverse operation.
The function split4 does the reverse operation.
@note Function textual ID for merge3 is "org.opencv.core.transform.merge3"
@note Function textual ID for merge4 is "org.opencv.core.transform.merge4"
@note
- Function textual ID is "org.opencv.core.transform.merge4"
@param src1 first input matrix to be merged
@param src2 second input matrix to be merged
@param src3 third input matrix to be merged
@param src4 fourth input matrix to be merged
@sa split4, split3
@param src1 first input @ref CV_8UC1 matrix to be merged.
@param src2 second input @ref CV_8UC1 matrix to be merged.
@param src3 third input @ref CV_8UC1 matrix to be merged.
@param src4 fourth input @ref CV_8UC1 matrix to be merged.
@sa merge3, split4, split3
*/
GAPI_EXPORTS GMat merge4(const GMat& src1, const GMat& src2, const GMat& src3, const GMat& src4);
/** @brief Creates one 3-channel matrix out of 3 single-channel ones.
The function merges several matrices to make a single multi-channel matrix. That is, each
element of the output matrix will be a concatenation of the elements of the input matrices, where
elements of i-th input matrix are treated as mv[i].channels()-element vectors.
Output matrix must be of @ref CV_8UC3 type.
The function split3 does the reverse operation.
@note
- Function textual ID is "org.opencv.core.transform.merge3"
@param src1 first input @ref CV_8UC1 matrix to be merged.
@param src2 second input @ref CV_8UC1 matrix to be merged.
@param src3 third input @ref CV_8UC1 matrix to be merged.
@sa merge4, split4, split3
*/
GAPI_EXPORTS GMat merge3(const GMat& src1, const GMat& src2, const GMat& src3);
/** @brief Divides a 3-channel (4-channel) matrix into 3(4) single-channel matrices.
/** @brief Divides a 4-channel matrix into 4 single-channel matrices.
The function splits a 3-channel (4-channel) matrix into 3(4) single-channel matrices:
The function splits a 4-channel matrix into 4 single-channel matrices:
\f[\texttt{mv} [c](I) = \texttt{src} (I)_c\f]
All output matrices must be in @ref CV_8UC1.
All output matrices must be of @ref CV_8UC1 type.
@note Function textual for split3 ID is "org.opencv.core.transform.split3"
@note Function textual for split4 ID is "org.opencv.core.transform.split4"
The function merge4 does the reverse operation.
@param src input @ref CV_8UC4 (@ref CV_8UC3) matrix.
@sa merge3, merge4
@note
- Function textual ID is "org.opencv.core.transform.split4"
@param src input @ref CV_8UC4 matrix.
@sa split3, merge3, merge4
*/
GAPI_EXPORTS std::tuple<GMat, GMat, GMat,GMat> split4(const GMat& src);
/** @brief Divides a 3-channel matrix into 3 single-channel matrices.
The function splits a 3-channel matrix into 3 single-channel matrices:
\f[\texttt{mv} [c](I) = \texttt{src} (I)_c\f]
All output matrices must be of @ref CV_8UC1 type.
The function merge3 does the reverse operation.
@note
- Function textual ID is "org.opencv.core.transform.split3"
@param src input @ref CV_8UC3 matrix.
@sa split4, merge3, merge4
*/
GAPI_EXPORTS_W std::tuple<GMat, GMat, GMat> split3(const GMat& src);
/** @brief Applies a generic geometrical transformation to an image.
@@ -1463,21 +1596,21 @@ convert from floating to fixed-point representations of a map is that they can y
cvFloor(y)) and \f$map_2\f$ contains indices in a table of interpolation coefficients.
Output image must be of the same size and depth as input one.
@note Function textual ID is "org.opencv.core.transform.remap"
@note
- Function textual ID is "org.opencv.core.transform.remap"
- Due to current implementation limitations the size of an input and output images should be less than 32767x32767.
@param src Source image.
@param map1 The first map of either (x,y) points or just x values having the type CV_16SC2,
CV_32FC1, or CV_32FC2.
@param map2 The second map of y values having the type CV_16UC1, CV_32FC1, or none (empty map
if map1 is (x,y) points), respectively.
@param interpolation Interpolation method (see cv::InterpolationFlags). The method INTER_AREA is
not supported by this function.
@param interpolation Interpolation method (see cv::InterpolationFlags). The methods #INTER_AREA
and #INTER_LINEAR_EXACT are not supported by this function.
@param borderMode Pixel extrapolation method (see cv::BorderTypes). When
borderMode=BORDER_TRANSPARENT, it means that the pixels in the destination image that
corresponds to the "outliers" in the source image are not modified by the function.
@param borderValue Value used in case of a constant border. By default, it is 0.
@note
Due to current implementation limitations the size of an input and output images should be less than 32767x32767.
*/
GAPI_EXPORTS GMat remap(const GMat& src, const Mat& map1, const Mat& map2,
int interpolation, int borderMode = BORDER_CONSTANT,
@@ -1732,9 +1865,83 @@ GAPI_EXPORTS GMat warpAffine(const GMat& src, const Mat& M, const Size& dsize, i
int borderMode = cv::BORDER_CONSTANT, const Scalar& borderValue = Scalar());
//! @} gapi_transform
/** @brief Finds centers of clusters and groups input samples around the clusters.
The function kmeans implements a k-means algorithm that finds the centers of K clusters
and groups the input samples around the clusters. As an output, \f$\texttt{bestLabels}_i\f$
contains a 0-based cluster index for the \f$i^{th}\f$ sample.
@note
- Function textual ID is "org.opencv.core.kmeansND"
- In case of an N-dimentional points' set given, input GMat can have the following traits:
2 dimensions, a single row or column if there are N channels,
or N columns if there is a single channel. Mat should have @ref CV_32F depth.
- Although, if GMat with height != 1, width != 1, channels != 1 given as data, n-dimensional
samples are considered given in amount of A, where A = height, n = width * channels.
- In case of GMat given as data:
- the output labels are returned as 1-channel GMat with sizes
width = 1, height = A, where A is samples amount, or width = bestLabels.width,
height = bestLabels.height if bestLabels given;
- the cluster centers are returned as 1-channel GMat with sizes
width = n, height = K, where n is samples' dimentionality and K is clusters' amount.
- As one of possible usages, if you want to control the initial labels for each attempt
by yourself, you can utilize just the core of the function. To do that, set the number
of attempts to 1, initialize labels each time using a custom algorithm, pass them with the
( flags = #KMEANS_USE_INITIAL_LABELS ) flag, and then choose the best (most-compact) clustering.
@param data Data for clustering. An array of N-Dimensional points with float coordinates is needed.
Function can take GArray<Point2f>, GArray<Point3f> for 2D and 3D cases or GMat for any
dimentionality and channels.
@param K Number of clusters to split the set by.
@param bestLabels Optional input integer array that can store the supposed initial cluster indices
for every sample. Used when ( flags = #KMEANS_USE_INITIAL_LABELS ) flag is set.
@param criteria The algorithm termination criteria, that is, the maximum number of iterations
and/or the desired accuracy. The accuracy is specified as criteria.epsilon. As soon as each of
the cluster centers moves by less than criteria.epsilon on some iteration, the algorithm stops.
@param attempts Flag to specify the number of times the algorithm is executed using different
initial labellings. The algorithm returns the labels that yield the best compactness (see the first
function return value).
@param flags Flag that can take values of cv::KmeansFlags .
@return
- Compactness measure that is computed as
\f[\sum _i \| \texttt{samples} _i - \texttt{centers} _{ \texttt{labels} _i} \| ^2\f]
after every attempt. The best (minimum) value is chosen and the corresponding labels and the
compactness value are returned by the function.
- Integer array that stores the cluster indices for every sample.
- Array of the cluster centers.
*/
GAPI_EXPORTS std::tuple<GOpaque<double>,GMat,GMat>
kmeans(const GMat& data, const int K, const GMat& bestLabels,
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
/** @overload
@note
- Function textual ID is "org.opencv.core.kmeansNDNoInit"
- #KMEANS_USE_INITIAL_LABELS flag must not be set while using this overload.
*/
GAPI_EXPORTS std::tuple<GOpaque<double>,GMat,GMat>
kmeans(const GMat& data, const int K, const TermCriteria& criteria, const int attempts,
const KmeansFlags flags);
/** @overload
@note Function textual ID is "org.opencv.core.kmeans2D"
*/
GAPI_EXPORTS std::tuple<GOpaque<double>,GArray<int>,GArray<Point2f>>
kmeans(const GArray<Point2f>& data, const int K, const GArray<int>& bestLabels,
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
/** @overload
@note Function textual ID is "org.opencv.core.kmeans3D"
*/
GAPI_EXPORTS std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>>
kmeans(const GArray<Point3f>& data, const int K, const GArray<int>& bestLabels,
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
namespace streaming {
/** @brief Gets dimensions from Mat.
@note Function textual ID is "org.opencv.core.size"
@note Function textual ID is "org.opencv.streaming.size"
@param src Input tensor
@return Size (tensor dimensions).
@@ -1744,12 +1951,13 @@ GAPI_EXPORTS GOpaque<Size> size(const GMat& src);
/** @overload
Gets dimensions from rectangle.
@note Function textual ID is "org.opencv.core.sizeR"
@note Function textual ID is "org.opencv.streaming.sizeR"
@param r Input rectangle.
@return Size (rectangle dimensions).
*/
GAPI_EXPORTS GOpaque<Size> size(const GOpaque<Rect>& r);
} //namespace streaming
} //namespace gapi
} //namespace cv

View File

@@ -101,6 +101,7 @@ public:
const cv::Scalar& inVal(int input);
cv::Scalar& outValR(int output); // FIXME: Avoid cv::Scalar s = ctx.outValR()
cv::MediaFrame& outFrame(int output);
template<typename T> std::vector<T>& outVecR(int output) // FIXME: the same issue
{
return outVecRef(output).wref<T>();
@@ -164,7 +165,7 @@ template<> struct get_in<cv::GMatP>
};
template<> struct get_in<cv::GFrame>
{
static cv::Mat get(GCPUContext &ctx, int idx) { return get_in<cv::GMat>::get(ctx, idx); }
static cv::MediaFrame get(GCPUContext &ctx, int idx) { return ctx.inArg<cv::MediaFrame>(idx); }
};
template<> struct get_in<cv::GScalar>
{
@@ -258,6 +259,13 @@ template<> struct get_out<cv::GScalar>
return ctx.outValR(idx);
}
};
template<> struct get_out<cv::GFrame>
{
static cv::MediaFrame& get(GCPUContext &ctx, int idx)
{
return ctx.outFrame(idx);
}
};
template<typename U> struct get_out<cv::GArray<U>>
{
static std::vector<U>& get(GCPUContext &ctx, int idx)
@@ -271,6 +279,11 @@ template<> struct get_out<cv::GArray<cv::GMat> >: public get_out<cv::GArray<cv::
{
};
// FIXME(dm): GArray<vector<U>>/GArray<GArray<U>> conversion should be done more gracefully in the system
template<typename U> struct get_out<cv::GArray<cv::GArray<U>> >: public get_out<cv::GArray<std::vector<U>> >
{
};
template<typename U> struct get_out<cv::GOpaque<U>>
{
static U& get(GCPUContext &ctx, int idx)
@@ -443,7 +456,7 @@ struct OCVStCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>> :
template<class Impl, class K>
class GCPUKernelImpl: public cv::detail::KernelTag
{
using CallHelper = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
using CallHelper = cv::detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
public:
using API = K;
@@ -497,7 +510,7 @@ private:
template<typename K, typename Callable>
gapi::cpu::GOCVFunctor gapi::cpu::ocv_kernel(Callable& c)
{
using P = detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
using P = cv::detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
return GOCVFunctor{ K::id()
, &K::getOutMeta
, std::bind(&P::callFunctor, std::placeholders::_1, std::ref(c))
@@ -507,7 +520,7 @@ gapi::cpu::GOCVFunctor gapi::cpu::ocv_kernel(Callable& c)
template<typename K, typename Callable>
gapi::cpu::GOCVFunctor gapi::cpu::ocv_kernel(const Callable& c)
{
using P = detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
using P = cv::detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
return GOCVFunctor{ K::id()
, &K::getOutMeta
, std::bind(&P::callFunctor, std::placeholders::_1, c)

View File

@@ -9,11 +9,14 @@
#define OPENCV_GAPI_GARG_HPP
#include <vector>
#include <unordered_map>
#include <type_traits>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/own/mat.hpp>
#include <opencv2/gapi/media.hpp>
#include <opencv2/gapi/util/util.hpp>
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/gapi/util/variant.hpp>
@@ -21,9 +24,11 @@
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/gframe.hpp>
#include <opencv2/gapi/gtype_traits.hpp>
#include <opencv2/gapi/gmetaarg.hpp>
#include <opencv2/gapi/streaming/source.hpp>
#include <opencv2/gapi/rmat.hpp>
namespace cv {
@@ -90,16 +95,73 @@ using GArgs = std::vector<GArg>;
// FIXME: Express as M<GProtoArg...>::type
// FIXME: Move to a separate file!
using GRunArg = util::variant<
using GRunArgBase = util::variant<
#if !defined(GAPI_STANDALONE)
cv::UMat,
#endif // !defined(GAPI_STANDALONE)
cv::RMat,
cv::gapi::wip::IStreamSource::Ptr,
cv::Mat,
cv::Scalar,
cv::detail::VectorRef,
cv::detail::OpaqueRef
cv::detail::OpaqueRef,
cv::MediaFrame
>;
namespace detail {
template<typename,typename>
struct in_variant;
template<typename T, typename... Types>
struct in_variant<T, util::variant<Types...> >
: std::integral_constant<bool, cv::detail::contains<T, Types...>::value > {
};
} // namespace detail
struct GAPI_EXPORTS GRunArg: public GRunArgBase
{
// Metadata information here
using Meta = std::unordered_map<std::string, util::any>;
Meta meta;
// Mimic the old GRunArg semantics here, old of the times when
// GRunArg was an alias to variant<>
GRunArg();
GRunArg(const cv::GRunArg &arg);
GRunArg(cv::GRunArg &&arg);
GRunArg& operator= (const GRunArg &arg);
GRunArg& operator= (GRunArg &&arg);
template <typename T>
GRunArg(const T &t,
const Meta &m = Meta{},
typename std::enable_if< detail::in_variant<T, GRunArgBase>::value, int>::type = 0)
: GRunArgBase(t)
, meta(m)
{
}
template <typename T>
GRunArg(T &&t,
const Meta &m = Meta{},
typename std::enable_if< detail::in_variant<T, GRunArgBase>::value, int>::type = 0)
: GRunArgBase(std::move(t))
, meta(m)
{
}
template <typename T> auto operator= (const T &t)
-> typename std::enable_if< detail::in_variant<T, GRunArgBase>::value, cv::GRunArg>::type&
{
GRunArgBase::operator=(t);
return *this;
}
template <typename T> auto operator= (T&& t)
-> typename std::enable_if< detail::in_variant<T, GRunArgBase>::value, cv::GRunArg>::type&
{
GRunArgBase::operator=(std::move(t));
return *this;
}
};
using GRunArgs = std::vector<GRunArg>;
// TODO: Think about the addition operator
@@ -124,11 +186,13 @@ namespace gapi
namespace wip
{
/**
* @brief This aggregate type represents all types which G-API can handle (via variant).
* @brief This aggregate type represents all types which G-API can
* handle (via variant).
*
* It only exists to overcome C++ language limitations (where a `using`-defined class can't be forward-declared).
* It only exists to overcome C++ language limitations (where a
* `using`-defined class can't be forward-declared).
*/
struct Data: public GRunArg
struct GAPI_EXPORTS Data: public GRunArg
{
using GRunArg::GRunArg;
template <typename T>
@@ -144,7 +208,9 @@ using GRunArgP = util::variant<
cv::UMat*,
#endif // !defined(GAPI_STANDALONE)
cv::Mat*,
cv::RMat*,
cv::Scalar*,
cv::MediaFrame*,
cv::detail::VectorRef,
cv::detail::OpaqueRef
>;

View File

@@ -284,6 +284,14 @@ namespace detail
return static_cast<VectorRefT<T>&>(*m_ref).rref();
}
// Check if was created for/from std::vector<T>
template <typename T> bool holds() const
{
if (!m_ref) return false;
using U = typename std::decay<T>::type;
return dynamic_cast<VectorRefT<U>*>(m_ref.get()) != nullptr;
}
void mov(VectorRef &v)
{
m_ref->mov(*v.m_ref);
@@ -341,15 +349,18 @@ public:
explicit GArray(detail::GArrayU &&ref) // GArrayU-based constructor
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
detail::GArrayU strip() const { return m_ref; }
/// @private
detail::GArrayU strip() const {
return m_ref;
}
/// @private
static void VCtor(detail::VectorRef& vref) {
vref.reset<HT>();
}
private:
static void VCTor(detail::VectorRef& vref) {
vref.reset<HT>();
vref.storeKind<HT>();
}
void putDetails() {
m_ref.setConstructFcn(&VCTor);
m_ref.setConstructFcn(&VCtor);
m_ref.specifyType<HT>(); // FIXME: to unify those 2 to avoid excessive dynamic_cast
m_ref.storeKind<HT>(); //
}
@@ -357,6 +368,8 @@ private:
detail::GArrayU m_ref;
};
using GArrayP2f = GArray<cv::Point2f>;
/** @} */
} // namespace cv

View File

@@ -11,6 +11,7 @@
#include <opencv2/gapi/garg.hpp> // GArg
#include <opencv2/gapi/gmat.hpp> // GMat
#include <opencv2/gapi/gscalar.hpp> // GScalar
#include <opencv2/gapi/gframe.hpp> // GFrame
#include <opencv2/gapi/garray.hpp> // GArray<T>
#include <opencv2/gapi/gopaque.hpp> // GOpaque<T>
@@ -41,6 +42,7 @@ public:
GMat yield (int output = 0);
GMatP yieldP (int output = 0);
GScalar yieldScalar(int output = 0);
GFrame yieldFrame (int output = 0);
template<class T> GArray<T> yieldArray(int output = 0)
{
@@ -56,11 +58,16 @@ public:
Priv& priv();
const Priv& priv() const;
protected:
std::shared_ptr<Priv> m_priv;
// GKernel and params can be modified, it's needed for infer<Generic>,
// because information about output shapes doesn't exist in compile time
GKernel& kernel();
cv::util::any& params();
void setArgs(std::vector<GArg> &&args);
protected:
std::shared_ptr<Priv> m_priv;
// Public versions return a typed array or opaque, those are implementation details
detail::GArrayU yieldArray(int output = 0);
detail::GOpaqueU yieldOpaque(int output = 0);

View File

@@ -19,6 +19,7 @@
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/own/assert.hpp>
#include <opencv2/gapi/render/render_types.hpp>
#include <opencv2/gapi/s11n/base.hpp>
namespace cv {
@@ -44,12 +45,16 @@ namespace detail
CV_BOOL, // bool user G-API data
CV_INT, // int user G-API data
CV_DOUBLE, // double user G-API data
CV_FLOAT, // float user G-API data
CV_UINT64, // uint64_t user G-API data
CV_STRING, // std::string user G-API data
CV_POINT, // cv::Point user G-API data
CV_POINT2F, // cv::Point2f user G-API data
CV_SIZE, // cv::Size user G-API data
CV_RECT, // cv::Rect user G-API data
CV_SCALAR, // cv::Scalar user G-API data
CV_MAT, // cv::Mat user G-API data
CV_PRIM, // cv::gapi::wip::draw::Prim user G-API data
CV_DRAW_PRIM, // cv::gapi::wip::draw::Prim user G-API data
};
// Type traits helper which simplifies the extraction of kind from type
@@ -57,19 +62,24 @@ namespace detail
template<typename T> struct GOpaqueTraits { static constexpr const OpaqueKind kind = OpaqueKind::CV_UNKNOWN; };
template<> struct GOpaqueTraits<int> { static constexpr const OpaqueKind kind = OpaqueKind::CV_INT; };
template<> struct GOpaqueTraits<double> { static constexpr const OpaqueKind kind = OpaqueKind::CV_DOUBLE; };
template<> struct GOpaqueTraits<cv::Size> { static constexpr const OpaqueKind kind = OpaqueKind::CV_SIZE; };
template<> struct GOpaqueTraits<float> { static constexpr const OpaqueKind kind = OpaqueKind::CV_FLOAT; };
template<> struct GOpaqueTraits<uint64_t> { static constexpr const OpaqueKind kind = OpaqueKind::CV_UINT64; };
template<> struct GOpaqueTraits<bool> { static constexpr const OpaqueKind kind = OpaqueKind::CV_BOOL; };
template<> struct GOpaqueTraits<std::string> { static constexpr const OpaqueKind kind = OpaqueKind::CV_STRING; };
template<> struct GOpaqueTraits<cv::Size> { static constexpr const OpaqueKind kind = OpaqueKind::CV_SIZE; };
template<> struct GOpaqueTraits<cv::Scalar> { static constexpr const OpaqueKind kind = OpaqueKind::CV_SCALAR; };
template<> struct GOpaqueTraits<cv::Point> { static constexpr const OpaqueKind kind = OpaqueKind::CV_POINT; };
template<> struct GOpaqueTraits<cv::Point2f> { static constexpr const OpaqueKind kind = OpaqueKind::CV_POINT2F; };
template<> struct GOpaqueTraits<cv::Mat> { static constexpr const OpaqueKind kind = OpaqueKind::CV_MAT; };
template<> struct GOpaqueTraits<cv::Rect> { static constexpr const OpaqueKind kind = OpaqueKind::CV_RECT; };
template<> struct GOpaqueTraits<cv::GMat> { static constexpr const OpaqueKind kind = OpaqueKind::CV_MAT; };
template<> struct GOpaqueTraits<cv::gapi::wip::draw::Prim>
{ static constexpr const OpaqueKind kind = OpaqueKind::CV_PRIM; };
// GArray is not supporting bool type for now due to difference in std::vector<bool> implementation
using GOpaqueTraitsArrayTypes = std::tuple<int, double, cv::Size, cv::Scalar, cv::Point, cv::Mat, cv::Rect, cv::gapi::wip::draw::Prim>;
{ static constexpr const OpaqueKind kind = OpaqueKind::CV_DRAW_PRIM; };
using GOpaqueTraitsArrayTypes = std::tuple<int, double, float, uint64_t, bool, std::string, cv::Size, cv::Scalar, cv::Point, cv::Point2f,
cv::Mat, cv::Rect, cv::gapi::wip::draw::Prim>;
// GOpaque is not supporting cv::Mat and cv::Scalar since there are GScalar and GMat types
using GOpaqueTraitsOpaqueTypes = std::tuple<bool, int, double, cv::Size, cv::Point, cv::Rect, cv::gapi::wip::draw::Prim>;
using GOpaqueTraitsOpaqueTypes = std::tuple<int, double, float, uint64_t, bool, std::string, cv::Size, cv::Point, cv::Point2f, cv::Rect,
cv::gapi::wip::draw::Prim>;
} // namespace detail
// This definition is here because it is reused by both public(?) and internal
@@ -87,6 +97,15 @@ enum class GShape: int
GFRAME,
};
namespace gapi {
namespace s11n {
namespace detail {
template<typename T> struct wrap_serialize;
} // namespace detail
} // namespace s11n
} // namespace gapi
struct GCompileArg;
namespace detail {
@@ -132,7 +151,7 @@ namespace detail {
* passed in (a variadic template parameter pack) into a vector of
* cv::GCompileArg objects.
*/
struct GAPI_EXPORTS_W_SIMPLE GCompileArg
struct GCompileArg
{
public:
// NB: Required for pythnon bindings
@@ -144,6 +163,9 @@ public:
template<typename T, typename std::enable_if<!detail::is_compile_arg<T>::value, int>::type = 0>
explicit GCompileArg(T &&t)
: tag(detail::CompileArgTag<typename std::decay<T>::type>::tag())
, serializeF(cv::gapi::s11n::detail::has_S11N_spec<T>::value ?
&cv::gapi::s11n::detail::wrap_serialize<T>::serialize :
nullptr)
, arg(t)
{
}
@@ -158,7 +180,16 @@ public:
return util::any_cast<T>(arg);
}
void serialize(cv::gapi::s11n::IOStream& os) const
{
if (serializeF)
{
serializeF(os, *this);
}
}
private:
std::function<void(cv::gapi::s11n::IOStream&, const GCompileArg&)> serializeF;
util::any arg;
};
@@ -191,6 +222,19 @@ inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args)
}
return cv::util::optional<T>();
}
namespace s11n {
namespace detail {
template<typename T> struct wrap_serialize
{
static void serialize(IOStream& os, const GCompileArg& arg)
{
using DT = typename std::decay<T>::type;
S11N<DT>::serialize(os, arg.get<DT>());
}
};
} // namespace detail
} // namespace s11n
} // namespace gapi
/**

View File

@@ -37,14 +37,12 @@ namespace detail
}
// Forward-declare the serialization objects
namespace gimpl {
namespace gapi {
namespace s11n {
namespace I {
struct IStream;
struct OStream;
} // namespace I
struct IIStream;
struct IOStream;
} // namespace s11n
} // namespace gimpl
} // namespace gapi
/**
* \addtogroup gapi_main_classes
@@ -259,6 +257,9 @@ public:
*/
void apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {}); // Arg-to-arg overload
/// @private -- Exclude this function from OpenCV documentation
GAPI_WRAP GRunArgs apply(GRunArgs &&ins, GCompileArgs &&args = {});
/// @private -- Exclude this function from OpenCV documentation
void apply(const std::vector<cv::Mat>& ins, // Compatibility overload
const std::vector<cv::Mat>& outs,
@@ -286,7 +287,7 @@ public:
* @param args compilation arguments for underlying compilation
* process.
*/
GAPI_WRAP void apply(cv::Mat in, CV_OUT cv::Scalar &out, GCompileArgs &&args = {}); // Unary overload (scalar)
void apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args = {}); // Unary overload (scalar)
/**
* @brief Execute a binary computation (with compilation on the fly)
@@ -298,7 +299,7 @@ public:
* @param args compilation arguments for underlying compilation
* process.
*/
GAPI_WRAP void apply(cv::Mat in1, cv::Mat in2, CV_OUT cv::Mat &out, GCompileArgs &&args = {}); // Binary overload
void apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args = {}); // Binary overload
/**
* @brief Execute an binary computation (with compilation on the fly)
@@ -435,7 +436,7 @@ public:
*
* @sa @ref gapi_compile_args
*/
GStreamingCompiled compileStreaming(GMetaArgs &&in_metas, GCompileArgs &&args = {});
GAPI_WRAP GStreamingCompiled compileStreaming(GMetaArgs &&in_metas, GCompileArgs &&args = {});
/**
* @brief Compile the computation for streaming mode.
@@ -456,7 +457,7 @@ public:
*
* @sa @ref gapi_compile_args
*/
GStreamingCompiled compileStreaming(GCompileArgs &&args = {});
GAPI_WRAP GStreamingCompiled compileStreaming(GCompileArgs &&args = {});
// 2. Direct metadata version
/**
@@ -506,9 +507,9 @@ public:
/// @private
const Priv& priv() const;
/// @private
explicit GComputation(cv::gimpl::s11n::I::IStream &);
explicit GComputation(cv::gapi::s11n::IIStream &);
/// @private
void serialize(cv::gimpl::s11n::I::OStream &) const;
void serialize(cv::gapi::s11n::IOStream &) const;
protected:
@@ -528,6 +529,7 @@ protected:
GCompileArgs comp_args = std::get<sizeof...(Ts)-1>(meta_and_compile_args);
return compileStreaming(std::move(meta_args), std::move(comp_args));
}
void recompile(GMetaArgs&& in_metas, GCompileArgs &&args);
/// @private
std::shared_ptr<Priv> m_priv;
};

View File

@@ -42,16 +42,29 @@ private:
};
/** @} */
enum class MediaFormat: int
{
BGR = 0,
NV12,
};
/**
* \addtogroup gapi_meta_args
* @{
*/
struct GAPI_EXPORTS GFrameDesc
{
MediaFormat fmt;
cv::Size size;
bool operator== (const GFrameDesc &) const;
};
static inline GFrameDesc empty_gframe_desc() { return GFrameDesc{}; }
/** @} */
class MediaFrame;
GAPI_EXPORTS GFrameDesc descr_of(const MediaFrame &frame);
GAPI_EXPORTS std::ostream& operator<<(std::ostream& os, const cv::GFrameDesc &desc);
} // namespace cv

View File

@@ -26,8 +26,16 @@
namespace cv {
using GShapes = std::vector<GShape>;
using GKinds = std::vector<cv::detail::OpaqueKind>;
struct GTypeInfo
{
GShape shape;
cv::detail::OpaqueKind kind;
};
using GShapes = std::vector<GShape>;
using GKinds = std::vector<cv::detail::OpaqueKind>;
using GCtors = std::vector<detail::HostCtor>;
using GTypesInfo = std::vector<GTypeInfo>;
// GKernel describes kernel API to the system
// FIXME: add attributes of a kernel, (e.g. number and types
@@ -41,6 +49,7 @@ struct GAPI_EXPORTS GKernel
M outMeta; // generic adaptor to API::outMeta(...)
GShapes outShapes; // types (shapes) kernel's outputs
GKinds inKinds; // kinds of kernel's inputs (fixme: below)
GCtors outCtors; // captured constructors for template output types
};
// TODO: It's questionable if inKinds should really be here. Instead,
// this information could come from meta.
@@ -60,30 +69,31 @@ namespace detail
// yield() is used in graph construction time as a generic method to obtain
// lazy "return value" of G-API operations
//
namespace
template<typename T> struct Yield;
template<> struct Yield<cv::GMat>
{
template<typename T> struct Yield;
template<> struct Yield<cv::GMat>
{
static inline cv::GMat yield(cv::GCall &call, int i) { return call.yield(i); }
};
template<> struct Yield<cv::GMatP>
{
static inline cv::GMatP yield(cv::GCall &call, int i) { return call.yieldP(i); }
};
template<> struct Yield<cv::GScalar>
{
static inline cv::GScalar yield(cv::GCall &call, int i) { return call.yieldScalar(i); }
};
template<typename U> struct Yield<cv::GArray<U> >
{
static inline cv::GArray<U> yield(cv::GCall &call, int i) { return call.yieldArray<U>(i); }
};
template<typename U> struct Yield<cv::GOpaque<U> >
{
static inline cv::GOpaque<U> yield(cv::GCall &call, int i) { return call.yieldOpaque<U>(i); }
};
} // anonymous namespace
static inline cv::GMat yield(cv::GCall &call, int i) { return call.yield(i); }
};
template<> struct Yield<cv::GMatP>
{
static inline cv::GMatP yield(cv::GCall &call, int i) { return call.yieldP(i); }
};
template<> struct Yield<cv::GScalar>
{
static inline cv::GScalar yield(cv::GCall &call, int i) { return call.yieldScalar(i); }
};
template<typename U> struct Yield<cv::GArray<U> >
{
static inline cv::GArray<U> yield(cv::GCall &call, int i) { return call.yieldArray<U>(i); }
};
template<typename U> struct Yield<cv::GOpaque<U> >
{
static inline cv::GOpaque<U> yield(cv::GCall &call, int i) { return call.yieldOpaque<U>(i); }
};
template<> struct Yield<GFrame>
{
static inline cv::GFrame yield(cv::GCall &call, int i) { return call.yieldFrame(i); }
};
////////////////////////////////////////////////////////////////////////////
// Helper classes which brings outputMeta() marshalling to kernel
@@ -95,11 +105,12 @@ namespace detail
template<typename T> struct MetaType;
template<> struct MetaType<cv::GMat> { using type = GMatDesc; };
template<> struct MetaType<cv::GMatP> { using type = GMatDesc; };
template<> struct MetaType<cv::GFrame> { using type = GMatDesc; };
template<> struct MetaType<cv::GFrame> { using type = GFrameDesc; };
template<> struct MetaType<cv::GScalar> { using type = GScalarDesc; };
template<typename U> struct MetaType<cv::GArray<U> > { using type = GArrayDesc; };
template<typename U> struct MetaType<cv::GOpaque<U> > { using type = GOpaqueDesc; };
template<typename T> struct MetaType { using type = T; }; // opaque args passed as-is
// FIXME: Move it to type traits?
// 2. Hacky test based on MetaType to check if we operate on G-* type or not
template<typename T> using is_nongapi_type = std::is_same<T, typename MetaType<T>::type>;
@@ -214,7 +225,8 @@ public:
, K::tag()
, &K::getOutMeta
, {detail::GTypeTraits<R>::shape...}
, {detail::GTypeTraits<Args>::op_kind...}});
, {detail::GTypeTraits<Args>::op_kind...}
, {detail::GObtainCtor<R>::get()...}});
call.pass(args...); // TODO: std::forward() here?
return yield(call, typename detail::MkSeq<sizeof...(R)>::type());
}
@@ -231,15 +243,14 @@ public:
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R>;
static_assert(!cv::detail::contains<GFrame, OutArgs>::value, "Values of GFrame type can't be used as operation outputs");
static R on(Args... args)
{
cv::GCall call(GKernel{ K::id()
, K::tag()
, &K::getOutMeta
, {detail::GTypeTraits<R>::shape}
, {detail::GTypeTraits<Args>::op_kind...}});
, {detail::GTypeTraits<Args>::op_kind...}
, {detail::GObtainCtor<R>::get()}});
call.pass(args...);
return detail::Yield<R>::yield(call, 0);
}
@@ -458,11 +469,6 @@ namespace gapi {
std::vector<GTransform> m_transformations;
protected:
/// @private
// Check if package contains ANY implementation of a kernel API
// by API textual id.
bool includesAPI(const std::string &id) const;
/// @private
// Remove ALL implementations of the given API (identified by ID)
void removeAPI(const std::string &id);
@@ -565,6 +571,9 @@ namespace gapi {
return includesAPI(KAPI::id());
}
/// @private
bool includesAPI(const std::string &id) const;
// FIXME: The below comment is wrong, and who needs this function?
/**
* @brief Find a kernel (by its API)

View File

@@ -65,6 +65,8 @@ public:
using GMat::GMat;
};
class RMat;
/** @} */
/**
@@ -113,6 +115,8 @@ struct GAPI_EXPORTS GMatDesc
// and as a 3-channel planar mat with height divided by 3)
bool canDescribe(const cv::Mat& mat) const;
bool canDescribe(const cv::RMat& mat) const;
// Meta combinator: return a new GMatDesc which differs in size by delta
// (all other fields are taken unchanged from this GMatDesc)
// FIXME: a better name?
@@ -199,6 +203,27 @@ struct GAPI_EXPORTS GMatDesc
static inline GMatDesc empty_gmat_desc() { return GMatDesc{-1,-1,{-1,-1}}; }
namespace gapi { namespace detail {
/** Checks GMatDesc fields if the passed matrix is a set of n-dimentional points.
@param in GMatDesc to check.
@param n expected dimensionality.
@return the amount of points. In case input matrix can't be described as vector of points
of expected dimensionality, returns -1.
*/
int checkVector(const GMatDesc& in, const size_t n);
/** @overload
Checks GMatDesc fields if the passed matrix can be described as a set of points of any
dimensionality.
@return array of two elements in form of std::vector<int>: the amount of points
and their calculated dimensionality. In case input matrix can't be described as vector of points,
returns {-1, -1}.
*/
std::vector<int> checkVector(const GMatDesc& in);
}} // namespace gapi::detail
#if !defined(GAPI_STANDALONE)
GAPI_EXPORTS GMatDesc descr_of(const cv::UMat &mat);
#endif // !defined(GAPI_STANDALONE)
@@ -209,6 +234,8 @@ namespace gapi { namespace own {
GAPI_EXPORTS GMatDesc descr_of(const Mat &mat);
}}//gapi::own
GAPI_EXPORTS GMatDesc descr_of(const RMat &mat);
#if !defined(GAPI_STANDALONE)
GAPI_EXPORTS GMatDesc descr_of(const cv::Mat &mat);
#else

View File

@@ -18,6 +18,7 @@
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/gframe.hpp>
namespace cv
{
@@ -38,6 +39,7 @@ using GMetaArg = util::variant
, GScalarDesc
, GArrayDesc
, GOpaqueDesc
, GFrameDesc
>;
GAPI_EXPORTS std::ostream& operator<<(std::ostream& os, const GMetaArg &);

View File

@@ -15,6 +15,7 @@
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/gapi/util/variant.hpp>
#include <opencv2/gapi/util/throw.hpp>
#include <opencv2/gapi/util/type_traits.hpp>
@@ -119,6 +120,7 @@ namespace detail
virtual void mov(BasicOpaqueRef &ref) = 0;
virtual const void* ptr() const = 0;
virtual void set(const cv::util::any &a) = 0;
};
template<typename T> class OpaqueRefT final: public BasicOpaqueRef
@@ -212,6 +214,10 @@ namespace detail
}
virtual const void* ptr() const override { return &rref(); }
virtual void set(const cv::util::any &a) override {
wref() = util::any_cast<T>(a);
}
};
// This class strips type information from OpaqueRefT<> and makes it usable
@@ -240,7 +246,7 @@ namespace detail
// FIXME: probably won't work with const object
explicit OpaqueRef(T&& obj) :
m_ref(new OpaqueRefT<util::decay_t<T>>(std::forward<T>(obj))),
m_kind(GOpaqueTraits<T>::kind) {}
m_kind(GOpaqueTraits<util::decay_t<T>>::kind) {}
cv::detail::OpaqueKind getKind() const
{
@@ -285,6 +291,13 @@ namespace detail
// May be used to uniquely identify this object internally
const void *ptr() const { return m_ref->ptr(); }
// Introduced for in-graph meta handling
OpaqueRef& operator= (const cv::util::any &a)
{
m_ref->set(a);
return *this;
}
};
} // namespace detail
@@ -295,25 +308,27 @@ namespace detail
template<typename T> class GOpaque
{
public:
GOpaque() { putDetails(); } // Empty constructor
explicit GOpaque(detail::GOpaqueU &&ref) // GOpaqueU-based constructor
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
detail::GOpaqueU strip() const { return m_ref; }
private:
// Host type (or Flat type) - the type this GOpaque is actually
// specified to.
using HT = typename detail::flatten_g<util::decay_t<T>>::type;
static void CTor(detail::OpaqueRef& ref) {
ref.reset<HT>();
ref.storeKind<HT>();
GOpaque() { putDetails(); } // Empty constructor
explicit GOpaque(detail::GOpaqueU &&ref) // GOpaqueU-based constructor
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
/// @private
detail::GOpaqueU strip() const {
return m_ref;
}
/// @private
static void Ctor(detail::OpaqueRef& ref) {
ref.reset<HT>();
}
private:
void putDetails() {
m_ref.setConstructFcn(&CTor);
m_ref.specifyType<HT>(); // FIXME: to unify those 2 to avoid excessive dynamic_cast
m_ref.storeKind<HT>(); //
m_ref.setConstructFcn(&Ctor);
m_ref.specifyType<HT>();
m_ref.storeKind<HT>();
}
detail::GOpaqueU m_ref;

View File

@@ -135,7 +135,7 @@ GRunArg value_of(const GOrigin &origin);
// Transform run-time computation arguments into a collection of metadata
// extracted from that arguments
GMetaArg GAPI_EXPORTS descr_of(const GRunArg &arg );
GMetaArgs GAPI_EXPORTS descr_of(const GRunArgs &args);
GMetaArgs GAPI_EXPORTS_W descr_of(const GRunArgs &args);
// Transform run-time operation result argument into metadata extracted from that argument
// Used to compare the metadata, which generated at compile time with the metadata result operation in run time

View File

@@ -8,15 +8,99 @@
#ifndef OPENCV_GAPI_GSTREAMING_COMPILED_HPP
#define OPENCV_GAPI_GSTREAMING_COMPILED_HPP
#include <memory>
#include <vector>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/own/assert.hpp>
#include <opencv2/gapi/util/optional.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/streaming/source.hpp>
namespace cv {
template<class T> using optional = cv::util::optional<T>;
namespace detail {
template<typename T> struct wref_spec {
using type = T;
};
template<typename T> struct wref_spec<std::vector<T> > {
using type = T;
};
template<typename RefHolder>
struct OptRef {
struct OptHolder {
virtual void mov(RefHolder &h) = 0;
virtual void reset() = 0;
virtual ~OptHolder() = default;
using Ptr = std::shared_ptr<OptHolder>;
};
template<class T> struct Holder final: OptHolder {
std::reference_wrapper<cv::optional<T> > m_opt_ref;
explicit Holder(cv::optional<T>& opt) : m_opt_ref(std::ref(opt)) {
}
virtual void mov(RefHolder &h) override {
using U = typename wref_spec<T>::type;
m_opt_ref.get() = cv::util::make_optional(std::move(h.template wref<U>()));
}
virtual void reset() override {
m_opt_ref.get().reset();
}
};
template<class T>
explicit OptRef(cv::optional<T>& t) : m_opt{new Holder<T>(t)} {}
void mov(RefHolder &h) { m_opt->mov(h); }
void reset() { m_opt->reset();}
private:
typename OptHolder::Ptr m_opt;
};
using OptionalVectorRef = OptRef<cv::detail::VectorRef>;
using OptionalOpaqueRef = OptRef<cv::detail::OpaqueRef>;
} // namespace detail
// TODO: Keep it in sync with GRunArgP (derive the type automatically?)
using GOptRunArgP = util::variant<
optional<cv::Mat>*,
optional<cv::RMat>*,
optional<cv::Scalar>*,
cv::detail::OptionalVectorRef,
cv::detail::OptionalOpaqueRef
>;
using GOptRunArgsP = std::vector<GOptRunArgP>;
namespace detail {
template<typename T> inline GOptRunArgP wrap_opt_arg(optional<T>& arg) {
// By default, T goes to an OpaqueRef. All other types are specialized
return GOptRunArgP{OptionalOpaqueRef(arg)};
}
template<typename T> inline GOptRunArgP wrap_opt_arg(optional<std::vector<T> >& arg) {
return GOptRunArgP{OptionalVectorRef(arg)};
}
template<> inline GOptRunArgP wrap_opt_arg(optional<cv::Mat> &m) {
return GOptRunArgP{&m};
}
template<> inline GOptRunArgP wrap_opt_arg(optional<cv::Scalar> &s) {
return GOptRunArgP{&s};
}
} // namespace detail
// Now cv::gout() may produce an empty vector (see "dynamic graphs"), so
// there may be a conflict between these two. State here that Opt version
// _must_ have at least one input for this overload
template<typename T, typename... Ts>
inline GOptRunArgsP gout(optional<T>&arg, optional<Ts>&... args)
{
return GOptRunArgsP{ detail::wrap_opt_arg(arg), detail::wrap_opt_arg(args)... };
}
/**
* \addtogroup gapi_main_classes
* @{
@@ -49,11 +133,11 @@ namespace cv {
*
* @sa GCompiled
*/
class GAPI_EXPORTS GStreamingCompiled
class GAPI_EXPORTS_W_SIMPLE GStreamingCompiled
{
public:
class GAPI_EXPORTS Priv;
GStreamingCompiled();
GAPI_WRAP GStreamingCompiled();
// FIXME: More overloads?
/**
@@ -96,7 +180,7 @@ public:
* @param ins vector of inputs to process.
* @sa gin
*/
void setSource(GRunArgs &&ins);
GAPI_WRAP void setSource(GRunArgs &&ins);
/**
* @brief Specify an input video stream for a single-input
@@ -109,7 +193,23 @@ public:
* @param s a shared pointer to IStreamSource representing the
* input video stream.
*/
void setSource(const gapi::wip::IStreamSource::Ptr& s);
GAPI_WRAP void setSource(const gapi::wip::IStreamSource::Ptr& s);
/**
* @brief Constructs and specifies an input video stream for a
* single-input computation pipeline with the given parameters.
*
* Throws if pipeline is already running. Use stop() and then
* setSource() to run the graph on a new video stream.
*
* @overload
* @param args arguments used to contruct and initialize a stream
* source.
*/
template<typename T, typename... Args>
void setSource(Args&&... args) {
setSource(cv::gapi::wip::make_src<T>(std::forward<Args>(args)...));
}
/**
* @brief Start the pipeline execution.
@@ -126,7 +226,7 @@ public:
* start()/stop()/setSource() may be called on the same object in
* multiple threads in your application.
*/
void start();
GAPI_WRAP void start();
/**
* @brief Get the next processed frame from the pipeline.
@@ -150,6 +250,47 @@ public:
*/
bool pull(cv::GRunArgsP &&outs);
// NB: Used from python
GAPI_WRAP std::tuple<bool, cv::GRunArgs> pull();
/**
* @brief Get some next available data from the pipeline.
*
* This method takes a vector of cv::optional object. An object is
* assigned to some value if this value is available (ready) at
* the time of the call, and resets the object to empty() if it is
* not.
*
* This is a blocking method which guarantees that some data has
* been written to the output vector on return.
*
* Using this method only makes sense if the graph has
* desynchronized parts (see cv::gapi::desync). If there is no
* desynchronized parts in the graph, the behavior of this
* method is identical to the regular pull() (all data objects are
* produced synchronously in the output vector).
*
* Use gout() to create an output parameter vector.
*
* Output vectors must have the same number of elements as defined
* in the cv::GComputation protocol (at the moment of its
* construction). Shapes of elements also must conform to protocol
* (e.g. cv::optional<cv::Mat> needs to be passed where cv::GMat
* has been declared as output, and so on). Run-time exception is
* generated on type mismatch.
*
* This method writes new data into objects passed via output
* vector. If there is no data ready yet, this method blocks. Use
* try_pull() if you need a non-blocking version.
*
* @param outs vector of output parameters to obtain.
* @return true if next result has been obtained,
* false marks end of the stream.
*
* @sa cv::gapi::desync
*/
bool pull(cv::GOptRunArgsP &&outs);
/**
* @brief Try to get the next processed frame from the pipeline.
*
@@ -172,7 +313,7 @@ public:
*
* Throws if the pipeline is not running.
*/
void stop();
GAPI_WRAP void stop();
/**
* @brief Test if the pipeline is running.
@@ -184,7 +325,7 @@ public:
*
* @return true if the current stream is not over yet.
*/
bool running() const;
GAPI_WRAP bool running() const;
/// @private
Priv& priv();

View File

@@ -17,6 +17,7 @@
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/gframe.hpp>
#include <opencv2/gapi/streaming/source.hpp>
#include <opencv2/gapi/media.hpp>
#include <opencv2/gapi/gcommon.hpp>
namespace cv
@@ -67,7 +68,7 @@ namespace detail
template<> struct GTypeTraits<cv::GFrame>
{
static constexpr const ArgKind kind = ArgKind::GFRAME;
static constexpr const GShape shape = GShape::GMAT;
static constexpr const GShape shape = GShape::GFRAME;
static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
};
template<> struct GTypeTraits<cv::GScalar>
@@ -121,9 +122,11 @@ namespace detail
template<> struct GTypeOf<cv::UMat> { using type = cv::GMat; };
#endif // !defined(GAPI_STANDALONE)
template<> struct GTypeOf<cv::Mat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::RMat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::Scalar> { using type = cv::GScalar; };
template<typename U> struct GTypeOf<std::vector<U> > { using type = cv::GArray<U>; };
template<typename U> struct GTypeOf { using type = cv::GOpaque<U>;};
template<> struct GTypeOf<cv::MediaFrame> { using type = cv::GFrame; };
// FIXME: This is not quite correct since IStreamSource may produce not only Mat but also Scalar
// and vector data. TODO: Extend the type dispatching on these types too.
template<> struct GTypeOf<cv::gapi::wip::IStreamSource::Ptr> { using type = cv::GMat;};
@@ -188,6 +191,29 @@ namespace detail
template<typename T> using wrap_gapi_helper = WrapValue<typename std::decay<T>::type>;
template<typename T> using wrap_host_helper = WrapValue<typename std::decay<g_type_of_t<T> >::type>;
// Union type for various user-defined type constructors (GArray<T>,
// GOpaque<T>, etc)
//
// TODO: Replace construct-only API with a more generic one (probably
// with bits of introspection)
//
// Not required for non-user-defined types (GMat, GScalar, etc)
using HostCtor = util::variant
< util::monostate
, detail::ConstructVec
, detail::ConstructOpaque
>;
template<typename T> struct GObtainCtor {
static HostCtor get() { return HostCtor{}; }
};
template<typename T> struct GObtainCtor<GArray<T> > {
static HostCtor get() { return HostCtor{ConstructVec{&GArray<T>::VCtor}}; };
};
template<typename T> struct GObtainCtor<GOpaque<T> > {
static HostCtor get() { return HostCtor{ConstructOpaque{&GOpaque<T>::Ctor}}; };
};
} // namespace detail
} // namespace cv

View File

@@ -21,14 +21,36 @@
@{
@defgroup gapi_filters Graph API: Image filters
@defgroup gapi_colorconvert Graph API: Converting image from one color space to another
@defgroup gapi_feature Graph API: Image Feature Detection
@defgroup gapi_shape Graph API: Image Structural Analysis and Shape Descriptors
@}
*/
namespace {
void validateFindingContoursMeta(const int depth, const int chan, const int mode)
{
GAPI_Assert(chan == 1);
switch (mode)
{
case cv::RETR_CCOMP:
GAPI_Assert(depth == CV_8U || depth == CV_32S);
break;
case cv::RETR_FLOODFILL:
GAPI_Assert(depth == CV_32S);
break;
default:
GAPI_Assert(depth == CV_8U);
break;
}
}
} // anonymous namespace
namespace cv { namespace gapi {
namespace imgproc {
using GMat2 = std::tuple<GMat,GMat>;
using GMat3 = std::tuple<GMat,GMat,GMat>; // FIXME: how to avoid this?
using GFindContoursOutput = std::tuple<GArray<GArray<Point>>,GArray<Vec4i>>;
G_TYPED_KERNEL(GFilter2D, <GMat(GMat,int,Mat,Point,Scalar,int,Scalar)>,"org.opencv.imgproc.filters.filter2D") {
static GMatDesc outMeta(GMatDesc in, int ddepth, Mat, Point, Scalar, int, Scalar) {
@@ -78,6 +100,14 @@ namespace imgproc {
}
};
G_TYPED_KERNEL(GMorphologyEx, <GMat(GMat,MorphTypes,Mat,Point,int,BorderTypes,Scalar)>,
"org.opencv.imgproc.filters.morphologyEx") {
static GMatDesc outMeta(const GMatDesc &in, MorphTypes, Mat, Point, int,
BorderTypes, Scalar) {
return in;
}
};
G_TYPED_KERNEL(GSobel, <GMat(GMat,int,int,int,int,double,double,int,Scalar)>, "org.opencv.imgproc.filters.sobel") {
static GMatDesc outMeta(GMatDesc in, int ddepth, int, int, int, double, double, int, Scalar) {
return in.withDepth(ddepth);
@@ -110,7 +140,7 @@ namespace imgproc {
}
};
G_TYPED_KERNEL(GCanny, <GMat(GMat,double,double,int,bool)>, "org.opencv.imgproc.canny"){
G_TYPED_KERNEL(GCanny, <GMat(GMat,double,double,int,bool)>, "org.opencv.imgproc.feature.canny"){
static GMatDesc outMeta(GMatDesc in, double, double, int, bool) {
return in.withType(CV_8U, 1);
}
@@ -118,12 +148,164 @@ namespace imgproc {
G_TYPED_KERNEL(GGoodFeatures,
<cv::GArray<cv::Point2f>(GMat,int,double,double,Mat,int,bool,double)>,
"org.opencv.imgproc.goodFeaturesToTrack") {
"org.opencv.imgproc.feature.goodFeaturesToTrack") {
static GArrayDesc outMeta(GMatDesc, int, double, double, const Mat&, int, bool, double) {
return empty_array_desc();
}
};
using RetrMode = RetrievalModes;
using ContMethod = ContourApproximationModes;
G_TYPED_KERNEL(GFindContours, <GArray<GArray<Point>>(GMat,RetrMode,ContMethod,GOpaque<Point>)>,
"org.opencv.imgproc.shape.findContours")
{
static GArrayDesc outMeta(GMatDesc in, RetrMode mode, ContMethod, GOpaqueDesc)
{
validateFindingContoursMeta(in.depth, in.chan, mode);
return empty_array_desc();
}
};
// FIXME oc: make default value offset = Point()
G_TYPED_KERNEL(GFindContoursNoOffset, <GArray<GArray<Point>>(GMat,RetrMode,ContMethod)>,
"org.opencv.imgproc.shape.findContoursNoOffset")
{
static GArrayDesc outMeta(GMatDesc in, RetrMode mode, ContMethod)
{
validateFindingContoursMeta(in.depth, in.chan, mode);
return empty_array_desc();
}
};
G_TYPED_KERNEL(GFindContoursH,<GFindContoursOutput(GMat,RetrMode,ContMethod,GOpaque<Point>)>,
"org.opencv.imgproc.shape.findContoursH")
{
static std::tuple<GArrayDesc,GArrayDesc>
outMeta(GMatDesc in, RetrMode mode, ContMethod, GOpaqueDesc)
{
validateFindingContoursMeta(in.depth, in.chan, mode);
return std::make_tuple(empty_array_desc(), empty_array_desc());
}
};
// FIXME oc: make default value offset = Point()
G_TYPED_KERNEL(GFindContoursHNoOffset,<GFindContoursOutput(GMat,RetrMode,ContMethod)>,
"org.opencv.imgproc.shape.findContoursHNoOffset")
{
static std::tuple<GArrayDesc,GArrayDesc>
outMeta(GMatDesc in, RetrMode mode, ContMethod)
{
validateFindingContoursMeta(in.depth, in.chan, mode);
return std::make_tuple(empty_array_desc(), empty_array_desc());
}
};
G_TYPED_KERNEL(GBoundingRectMat, <GOpaque<Rect>(GMat)>,
"org.opencv.imgproc.shape.boundingRectMat") {
static GOpaqueDesc outMeta(GMatDesc in) {
if (in.depth == CV_8U)
{
GAPI_Assert(in.chan == 1);
}
else
{
GAPI_Assert (in.depth == CV_32S || in.depth == CV_32F);
int amount = detail::checkVector(in, 2u);
GAPI_Assert(amount != -1 &&
"Input Mat can't be described as vector of 2-dimentional points");
}
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GBoundingRectVector32S, <GOpaque<Rect>(GArray<Point2i>)>,
"org.opencv.imgproc.shape.boundingRectVector32S") {
static GOpaqueDesc outMeta(GArrayDesc) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GBoundingRectVector32F, <GOpaque<Rect>(GArray<Point2f>)>,
"org.opencv.imgproc.shape.boundingRectVector32F") {
static GOpaqueDesc outMeta(GArrayDesc) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine2DMat, <GOpaque<Vec4f>(GMat,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine2DMat") {
static GOpaqueDesc outMeta(GMatDesc in,DistanceTypes,double,double,double) {
int amount = detail::checkVector(in, 2u);
GAPI_Assert(amount != -1 &&
"Input Mat can't be described as vector of 2-dimentional points");
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine2DVector32S,
<GOpaque<Vec4f>(GArray<Point2i>,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine2DVector32S") {
static GOpaqueDesc outMeta(GArrayDesc,DistanceTypes,double,double,double) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine2DVector32F,
<GOpaque<Vec4f>(GArray<Point2f>,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine2DVector32F") {
static GOpaqueDesc outMeta(GArrayDesc,DistanceTypes,double,double,double) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine2DVector64F,
<GOpaque<Vec4f>(GArray<Point2d>,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine2DVector64F") {
static GOpaqueDesc outMeta(GArrayDesc,DistanceTypes,double,double,double) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine3DMat, <GOpaque<Vec6f>(GMat,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine3DMat") {
static GOpaqueDesc outMeta(GMatDesc in,int,double,double,double) {
int amount = detail::checkVector(in, 3u);
GAPI_Assert(amount != -1 &&
"Input Mat can't be described as vector of 3-dimentional points");
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine3DVector32S,
<GOpaque<Vec6f>(GArray<Point3i>,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine3DVector32S") {
static GOpaqueDesc outMeta(GArrayDesc,DistanceTypes,double,double,double) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine3DVector32F,
<GOpaque<Vec6f>(GArray<Point3f>,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine3DVector32F") {
static GOpaqueDesc outMeta(GArrayDesc,DistanceTypes,double,double,double) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GFitLine3DVector64F,
<GOpaque<Vec6f>(GArray<Point3d>,DistanceTypes,double,double,double)>,
"org.opencv.imgproc.shape.fitLine3DVector64F") {
static GOpaqueDesc outMeta(GArrayDesc,DistanceTypes,double,double,double) {
return empty_gopaque_desc();
}
};
G_TYPED_KERNEL(GBGR2RGB, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2rgb") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GRGB2YUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2yuv") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
@@ -136,6 +318,42 @@ namespace imgproc {
}
};
G_TYPED_KERNEL(GBGR2I420, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2i420") {
static GMatDesc outMeta(GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
GAPI_Assert(in.size.height % 2 == 0);
return in.withType(in.depth, 1).withSize(Size(in.size.width, in.size.height * 3 / 2));
}
};
G_TYPED_KERNEL(GRGB2I420, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2i420") {
static GMatDesc outMeta(GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
GAPI_Assert(in.size.height % 2 == 0);
return in.withType(in.depth, 1).withSize(Size(in.size.width, in.size.height * 3 / 2));
}
};
G_TYPED_KERNEL(GI4202BGR, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.i4202bgr") {
static GMatDesc outMeta(GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 1);
GAPI_Assert(in.size.height % 3 == 0);
return in.withType(in.depth, 3).withSize(Size(in.size.width, in.size.height * 2 / 3));
}
};
G_TYPED_KERNEL(GI4202RGB, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.i4202rgb") {
static GMatDesc outMeta(GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 1);
GAPI_Assert(in.size.height % 3 == 0);
return in.withType(in.depth, 3).withSize(Size(in.size.width, in.size.height * 2 / 3));
}
};
G_TYPED_KERNEL(GNV12toRGB, <GMat(GMat, GMat)>, "org.opencv.imgproc.colorconvert.nv12torgb") {
static GMatDesc outMeta(GMatDesc in_y, GMatDesc in_uv) {
GAPI_Assert(in_y.chan == 1);
@@ -230,7 +448,7 @@ namespace imgproc {
}
};
G_TYPED_KERNEL(GNV12toRGBp, <GMatP(GMat,GMat)>, "org.opencv.colorconvert.imgproc.nv12torgbp") {
G_TYPED_KERNEL(GNV12toRGBp, <GMatP(GMat,GMat)>, "org.opencv.imgproc.colorconvert.nv12torgbp") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
@@ -244,7 +462,7 @@ namespace imgproc {
}
};
G_TYPED_KERNEL(GNV12toGray, <GMat(GMat,GMat)>, "org.opencv.colorconvert.imgproc.nv12togray") {
G_TYPED_KERNEL(GNV12toGray, <GMat(GMat,GMat)>, "org.opencv.imgproc.colorconvert.nv12togray") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
@@ -259,7 +477,7 @@ namespace imgproc {
}
};
G_TYPED_KERNEL(GNV12toBGRp, <GMatP(GMat,GMat)>, "org.opencv.colorconvert.imgproc.nv12tobgrp") {
G_TYPED_KERNEL(GNV12toBGRp, <GMatP(GMat,GMat)>, "org.opencv.imgproc.colorconvert.nv12tobgrp") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
@@ -285,10 +503,10 @@ kernel kernelY. The final result is returned.
Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note In case of floating-point computation, rounding to nearest even is procedeed
@note
- In case of floating-point computation, rounding to nearest even is procedeed
if hardware supports it (if not - to nearest value).
@note Function textual ID is "org.opencv.imgproc.filters.sepfilter"
- Function textual ID is "org.opencv.imgproc.filters.sepfilter"
@param src Source image.
@param ddepth desired depth of the destination image (the following combinations of src.depth() and ddepth are supported:
@@ -327,9 +545,9 @@ anchor.y - 1)`.
Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same size and number of channels an input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.filter2D"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.filter2D"
@param src input image.
@param ddepth desired depth of the destination image
@@ -364,9 +582,9 @@ algorithms, and so on). If you need to compute pixel sums over variable-size win
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.boxfilter"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.boxfilter"
@param src Source image.
@param dtype the output image depth (-1 to set the input image data type).
@@ -393,9 +611,9 @@ true, borderType)`.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.blur"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.blur"
@param src Source image.
@param ksize blurring kernel size.
@@ -421,9 +639,9 @@ Output image must have the same type and number of channels an input image.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.gaussianBlur"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.gaussianBlur"
@param src input image;
@param ksize Gaussian kernel size. ksize.width and ksize.height can differ but they both must be
@@ -446,16 +664,16 @@ GAPI_EXPORTS GMat gaussianBlur(const GMat& src, const Size& ksize, double sigmaX
The function smoothes an image using the median filter with the \f$\texttt{ksize} \times
\texttt{ksize}\f$ aperture. Each channel of a multi-channel image is processed independently.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
The median filter uses cv::BORDER_REPLICATE internally to cope with border pixels, see cv::BorderTypes
@note Function textual ID is "org.opencv.imgproc.filters.medianBlur"
- Function textual ID is "org.opencv.imgproc.filters.medianBlur"
@param src input matrix (image)
@param ksize aperture linear size; it must be odd and greater than 1, for example: 3, 5, 7 ...
@sa boxFilter, gaussianBlur
*/
GAPI_EXPORTS GMat medianBlur(const GMat& src, int ksize);
GAPI_EXPORTS_W GMat medianBlur(const GMat& src, int ksize);
/** @brief Erodes an image by using a specific structuring element.
@@ -467,9 +685,9 @@ shape of a pixel neighborhood over which the minimum is taken:
Erosion can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.erode"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.erode"
@param src input image
@param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular
@@ -479,7 +697,7 @@ anchor is at the element center.
@param iterations number of times erosion is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa dilate
@sa dilate, morphologyEx
*/
GAPI_EXPORTS GMat erode(const GMat& src, const Mat& kernel, const Point& anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
@@ -491,7 +709,9 @@ The function erodes the source image using the rectangular structuring element w
Erosion can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.erode"
@param src input image
@param iterations number of times erosion is applied.
@@ -512,9 +732,9 @@ shape of a pixel neighborhood over which the maximum is taken:
Dilation can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.dilate"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.dilate"
@param src input image.
@param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular
@@ -539,9 +759,9 @@ shape of a pixel neighborhood over which the maximum is taken:
Dilation can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.dilate"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.dilate"
@param src input image.
@param iterations number of times dilation is applied.
@@ -554,6 +774,38 @@ GAPI_EXPORTS GMat dilate3x3(const GMat& src, int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue());
/** @brief Performs advanced morphological transformations.
The function can perform advanced morphological transformations using an erosion and dilation as
basic operations.
Any of the operations can be done in-place. In case of multi-channel images, each channel is
processed independently.
@note
- Function textual ID is "org.opencv.imgproc.filters.morphologyEx"
- The number of iterations is the number of times erosion or dilatation operation will be
applied. For instance, an opening operation (#MORPH_OPEN) with two iterations is equivalent to
apply successively: erode -> erode -> dilate -> dilate
(and not erode -> dilate -> erode -> dilate).
@param src Input image.
@param op Type of a morphological operation, see #MorphTypes
@param kernel Structuring element. It can be created using #getStructuringElement.
@param anchor Anchor position within the element. Both negative values mean that the anchor is at
the kernel center.
@param iterations Number of times erosion and dilation are applied.
@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported.
@param borderValue Border value in case of a constant border. The default value has a special
meaning.
@sa dilate, erode, getStructuringElement
*/
GAPI_EXPORTS GMat morphologyEx(const GMat &src, const MorphTypes op, const Mat &kernel,
const Point &anchor = Point(-1,-1),
const int iterations = 1,
const BorderTypes borderType = BORDER_CONSTANT,
const Scalar &borderValue = morphologyDefaultBorderValue());
/** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator.
In all cases except one, the \f$\texttt{ksize} \times \texttt{ksize}\f$ separable kernel is used to
@@ -583,9 +835,9 @@ The second case corresponds to a kernel of:
\f[\vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1}\f]
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.sobel"
@note
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.sobel"
@param src input image.
@param ddepth output image depth, see @ref filter_depths "combinations"; in the case of
@@ -634,11 +886,10 @@ The second case corresponds to a kernel of:
\f[\vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1}\f]
@note First returned matrix correspons to dx derivative while the second one to dy.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.sobelxy"
@note
- First returned matrix correspons to dx derivative while the second one to dy.
- Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
- Function textual ID is "org.opencv.imgproc.filters.sobelxy"
@param src input image.
@param ddepth output image depth, see @ref filter_depths "combinations"; in the case of
@@ -719,6 +970,10 @@ proportional to sigmaSpace.
GAPI_EXPORTS GMat bilateralFilter(const GMat& src, int d, double sigmaColor, double sigmaSpace,
int borderType = BORDER_DEFAULT);
//! @} gapi_filters
//! @addtogroup gapi_feature
//! @{
/** @brief Finds edges in an image using the Canny algorithm.
The function finds edges in the input image and marks them in the output map edges using the
@@ -726,7 +981,7 @@ Canny algorithm. The smallest value between threshold1 and threshold2 is used fo
largest value is used to find initial segments of strong edges. See
<http://en.wikipedia.org/wiki/Canny_edge_detector>
@note Function textual ID is "org.opencv.imgproc.filters.canny"
@note Function textual ID is "org.opencv.imgproc.feature.canny"
@param image 8-bit input image.
@param threshold1 first threshold for the hysteresis procedure.
@@ -757,11 +1012,11 @@ described in @cite Shi94
The function can be used to initialize a point-based tracker of an object.
@note If the function is called with different values A and B of the parameter qualityLevel , and
@note
- If the function is called with different values A and B of the parameter qualityLevel , and
A \> B, the vector of returned corners with qualityLevel=A will be the prefix of the output vector
with qualityLevel=B .
@note Function textual ID is "org.opencv.imgproc.goodFeaturesToTrack"
- Function textual ID is "org.opencv.imgproc.feature.goodFeaturesToTrack"
@param image Input 8-bit or floating-point 32-bit, single-channel image.
@param maxCorners Maximum number of corners to return. If there are more corners than are found,
@@ -784,7 +1039,7 @@ or #cornerMinEigenVal.
@return vector of detected corners.
*/
GAPI_EXPORTS GArray<Point2f> goodFeaturesToTrack(const GMat &image,
GAPI_EXPORTS_W GArray<Point2f> goodFeaturesToTrack(const GMat &image,
int maxCorners,
double qualityLevel,
double minDistance,
@@ -795,6 +1050,8 @@ GAPI_EXPORTS GArray<Point2f> goodFeaturesToTrack(const GMat &image,
/** @brief Equalizes the histogram of a grayscale image.
//! @} gapi_feature
The function equalizes the histogram of the input image using the following algorithm:
- Calculate the histogram \f$H\f$ for src .
@@ -804,18 +1061,288 @@ The function equalizes the histogram of the input image using the following algo
- Transform the image using \f$H'\f$ as a look-up table: \f$\texttt{dst}(x,y) = H'(\texttt{src}(x,y))\f$
The algorithm normalizes the brightness and increases the contrast of the image.
@note The returned image is of the same size and type as input.
@note Function textual ID is "org.opencv.imgproc.equalizeHist"
@note
- The returned image is of the same size and type as input.
- Function textual ID is "org.opencv.imgproc.equalizeHist"
@param src Source 8-bit single channel image.
*/
GAPI_EXPORTS GMat equalizeHist(const GMat& src);
//! @} gapi_filters
//! @addtogroup gapi_shape
//! @{
/** @brief Finds contours in a binary image.
The function retrieves contours from the binary image using the algorithm @cite Suzuki85 .
The contours are a useful tool for shape analysis and object detection and recognition.
See squares.cpp in the OpenCV sample directory.
@note Function textual ID is "org.opencv.imgproc.shape.findContours"
@param src Input gray-scale image @ref CV_8UC1. Non-zero pixels are treated as 1's. Zero
pixels remain 0's, so the image is treated as binary . You can use #compare, #inRange, #threshold ,
#adaptiveThreshold, #Canny, and others to create a binary image out of a grayscale or color one.
If mode equals to #RETR_CCOMP, the input can also be a 32-bit integer
image of labels ( @ref CV_32SC1 ). If #RETR_FLOODFILL then @ref CV_32SC1 is supported only.
@param mode Contour retrieval mode, see #RetrievalModes
@param method Contour approximation method, see #ContourApproximationModes
@param offset Optional offset by which every contour point is shifted. This is useful if the
contours are extracted from the image ROI and then they should be analyzed in the whole image
context.
@return GArray of detected contours. Each contour is stored as a GArray of points.
*/
GAPI_EXPORTS GArray<GArray<Point>>
findContours(const GMat &src, const RetrievalModes mode, const ContourApproximationModes method,
const GOpaque<Point> &offset);
// FIXME oc: make default value offset = Point()
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.findContoursNoOffset"
*/
GAPI_EXPORTS GArray<GArray<Point>>
findContours(const GMat &src, const RetrievalModes mode, const ContourApproximationModes method);
/** @brief Finds contours and their hierarchy in a binary image.
The function retrieves contours from the binary image using the algorithm @cite Suzuki85
and calculates their hierarchy.
The contours are a useful tool for shape analysis and object detection and recognition.
See squares.cpp in the OpenCV sample directory.
@note Function textual ID is "org.opencv.imgproc.shape.findContoursH"
@param src Input gray-scale image @ref CV_8UC1. Non-zero pixels are treated as 1's. Zero
pixels remain 0's, so the image is treated as binary . You can use #compare, #inRange, #threshold ,
#adaptiveThreshold, #Canny, and others to create a binary image out of a grayscale or color one.
If mode equals to #RETR_CCOMP, the input can also be a 32-bit integer
image of labels ( @ref CV_32SC1 ). If #RETR_FLOODFILL -- @ref CV_32SC1 supports only.
@param mode Contour retrieval mode, see #RetrievalModes
@param method Contour approximation method, see #ContourApproximationModes
@param offset Optional offset by which every contour point is shifted. This is useful if the
contours are extracted from the image ROI and then they should be analyzed in the whole image
context.
@return
- GArray of detected contours. Each contour is stored as a GArray of points.
- Optional output GArray of cv::Vec4i, containing information about the image topology.
It has as many elements as the number of contours. For each i-th contour contours[i], the elements
hierarchy[i][0] , hierarchy[i][1] , hierarchy[i][2] , and hierarchy[i][3] are set to 0-based
indices in contours of the next and previous contours at the same hierarchical level, the first
child contour and the parent contour, respectively. If for the contour i there are no next,
previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative.
*/
GAPI_EXPORTS std::tuple<GArray<GArray<Point>>,GArray<Vec4i>>
findContoursH(const GMat &src, const RetrievalModes mode, const ContourApproximationModes method,
const GOpaque<Point> &offset);
// FIXME oc: make default value offset = Point()
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.findContoursHNoOffset"
*/
GAPI_EXPORTS std::tuple<GArray<GArray<Point>>,GArray<Vec4i>>
findContoursH(const GMat &src, const RetrievalModes mode, const ContourApproximationModes method);
/** @brief Calculates the up-right bounding rectangle of a point set or non-zero pixels
of gray-scale image.
The function calculates and returns the minimal up-right bounding rectangle for the specified
point set or non-zero pixels of gray-scale image.
@note
- Function textual ID is "org.opencv.imgproc.shape.boundingRectMat"
- In case of a 2D points' set given, Mat should be 2-dimensional, have a single row or column
if there are 2 channels, or have 2 columns if there is a single channel. Mat should have either
@ref CV_32S or @ref CV_32F depth
@param src Input gray-scale image @ref CV_8UC1; or input set of @ref CV_32S or @ref CV_32F
2D points stored in Mat.
*/
GAPI_EXPORTS GOpaque<Rect> boundingRect(const GMat& src);
/** @overload
Calculates the up-right bounding rectangle of a point set.
@note Function textual ID is "org.opencv.imgproc.shape.boundingRectVector32S"
@param src Input 2D point set, stored in std::vector<cv::Point2i>.
*/
GAPI_EXPORTS GOpaque<Rect> boundingRect(const GArray<Point2i>& src);
/** @overload
Calculates the up-right bounding rectangle of a point set.
@note Function textual ID is "org.opencv.imgproc.shape.boundingRectVector32F"
@param src Input 2D point set, stored in std::vector<cv::Point2f>.
*/
GAPI_EXPORTS GOpaque<Rect> boundingRect(const GArray<Point2f>& src);
/** @brief Fits a line to a 2D point set.
The function fits a line to a 2D point set by minimizing \f$\sum_i \rho(r_i)\f$ where
\f$r_i\f$ is a distance between the \f$i^{th}\f$ point, the line and \f$\rho(r)\f$ is a distance
function, one of the following:
- DIST_L2
\f[\rho (r) = r^2/2 \quad \text{(the simplest and the fastest least-squares method)}\f]
- DIST_L1
\f[\rho (r) = r\f]
- DIST_L12
\f[\rho (r) = 2 \cdot ( \sqrt{1 + \frac{r^2}{2}} - 1)\f]
- DIST_FAIR
\f[\rho \left (r \right ) = C^2 \cdot \left ( \frac{r}{C} - \log{\left(1 + \frac{r}{C}\right)} \right ) \quad \text{where} \quad C=1.3998\f]
- DIST_WELSCH
\f[\rho \left (r \right ) = \frac{C^2}{2} \cdot \left ( 1 - \exp{\left(-\left(\frac{r}{C}\right)^2\right)} \right ) \quad \text{where} \quad C=2.9846\f]
- DIST_HUBER
\f[\rho (r) = \fork{r^2/2}{if \(r < C\)}{C \cdot (r-C/2)}{otherwise} \quad \text{where} \quad C=1.345\f]
The algorithm is based on the M-estimator ( <http://en.wikipedia.org/wiki/M-estimator> ) technique
that iteratively fits the line using the weighted least-squares algorithm. After each iteration the
weights \f$w_i\f$ are adjusted to be inversely proportional to \f$\rho(r_i)\f$ .
@note
- Function textual ID is "org.opencv.imgproc.shape.fitLine2DMat"
- In case of an N-dimentional points' set given, Mat should be 2-dimensional, have a single row
or column if there are N channels, or have N columns if there is a single channel.
@param src Input set of 2D points stored in one of possible containers: Mat,
std::vector<cv::Point2i>, std::vector<cv::Point2f>, std::vector<cv::Point2d>.
@param distType Distance used by the M-estimator, see #DistanceTypes. @ref DIST_USER
and @ref DIST_C are not suppored.
@param param Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value
is chosen.
@param reps Sufficient accuracy for the radius (distance between the coordinate origin and the
line). 1.0 would be a good default value for reps. If it is 0, a default value is chosen.
@param aeps Sufficient accuracy for the angle. 0.01 would be a good default value for aeps.
If it is 0, a default value is chosen.
@return Output line parameters: a vector of 4 elements (like Vec4f) - (vx, vy, x0, y0),
where (vx, vy) is a normalized vector collinear to the line and (x0, y0) is a point on the line.
*/
GAPI_EXPORTS GOpaque<Vec4f> fitLine2D(const GMat& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.fitLine2DVector32S"
*/
GAPI_EXPORTS GOpaque<Vec4f> fitLine2D(const GArray<Point2i>& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.fitLine2DVector32F"
*/
GAPI_EXPORTS GOpaque<Vec4f> fitLine2D(const GArray<Point2f>& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.fitLine2DVector64F"
*/
GAPI_EXPORTS GOpaque<Vec4f> fitLine2D(const GArray<Point2d>& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
/** @brief Fits a line to a 3D point set.
The function fits a line to a 3D point set by minimizing \f$\sum_i \rho(r_i)\f$ where
\f$r_i\f$ is a distance between the \f$i^{th}\f$ point, the line and \f$\rho(r)\f$ is a distance
function, one of the following:
- DIST_L2
\f[\rho (r) = r^2/2 \quad \text{(the simplest and the fastest least-squares method)}\f]
- DIST_L1
\f[\rho (r) = r\f]
- DIST_L12
\f[\rho (r) = 2 \cdot ( \sqrt{1 + \frac{r^2}{2}} - 1)\f]
- DIST_FAIR
\f[\rho \left (r \right ) = C^2 \cdot \left ( \frac{r}{C} - \log{\left(1 + \frac{r}{C}\right)} \right ) \quad \text{where} \quad C=1.3998\f]
- DIST_WELSCH
\f[\rho \left (r \right ) = \frac{C^2}{2} \cdot \left ( 1 - \exp{\left(-\left(\frac{r}{C}\right)^2\right)} \right ) \quad \text{where} \quad C=2.9846\f]
- DIST_HUBER
\f[\rho (r) = \fork{r^2/2}{if \(r < C\)}{C \cdot (r-C/2)}{otherwise} \quad \text{where} \quad C=1.345\f]
The algorithm is based on the M-estimator ( <http://en.wikipedia.org/wiki/M-estimator> ) technique
that iteratively fits the line using the weighted least-squares algorithm. After each iteration the
weights \f$w_i\f$ are adjusted to be inversely proportional to \f$\rho(r_i)\f$ .
@note
- Function textual ID is "org.opencv.imgproc.shape.fitLine3DMat"
- In case of an N-dimentional points' set given, Mat should be 2-dimensional, have a single row
or column if there are N channels, or have N columns if there is a single channel.
@param src Input set of 3D points stored in one of possible containers: Mat,
std::vector<cv::Point3i>, std::vector<cv::Point3f>, std::vector<cv::Point3d>.
@param distType Distance used by the M-estimator, see #DistanceTypes. @ref DIST_USER
and @ref DIST_C are not suppored.
@param param Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value
is chosen.
@param reps Sufficient accuracy for the radius (distance between the coordinate origin and the
line). 1.0 would be a good default value for reps. If it is 0, a default value is chosen.
@param aeps Sufficient accuracy for the angle. 0.01 would be a good default value for aeps.
If it is 0, a default value is chosen.
@return Output line parameters: a vector of 6 elements (like Vec6f) - (vx, vy, vz, x0, y0, z0),
where (vx, vy, vz) is a normalized vector collinear to the line and (x0, y0, z0) is a point on
the line.
*/
GAPI_EXPORTS GOpaque<Vec6f> fitLine3D(const GMat& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.fitLine3DVector32S"
*/
GAPI_EXPORTS GOpaque<Vec6f> fitLine3D(const GArray<Point3i>& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.fitLine3DVector32F"
*/
GAPI_EXPORTS GOpaque<Vec6f> fitLine3D(const GArray<Point3f>& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
/** @overload
@note Function textual ID is "org.opencv.imgproc.shape.fitLine3DVector64F"
*/
GAPI_EXPORTS GOpaque<Vec6f> fitLine3D(const GArray<Point3d>& src, const DistanceTypes distType,
const double param = 0., const double reps = 0.,
const double aeps = 0.);
//! @} gapi_shape
//! @addtogroup gapi_colorconvert
//! @{
/** @brief Converts an image from BGR color space to RGB color space.
The function converts an input image from BGR color space to RGB.
The conventional ranges for B, G, and R channel values are 0 to 255.
Output image is 8-bit unsigned 3-channel image @ref CV_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2rgb"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa RGB2BGR
*/
GAPI_EXPORTS GMat BGR2RGB(const GMat& src);
/** @brief Converts an image from RGB color space to gray-scaled.
The conventional ranges for R, G, and B channel values are 0 to 255.
Resulting gray color value computed as
@@ -826,7 +1353,7 @@ Resulting gray color value computed as
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1.
@sa RGB2YUV
*/
GAPI_EXPORTS GMat RGB2Gray(const GMat& src);
GAPI_EXPORTS_W GMat RGB2Gray(const GMat& src);
/** @overload
Resulting gray color value computed as
@@ -871,6 +1398,70 @@ Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
*/
GAPI_EXPORTS GMat RGB2YUV(const GMat& src);
/** @brief Converts an image from BGR color space to I420 color space.
The function converts an input image from BGR color space to I420.
The conventional ranges for R, G, and B channel values are 0 to 255.
Output image must be 8-bit unsigned 1-channel image. @ref CV_8UC1.
Width of I420 output image must be the same as width of input image.
Height of I420 output image must be equal 3/2 from height of input image.
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2i420"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa I4202BGR
*/
GAPI_EXPORTS GMat BGR2I420(const GMat& src);
/** @brief Converts an image from RGB color space to I420 color space.
The function converts an input image from RGB color space to I420.
The conventional ranges for R, G, and B channel values are 0 to 255.
Output image must be 8-bit unsigned 1-channel image. @ref CV_8UC1.
Width of I420 output image must be the same as width of input image.
Height of I420 output image must be equal 3/2 from height of input image.
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2i420"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa I4202RGB
*/
GAPI_EXPORTS GMat RGB2I420(const GMat& src);
/** @brief Converts an image from I420 color space to BGR color space.
The function converts an input image from I420 color space to BGR.
The conventional ranges for B, G, and R channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image. @ref CV_8UC3.
Width of BGR output image must be the same as width of input image.
Height of BGR output image must be equal 2/3 from height of input image.
@note Function textual ID is "org.opencv.imgproc.colorconvert.i4202bgr"
@param src input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@sa BGR2I420
*/
GAPI_EXPORTS GMat I4202BGR(const GMat& src);
/** @brief Converts an image from I420 color space to BGR color space.
The function converts an input image from I420 color space to BGR.
The conventional ranges for B, G, and R channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image. @ref CV_8UC3.
Width of RGB output image must be the same as width of input image.
Height of RGB output image must be equal 2/3 from height of input image.
@note Function textual ID is "org.opencv.imgproc.colorconvert.i4202rgb"
@param src input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@sa RGB2I420
*/
GAPI_EXPORTS GMat I4202RGB(const GMat& src);
/** @brief Converts an image from BGR color space to LUV color space.
The function converts an input image from BGR color space to LUV.

View File

@@ -2,7 +2,7 @@
// 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
// Copyright (C) 2019-2020 Intel Corporation
#ifndef OPENCV_GAPI_INFER_HPP
@@ -16,6 +16,7 @@
#include <utility> // tuple
#include <type_traits> // is_same, false_type
#include <opencv2/gapi/util/util.hpp> // all_satisfy
#include <opencv2/gapi/util/any.hpp> // any<>
#include <opencv2/gapi/gkernel.hpp> // GKernelType[M], GBackend
#include <opencv2/gapi/garg.hpp> // GArg
@@ -27,40 +28,54 @@ namespace cv {
template<typename, typename> class GNetworkType;
namespace detail {
template<typename, typename>
struct valid_infer2_types;
// Terminal case 1 (50/50 success)
template<typename T>
struct valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> > {
// By default, Nets are limited to GMat argument types only
// for infer2, every GMat argument may translate to either
// GArray<GMat> or GArray<Rect>. GArray<> part is stripped
// already at this point.
static constexpr const auto value =
std::is_same<typename std::decay<T>::type, cv::GMat>::value
|| std::is_same<typename std::decay<T>::type, cv::Rect>::value;
};
// Infer ///////////////////////////////////////////////////////////////////////
template<typename T>
struct accepted_infer_types {
static constexpr const auto value =
std::is_same<typename std::decay<T>::type, cv::GMat>::value
|| std::is_same<typename std::decay<T>::type, cv::GFrame>::value;
};
// Terminal case 2 (100% failure)
template<typename... Ts>
struct valid_infer2_types< std::tuple<>, std::tuple<Ts...> >
: public std::false_type {
};
template<typename... Ts>
using valid_infer_types = all_satisfy<accepted_infer_types, Ts...>;
// Terminal case 3 (100% failure)
template<typename... Ns>
struct valid_infer2_types< std::tuple<Ns...>, std::tuple<> >
: public std::false_type {
};
// Infer2 //////////////////////////////////////////////////////////////////////
// Recursion -- generic
template<typename... Ns, typename T, typename...Ts>
struct valid_infer2_types< std::tuple<cv::GMat,Ns...>, std::tuple<T,Ts...> > {
static constexpr const auto value =
valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> >::value
&& valid_infer2_types< std::tuple<Ns...>, std::tuple<Ts...> >::value;
};
template<typename, typename>
struct valid_infer2_types;
// Terminal case 1 (50/50 success)
template<typename T>
struct valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> > {
// By default, Nets are limited to GMat argument types only
// for infer2, every GMat argument may translate to either
// GArray<GMat> or GArray<Rect>. GArray<> part is stripped
// already at this point.
static constexpr const auto value =
std::is_same<typename std::decay<T>::type, cv::GMat>::value
|| std::is_same<typename std::decay<T>::type, cv::Rect>::value;
};
// Terminal case 2 (100% failure)
template<typename... Ts>
struct valid_infer2_types< std::tuple<>, std::tuple<Ts...> >
: public std::false_type {
};
// Terminal case 3 (100% failure)
template<typename... Ns>
struct valid_infer2_types< std::tuple<Ns...>, std::tuple<> >
: public std::false_type {
};
// Recursion -- generic
template<typename... Ns, typename T, typename...Ts>
struct valid_infer2_types< std::tuple<cv::GMat,Ns...>, std::tuple<T,Ts...> > {
static constexpr const auto value =
valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> >::value
&& valid_infer2_types< std::tuple<Ns...>, std::tuple<Ts...> >::value;
};
} // namespace detail
// TODO: maybe tuple_wrap_helper from util.hpp may help with this.
@@ -76,7 +91,6 @@ public:
using API = std::function<Result(Args...)>;
using ResultL = std::tuple< cv::GArray<R>... >;
using APIList = std::function<ResultL(cv::GArray<cv::Rect>, Args...)>;
};
// Single-return-value network definition (specialized base class)
@@ -91,17 +105,48 @@ public:
using API = std::function<R(Args...)>;
using ResultL = cv::GArray<R>;
using APIList = std::function<ResultL(cv::GArray<cv::Rect>, Args...)>;
};
// InferAPI: Accepts either GMat or GFrame for very individual network's input
template<class Net, class... Ts>
struct InferAPI {
using type = typename std::enable_if
< detail::valid_infer_types<Ts...>::value
&& std::tuple_size<typename Net::InArgs>::value == sizeof...(Ts)
, std::function<typename Net::Result(Ts...)>
>::type;
};
// InferAPIRoi: Accepts a rectangle and either GMat or GFrame
template<class Net, class T>
struct InferAPIRoi {
using type = typename std::enable_if
< detail::valid_infer_types<T>::value
&& std::tuple_size<typename Net::InArgs>::value == 1u
, std::function<typename Net::Result(cv::GOpaque<cv::Rect>, T)>
>::type;
};
// InferAPIList: Accepts a list of rectangles and list of GMat/GFrames;
// crops every input.
template<class Net, class... Ts>
struct InferAPIList {
using type = typename std::enable_if
< detail::valid_infer_types<Ts...>::value
&& std::tuple_size<typename Net::InArgs>::value == sizeof...(Ts)
, std::function<typename Net::ResultL(cv::GArray<cv::Rect>, Ts...)>
>::type;
};
// APIList2 is also template to allow different calling options
// (GArray<cv::Rect> vs GArray<cv::GMat> per input)
template<class Net, class... Ts>
template<class Net, typename T, class... Ts>
struct InferAPIList2 {
using type = typename std::enable_if
< cv::detail::valid_infer2_types< typename Net::InArgs
< detail::valid_infer_types<T>::value &&
cv::detail::valid_infer2_types< typename Net::InArgs
, std::tuple<Ts...> >::value,
std::function<typename Net::ResultL(cv::GMat, cv::GArray<Ts>...)>
std::function<typename Net::ResultL(T, cv::GArray<Ts>...)>
>::type;
};
@@ -114,22 +159,75 @@ struct InferAPIList2 {
// a particular backend, not by a network itself.
struct GInferBase {
static constexpr const char * id() {
return "org.opencv.dnn.infer"; // Universal stub
return "org.opencv.dnn.infer"; // Universal stub
}
static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
return GMetaArgs{}; // One more universal stub
return GMetaArgs{}; // One more universal stub
}
};
// Struct stores network input/output names.
// Used by infer<Generic>
struct InOutInfo
{
std::vector<std::string> in_names;
std::vector<std::string> out_names;
};
/**
* @{
* @brief G-API object used to collect network inputs
*/
class GAPI_EXPORTS_W_SIMPLE GInferInputs
{
using Map = std::unordered_map<std::string, GMat>;
public:
GAPI_WRAP GInferInputs();
GAPI_WRAP void setInput(const std::string& name, const cv::GMat& value);
cv::GMat& operator[](const std::string& name);
const Map& getBlobs() const;
private:
std::shared_ptr<Map> in_blobs;
};
/** @} */
/**
* @{
* @brief G-API object used to collect network outputs
*/
struct GAPI_EXPORTS_W_SIMPLE GInferOutputs
{
public:
GAPI_WRAP GInferOutputs() = default;
GInferOutputs(std::shared_ptr<cv::GCall> call);
GAPI_WRAP cv::GMat at(const std::string& name);
private:
struct Priv;
std::shared_ptr<Priv> m_priv;
};
/** @} */
// Base "InferROI" kernel.
// All notes from "Infer" kernel apply here as well.
struct GInferROIBase {
static constexpr const char * id() {
return "org.opencv.dnn.infer-roi"; // Universal stub
}
static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
return GMetaArgs{}; // One more universal stub
}
};
// Base "Infer list" kernel.
// All notes from "Infer" kernel apply here as well.
struct GInferListBase {
static constexpr const char * id() {
return "org.opencv.dnn.infer-roi"; // Universal stub
return "org.opencv.dnn.infer-roi-list-1"; // Universal stub
}
static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
return GMetaArgs{}; // One more universal stub
return GMetaArgs{}; // One more universal stub
}
};
@@ -137,33 +235,46 @@ struct GInferListBase {
// All notes from "Infer" kernel apply here as well.
struct GInferList2Base {
static constexpr const char * id() {
return "org.opencv.dnn.infer-roi-list"; // Universal stub
return "org.opencv.dnn.infer-roi-list-2"; // Universal stub
}
static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
return GMetaArgs{}; // One more universal stub
return GMetaArgs{}; // One more universal stub
}
};
// A generic inference kernel. API (::on()) is fully defined by the Net
// template parameter.
// Acts as a regular kernel in graph (via KernelTypeMedium).
template<typename Net>
template<typename Net, typename... Args>
struct GInfer final
: public GInferBase
, public detail::KernelTypeMedium< GInfer<Net>
, typename Net::API > {
, public detail::KernelTypeMedium< GInfer<Net, Args...>
, typename InferAPI<Net, Args...>::type > {
using GInferBase::getOutMeta; // FIXME: name lookup conflict workaround?
static constexpr const char* tag() { return Net::tag(); }
};
// A specific roi-inference kernel. API (::on()) is fixed here and
// verified against Net.
template<typename Net, typename T>
struct GInferROI final
: public GInferROIBase
, public detail::KernelTypeMedium< GInferROI<Net, T>
, typename InferAPIRoi<Net, T>::type > {
using GInferROIBase::getOutMeta; // FIXME: name lookup conflict workaround?
static constexpr const char* tag() { return Net::tag(); }
};
// A generic roi-list inference kernel. API (::on()) is derived from
// the Net template parameter (see more in infer<> overload).
template<typename Net>
template<typename Net, typename... Args>
struct GInferList final
: public GInferListBase
, public detail::KernelTypeMedium< GInferList<Net>
, typename Net::APIList > {
, public detail::KernelTypeMedium< GInferList<Net, Args...>
, typename InferAPIList<Net, Args...>::type > {
using GInferListBase::getOutMeta; // FIXME: name lookup conflict workaround?
static constexpr const char* tag() { return Net::tag(); }
@@ -174,11 +285,11 @@ struct GInferList final
// overload).
// Takes an extra variadic template list to reflect how this network
// was called (with Rects or GMats as array parameters)
template<typename Net, typename... Args>
template<typename Net, typename T, typename... Args>
struct GInferList2 final
: public GInferList2Base
, public detail::KernelTypeMedium< GInferList2<Net, Args...>
, typename InferAPIList2<Net, Args...>::type > {
, public detail::KernelTypeMedium< GInferList2<Net, T, Args...>
, typename InferAPIList2<Net, T, Args...>::type > {
using GInferList2Base::getOutMeta; // FIXME: name lookup conflict workaround?
static constexpr const char* tag() { return Net::tag(); }
@@ -195,6 +306,23 @@ struct GInferList2 final
namespace cv {
namespace gapi {
/** @brief Calculates response for the specified network (template
* parameter) for the specified region in the source image.
* Currently expects a single-input network only.
*
* @tparam A network type defined with G_API_NET() macro.
* @param in input image where to take ROI from.
* @param roi an object describing the region of interest
* in the source image. May be calculated in the same graph dynamically.
* @return an object of return type as defined in G_API_NET().
* If a network has multiple return values (defined with a tuple), a tuple of
* objects of appropriate type is returned.
* @sa G_API_NET()
*/
template<typename Net, typename T>
typename Net::Result infer(cv::GOpaque<cv::Rect> roi, T in) {
return GInferROI<Net, T>::on(roi, in);
}
/** @brief Calculates responses for the specified network (template
* parameter) for every region in the source image.
@@ -211,7 +339,7 @@ namespace gapi {
*/
template<typename Net, typename... Args>
typename Net::ResultL infer(cv::GArray<cv::Rect> roi, Args&&... args) {
return GInferList<Net>::on(roi, std::forward<Args>(args)...);
return GInferList<Net, Args...>::on(roi, std::forward<Args>(args)...);
}
/** @brief Calculates responses for the specified network (template
@@ -231,11 +359,12 @@ typename Net::ResultL infer(cv::GArray<cv::Rect> roi, Args&&... args) {
* GArray<> objects is returned with the appropriate types inside.
* @sa G_API_NET()
*/
template<typename Net, typename... Args>
typename Net::ResultL infer2(cv::GMat image, cv::GArray<Args>... args) {
template<typename Net, typename T, typename... Args>
typename Net::ResultL infer2(T image, cv::GArray<Args>... args) {
// FIXME: Declared as "2" because in the current form it steals
// overloads from the regular infer
return GInferList2<Net, Args...>::on(image, args...);
return GInferList2<Net, T, Args...>::on(image, args...);
}
/**
@@ -251,9 +380,54 @@ typename Net::ResultL infer2(cv::GMat image, cv::GArray<Args>... args) {
*/
template<typename Net, typename... Args>
typename Net::Result infer(Args&&... args) {
return GInfer<Net>::on(std::forward<Args>(args)...);
return GInfer<Net, Args...>::on(std::forward<Args>(args)...);
}
/**
* @brief Special network type
*/
struct Generic { };
/**
* @brief Calculates response for generic network
*
* @param tag a network tag
* @param inputs networks's inputs
* @return a GInferOutputs
*/
template<typename T = Generic> GInferOutputs
infer(const std::string& tag, const GInferInputs& inputs)
{
std::vector<GArg> input_args;
std::vector<std::string> input_names;
const auto& blobs = inputs.getBlobs();
for (auto&& p : blobs)
{
input_names.push_back(p.first);
input_args.emplace_back(p.second);
}
GKinds kinds(blobs.size(), cv::detail::OpaqueKind::CV_MAT);
auto call = std::make_shared<cv::GCall>(GKernel{
GInferBase::id(),
tag,
GInferBase::getOutMeta,
{}, // outShape will be filled later
std::move(kinds),
{}, // outCtors will be filled later
});
call->setArgs(std::move(input_args));
call->params() = InOutInfo{input_names, {}};
return GInferOutputs{std::move(call)};
}
GAPI_EXPORTS_W inline GInferOutputs infer(const String& name, const GInferInputs& inputs)
{
return infer<Generic>(name, inputs);
}
} // namespace gapi
} // namespace cv
@@ -283,9 +457,9 @@ struct GAPI_EXPORTS GNetParam {
*
* @sa cv::gapi::networks
*/
struct GAPI_EXPORTS GNetPackage {
GNetPackage() : GNetPackage({}) {}
explicit GNetPackage(std::initializer_list<GNetParam> &&ii);
struct GAPI_EXPORTS_W_SIMPLE GNetPackage {
GAPI_WRAP GNetPackage() = default;
explicit GNetPackage(std::initializer_list<GNetParam> ii);
std::vector<GBackend> backends() const;
std::vector<GNetParam> networks;
};

View File

@@ -0,0 +1,56 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_INFER_BINDINGS_IE_HPP
#define OPENCV_GAPI_INFER_BINDINGS_IE_HPP
#include <opencv2/gapi/util/any.hpp>
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
#include <opencv2/gapi/infer/ie.hpp> // Params
#include <string>
namespace cv {
namespace gapi {
namespace ie {
// NB: Used by python wrapper
// This class can be marked as SIMPLE, because it's implemented as pimpl
class GAPI_EXPORTS_W_SIMPLE PyParams {
public:
PyParams() = default;
PyParams(const std::string &tag,
const std::string &model,
const std::string &weights,
const std::string &device);
PyParams(const std::string &tag,
const std::string &model,
const std::string &device);
GBackend backend() const;
std::string tag() const;
cv::util::any params() const;
private:
std::shared_ptr<Params<cv::gapi::Generic>> m_priv;
};
GAPI_EXPORTS_W PyParams params(const std::string &tag,
const std::string &model,
const std::string &weights,
const std::string &device);
GAPI_EXPORTS_W PyParams params(const std::string &tag,
const std::string &model,
const std::string &device);
} // namespace ie
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_INFER_BINDINGS_IE_HPP

View File

@@ -11,12 +11,14 @@
#include <string>
#include <array>
#include <tuple> // tuple, tuple_size
#include <map>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
#include <opencv2/gapi/infer.hpp> // Generic
namespace cv {
namespace gapi {
@@ -41,6 +43,8 @@ enum class TraitAs: int
IMAGE //!< G-API traits an associated cv::Mat as an image so creates an "image" blob (NCHW/NHWC, etc)
};
using IEConfig = std::map<std::string, std::string>;
namespace detail {
struct ParamDesc {
std::string model_path;
@@ -58,6 +62,11 @@ namespace detail {
// (e.g. topology's partial execution)
std::size_t num_in; // How many inputs are defined in the operation
std::size_t num_out; // How many outputs are defined in the operation
enum class Kind { Load, Import };
Kind kind;
bool is_generic;
IEConfig config;
};
} // namespace detail
@@ -80,7 +89,19 @@ public:
: desc{ model, weights, device, {}, {}, {}
, std::tuple_size<typename Net::InArgs>::value // num_in
, std::tuple_size<typename Net::OutArgs>::value // num_out
} {
, detail::ParamDesc::Kind::Load
, false
, {}} {
};
Params(const std::string &model,
const std::string &device)
: desc{ model, {}, device, {}, {}, {}
, std::tuple_size<typename Net::InArgs>::value // num_in
, std::tuple_size<typename Net::OutArgs>::value // num_out
, detail::ParamDesc::Kind::Import
, false
, {}} {
};
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &ll) {
@@ -106,18 +127,65 @@ public:
return *this;
}
Params& pluginConfig(IEConfig&& cfg) {
desc.config = std::move(cfg);
return *this;
}
Params& pluginConfig(const IEConfig& cfg) {
desc.config = cfg;
return *this;
}
// BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return Net::tag(); }
cv::util::any params() const { return { desc }; }
GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return Net::tag(); }
cv::util::any params() const { return { desc }; }
// END(G-API's network parametrization API)
protected:
detail::ParamDesc desc;
};
template<>
class Params<cv::gapi::Generic> {
public:
Params(const std::string &tag,
const std::string &model,
const std::string &weights,
const std::string &device)
: desc{ model, weights, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Load, true, {}}, m_tag(tag) {
};
Params(const std::string &tag,
const std::string &model,
const std::string &device)
: desc{ model, {}, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Import, true, {}}, m_tag(tag) {
};
Params& pluginConfig(IEConfig&& cfg) {
desc.config = std::move(cfg);
return *this;
}
Params& pluginConfig(const IEConfig& cfg) {
desc.config = cfg;
return *this;
}
// BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return m_tag; }
cv::util::any params() const { return { desc }; }
// END(G-API's network parametrization API)
protected:
detail::ParamDesc desc;
std::string m_tag;
};
} // namespace ie
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_INFER_HPP
#endif // OPENCV_GAPI_INFER_IE_HPP

View File

@@ -0,0 +1,138 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_INFER_ONNX_HPP
#define OPENCV_GAPI_INFER_ONNX_HPP
#include <unordered_map>
#include <string>
#include <array>
#include <tuple> // tuple, tuple_size
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
namespace cv {
namespace gapi {
namespace onnx {
GAPI_EXPORTS cv::gapi::GBackend backend();
enum class TraitAs: int {
TENSOR, //!< G-API traits an associated cv::Mat as a raw tensor
// and passes dimensions as-is
IMAGE //!< G-API traits an associated cv::Mat as an image so
// creates an "image" blob (NCHW/NHWC, etc)
};
using PostProc = std::function<void(const std::unordered_map<std::string, cv::Mat> &,
std::unordered_map<std::string, cv::Mat> &)>;
namespace detail {
struct ParamDesc {
std::string model_path;
// NB: nun_* may differ from topology's real input/output port numbers
// (e.g. topology's partial execution)
std::size_t num_in; // How many inputs are defined in the operation
std::size_t num_out; // How many outputs are defined in the operation
// NB: Here order follows the `Net` API
std::vector<std::string> input_names;
std::vector<std::string> output_names;
using ConstInput = std::pair<cv::Mat, TraitAs>;
std::unordered_map<std::string, ConstInput> const_inputs;
std::vector<cv::Scalar> mean;
std::vector<cv::Scalar> stdev;
std::vector<cv::GMatDesc> out_metas;
PostProc custom_post_proc;
std::vector<bool> normalize;
};
} // namespace detail
template<typename Net>
struct PortCfg {
using In = std::array
< std::string
, std::tuple_size<typename Net::InArgs>::value >;
using Out = std::array
< std::string
, std::tuple_size<typename Net::OutArgs>::value >;
using NormCoefs = std::array
< cv::Scalar
, std::tuple_size<typename Net::InArgs>::value >;
using Normalize = std::array
< bool
, std::tuple_size<typename Net::InArgs>::value >;
};
template<typename Net> class Params {
public:
Params(const std::string &model) {
desc.model_path = model;
desc.num_in = std::tuple_size<typename Net::InArgs>::value;
desc.num_out = std::tuple_size<typename Net::OutArgs>::value;
};
// BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::onnx::backend(); }
std::string tag() const { return Net::tag(); }
cv::util::any params() const { return { desc }; }
// END(G-API's network parametrization API)
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &ll) {
desc.input_names.assign(ll.begin(), ll.end());
return *this;
}
Params<Net>& cfgOutputLayers(const typename PortCfg<Net>::Out &ll) {
desc.output_names.assign(ll.begin(), ll.end());
return *this;
}
Params<Net>& constInput(const std::string &layer_name,
const cv::Mat &data,
TraitAs hint = TraitAs::TENSOR) {
desc.const_inputs[layer_name] = {data, hint};
return *this;
}
Params<Net>& cfgMeanStd(const typename PortCfg<Net>::NormCoefs &m,
const typename PortCfg<Net>::NormCoefs &s) {
desc.mean.assign(m.begin(), m.end());
desc.stdev.assign(s.begin(), s.end());
return *this;
}
Params<Net>& cfgPostProc(const std::vector<cv::GMatDesc> &outs,
const PostProc &pp) {
desc.out_metas = outs;
desc.custom_post_proc = pp;
return *this;
}
Params<Net>& cfgNormalize(const typename PortCfg<Net>::Normalize &n) {
desc.normalize.assign(n.begin(), n.end());
return *this;
}
protected:
detail::ParamDesc desc;
};
} // namespace onnx
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_INFER_HPP

View File

@@ -122,4 +122,16 @@ GAPI_EXPORTS std::tuple<GArray<Rect>, GArray<int>> parseYolo(const GMat& in,
} // namespace gapi
} // namespace cv
// Reimport parseSSD & parseYolo under their initial namespace
namespace cv {
namespace gapi {
namespace streaming {
using cv::gapi::parseSSD;
using cv::gapi::parseYolo;
} // namespace streaming
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_PARSERS_HPP

View File

@@ -0,0 +1,73 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_MEDIA_HPP
#define OPENCV_GAPI_MEDIA_HPP
#include <memory> // unique_ptr<>, shared_ptr<>
#include <array> // array<>
#include <functional> // function<>
#include <utility> // forward<>()
#include <opencv2/gapi/gframe.hpp>
namespace cv {
class GAPI_EXPORTS MediaFrame {
public:
enum class Access { R, W };
class IAdapter;
class View;
using AdapterPtr = std::unique_ptr<IAdapter>;
MediaFrame();
explicit MediaFrame(AdapterPtr &&);
template<class T, class... Args> static cv::MediaFrame Create(Args&&...);
View access(Access) const;
cv::GFrameDesc desc() const;
private:
struct Priv;
std::shared_ptr<Priv> m;
};
template<class T, class... Args>
inline cv::MediaFrame cv::MediaFrame::Create(Args&&... args) {
std::unique_ptr<T> ptr(new T(std::forward<Args>(args)...));
return cv::MediaFrame(std::move(ptr));
}
class GAPI_EXPORTS MediaFrame::View final {
public:
static constexpr const size_t MAX_PLANES = 4;
using Ptrs = std::array<void*, MAX_PLANES>;
using Strides = std::array<std::size_t, MAX_PLANES>; // in bytes
using Callback = std::function<void()>;
View(Ptrs&& ptrs, Strides&& strs, Callback &&cb = [](){});
View(const View&) = delete;
View(View&&) = default;
View& operator = (const View&) = delete;
~View();
Ptrs ptr;
Strides stride;
private:
Callback m_cb;
};
class GAPI_EXPORTS MediaFrame::IAdapter {
public:
virtual ~IAdapter() = 0;
virtual cv::GFrameDesc meta() const = 0;
virtual MediaFrame::View access(MediaFrame::Access) = 0;
};
} //namespace cv
#endif // OPENCV_GAPI_MEDIA_HPP

View File

@@ -2,7 +2,7 @@
// 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) 2018-2019 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GOCLKERNEL_HPP
@@ -75,7 +75,7 @@ public:
protected:
detail::VectorRef& outVecRef(int output);
detail::VectorRef& outOpaqueRef(int output);
detail::OpaqueRef& outOpaqueRef(int output);
std::vector<GArg> m_args;
std::unordered_map<std::size_t, GRunArgP> m_results;

View File

@@ -21,11 +21,12 @@
# include <opencv2/gapi/own/mat.hpp>
// replacement of cv's structures:
namespace cv {
using Rect = gapi::own::Rect;
using Size = gapi::own::Size;
using Point = gapi::own::Point;
using Scalar = gapi::own::Scalar;
using Mat = gapi::own::Mat;
using Rect = gapi::own::Rect;
using Size = gapi::own::Size;
using Point = gapi::own::Point;
using Point2f = gapi::own::Point2f;
using Scalar = gapi::own::Scalar;
using Mat = gapi::own::Mat;
} // namespace cv
#endif // !defined(GAPI_STANDALONE)

View File

@@ -2,16 +2,28 @@
// 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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_OWN_ASSERT_HPP
#define OPENCV_GAPI_OWN_ASSERT_HPP
#include <opencv2/gapi/util/compiler_hints.hpp>
#define GAPI_DbgAssertNoOp(expr) { \
constexpr bool _assert_tmp = false && (expr); \
cv::util::suppress_unused_warning(_assert_tmp); \
}
#if !defined(GAPI_STANDALONE)
#include <opencv2/core/base.hpp>
#define GAPI_Assert CV_Assert
#define GAPI_DbgAssert CV_DbgAssert
#if defined _DEBUG || defined CV_STATIC_ANALYSIS
# define GAPI_DbgAssert CV_DbgAssert
#else
# define GAPI_DbgAssert(expr) GAPI_DbgAssertNoOp(expr)
#endif
#else
#include <stdexcept>
@@ -33,7 +45,7 @@ namespace detail
#ifdef NDEBUG
# define GAPI_DbgAssert(expr)
# define GAPI_DbgAssert(expr) GAPI_DbgAssertNoOp(expr)
#else
# define GAPI_DbgAssert(expr) GAPI_Assert(expr)
#endif

View File

@@ -254,6 +254,18 @@ namespace cv { namespace gapi { namespace own {
*this = std::move(tmp);
}
/** @brief Creates a full copy of the matrix and the underlying data.
The method creates a full copy of the matrix. The original step[] is not taken into account.
So, the copy has a continuous buffer occupying total() * elemSize() bytes.
*/
Mat clone() const
{
Mat m;
copyTo(m);
return m;
}
/** @brief Copies the matrix to another one.
The method copies the matrix data to another matrix. Before copying the data, the method invokes :

View File

@@ -28,6 +28,16 @@ public:
int y = 0;
};
class Point2f
{
public:
Point2f() = default;
Point2f(float _x, float _y) : x(_x), y(_y) {};
float x = 0.f;
float y = 0.f;
};
class Rect
{
public:

View File

@@ -252,7 +252,7 @@ struct Mosaic
{
}
Mosaic() = default;
Mosaic() : cellSz(0), decim(0) {}
/*@{*/
cv::Rect mos; //!< Coordinates of the mosaic

View File

@@ -8,6 +8,17 @@
#define OPENCV_GAPI_RMAT_HPP
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/own/exports.hpp>
// Forward declaration
namespace cv {
namespace gapi {
namespace s11n {
struct IOStream;
struct IIStream;
} // namespace s11n
} // namespace gapi
} // namespace cv
namespace cv {
@@ -31,7 +42,7 @@ namespace cv {
// performCalculations(in_view, out_view);
// // data from out_view is transferred to the device when out_view is destroyed
// }
class RMat
class GAPI_EXPORTS RMat
{
public:
// A lightweight wrapper on image data:
@@ -39,43 +50,50 @@ public:
// - Doesn't implement copy semantics (it's assumed that a view is created each time
// wrapped data is being accessed);
// - Has an optional callback which is called when the view is destroyed.
class View
class GAPI_EXPORTS View
{
public:
using DestroyCallback = std::function<void()>;
using stepsT = std::vector<size_t>;
View() = default;
View(const GMatDesc& desc, uchar* data, size_t step = 0u, DestroyCallback&& cb = nullptr)
: m_desc(desc), m_data(data), m_step(step == 0u ? elemSize()*cols() : step), m_cb(cb)
{}
View(const GMatDesc& desc, uchar* data, const stepsT& steps = {}, DestroyCallback&& cb = nullptr);
View(const GMatDesc& desc, uchar* data, size_t step, DestroyCallback&& cb = nullptr);
View(const View&) = delete;
View(View&&) = default;
View& operator=(const View&) = delete;
View& operator=(View&&) = default;
View(View&&) = default;
View& operator=(View&& v);
~View() { if (m_cb) m_cb(); }
cv::Size size() const { return m_desc.size; }
const std::vector<int>& dims() const { return m_desc.dims; }
int cols() const { return m_desc.size.width; }
int rows() const { return m_desc.size.height; }
int type() const { return CV_MAKE_TYPE(depth(), chan()); }
int type() const;
int depth() const { return m_desc.depth; }
int chan() const { return m_desc.chan; }
size_t elemSize() const { return CV_ELEM_SIZE(type()); }
template<typename T = uchar> T* ptr(int y = 0, int x = 0) {
return reinterpret_cast<T*>(m_data + m_step*y + x*CV_ELEM_SIZE(type()));
template<typename T = uchar> T* ptr(int y = 0) {
return reinterpret_cast<T*>(m_data + step()*y);
}
template<typename T = uchar> const T* ptr(int y = 0, int x = 0) const {
return reinterpret_cast<const T*>(m_data + m_step*y + x*CV_ELEM_SIZE(type()));
template<typename T = uchar> const T* ptr(int y = 0) const {
return reinterpret_cast<T*>(m_data + step()*y);
}
size_t step() const { return m_step; }
template<typename T = uchar> T* ptr(int y, int x) {
return reinterpret_cast<T*>(m_data + step()*y + step(1)*x);
}
template<typename T = uchar> const T* ptr(int y, int x) const {
return reinterpret_cast<const T*>(m_data + step()*y + step(1)*x);
}
size_t step(size_t i = 0) const { GAPI_DbgAssert(i<m_steps.size()); return m_steps[i]; }
const stepsT& steps() const { return m_steps; }
private:
GMatDesc m_desc;
uchar* m_data = nullptr;
size_t m_step = 0u;
stepsT m_steps = {0u};
DestroyCallback m_cb = nullptr;
};
@@ -88,7 +106,13 @@ public:
// Implementation is responsible for setting the appropriate callback to
// the view when accessed for writing, to ensure that the data from the view
// is transferred to the device when the view is destroyed
virtual View access(Access) const = 0;
virtual View access(Access) = 0;
virtual void serialize(cv::gapi::s11n::IOStream&) {
GAPI_Assert(false && "Generic serialize method should never be called for RMat adapter");
}
virtual void deserialize(cv::gapi::s11n::IIStream&) {
GAPI_Assert(false && "Generic deserialize method should never be called for RMat adapter");
}
};
using AdapterP = std::shared_ptr<Adapter>;
@@ -112,6 +136,10 @@ public:
return dynamic_cast<T*>(m_adapter.get());
}
void serialize(cv::gapi::s11n::IOStream& os) const {
m_adapter->serialize(os);
}
private:
AdapterP m_adapter = nullptr;
};

View File

@@ -8,21 +8,27 @@
#define OPENCV_GAPI_S11N_HPP
#include <vector>
#include <map>
#include <unordered_map>
#include <opencv2/gapi/s11n/base.hpp>
#include <opencv2/gapi/gcomputation.hpp>
#include <opencv2/gapi/rmat.hpp>
namespace cv {
namespace gapi {
namespace detail {
GAPI_EXPORTS cv::GComputation getGraph(const std::vector<char> &p);
} // namespace detail
namespace detail {
GAPI_EXPORTS cv::GMetaArgs getMetaArgs(const std::vector<char> &p);
} // namespace detail
namespace detail {
GAPI_EXPORTS cv::GRunArgs getRunArgs(const std::vector<char> &p);
template<typename... Types>
cv::GCompileArgs getCompileArgs(const std::vector<char> &p);
template<typename RMatAdapterType>
cv::GRunArgs getRunArgsWithRMats(const std::vector<char> &p);
} // namespace detail
GAPI_EXPORTS std::vector<char> serialize(const cv::GComputation &c);
@@ -33,6 +39,7 @@ T deserialize(const std::vector<char> &p);
//} //ananymous namespace
GAPI_EXPORTS std::vector<char> serialize(const cv::GCompileArgs&);
GAPI_EXPORTS std::vector<char> serialize(const cv::GMetaArgs&);
GAPI_EXPORTS std::vector<char> serialize(const cv::GRunArgs&);
@@ -51,7 +58,307 @@ cv::GRunArgs deserialize(const std::vector<char> &p) {
return detail::getRunArgs(p);
}
template<typename T, typename... Types> inline
typename std::enable_if<std::is_same<T, GCompileArgs>::value, GCompileArgs>::
type deserialize(const std::vector<char> &p) {
return detail::getCompileArgs<Types...>(p);
}
template<typename T, typename RMatAdapterType> inline
typename std::enable_if<std::is_same<T, GRunArgs>::value, GRunArgs>::
type deserialize(const std::vector<char> &p) {
return detail::getRunArgsWithRMats<RMatAdapterType>(p);
}
} // namespace gapi
} // namespace cv
namespace cv {
namespace gapi {
namespace s11n {
struct GAPI_EXPORTS IOStream {
virtual ~IOStream() = default;
// Define the native support for basic C++ types at the API level:
virtual IOStream& operator<< (bool) = 0;
virtual IOStream& operator<< (char) = 0;
virtual IOStream& operator<< (unsigned char) = 0;
virtual IOStream& operator<< (short) = 0;
virtual IOStream& operator<< (unsigned short) = 0;
virtual IOStream& operator<< (int) = 0;
virtual IOStream& operator<< (uint32_t) = 0;
virtual IOStream& operator<< (uint64_t) = 0;
virtual IOStream& operator<< (float) = 0;
virtual IOStream& operator<< (double) = 0;
virtual IOStream& operator<< (const std::string&) = 0;
};
struct GAPI_EXPORTS IIStream {
virtual ~IIStream() = default;
virtual IIStream& operator>> (bool &) = 0;
virtual IIStream& operator>> (std::vector<bool>::reference) = 0;
virtual IIStream& operator>> (char &) = 0;
virtual IIStream& operator>> (unsigned char &) = 0;
virtual IIStream& operator>> (short &) = 0;
virtual IIStream& operator>> (unsigned short &) = 0;
virtual IIStream& operator>> (int &) = 0;
virtual IIStream& operator>> (float &) = 0;
virtual IIStream& operator>> (double &) = 0;
virtual IIStream& operator >> (uint32_t &) = 0;
virtual IIStream& operator >> (uint64_t &) = 0;
virtual IIStream& operator>> (std::string &) = 0;
};
namespace detail {
GAPI_EXPORTS std::unique_ptr<IIStream> getInStream(const std::vector<char> &p);
} // namespace detail
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// S11N operators
// Note: operators for basic types are defined in IIStream/IOStream
// OpenCV types ////////////////////////////////////////////////////////////////
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::Point &pt);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::Point &pt);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::Point2f &pt);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::Point2f &pt);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::Size &sz);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::Size &sz);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::Rect &rc);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::Rect &rc);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::Scalar &s);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::Scalar &s);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::Mat &m);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::Mat &m);
// FIXME: for GRunArgs serailization
#if !defined(GAPI_STANDALONE)
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::UMat &);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::UMat &);
#endif // !defined(GAPI_STANDALONE)
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::RMat &r);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::RMat &r);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::gapi::wip::IStreamSource::Ptr &);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::gapi::wip::IStreamSource::Ptr &);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::detail::VectorRef &);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::detail::VectorRef &);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::detail::OpaqueRef &);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::detail::OpaqueRef &);
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::MediaFrame &);
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::MediaFrame &);
// Generic STL types ////////////////////////////////////////////////////////////////
template<typename K, typename V>
IOStream& operator<< (IOStream& os, const std::map<K, V> &m) {
const uint32_t sz = static_cast<uint32_t>(m.size());
os << sz;
for (const auto& it : m) os << it.first << it.second;
return os;
}
template<typename K, typename V>
IIStream& operator>> (IIStream& is, std::map<K, V> &m) {
m.clear();
uint32_t sz = 0u;
is >> sz;
for (std::size_t i = 0; i < sz; ++i) {
K k{};
V v{};
is >> k >> v;
m[k] = v;
}
return is;
}
template<typename K, typename V>
IOStream& operator<< (IOStream& os, const std::unordered_map<K, V> &m) {
const uint32_t sz = static_cast<uint32_t>(m.size());
os << sz;
for (auto &&it : m) os << it.first << it.second;
return os;
}
template<typename K, typename V>
IIStream& operator>> (IIStream& is, std::unordered_map<K, V> &m) {
m.clear();
uint32_t sz = 0u;
is >> sz;
for (std::size_t i = 0; i < sz; ++i) {
K k{};
V v{};
is >> k >> v;
m[k] = v;
}
return is;
}
template<typename T>
IOStream& operator<< (IOStream& os, const std::vector<T> &ts) {
const uint32_t sz = static_cast<uint32_t>(ts.size());
os << sz;
for (auto &&v : ts) os << v;
return os;
}
template<typename T>
IIStream& operator>> (IIStream& is, std::vector<T> &ts) {
uint32_t sz = 0u;
is >> sz;
if (sz == 0u) {
ts.clear();
}
else {
ts.resize(sz);
for (std::size_t i = 0; i < sz; ++i) is >> ts[i];
}
return is;
}
// Generic: variant serialization
namespace detail {
template<typename V>
IOStream& put_v(IOStream&, const V&, std::size_t) {
GAPI_Assert(false && "variant>>: requested index is invalid");
};
template<typename V, typename X, typename... Xs>
IOStream& put_v(IOStream& os, const V& v, std::size_t x) {
return (x == 0u)
? os << cv::util::get<X>(v)
: put_v<V, Xs...>(os, v, x-1);
}
template<typename V>
IIStream& get_v(IIStream&, V&, std::size_t, std::size_t) {
GAPI_Assert(false && "variant<<: requested index is invalid");
}
template<typename V, typename X, typename... Xs>
IIStream& get_v(IIStream& is, V& v, std::size_t i, std::size_t gi) {
if (i == gi) {
X x{};
is >> x;
v = V{std::move(x)};
return is;
} else return get_v<V, Xs...>(is, v, i+1, gi);
}
} // namespace detail
template<typename... Ts>
IOStream& operator<< (IOStream& os, const cv::util::variant<Ts...> &v) {
os << static_cast<uint32_t>(v.index());
return detail::put_v<cv::util::variant<Ts...>, Ts...>(os, v, v.index());
}
template<typename... Ts>
IIStream& operator>> (IIStream& is, cv::util::variant<Ts...> &v) {
int idx = -1;
is >> idx;
GAPI_Assert(idx >= 0 && idx < (int)sizeof...(Ts));
return detail::get_v<cv::util::variant<Ts...>, Ts...>(is, v, 0u, idx);
}
// FIXME: consider a better solution
template<typename... Ts>
void getRunArgByIdx (IIStream& is, cv::util::variant<Ts...> &v, uint32_t idx) {
is = detail::get_v<cv::util::variant<Ts...>, Ts...>(is, v, 0u, idx);
}
} // namespace s11n
namespace detail
{
template<typename T> struct try_deserialize_comparg;
template<> struct try_deserialize_comparg<std::tuple<>> {
static cv::util::optional<GCompileArg> exec(const std::string&, cv::gapi::s11n::IIStream&) {
return { };
}
};
template<typename T, typename... Types>
struct try_deserialize_comparg<std::tuple<T, Types...>> {
static cv::util::optional<GCompileArg> exec(const std::string& tag, cv::gapi::s11n::IIStream& is) {
if (tag == cv::detail::CompileArgTag<T>::tag()) {
static_assert(cv::gapi::s11n::detail::has_S11N_spec<T>::value,
"cv::gapi::deserialize<GCompileArgs, Types...> expects Types to have S11N "
"specializations with deserialization callbacks!");
return cv::util::optional<GCompileArg>(
GCompileArg { cv::gapi::s11n::detail::S11N<T>::deserialize(is) });
}
return try_deserialize_comparg<std::tuple<Types...>>::exec(tag, is);
}
};
template<typename T> struct deserialize_runarg;
template<typename RMatAdapterType>
struct deserialize_runarg {
static GRunArg exec(cv::gapi::s11n::IIStream& is, uint32_t idx) {
if (idx == GRunArg::index_of<RMat>()) {
auto ptr = std::make_shared<RMatAdapterType>();
ptr->deserialize(is);
return GRunArg { RMat(std::move(ptr)) };
} else { // non-RMat arg - use default deserialization
GRunArg arg;
getRunArgByIdx(is, arg, idx);
return arg;
}
}
};
template<typename... Types>
inline cv::util::optional<GCompileArg> tryDeserializeCompArg(const std::string& tag,
const std::vector<char>& sArg) {
std::unique_ptr<cv::gapi::s11n::IIStream> pArgIs = cv::gapi::s11n::detail::getInStream(sArg);
return try_deserialize_comparg<std::tuple<Types...>>::exec(tag, *pArgIs);
}
template<typename... Types>
cv::GCompileArgs getCompileArgs(const std::vector<char> &sArgs) {
cv::GCompileArgs args;
std::unique_ptr<cv::gapi::s11n::IIStream> pIs = cv::gapi::s11n::detail::getInStream(sArgs);
cv::gapi::s11n::IIStream& is = *pIs;
uint32_t sz = 0;
is >> sz;
for (uint32_t i = 0; i < sz; ++i) {
std::string tag;
is >> tag;
std::vector<char> sArg;
is >> sArg;
cv::util::optional<GCompileArg> dArg =
cv::gapi::detail::tryDeserializeCompArg<Types...>(tag, sArg);
if (dArg.has_value())
{
args.push_back(dArg.value());
}
}
return args;
}
template<typename RMatAdapterType>
cv::GRunArgs getRunArgsWithRMats(const std::vector<char> &p) {
std::unique_ptr<cv::gapi::s11n::IIStream> pIs = cv::gapi::s11n::detail::getInStream(p);
cv::gapi::s11n::IIStream& is = *pIs;
cv::GRunArgs args;
uint32_t sz = 0;
is >> sz;
for (uint32_t i = 0; i < sz; ++i) {
uint32_t idx = 0;
is >> idx;
args.push_back(cv::gapi::detail::deserialize_runarg<RMatAdapterType>::exec(is, idx));
}
return args;
}
} // namespace detail
} // namespace gapi
} // namespace cv

View File

@@ -0,0 +1,46 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_S11N_BASE_HPP
#define OPENCV_GAPI_S11N_BASE_HPP
#include <opencv2/gapi/own/assert.hpp>
#include <opencv2/gapi/own/exports.hpp>
namespace cv {
namespace gapi {
namespace s11n {
struct IOStream;
struct IIStream;
namespace detail {
struct NotImplemented {
};
// The default S11N for custom types is NotImplemented
// Don't! sublass from NotImplemented if you actually implement S11N.
template<typename T>
struct S11N: public NotImplemented {
static void serialize(IOStream &, const T &) {
GAPI_Assert(false && "No serialization routine is provided!");
}
static T deserialize(IIStream &) {
GAPI_Assert(false && "No deserialization routine is provided!");
}
};
template<typename T> struct has_S11N_spec {
static constexpr bool value = !std::is_base_of<NotImplemented,
S11N<typename std::decay<T>::type>>::value;
};
} // namespace detail
} // namespace s11n
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_S11N_BASE_HPP

View File

@@ -21,9 +21,11 @@
* Note for developers: please don't put videoio dependency in G-API
* because of this file.
*/
#include <chrono>
#include <opencv2/videoio.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/streaming/meta.hpp>
namespace cv {
namespace gapi {
@@ -55,6 +57,7 @@ protected:
cv::VideoCapture cap;
cv::Mat first;
bool first_pulled = false;
int64_t counter = 0;
void prep()
{
@@ -80,19 +83,26 @@ protected:
GAPI_Assert(!first.empty());
first_pulled = true;
data = first; // no need to clone here since it was cloned already
return true;
}
if (!cap.isOpened()) return false;
cv::Mat frame;
if (!cap.read(frame))
else
{
// end-of-stream happened
return false;
if (!cap.isOpened()) return false;
cv::Mat frame;
if (!cap.read(frame))
{
// end-of-stream happened
return false;
}
// Same reason to clone as in prep()
data = frame.clone();
}
// Same reason to clone as in prep()
data = frame.clone();
// Tag data with seq_id/ts
const auto now = std::chrono::system_clock::now();
const auto dur = std::chrono::duration_cast<std::chrono::microseconds>
(now.time_since_epoch());
data.meta[cv::gapi::streaming::meta_tag::timestamp] = int64_t{dur.count()};
data.meta[cv::gapi::streaming::meta_tag::seq_id] = int64_t{counter++};
return true;
}
@@ -103,6 +113,12 @@ protected:
}
};
// NB: Overload for using from python
GAPI_EXPORTS_W cv::Ptr<IStreamSource> inline make_capture_src(const std::string& path)
{
return make_src<GCaptureSource>(path);
}
} // namespace wip
} // namespace gapi
} // namespace cv

View File

@@ -0,0 +1,84 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_GSTREAMING_DESYNC_HPP
#define OPENCV_GAPI_GSTREAMING_DESYNC_HPP
#include <tuple>
#include <opencv2/gapi/util/util.hpp>
#include <opencv2/gapi/gtype_traits.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/gcall.hpp>
#include <opencv2/gapi/gkernel.hpp>
namespace cv {
namespace gapi {
namespace streaming {
namespace detail {
struct GDesync {
static const char *id() {
return "org.opencv.streaming.desync";
}
// An universal yield for desync.
// Yields output objects according to the input Types...
// Reuses gkernel machinery.
// FIXME: This function can be generic and declared in gkernel.hpp
// (it is there already, but a part of GKernelType[M]
template<typename... R, int... IIs>
static std::tuple<R...> yield(cv::GCall &call, cv::detail::Seq<IIs...>) {
return std::make_tuple(cv::detail::Yield<R>::yield(call, IIs)...);
}
};
template<typename G>
G desync(const G &g) {
cv::GKernel k{
GDesync::id() // kernel id
, "" // kernel tag
, [](const GMetaArgs &a, const GArgs &) {return a;} // outMeta callback
, {cv::detail::GTypeTraits<G>::shape} // output Shape
, {cv::detail::GTypeTraits<G>::op_kind} // input data kinds
, {cv::detail::GObtainCtor<G>::get()} // output template ctors
};
cv::GCall call(std::move(k));
call.pass(g);
return std::get<0>(GDesync::yield<G>(call, cv::detail::MkSeq<1>::type()));
}
} // namespace detail
/**
* @brief Starts a desynchronized branch in the graph.
*
* This operation takes a single G-API data object and returns a
* graph-level "duplicate" of this object.
*
* Operations which use this data object can be desynchronized
* from the rest of the graph.
*
* This operation has no effect when a GComputation is compiled with
* regular cv::GComputation::compile(), since cv::GCompiled objects
* always produce their full output vectors.
*
* This operation only makes sense when a GComputation is compiled in
* straming mode with cv::GComputation::compileStreaming(). If this
* operation is used and there are desynchronized outputs, the user
* should use a special version of cv::GStreamingCompiled::pull()
* which produces an array of cv::util::optional<> objects.
*
* @note This feature is highly experimental now and is currently
* limited to a single GMat argument only.
*/
GAPI_EXPORTS GMat desync(const GMat &g);
} // namespace streaming
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GSTREAMING_DESYNC_HPP

View File

@@ -0,0 +1,52 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_GSTREAMING_FORMAT_HPP
#define OPENCV_GAPI_GSTREAMING_FORMAT_HPP
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
namespace cv {
namespace gapi {
namespace streaming {
cv::gapi::GKernelPackage kernels();
cv::gapi::GBackend backend();
// FIXME: Make a generic kernel
G_API_OP(GCopy, <GFrame(GFrame)>, "org.opencv.streaming.copy")
{
static GFrameDesc outMeta(const GFrameDesc& in) { return in; }
};
G_API_OP(GBGR, <GMat(GFrame)>, "org.opencv.streaming.BGR")
{
static GMatDesc outMeta(const GFrameDesc& in) { return GMatDesc{CV_8U, 3, in.size}; }
};
/** @brief Gets copy from the input frame
@note Function textual ID is "org.opencv.streaming.copy"
@param in Input frame
@return Copy of the input frame
*/
GAPI_EXPORTS cv::GFrame copy(const cv::GFrame& in);
/** @brief Gets bgr plane from input frame
@note Function textual ID is "org.opencv.streaming.BGR"
@param in Input frame
@return Image in BGR format
*/
GAPI_EXPORTS cv::GMat BGR (const cv::GFrame& in);
} // namespace streaming
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GSTREAMING_FORMAT_HPP

View File

@@ -0,0 +1,79 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_GSTREAMING_META_HPP
#define OPENCV_GAPI_GSTREAMING_META_HPP
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/gcall.hpp>
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/gtype_traits.hpp>
namespace cv {
namespace gapi {
namespace streaming {
// FIXME: the name is debatable
namespace meta_tag {
static constexpr const char * timestamp = "org.opencv.gapi.meta.timestamp";
static constexpr const char * seq_id = "org.opencv.gapi.meta.seq_id";
} // namespace meta_tag
namespace detail {
struct GMeta {
static const char *id() {
return "org.opencv.streaming.meta";
}
// A universal yield for meta(), same as in GDesync
template<typename... R, int... IIs>
static std::tuple<R...> yield(cv::GCall &call, cv::detail::Seq<IIs...>) {
return std::make_tuple(cv::detail::Yield<R>::yield(call, IIs)...);
}
// Also a universal outMeta stub here
static GMetaArgs getOutMeta(const GMetaArgs &args, const GArgs &) {
return args;
}
};
} // namespace detail
template<typename T, typename G>
cv::GOpaque<T> meta(G g, const std::string &tag) {
using O = cv::GOpaque<T>;
cv::GKernel k{
detail::GMeta::id() // kernel id
, tag // kernel tag. Use meta tag here
, &detail::GMeta::getOutMeta // outMeta callback
, {cv::detail::GTypeTraits<O>::shape} // output Shape
, {cv::detail::GTypeTraits<G>::op_kind} // input data kinds
, {cv::detail::GObtainCtor<O>::get()} // output template ctors
};
cv::GCall call(std::move(k));
call.pass(g);
return std::get<0>(detail::GMeta::yield<O>(call, cv::detail::MkSeq<1>::type()));
}
template<typename G>
cv::GOpaque<int64_t> timestamp(G g) {
return meta<int64_t>(g, meta_tag::timestamp);
}
template<typename G>
cv::GOpaque<int64_t> seq_id(G g) {
return meta<int64_t>(g, meta_tag::seq_id);
}
template<typename G>
cv::GOpaque<int64_t> seqNo(G g) {
// Old name, compatibility only
return seq_id(g);
}
} // namespace streaming
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GSTREAMING_META_HPP

View File

@@ -0,0 +1,34 @@
// 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) 2020 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_COPY_THROUGH_MOVE_HPP
#define OPENCV_GAPI_UTIL_COPY_THROUGH_MOVE_HPP
#include <opencv2/gapi/util/type_traits.hpp> //decay_t
namespace cv
{
namespace util
{
//This is a tool to move initialize captures of a lambda in C++11
template<typename T>
struct copy_through_move_t{
T value;
const T& get() const {return value;}
T& get() {return value;}
copy_through_move_t(T&& g) : value(std::move(g)) {}
copy_through_move_t(copy_through_move_t&&) = default;
copy_through_move_t(copy_through_move_t const& lhs) : copy_through_move_t(std::move(const_cast<copy_through_move_t&>(lhs))) {}
};
template<typename T>
copy_through_move_t<util::decay_t<T>> copy_through_move(T&& t){
return std::forward<T>(t);
}
} // namespace util
} // namespace cv
#endif /* OPENCV_GAPI_UTIL_COPY_THROUGH_MOVE_HPP */

View File

@@ -35,9 +35,9 @@ namespace util
// instead {}
optional() {};
optional(const optional&) = default;
explicit optional(T &&value) noexcept;
explicit optional(const T &value) noexcept;
optional(optional &&) noexcept;
explicit optional(T&&) noexcept;
explicit optional(const T&) noexcept;
optional(optional&&) noexcept;
// TODO: optional(nullopt_t) noexcept;
// TODO: optional(const optional<U> &)
// TODO: optional(optional<U> &&)
@@ -46,8 +46,8 @@ namespace util
// TODO: optional(U&& value);
// Assignment
optional& operator=(const optional& rhs) = default;
optional& operator=(optional&& rhs);
optional& operator=(const optional&) = default;
optional& operator=(optional&&);
// Observers
T* operator-> ();

View File

@@ -16,6 +16,32 @@
*/
namespace cv { namespace gapi {
/** @brief Structure for the Kalman filter's initialization parameters.*/
struct GAPI_EXPORTS KalmanParams
{
// initial state
//! corrected state (x(k)): x(k)=x'(k)+K(k)*(z(k)-H*x'(k))
Mat state;
//! posteriori error estimate covariance matrix (P(k)): P(k)=(I-K(k)*H)*P'(k)
Mat errorCov;
// dynamic system description
//! state transition matrix (A)
Mat transitionMatrix;
//! measurement matrix (H)
Mat measurementMatrix;
//! process noise covariance matrix (Q)
Mat processNoiseCov;
//! measurement noise covariance matrix (R)
Mat measurementNoiseCov;
//! control matrix (B) (Optional: not used if there's no control)
Mat controlMatrix;
};
namespace video
{
using GBuildPyrOutput = std::tuple<GArray<GMat>, GScalar>;
@@ -62,6 +88,95 @@ G_TYPED_KERNEL(GCalcOptFlowLKForPyr,
return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc());
}
};
enum BackgroundSubtractorType
{
TYPE_BS_MOG2,
TYPE_BS_KNN
};
/** @brief Structure for the Background Subtractor operation's initialization parameters.*/
struct BackgroundSubtractorParams
{
//! Type of the Background Subtractor operation.
BackgroundSubtractorType operation = TYPE_BS_MOG2;
//! Length of the history.
int history = 500;
//! For MOG2: Threshold on the squared Mahalanobis distance between the pixel
//! and the model to decide whether a pixel is well described by
//! the background model.
//! For KNN: Threshold on the squared distance between the pixel and the sample
//! to decide whether a pixel is close to that sample.
double threshold = 16;
//! If true, the algorithm will detect shadows and mark them.
bool detectShadows = true;
//! The value between 0 and 1 that indicates how fast
//! the background model is learnt.
//! Negative parameter value makes the algorithm use some automatically
//! chosen learning rate.
double learningRate = -1;
//! default constructor
BackgroundSubtractorParams() {}
/** Full constructor
@param op MOG2/KNN Background Subtractor type.
@param histLength Length of the history.
@param thrshld For MOG2: Threshold on the squared Mahalanobis distance between
the pixel and the model to decide whether a pixel is well described by the background model.
For KNN: Threshold on the squared distance between the pixel and the sample to decide
whether a pixel is close to that sample.
@param detect If true, the algorithm will detect shadows and mark them. It decreases the
speed a bit, so if you do not need this feature, set the parameter to false.
@param lRate The value between 0 and 1 that indicates how fast the background model is learnt.
Negative parameter value makes the algorithm to use some automatically chosen learning rate.
*/
BackgroundSubtractorParams(BackgroundSubtractorType op, int histLength,
double thrshld, bool detect, double lRate) : operation(op),
history(histLength),
threshold(thrshld),
detectShadows(detect),
learningRate(lRate){}
};
G_TYPED_KERNEL(GBackgroundSubtractor, <GMat(GMat, BackgroundSubtractorParams)>,
"org.opencv.video.BackgroundSubtractor")
{
static GMatDesc outMeta(const GMatDesc& in, const BackgroundSubtractorParams& bsParams)
{
GAPI_Assert(bsParams.history >= 0);
GAPI_Assert(bsParams.learningRate <= 1);
return in.withType(CV_8U, 1);
}
};
void checkParams(const cv::gapi::KalmanParams& kfParams,
const cv::GMatDesc& measurement, const cv::GMatDesc& control = {});
G_TYPED_KERNEL(GKalmanFilter, <GMat(GMat, GOpaque<bool>, GMat, KalmanParams)>,
"org.opencv.video.KalmanFilter")
{
static GMatDesc outMeta(const GMatDesc& measurement, const GOpaqueDesc&,
const GMatDesc& control, const KalmanParams& kfParams)
{
checkParams(kfParams, measurement, control);
return measurement.withSize(Size(1, kfParams.transitionMatrix.rows));
}
};
G_TYPED_KERNEL(GKalmanFilterNoControl, <GMat(GMat, GOpaque<bool>, KalmanParams)>, "org.opencv.video.KalmanFilterNoControl")
{
static GMatDesc outMeta(const GMatDesc& measurement, const GOpaqueDesc&, const KalmanParams& kfParams)
{
checkParams(kfParams, measurement);
return measurement.withSize(Size(1, kfParams.transitionMatrix.rows));
}
};
} //namespace video
//! @addtogroup gapi_video
@@ -83,8 +198,9 @@ G_TYPED_KERNEL(GCalcOptFlowLKForPyr,
@param tryReuseInputImage put ROI of input image into the pyramid if possible. You can pass false
to force data copying.
@return output pyramid.
@return number of levels in constructed pyramid. Can be less than maxLevel.
@return
- output pyramid.
- number of levels in constructed pyramid. Can be less than maxLevel.
*/
GAPI_EXPORTS std::tuple<GArray<GMat>, GScalar>
buildOpticalFlowPyramid(const GMat &img,
@@ -131,11 +247,12 @@ by number of pixels in a window; if this value is less than minEigThreshold, the
feature is filtered out and its flow is not processed, so it allows to remove bad points and get a
performance boost.
@return GArray of 2D points (with single-precision floating-point coordinates)
@return
- GArray of 2D points (with single-precision floating-point coordinates)
containing the calculated new positions of input features in the second image.
@return status GArray (of unsigned chars); each element of the vector is set to 1 if
- status GArray (of unsigned chars); each element of the vector is set to 1 if
the flow for the corresponding features has been found, otherwise, it is set to 0.
@return GArray of errors (doubles); each element of the vector is set to an error for the
- GArray of errors (doubles); each element of the vector is set to an error for the
corresponding feature, type of the error measure can be set in flags parameter; if the flow wasn't
found then the error is not defined (use the status parameter to find such cases).
*/
@@ -169,8 +286,75 @@ calcOpticalFlowPyrLK(const GArray<GMat> &prevPyr,
int flags = 0,
double minEigThresh = 1e-4);
/** @brief Gaussian Mixture-based or K-nearest neighbours-based Background/Foreground Segmentation Algorithm.
The operation generates a foreground mask.
@return Output image is foreground mask, i.e. 8-bit unsigned 1-channel (binary) matrix @ref CV_8UC1.
@note Functional textual ID is "org.opencv.video.BackgroundSubtractor"
@param src input image: Floating point frame is used without scaling and should be in range [0,255].
@param bsParams Set of initialization parameters for Background Subtractor kernel.
*/
GAPI_EXPORTS GMat BackgroundSubtractor(const GMat& src, const cv::gapi::video::BackgroundSubtractorParams& bsParams);
/** @brief Standard Kalman filter algorithm <http://en.wikipedia.org/wiki/Kalman_filter>.
@note Functional textual ID is "org.opencv.video.KalmanFilter"
@param measurement input matrix: 32-bit or 64-bit float 1-channel matrix containing measurements.
@param haveMeasurement dynamic input flag that indicates whether we get measurements
at a particular iteration .
@param control input matrix: 32-bit or 64-bit float 1-channel matrix contains control data
for changing dynamic system.
@param kfParams Set of initialization parameters for Kalman filter kernel.
@return Output matrix is predicted or corrected state. They can be 32-bit or 64-bit float
1-channel matrix @ref CV_32FC1 or @ref CV_64FC1.
@details If measurement matrix is given (haveMeasurements == true), corrected state will
be returned which corresponds to the pipeline
cv::KalmanFilter::predict(control) -> cv::KalmanFilter::correct(measurement).
Otherwise, predicted state will be returned which corresponds to the call of
cv::KalmanFilter::predict(control).
@sa cv::KalmanFilter
*/
GAPI_EXPORTS GMat KalmanFilter(const GMat& measurement, const GOpaque<bool>& haveMeasurement,
const GMat& control, const cv::gapi::KalmanParams& kfParams);
/** @overload
The case of Standard Kalman filter algorithm when there is no control in a dynamic system.
In this case the controlMatrix is empty and control vector is absent.
@note Function textual ID is "org.opencv.video.KalmanFilterNoControl"
@param measurement input matrix: 32-bit or 64-bit float 1-channel matrix containing measurements.
@param haveMeasurement dynamic input flag that indicates whether we get measurements
at a particular iteration.
@param kfParams Set of initialization parameters for Kalman filter kernel.
@return Output matrix is predicted or corrected state. They can be 32-bit or 64-bit float
1-channel matrix @ref CV_32FC1 or @ref CV_64FC1.
@sa cv::KalmanFilter
*/
GAPI_EXPORTS GMat KalmanFilter(const GMat& measurement, const GOpaque<bool>& haveMeasurement,
const cv::gapi::KalmanParams& kfParams);
//! @} gapi_video
} //namespace gapi
} //namespace cv
namespace cv { namespace detail {
template<> struct CompileArgTag<cv::gapi::video::BackgroundSubtractorParams>
{
static const char* tag()
{
return "org.opencv.video.background_substractor_params";
}
};
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_VIDEO_HPP

View File

@@ -1,4 +1,18 @@
#ifndef OPENCV_GAPI_PYOPENCV_GAPI_HPP
#define OPENCV_GAPI_PYOPENCV_GAPI_HPP
#ifdef HAVE_OPENCV_GAPI
// NB: Python wrapper replaces :: with _ for classes
using gapi_GKernelPackage = cv::gapi::GKernelPackage;
using gapi_GNetPackage = cv::gapi::GNetPackage;
using gapi_ie_PyParams = cv::gapi::ie::PyParams;
using gapi_wip_IStreamSource_Ptr = cv::Ptr<cv::gapi::wip::IStreamSource>;
// FIXME: Python wrapper generate code without namespace std,
// so it cause error: "string wasn't declared"
// WA: Create using
using std::string;
template<>
bool pyopencv_to(PyObject* obj, std::vector<GCompileArg>& value, const ArgInfo& info)
@@ -12,6 +26,90 @@ PyObject* pyopencv_from(const std::vector<GCompileArg>& value)
return pyopencv_from_generic_vec(value);
}
template<>
bool pyopencv_to(PyObject* obj, GRunArgs& value, const ArgInfo& info)
{
return pyopencv_to_generic_vec(obj, value, info);
}
static PyObject* from_grunarg(const GRunArg& v)
{
switch (v.index())
{
case GRunArg::index_of<cv::Mat>():
{
const auto& m = util::get<cv::Mat>(v);
return pyopencv_from(m);
}
case GRunArg::index_of<cv::Scalar>():
{
const auto& s = util::get<cv::Scalar>(v);
return pyopencv_from(s);
}
case GRunArg::index_of<cv::detail::VectorRef>():
{
const auto& vref = util::get<cv::detail::VectorRef>(v);
switch (vref.getKind())
{
case cv::detail::OpaqueKind::CV_POINT2F:
return pyopencv_from(vref.rref<cv::Point2f>());
default:
PyErr_SetString(PyExc_TypeError, "Unsupported kind for GArray");
return NULL;
}
}
default:
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs");
return NULL;
}
GAPI_Assert(false);
}
template<>
PyObject* pyopencv_from(const GRunArgs& value)
{
size_t i, n = value.size();
// NB: It doesn't make sense to return list with a single element
if (n == 1)
{
PyObject* item = from_grunarg(value[0]);
if(!item)
{
return NULL;
}
return item;
}
PyObject* list = PyList_New(n);
for(i = 0; i < n; ++i)
{
PyObject* item = from_grunarg(value[i]);
if(!item)
{
Py_DECREF(list);
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs");
return NULL;
}
PyList_SetItem(list, i, item);
}
return list;
}
template<>
bool pyopencv_to(PyObject* obj, GMetaArgs& value, const ArgInfo& info)
{
return pyopencv_to_generic_vec(obj, value, info);
}
template<>
PyObject* pyopencv_from(const GMetaArgs& value)
{
return pyopencv_from_generic_vec(value);
}
template <typename T>
static PyObject* extract_proto_args(PyObject* py_args, PyObject* kw)
{
@@ -19,14 +117,24 @@ static PyObject* extract_proto_args(PyObject* py_args, PyObject* kw)
GProtoArgs args;
Py_ssize_t size = PyTuple_Size(py_args);
for (int i = 0; i < size; ++i) {
for (int i = 0; i < size; ++i)
{
PyObject* item = PyTuple_GetItem(py_args, i);
if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr))) {
if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr)))
{
args.emplace_back(reinterpret_cast<pyopencv_GScalar_t*>(item)->v);
} else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GMat_TypePtr))) {
}
else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GMat_TypePtr)))
{
args.emplace_back(reinterpret_cast<pyopencv_GMat_t*>(item)->v);
} else {
PyErr_SetString(PyExc_TypeError, "cv.GIn() supports only cv.GMat and cv.GScalar");
}
else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayP2f_TypePtr)))
{
args.emplace_back(reinterpret_cast<pyopencv_GArrayP2f_t*>(item)->v.strip());
}
else
{
PyErr_SetString(PyExc_TypeError, "Unsupported type for cv.GIn()/cv.GOut()");
return NULL;
}
}
@@ -43,3 +151,64 @@ static PyObject* pyopencv_cv_GOut(PyObject* , PyObject* py_args, PyObject* kw)
{
return extract_proto_args<GProtoOutputArgs>(py_args, kw);
}
static PyObject* pyopencv_cv_gin(PyObject* , PyObject* py_args, PyObject* kw)
{
using namespace cv;
GRunArgs args;
Py_ssize_t size = PyTuple_Size(py_args);
for (int i = 0; i < size; ++i)
{
PyObject* item = PyTuple_GetItem(py_args, i);
if (PyTuple_Check(item))
{
cv::Scalar s;
if (pyopencv_to(item, s, ArgInfo("scalar", false)))
{
args.emplace_back(s);
}
else
{
PyErr_SetString(PyExc_TypeError, "Failed convert tuple to cv::Scalar");
return NULL;
}
}
else if (PyArray_Check(item))
{
cv::Mat m;
if (pyopencv_to(item, m, ArgInfo("mat", false)))
{
args.emplace_back(m);
}
else
{
PyErr_SetString(PyExc_TypeError, "Failed convert array to cv::Mat");
return NULL;
}
}
else if (PyObject_TypeCheck(item,
reinterpret_cast<PyTypeObject*>(pyopencv_gapi_wip_IStreamSource_TypePtr)))
{
cv::gapi::wip::IStreamSource::Ptr source =
reinterpret_cast<pyopencv_gapi_wip_IStreamSource_t*>(item)->v;
args.emplace_back(source);
}
else
{
PyErr_SetString(PyExc_TypeError, "cv.gin can works only with cv::Mat,"
"cv::Scalar, cv::gapi::wip::IStreamSource::Ptr");
return NULL;
}
}
return pyopencv_from_generic_vec(args);
}
static PyObject* pyopencv_cv_gout(PyObject* o, PyObject* py_args, PyObject* kw)
{
return pyopencv_cv_gin(o, py_args, kw);
}
#endif // HAVE_OPENCV_GAPI
#endif // OPENCV_GAPI_PYOPENCV_GAPI_HPP

View File

@@ -3,11 +3,30 @@
namespace cv
{
struct GAPI_EXPORTS_W_SIMPLE GCompileArg { };
GAPI_EXPORTS_W GCompileArgs compile_args(gapi::GKernelPackage pkg);
GAPI_EXPORTS_W GCompileArgs compile_args(gapi::GNetPackage pkg);
// NB: This classes doesn't exist in *.so
// HACK: Mark them as a class to force python wrapper generate code for this entities
class GAPI_EXPORTS_W_SIMPLE GProtoArg { };
class GAPI_EXPORTS_W_SIMPLE GProtoInputArgs { };
class GAPI_EXPORTS_W_SIMPLE GProtoOutputArgs { };
class GAPI_EXPORTS_W_SIMPLE GRunArg { };
class GAPI_EXPORTS_W_SIMPLE GMetaArg { };
class GAPI_EXPORTS_W_SIMPLE GArrayP2f { };
using GProtoInputArgs = GIOProtoArgs<In_Tag>;
using GProtoOutputArgs = GIOProtoArgs<Out_Tag>;
namespace gapi
{
GAPI_EXPORTS_W gapi::GNetPackage networks(const cv::gapi::ie::PyParams& params);
namespace wip
{
class GAPI_EXPORTS_W IStreamSource { };
} // namespace wip
} // namespace gapi
} // namespace cv

View File

@@ -2,29 +2,30 @@
import numpy as np
import cv2 as cv
import os
from tests_common import NewOpenCVTests
# Plaidml is an optional backend
pkgs = [
cv.gapi.core.ocl.kernels(),
cv.gapi.core.cpu.kernels(),
cv.gapi.core.fluid.kernels()
# cv.gapi.core.plaidml.kernels()
]
('ocl' , cv.gapi.core.ocl.kernels()),
('cpu' , cv.gapi.core.cpu.kernels()),
('fluid' , cv.gapi.core.fluid.kernels())
# ('plaidml', cv.gapi.core.plaidml.kernels())
]
class gapi_core_test(NewOpenCVTests):
def test_add(self):
# TODO: Extend to use any type and size here
sz = (1280, 720)
in1 = np.random.randint(0, 100, sz).astype(np.uint8)
in2 = np.random.randint(0, 100, sz).astype(np.uint8)
sz = (720, 1280)
in1 = np.full(sz, 100)
in2 = np.full(sz, 50)
# OpenCV
expected = in1 + in2
expected = cv.add(in1, in2)
# G-API
g_in1 = cv.GMat()
@@ -32,15 +33,39 @@ class gapi_core_test(NewOpenCVTests):
g_out = cv.gapi.add(g_in1, g_in2)
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
for pkg in pkgs:
actual = comp.apply(in1, in2, args=cv.compile_args(pkg))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in1, in2), args=cv.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
self.assertEqual(expected.dtype, actual.dtype, 'Failed on ' + pkg_name + ' backend')
def test_add_uint8(self):
sz = (720, 1280)
in1 = np.full(sz, 100, dtype=np.uint8)
in2 = np.full(sz, 50 , dtype=np.uint8)
# OpenCV
expected = cv.add(in1, in2)
# G-API
g_in1 = cv.GMat()
g_in2 = cv.GMat()
g_out = cv.gapi.add(g_in1, g_in2)
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in1, in2), args=cv.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
self.assertEqual(expected.dtype, actual.dtype, 'Failed on ' + pkg_name + ' backend')
def test_mean(self):
sz = (1280, 720, 3)
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
in_mat = cv.imread(img_path)
# OpenCV
expected = cv.mean(in_mat)
@@ -50,10 +75,57 @@ class gapi_core_test(NewOpenCVTests):
g_out = cv.gapi.mean(g_in)
comp = cv.GComputation(g_in, g_out)
for pkg in pkgs:
actual = comp.apply(in_mat, args=cv.compile_args(pkg))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in_mat), args=cv.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
def test_split3(self):
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
in_mat = cv.imread(img_path)
# OpenCV
expected = cv.split(in_mat)
# G-API
g_in = cv.GMat()
b, g, r = cv.gapi.split3(g_in)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(b, g, r))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in_mat), args=cv.compile_args(pkg))
# Comparison
for e, a in zip(expected, actual):
self.assertEqual(0.0, cv.norm(e, a, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
self.assertEqual(e.dtype, a.dtype, 'Failed on ' + pkg_name + ' backend')
def test_threshold(self):
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
in_mat = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
maxv = (30, 30)
# OpenCV
expected_thresh, expected_mat = cv.threshold(in_mat, maxv[0], maxv[0], cv.THRESH_TRIANGLE)
# G-API
g_in = cv.GMat()
g_sc = cv.GScalar()
mat, threshold = cv.gapi.threshold(g_in, g_sc, cv.THRESH_TRIANGLE)
comp = cv.GComputation(cv.GIn(g_in, g_sc), cv.GOut(mat, threshold))
for pkg_name, pkg in pkgs:
actual_mat, actual_thresh = comp.apply(cv.gin(in_mat, maxv), args=cv.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected_mat, actual_mat, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
self.assertEqual(expected_mat.dtype, actual_mat.dtype,
'Failed on ' + pkg_name + ' backend')
self.assertEqual(expected_thresh, actual_thresh[0],
'Failed on ' + pkg_name + ' backend')
if __name__ == '__main__':

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
from tests_common import NewOpenCVTests
# Plaidml is an optional backend
pkgs = [
('ocl' , cv.gapi.core.ocl.kernels()),
('cpu' , cv.gapi.core.cpu.kernels()),
('fluid' , cv.gapi.core.fluid.kernels())
# ('plaidml', cv.gapi.core.plaidml.kernels())
]
class gapi_imgproc_test(NewOpenCVTests):
def test_good_features_to_track(self):
# TODO: Extend to use any type and size here
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
in1 = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
# NB: goodFeaturesToTrack configuration
max_corners = 50
quality_lvl = 0.01
min_distance = 10
block_sz = 3
use_harris_detector = True
k = 0.04
mask = None
# OpenCV
expected = cv.goodFeaturesToTrack(in1, max_corners, quality_lvl,
min_distance, mask=mask,
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
# G-API
g_in = cv.GMat()
g_out = cv.gapi.goodFeaturesToTrack(g_in, max_corners, quality_lvl,
min_distance, mask, block_sz, use_harris_detector, k)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in1), args=cv.compile_args(pkg))
# NB: OpenCV & G-API have different output shapes:
# OpenCV - (num_points, 1, 2)
# G-API - (num_points, 2)
# Comparison
self.assertEqual(0.0, cv.norm(expected.flatten(), actual.flatten(), cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
def test_rgb2gray(self):
# TODO: Extend to use any type and size here
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
in1 = cv.imread(img_path)
# OpenCV
expected = cv.cvtColor(in1, cv.COLOR_RGB2GRAY)
# G-API
g_in = cv.GMat()
g_out = cv.gapi.RGB2Gray(g_in)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in1), args=cv.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
from tests_common import NewOpenCVTests
class test_gapi_infer(NewOpenCVTests):
def test_getAvailableTargets(self):
targets = cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_OPENCV)
self.assertTrue(cv.dnn.DNN_TARGET_CPU in targets)
def test_age_gender_infer(self):
# NB: Check IE
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
return
root_path = '/omz_intel_models/intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013'
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
device_id = 'CPU'
img = cv.resize(cv.imread(img_path), (62,62))
# OpenCV DNN
net = cv.dnn.readNetFromModelOptimizer(model_path, weights_path)
net.setPreferableBackend(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE)
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
blob = cv.dnn.blobFromImage(img)
net.setInput(blob)
dnn_age, dnn_gender = net.forward(net.getUnconnectedOutLayersNames())
# OpenCV G-API
g_in = cv.GMat()
inputs = cv.GInferInputs()
inputs.setInput('data', g_in)
outputs = cv.gapi.infer("net", inputs)
age_g = outputs.at("age_conv3")
gender_g = outputs.at("prob")
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(age_g, gender_g))
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
nets = cv.gapi.networks(pp)
args = cv.compile_args(nets)
gapi_age, gapi_gender = comp.apply(cv.gin(img), args=cv.compile_args(cv.gapi.networks(pp)))
# Check
self.assertEqual(0.0, cv.norm(dnn_gender, gapi_gender, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(dnn_age, gapi_age, cv.NORM_INF))
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@@ -2,25 +2,26 @@
import numpy as np
import cv2 as cv
import os
from tests_common import NewOpenCVTests
# Plaidml is an optional backend
pkgs = [
cv.gapi.core.ocl.kernels(),
cv.gapi.core.cpu.kernels(),
cv.gapi.core.fluid.kernels()
# cv.gapi.core.plaidml.kernels()
]
('ocl' , cv.gapi.core.ocl.kernels()),
('cpu' , cv.gapi.core.cpu.kernels()),
('fluid' , cv.gapi.core.fluid.kernels())
# ('plaidml', cv.gapi.core.plaidml.kernels())
]
class gapi_sample_pipelines(NewOpenCVTests):
# NB: This test check multiple outputs for operation
def test_mean_over_r(self):
sz = (100, 100, 3)
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
in_mat = cv.imread(img_path)
# # OpenCV
_, _, r_ch = cv.split(in_mat)
@@ -32,10 +33,11 @@ class gapi_sample_pipelines(NewOpenCVTests):
g_out = cv.gapi.mean(r)
comp = cv.GComputation(g_in, g_out)
for pkg in pkgs:
actual = comp.apply(in_mat, args=cv.compile_args(pkg))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in_mat), args=cv.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
if __name__ == '__main__':

View File

@@ -0,0 +1,202 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
from tests_common import NewOpenCVTests
class test_gapi_streaming(NewOpenCVTests):
def test_image_input(self):
sz = (1280, 720)
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
# OpenCV
expected = cv.medianBlur(in_mat, 3)
# G-API
g_in = cv.GMat()
g_out = cv.gapi.medianBlur(g_in, 3)
c = cv.GComputation(g_in, g_out)
ccomp = c.compileStreaming(cv.descr_of(cv.gin(in_mat)))
ccomp.setSource(cv.gin(in_mat))
ccomp.start()
_, actual = ccomp.pull()
# Assert
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_video_input(self):
ksize = 3
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
# OpenCV
cap = cv.VideoCapture(path)
# G-API
g_in = cv.GMat()
g_out = cv.gapi.medianBlur(g_in, ksize)
c = cv.GComputation(g_in, g_out)
ccomp = c.compileStreaming()
source = cv.gapi.wip.make_capture_src(path)
ccomp.setSource(source)
ccomp.start()
# Assert
max_num_frames = 10
proc_num_frames = 0
while cap.isOpened():
has_expected, expected = cap.read()
has_actual, actual = ccomp.pull()
self.assertEqual(has_expected, has_actual)
if not has_actual:
break
self.assertEqual(0.0, cv.norm(cv.medianBlur(expected, ksize), actual, cv.NORM_INF))
proc_num_frames += 1
if proc_num_frames == max_num_frames:
break;
def test_video_split3(self):
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
# OpenCV
cap = cv.VideoCapture(path)
# G-API
g_in = cv.GMat()
b, g, r = cv.gapi.split3(g_in)
c = cv.GComputation(cv.GIn(g_in), cv.GOut(b, g, r))
ccomp = c.compileStreaming()
source = cv.gapi.wip.make_capture_src(path)
ccomp.setSource(source)
ccomp.start()
# Assert
max_num_frames = 10
proc_num_frames = 0
while cap.isOpened():
has_expected, frame = cap.read()
has_actual, actual = ccomp.pull()
self.assertEqual(has_expected, has_actual)
if not has_actual:
break
expected = cv.split(frame)
for e, a in zip(expected, actual):
self.assertEqual(0.0, cv.norm(e, a, cv.NORM_INF))
proc_num_frames += 1
if proc_num_frames == max_num_frames:
break;
def test_video_add(self):
sz = (576, 768, 3)
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
# OpenCV
cap = cv.VideoCapture(path)
# G-API
g_in1 = cv.GMat()
g_in2 = cv.GMat()
out = cv.gapi.add(g_in1, g_in2)
c = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(out))
ccomp = c.compileStreaming()
source = cv.gapi.wip.make_capture_src(path)
ccomp.setSource(cv.gin(source, in_mat))
ccomp.start()
# Assert
max_num_frames = 10
proc_num_frames = 0
while cap.isOpened():
has_expected, frame = cap.read()
has_actual, actual = ccomp.pull()
self.assertEqual(has_expected, has_actual)
if not has_actual:
break
expected = cv.add(frame, in_mat)
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
proc_num_frames += 1
if proc_num_frames == max_num_frames:
break;
def test_video_good_features_to_track(self):
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
# NB: goodFeaturesToTrack configuration
max_corners = 50
quality_lvl = 0.01
min_distance = 10
block_sz = 3
use_harris_detector = True
k = 0.04
mask = None
# OpenCV
cap = cv.VideoCapture(path)
# G-API
g_in = cv.GMat()
g_gray = cv.gapi.RGB2Gray(g_in)
g_out = cv.gapi.goodFeaturesToTrack(g_gray, max_corners, quality_lvl,
min_distance, mask, block_sz, use_harris_detector, k)
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
ccomp = c.compileStreaming()
source = cv.gapi.wip.make_capture_src(path)
ccomp.setSource(source)
ccomp.start()
# Assert
max_num_frames = 10
proc_num_frames = 0
while cap.isOpened():
has_expected, frame = cap.read()
has_actual, actual = ccomp.pull()
self.assertEqual(has_expected, has_actual)
if not has_actual:
break
# OpenCV
frame = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
expected = cv.goodFeaturesToTrack(frame, max_corners, quality_lvl,
min_distance, mask=mask,
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
for e, a in zip(expected, actual):
# NB: OpenCV & G-API have different output shapes:
# OpenCV - (num_points, 1, 2)
# G-API - (num_points, 2)
self.assertEqual(0.0, cv.norm(e.flatten(), a.flatten(), cv.NORM_INF))
proc_num_frames += 1
if proc_num_frames == max_num_frames:
break;
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@@ -2,7 +2,7 @@
// 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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_CORE_PERF_TESTS_HPP
@@ -52,6 +52,7 @@ namespace opencv_test
class AbsDiffPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
class AbsDiffCPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
class SumPerfTest : public TestPerfParams<tuple<compare_scalar_f, cv::Size, MatType, cv::GCompileArgs>> {};
class CountNonZeroPerfTest : public TestPerfParams<tuple<compare_scalar_f, cv::Size, MatType, cv::GCompileArgs>> {};
class AddWeightedPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, cv::GCompileArgs>> {};
class NormPerfTest : public TestPerfParams<tuple<compare_scalar_f, NormTypes, cv::Size, MatType, cv::GCompileArgs>> {};
class IntegralPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};

View File

@@ -2,7 +2,7 @@
// 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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_CORE_PERF_TESTS_INL_HPP
@@ -1011,6 +1011,44 @@ PERF_TEST_P_(SumPerfTest, TestPerformance)
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
#pragma push_macro("countNonZero")
#undef countNonZero
PERF_TEST_P_(CountNonZeroPerfTest, TestPerformance)
{
compare_scalar_f cmpF;
cv::Size sz_in;
MatType type = -1;
cv::GCompileArgs compile_args;
std::tie(cmpF, sz_in, type, compile_args) = GetParam();
initMatrixRandU(type, sz_in, type, false);
int out_cnz_gapi, out_cnz_ocv;
// OpenCV code ///////////////////////////////////////////////////////////
out_cnz_ocv = cv::countNonZero(in_mat1);
// G-API code ////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::countNonZero(in);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
// Warm-up graph engine:
c.apply(cv::gin(in_mat1), cv::gout(out_cnz_gapi), std::move(compile_args));
TEST_CYCLE()
{
c.apply(cv::gin(in_mat1), cv::gout(out_cnz_gapi));
}
// Comparison ////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_cnz_gapi, out_cnz_ocv));
}
SANITY_CHECK_NOTHING();
}
#pragma pop_macro("countNonZero")
//------------------------------------------------------------------------------
PERF_TEST_P_(AddWeightedPerfTest, TestPerformance)
@@ -2086,7 +2124,7 @@ PERF_TEST_P_(SizePerfTest, TestPerformance)
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::size(in);
auto out = cv::gapi::streaming::size(in);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
cv::Size out_sz;
@@ -2118,7 +2156,7 @@ PERF_TEST_P_(SizeRPerfTest, TestPerformance)
// G-API code //////////////////////////////////////////////////////////////
cv::GOpaque<cv::Rect> op_rect;
auto out = cv::gapi::size(op_rect);
auto out = cv::gapi::streaming::size(op_rect);
cv::GComputation c(cv::GIn(op_rect), cv::GOut(out));
cv::Size out_sz;

View File

@@ -42,10 +42,15 @@ class GoodFeaturesPerfTest : public TestPerfParams<tuple<compare_vector_f<cv:
int,int,double,double,int,bool,
cv::GCompileArgs>> {};
class EqHistPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BGR2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BGR2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2YUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class YUV2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BGR2I420PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2I420PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class I4202BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class I4202RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2LabPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BGR2LUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class LUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};

View File

@@ -788,6 +788,44 @@ PERF_TEST_P_(EqHistPerfTest, TestPerformance)
//------------------------------------------------------------------------------
PERF_TEST_P_(BGR2RGBPerfTest, TestPerformance)
{
compare_f cmpF;
cv::Size sz;
cv::GCompileArgs compile_args;
std::tie(cmpF, sz, compile_args) = GetParam();
initMatrixRandN(CV_8UC3, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2RGB);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BGR2RGB(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
PERF_TEST_P_(RGB2GrayPerfTest, TestPerformance)
{
compare_f cmpF = get<0>(GetParam());
@@ -940,6 +978,158 @@ PERF_TEST_P_(YUV2RGBPerfTest, TestPerformance)
//------------------------------------------------------------------------------
PERF_TEST_P_(BGR2I420PerfTest, TestPerformance)
{
compare_f cmpF;
cv::Size sz;
cv::GCompileArgs compile_args;
std::tie(cmpF, sz, compile_args) = GetParam();
initMatrixRandN(CV_8UC3, sz, CV_8UC1, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2YUV_I420);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BGR2I420(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), Size(sz.width, sz.height * 3 / 2));
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
PERF_TEST_P_(RGB2I420PerfTest, TestPerformance)
{
compare_f cmpF;
cv::Size sz;
cv::GCompileArgs compile_args;
std::tie(cmpF, sz, compile_args) = GetParam();
initMatrixRandN(CV_8UC3, sz, CV_8UC1, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2YUV_I420);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2I420(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), Size(sz.width, sz.height * 3 / 2));
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
PERF_TEST_P_(I4202BGRPerfTest, TestPerformance)
{
compare_f cmpF;
cv::Size sz;
cv::GCompileArgs compile_args;
std::tie(cmpF, sz, compile_args) = GetParam();
initMatrixRandN(CV_8UC1, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2BGR_I420);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::I4202BGR(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), Size(sz.width, sz.height * 2 / 3));
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
PERF_TEST_P_(I4202RGBPerfTest, TestPerformance)
{
compare_f cmpF;
cv::Size sz;
cv::GCompileArgs compile_args;
std::tie(cmpF, sz, compile_args) = GetParam();
initMatrixRandN(CV_8UC1, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2RGB_I420);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::I4202RGB(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), Size(sz.width, sz.height * 2 / 3));
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
PERF_TEST_P_(RGB2LabPerfTest, TestPerformance)
{
compare_f cmpF = get<0>(GetParam());

Some files were not shown because too many files have changed in this diff Show More