feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

View File

@ -0,0 +1,299 @@
__all__ = ['op', 'kernel']
import sys
import cv2 as cv
# NB: Register function in specific module
def register(mname):
def parameterized(func):
sys.modules[mname].__dict__[func.__name__] = func
return func
return parameterized
@register('cv2.gapi')
def networks(*args):
return cv.gapi_GNetPackage(list(map(cv.detail.strip, args)))
@register('cv2.gapi')
def compile_args(*args):
return list(map(cv.GCompileArg, args))
@register('cv2')
def GIn(*args):
return [*args]
@register('cv2')
def GOut(*args):
return [*args]
@register('cv2')
def gin(*args):
return [*args]
@register('cv2.gapi')
def descr_of(*args):
return [*args]
@register('cv2')
class GOpaque():
# NB: Inheritance from c++ class cause segfault.
# So just aggregate cv.GOpaqueT instead of inheritance
def __new__(cls, argtype):
return cv.GOpaqueT(argtype)
class Bool():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_BOOL)
class Int():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_INT)
class Double():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_DOUBLE)
class Float():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_FLOAT)
class String():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_STRING)
class Point():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_POINT)
class Point2f():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_POINT2F)
class Size():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_SIZE)
class Rect():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_RECT)
class Prim():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_DRAW_PRIM)
class Any():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_ANY)
@register('cv2')
class GArray():
# NB: Inheritance from c++ class cause segfault.
# So just aggregate cv.GArrayT instead of inheritance
def __new__(cls, argtype):
return cv.GArrayT(argtype)
class Bool():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_BOOL)
class Int():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_INT)
class Double():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_DOUBLE)
class Float():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_FLOAT)
class String():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_STRING)
class Point():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_POINT)
class Point2f():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_POINT2F)
class Size():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_SIZE)
class Rect():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_RECT)
class Scalar():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_SCALAR)
class Mat():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_MAT)
class GMat():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_GMAT)
class Prim():
def __new__(self):
return cv.GArray(cv.gapi.CV_DRAW_PRIM)
class Any():
def __new__(self):
return cv.GArray(cv.gapi.CV_ANY)
# NB: Top lvl decorator takes arguments
def op(op_id, in_types, out_types):
garray_types= {
cv.GArray.Bool: cv.gapi.CV_BOOL,
cv.GArray.Int: cv.gapi.CV_INT,
cv.GArray.Double: cv.gapi.CV_DOUBLE,
cv.GArray.Float: cv.gapi.CV_FLOAT,
cv.GArray.String: cv.gapi.CV_STRING,
cv.GArray.Point: cv.gapi.CV_POINT,
cv.GArray.Point2f: cv.gapi.CV_POINT2F,
cv.GArray.Size: cv.gapi.CV_SIZE,
cv.GArray.Rect: cv.gapi.CV_RECT,
cv.GArray.Scalar: cv.gapi.CV_SCALAR,
cv.GArray.Mat: cv.gapi.CV_MAT,
cv.GArray.GMat: cv.gapi.CV_GMAT,
cv.GArray.Prim: cv.gapi.CV_DRAW_PRIM,
cv.GArray.Any: cv.gapi.CV_ANY
}
gopaque_types= {
cv.GOpaque.Size: cv.gapi.CV_SIZE,
cv.GOpaque.Rect: cv.gapi.CV_RECT,
cv.GOpaque.Bool: cv.gapi.CV_BOOL,
cv.GOpaque.Int: cv.gapi.CV_INT,
cv.GOpaque.Double: cv.gapi.CV_DOUBLE,
cv.GOpaque.Float: cv.gapi.CV_FLOAT,
cv.GOpaque.String: cv.gapi.CV_STRING,
cv.GOpaque.Point: cv.gapi.CV_POINT,
cv.GOpaque.Point2f: cv.gapi.CV_POINT2F,
cv.GOpaque.Size: cv.gapi.CV_SIZE,
cv.GOpaque.Rect: cv.gapi.CV_RECT,
cv.GOpaque.Prim: cv.gapi.CV_DRAW_PRIM,
cv.GOpaque.Any: cv.gapi.CV_ANY
}
type2str = {
cv.gapi.CV_BOOL: 'cv.gapi.CV_BOOL' ,
cv.gapi.CV_INT: 'cv.gapi.CV_INT' ,
cv.gapi.CV_DOUBLE: 'cv.gapi.CV_DOUBLE' ,
cv.gapi.CV_FLOAT: 'cv.gapi.CV_FLOAT' ,
cv.gapi.CV_STRING: 'cv.gapi.CV_STRING' ,
cv.gapi.CV_POINT: 'cv.gapi.CV_POINT' ,
cv.gapi.CV_POINT2F: 'cv.gapi.CV_POINT2F' ,
cv.gapi.CV_SIZE: 'cv.gapi.CV_SIZE',
cv.gapi.CV_RECT: 'cv.gapi.CV_RECT',
cv.gapi.CV_SCALAR: 'cv.gapi.CV_SCALAR',
cv.gapi.CV_MAT: 'cv.gapi.CV_MAT',
cv.gapi.CV_GMAT: 'cv.gapi.CV_GMAT',
cv.gapi.CV_DRAW_PRIM: 'cv.gapi.CV_DRAW_PRIM'
}
# NB: Second lvl decorator takes class to decorate
def op_with_params(cls):
if not in_types:
raise Exception('{} operation should have at least one input!'.format(cls.__name__))
if not out_types:
raise Exception('{} operation should have at least one output!'.format(cls.__name__))
for i, t in enumerate(out_types):
if t not in [cv.GMat, cv.GScalar, *garray_types, *gopaque_types]:
raise Exception('{} unsupported output type: {} in possition: {}'
.format(cls.__name__, t.__name__, i))
def on(*args):
if len(in_types) != len(args):
raise Exception('Invalid number of input elements!\nExpected: {}, Actual: {}'
.format(len(in_types), len(args)))
for i, (t, a) in enumerate(zip(in_types, args)):
if t in garray_types:
if not isinstance(a, cv.GArrayT):
raise Exception("{} invalid type for argument {}.\nExpected: {}, Actual: {}"
.format(cls.__name__, i, cv.GArrayT.__name__, type(a).__name__))
elif a.type() != garray_types[t]:
raise Exception("{} invalid GArrayT type for argument {}.\nExpected: {}, Actual: {}"
.format(cls.__name__, i, type2str[garray_types[t]], type2str[a.type()]))
elif t in gopaque_types:
if not isinstance(a, cv.GOpaqueT):
raise Exception("{} invalid type for argument {}.\nExpected: {}, Actual: {}"
.format(cls.__name__, i, cv.GOpaqueT.__name__, type(a).__name__))
elif a.type() != gopaque_types[t]:
raise Exception("{} invalid GOpaque type for argument {}.\nExpected: {}, Actual: {}"
.format(cls.__name__, i, type2str[gopaque_types[t]], type2str[a.type()]))
else:
if t != type(a):
raise Exception('{} invalid input type for argument {}.\nExpected: {}, Actual: {}'
.format(cls.__name__, i, t.__name__, type(a).__name__))
op = cv.gapi.__op(op_id, cls.outMeta, *args)
out_protos = []
for i, out_type in enumerate(out_types):
if out_type == cv.GMat:
out_protos.append(op.getGMat())
elif out_type == cv.GScalar:
out_protos.append(op.getGScalar())
elif out_type in gopaque_types:
out_protos.append(op.getGOpaque(gopaque_types[out_type]))
elif out_type in garray_types:
out_protos.append(op.getGArray(garray_types[out_type]))
else:
raise Exception("""In {}: G-API operation can't produce the output with type: {} in position: {}"""
.format(cls.__name__, out_type.__name__, i))
return tuple(out_protos) if len(out_protos) != 1 else out_protos[0]
# NB: Extend operation class
cls.id = op_id
cls.on = staticmethod(on)
return cls
return op_with_params
def kernel(op_cls):
# NB: Second lvl decorator takes class to decorate
def kernel_with_params(cls):
# NB: Add new members to kernel class
cls.id = op_cls.id
cls.outMeta = op_cls.outMeta
return cls
return kernel_with_params
# FIXME: On the c++ side every class is placed in cv2 module.
cv.gapi.wip.draw.Rect = cv.gapi_wip_draw_Rect
cv.gapi.wip.draw.Text = cv.gapi_wip_draw_Text
cv.gapi.wip.draw.Circle = cv.gapi_wip_draw_Circle
cv.gapi.wip.draw.Line = cv.gapi_wip_draw_Line
cv.gapi.wip.draw.Mosaic = cv.gapi_wip_draw_Mosaic
cv.gapi.wip.draw.Image = cv.gapi_wip_draw_Image
cv.gapi.wip.draw.Poly = cv.gapi_wip_draw_Poly
cv.gapi.streaming.queue_capacity = cv.gapi_streaming_queue_capacity

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,338 @@
// 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) 2021 Intel Corporation
#ifndef OPENCV_GAPI_PYTHON_BRIDGE_HPP
#define OPENCV_GAPI_PYTHON_BRIDGE_HPP
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/render/render_types.hpp> // Prim
#define ID(T, E) T
#define ID_(T, E) ID(T, E),
#define WRAP_ARGS(T, E, G) \
G(T, E)
#define SWITCH(type, LIST_G, HC) \
switch(type) { \
LIST_G(HC, HC) \
default: \
GAPI_Assert(false && "Unsupported type"); \
}
using cv::gapi::wip::draw::Prim;
#define GARRAY_TYPE_LIST_G(G, G2) \
WRAP_ARGS(bool , cv::gapi::ArgType::CV_BOOL, G) \
WRAP_ARGS(int , cv::gapi::ArgType::CV_INT, G) \
WRAP_ARGS(int64_t , cv::gapi::ArgType::CV_INT64, G) \
WRAP_ARGS(double , cv::gapi::ArgType::CV_DOUBLE, G) \
WRAP_ARGS(float , cv::gapi::ArgType::CV_FLOAT, G) \
WRAP_ARGS(std::string , cv::gapi::ArgType::CV_STRING, G) \
WRAP_ARGS(cv::Point , cv::gapi::ArgType::CV_POINT, G) \
WRAP_ARGS(cv::Point2f , cv::gapi::ArgType::CV_POINT2F, G) \
WRAP_ARGS(cv::Size , cv::gapi::ArgType::CV_SIZE, G) \
WRAP_ARGS(cv::Rect , cv::gapi::ArgType::CV_RECT, G) \
WRAP_ARGS(cv::Scalar , cv::gapi::ArgType::CV_SCALAR, G) \
WRAP_ARGS(cv::Mat , cv::gapi::ArgType::CV_MAT, G) \
WRAP_ARGS(Prim , cv::gapi::ArgType::CV_DRAW_PRIM, G) \
WRAP_ARGS(cv::GArg , cv::gapi::ArgType::CV_ANY, G) \
WRAP_ARGS(cv::GMat , cv::gapi::ArgType::CV_GMAT, G2) \
#define GOPAQUE_TYPE_LIST_G(G, G2) \
WRAP_ARGS(bool , cv::gapi::ArgType::CV_BOOL, G) \
WRAP_ARGS(int , cv::gapi::ArgType::CV_INT, G) \
WRAP_ARGS(int64_t , cv::gapi::ArgType::CV_INT64, G) \
WRAP_ARGS(double , cv::gapi::ArgType::CV_DOUBLE, G) \
WRAP_ARGS(float , cv::gapi::ArgType::CV_FLOAT, G) \
WRAP_ARGS(std::string , cv::gapi::ArgType::CV_STRING, G) \
WRAP_ARGS(cv::Point , cv::gapi::ArgType::CV_POINT, G) \
WRAP_ARGS(cv::Point2f , cv::gapi::ArgType::CV_POINT2F, G) \
WRAP_ARGS(cv::Size , cv::gapi::ArgType::CV_SIZE, G) \
WRAP_ARGS(cv::GArg , cv::gapi::ArgType::CV_ANY, G) \
WRAP_ARGS(cv::Rect , cv::gapi::ArgType::CV_RECT, G2) \
namespace cv {
namespace gapi {
// NB: cv.gapi.CV_BOOL in python
enum ArgType {
CV_BOOL,
CV_INT,
CV_INT64,
CV_DOUBLE,
CV_FLOAT,
CV_STRING,
CV_POINT,
CV_POINT2F,
CV_SIZE,
CV_RECT,
CV_SCALAR,
CV_MAT,
CV_GMAT,
CV_DRAW_PRIM,
CV_ANY,
};
GAPI_EXPORTS_W inline cv::GInferOutputs infer(const String& name, const cv::GInferInputs& inputs)
{
return infer<Generic>(name, inputs);
}
GAPI_EXPORTS_W inline GInferOutputs infer(const std::string& name,
const cv::GOpaque<cv::Rect>& roi,
const GInferInputs& inputs)
{
return infer<Generic>(name, roi, inputs);
}
GAPI_EXPORTS_W inline GInferListOutputs infer(const std::string& name,
const cv::GArray<cv::Rect>& rois,
const GInferInputs& inputs)
{
return infer<Generic>(name, rois, inputs);
}
GAPI_EXPORTS_W inline GInferListOutputs infer2(const std::string& name,
const cv::GMat in,
const GInferListInputs& inputs)
{
return infer2<Generic>(name, in, inputs);
}
} // namespace gapi
namespace detail {
template <template <typename> class Wrapper, typename T>
struct WrapType { using type = Wrapper<T>; };
template <template <typename> class T, typename... Types>
using MakeVariantType = cv::util::variant<typename WrapType<T, Types>::type...>;
template<typename T> struct ArgTypeTraits;
#define DEFINE_TYPE_TRAITS(T, E) \
template <> \
struct ArgTypeTraits<T> { \
static constexpr const cv::gapi::ArgType type = E; \
}; \
GARRAY_TYPE_LIST_G(DEFINE_TYPE_TRAITS, DEFINE_TYPE_TRAITS)
} // namespace detail
class GAPI_EXPORTS_W_SIMPLE GOpaqueT
{
public:
GOpaqueT() = default;
using Storage = cv::detail::MakeVariantType<cv::GOpaque, GOPAQUE_TYPE_LIST_G(ID_, ID)>;
template<typename T>
GOpaqueT(cv::GOpaque<T> arg) : m_type(cv::detail::ArgTypeTraits<T>::type), m_arg(arg) { };
GAPI_WRAP GOpaqueT(gapi::ArgType type) : m_type(type)
{
#define HC(T, K) case K: \
m_arg = cv::GOpaque<T>(); \
break;
SWITCH(type, GOPAQUE_TYPE_LIST_G, HC)
#undef HC
}
cv::detail::GOpaqueU strip() {
#define HC(T, K) case Storage:: index_of<cv::GOpaque<T>>(): \
return cv::util::get<cv::GOpaque<T>>(m_arg).strip(); \
SWITCH(m_arg.index(), GOPAQUE_TYPE_LIST_G, HC)
#undef HC
GAPI_Assert(false);
}
GAPI_WRAP gapi::ArgType type() { return m_type; }
const Storage& arg() const { return m_arg; }
private:
gapi::ArgType m_type;
Storage m_arg;
};
class GAPI_EXPORTS_W_SIMPLE GArrayT
{
public:
GArrayT() = default;
using Storage = cv::detail::MakeVariantType<cv::GArray, GARRAY_TYPE_LIST_G(ID_, ID)>;
template<typename T>
GArrayT(cv::GArray<T> arg) : m_type(cv::detail::ArgTypeTraits<T>::type), m_arg(arg) { };
GAPI_WRAP GArrayT(gapi::ArgType type) : m_type(type)
{
#define HC(T, K) case K: \
m_arg = cv::GArray<T>(); \
break;
SWITCH(type, GARRAY_TYPE_LIST_G, HC)
#undef HC
}
cv::detail::GArrayU strip() {
#define HC(T, K) case Storage:: index_of<cv::GArray<T>>(): \
return cv::util::get<cv::GArray<T>>(m_arg).strip(); \
SWITCH(m_arg.index(), GARRAY_TYPE_LIST_G, HC)
#undef HC
GAPI_Assert(false);
}
GAPI_WRAP gapi::ArgType type() { return m_type; }
const Storage& arg() const { return m_arg; }
private:
gapi::ArgType m_type;
Storage m_arg;
};
namespace gapi {
namespace wip {
class GAPI_EXPORTS_W_SIMPLE GOutputs
{
public:
GOutputs() = default;
GOutputs(const std::string& id, cv::GKernel::M outMeta, cv::GArgs &&ins);
GAPI_WRAP cv::GMat getGMat();
GAPI_WRAP cv::GScalar getGScalar();
GAPI_WRAP cv::GArrayT getGArray(cv::gapi::ArgType type);
GAPI_WRAP cv::GOpaqueT getGOpaque(cv::gapi::ArgType type);
private:
class Priv;
std::shared_ptr<Priv> m_priv;
};
GOutputs op(const std::string& id, cv::GKernel::M outMeta, cv::GArgs&& args);
template <typename... T>
GOutputs op(const std::string& id, cv::GKernel::M outMeta, T&&... args)
{
return op(id, outMeta, cv::GArgs{cv::GArg(std::forward<T>(args))... });
}
} // namespace wip
} // namespace gapi
} // namespace cv
cv::gapi::wip::GOutputs cv::gapi::wip::op(const std::string& id,
cv::GKernel::M outMeta,
cv::GArgs&& args)
{
cv::gapi::wip::GOutputs outputs{id, outMeta, std::move(args)};
return outputs;
}
class cv::gapi::wip::GOutputs::Priv
{
public:
Priv(const std::string& id, cv::GKernel::M outMeta, cv::GArgs &&ins);
cv::GMat getGMat();
cv::GScalar getGScalar();
cv::GArrayT getGArray(cv::gapi::ArgType);
cv::GOpaqueT getGOpaque(cv::gapi::ArgType);
private:
int output = 0;
std::unique_ptr<cv::GCall> m_call;
};
cv::gapi::wip::GOutputs::Priv::Priv(const std::string& id, cv::GKernel::M outMeta, cv::GArgs &&args)
{
cv::GKinds kinds;
kinds.reserve(args.size());
std::transform(args.begin(), args.end(), std::back_inserter(kinds),
[](const cv::GArg& arg) { return arg.opaque_kind; });
m_call.reset(new cv::GCall{cv::GKernel{id, {}, outMeta, {}, std::move(kinds), {}}});
m_call->setArgs(std::move(args));
}
cv::GMat cv::gapi::wip::GOutputs::Priv::getGMat()
{
m_call->kernel().outShapes.push_back(cv::GShape::GMAT);
// ...so _empty_ constructor is passed here.
m_call->kernel().outCtors.emplace_back(cv::util::monostate{});
return m_call->yield(output++);
}
cv::GScalar cv::gapi::wip::GOutputs::Priv::getGScalar()
{
m_call->kernel().outShapes.push_back(cv::GShape::GSCALAR);
// ...so _empty_ constructor is passed here.
m_call->kernel().outCtors.emplace_back(cv::util::monostate{});
return m_call->yieldScalar(output++);
}
cv::GArrayT cv::gapi::wip::GOutputs::Priv::getGArray(cv::gapi::ArgType type)
{
m_call->kernel().outShapes.push_back(cv::GShape::GARRAY);
#define HC(T, K) \
case K: \
m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<cv::GArray<T>>::get()); \
return cv::GArrayT(m_call->yieldArray<T>(output++)); \
SWITCH(type, GARRAY_TYPE_LIST_G, HC)
#undef HC
}
cv::GOpaqueT cv::gapi::wip::GOutputs::Priv::getGOpaque(cv::gapi::ArgType type)
{
m_call->kernel().outShapes.push_back(cv::GShape::GOPAQUE);
#define HC(T, K) \
case K: \
m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<cv::GOpaque<T>>::get()); \
return cv::GOpaqueT(m_call->yieldOpaque<T>(output++)); \
SWITCH(type, GOPAQUE_TYPE_LIST_G, HC)
#undef HC
}
cv::gapi::wip::GOutputs::GOutputs(const std::string& id,
cv::GKernel::M outMeta,
cv::GArgs &&ins) :
m_priv(new cv::gapi::wip::GOutputs::Priv(id, outMeta, std::move(ins)))
{
}
cv::GMat cv::gapi::wip::GOutputs::getGMat()
{
return m_priv->getGMat();
}
cv::GScalar cv::gapi::wip::GOutputs::getGScalar()
{
return m_priv->getGScalar();
}
cv::GArrayT cv::gapi::wip::GOutputs::getGArray(cv::gapi::ArgType type)
{
return m_priv->getGArray(type);
}
cv::GOpaqueT cv::gapi::wip::GOutputs::getGOpaque(cv::gapi::ArgType type)
{
return m_priv->getGOpaque(type);
}
#endif // OPENCV_GAPI_PYTHON_BRIDGE_HPP

View File

@ -0,0 +1,458 @@
import argparse
import time
import numpy as np
import cv2 as cv
# ------------------------Service operations------------------------
def weight_path(model_path):
""" Get path of weights based on path to IR
Params:
model_path: the string contains path to IR file
Return:
Path to weights file
"""
assert model_path.endswith('.xml'), "Wrong topology path was provided"
return model_path[:-3] + 'bin'
def build_argparser():
""" Parse arguments from command line
Return:
Pack of arguments from command line
"""
parser = argparse.ArgumentParser(description='This is an OpenCV-based version of Gaze Estimation example')
parser.add_argument('--input',
help='Path to the input video file')
parser.add_argument('--out',
help='Path to the output video file')
parser.add_argument('--facem',
default='face-detection-retail-0005.xml',
help='Path to OpenVINO face detection model (.xml)')
parser.add_argument('--faced',
default='CPU',
help='Target device for the face detection' +
'(e.g. CPU, GPU, VPU, ...)')
parser.add_argument('--headm',
default='head-pose-estimation-adas-0001.xml',
help='Path to OpenVINO head pose estimation model (.xml)')
parser.add_argument('--headd',
default='CPU',
help='Target device for the head pose estimation inference ' +
'(e.g. CPU, GPU, VPU, ...)')
parser.add_argument('--landm',
default='facial-landmarks-35-adas-0002.xml',
help='Path to OpenVINO landmarks detector model (.xml)')
parser.add_argument('--landd',
default='CPU',
help='Target device for the landmarks detector (e.g. CPU, GPU, VPU, ...)')
parser.add_argument('--gazem',
default='gaze-estimation-adas-0002.xml',
help='Path to OpenVINO gaze vector estimaiton model (.xml)')
parser.add_argument('--gazed',
default='CPU',
help='Target device for the gaze vector estimation inference ' +
'(e.g. CPU, GPU, VPU, ...)')
parser.add_argument('--eyem',
default='open-closed-eye-0001.xml',
help='Path to OpenVINO open closed eye model (.xml)')
parser.add_argument('--eyed',
default='CPU',
help='Target device for the eyes state inference (e.g. CPU, GPU, VPU, ...)')
return parser
# ------------------------Support functions for custom kernels------------------------
def intersection(surface, rect):
""" Remove zone of out of bound from ROI
Params:
surface: image bounds is rect representation (top left coordinates and width and height)
rect: region of interest is also has rect representation
Return:
Modified ROI with correct bounds
"""
l_x = max(surface[0], rect[0])
l_y = max(surface[1], rect[1])
width = min(surface[0] + surface[2], rect[0] + rect[2]) - l_x
height = min(surface[1] + surface[3], rect[1] + rect[3]) - l_y
if width < 0 or height < 0:
return (0, 0, 0, 0)
return (l_x, l_y, width, height)
def process_landmarks(r_x, r_y, r_w, r_h, landmarks):
""" Create points from result of inference of facial-landmarks network and size of input image
Params:
r_x: x coordinate of top left corner of input image
r_y: y coordinate of top left corner of input image
r_w: width of input image
r_h: height of input image
landmarks: result of inference of facial-landmarks network
Return:
Array of landmarks points for one face
"""
lmrks = landmarks[0]
raw_x = lmrks[::2] * r_w + r_x
raw_y = lmrks[1::2] * r_h + r_y
return np.array([[int(x), int(y)] for x, y in zip(raw_x, raw_y)])
def eye_box(p_1, p_2, scale=1.8):
""" Get bounding box of eye
Params:
p_1: point of left edge of eye
p_2: point of right edge of eye
scale: change size of box with this value
Return:
Bounding box of eye and its midpoint
"""
size = np.linalg.norm(p_1 - p_2)
midpoint = (p_1 + p_2) / 2
width = scale * size
height = width
p_x = midpoint[0] - (width / 2)
p_y = midpoint[1] - (height / 2)
return (int(p_x), int(p_y), int(width), int(height)), list(map(int, midpoint))
# ------------------------Custom graph operations------------------------
@cv.gapi.op('custom.GProcessPoses',
in_types=[cv.GArray.GMat, cv.GArray.GMat, cv.GArray.GMat],
out_types=[cv.GArray.GMat])
class GProcessPoses:
@staticmethod
def outMeta(arr_desc0, arr_desc1, arr_desc2):
return cv.empty_array_desc()
@cv.gapi.op('custom.GParseEyes',
in_types=[cv.GArray.GMat, cv.GArray.Rect, cv.GOpaque.Size],
out_types=[cv.GArray.Rect, cv.GArray.Rect, cv.GArray.Point, cv.GArray.Point])
class GParseEyes:
@staticmethod
def outMeta(arr_desc0, arr_desc1, arr_desc2):
return cv.empty_array_desc(), cv.empty_array_desc(), \
cv.empty_array_desc(), cv.empty_array_desc()
@cv.gapi.op('custom.GGetStates',
in_types=[cv.GArray.GMat, cv.GArray.GMat],
out_types=[cv.GArray.Int, cv.GArray.Int])
class GGetStates:
@staticmethod
def outMeta(arr_desc0, arr_desc1):
return cv.empty_array_desc(), cv.empty_array_desc()
# ------------------------Custom kernels------------------------
@cv.gapi.kernel(GProcessPoses)
class GProcessPosesImpl:
""" Custom kernel. Processed poses of heads
"""
@staticmethod
def run(in_ys, in_ps, in_rs):
""" Сustom kernel executable code
Params:
in_ys: yaw angle of head
in_ps: pitch angle of head
in_rs: roll angle of head
Return:
Arrays with heads poses
"""
return [np.array([ys[0], ps[0], rs[0]]).T for ys, ps, rs in zip(in_ys, in_ps, in_rs)]
@cv.gapi.kernel(GParseEyes)
class GParseEyesImpl:
""" Custom kernel. Get information about eyes
"""
@staticmethod
def run(in_landm_per_face, in_face_rcs, frame_size):
""" Сustom kernel executable code
Params:
in_landm_per_face: landmarks from inference of facial-landmarks network for each face
in_face_rcs: bounding boxes for each face
frame_size: size of input image
Return:
Arrays of ROI for left and right eyes, array of midpoints and
array of landmarks points
"""
left_eyes = []
right_eyes = []
midpoints = []
lmarks = []
surface = (0, 0, *frame_size)
for landm_face, rect in zip(in_landm_per_face, in_face_rcs):
points = process_landmarks(*rect, landm_face)
lmarks.extend(points)
rect, midpoint_l = eye_box(points[0], points[1])
left_eyes.append(intersection(surface, rect))
rect, midpoint_r = eye_box(points[2], points[3])
right_eyes.append(intersection(surface, rect))
midpoints.append(midpoint_l)
midpoints.append(midpoint_r)
return left_eyes, right_eyes, midpoints, lmarks
@cv.gapi.kernel(GGetStates)
class GGetStatesImpl:
""" Custom kernel. Get state of eye - open or closed
"""
@staticmethod
def run(eyesl, eyesr):
""" Сustom kernel executable code
Params:
eyesl: result of inference of open-closed-eye network for left eye
eyesr: result of inference of open-closed-eye network for right eye
Return:
States of left eyes and states of right eyes
"""
out_l_st = [int(st) for eye_l in eyesl for st in (eye_l[:, 0] < eye_l[:, 1]).ravel()]
out_r_st = [int(st) for eye_r in eyesr for st in (eye_r[:, 0] < eye_r[:, 1]).ravel()]
return out_l_st, out_r_st
if __name__ == '__main__':
ARGUMENTS = build_argparser().parse_args()
# ------------------------Demo's graph------------------------
g_in = cv.GMat()
# Detect faces
face_inputs = cv.GInferInputs()
face_inputs.setInput('data', g_in)
face_outputs = cv.gapi.infer('face-detection', face_inputs)
faces = face_outputs.at('detection_out')
# Parse faces
sz = cv.gapi.streaming.size(g_in)
faces_rc = cv.gapi.parseSSD(faces, sz, 0.5, False, False)
# Detect poses
head_inputs = cv.GInferInputs()
head_inputs.setInput('data', g_in)
face_outputs = cv.gapi.infer('head-pose', faces_rc, head_inputs)
angles_y = face_outputs.at('angle_y_fc')
angles_p = face_outputs.at('angle_p_fc')
angles_r = face_outputs.at('angle_r_fc')
# Parse poses
heads_pos = GProcessPoses.on(angles_y, angles_p, angles_r)
# Detect landmarks
landmark_inputs = cv.GInferInputs()
landmark_inputs.setInput('data', g_in)
landmark_outputs = cv.gapi.infer('facial-landmarks', faces_rc,
landmark_inputs)
landmark = landmark_outputs.at('align_fc3')
# Parse landmarks
left_eyes, right_eyes, mids, lmarks = GParseEyes.on(landmark, faces_rc, sz)
# Detect eyes
eyes_inputs = cv.GInferInputs()
eyes_inputs.setInput('input.1', g_in)
eyesl_outputs = cv.gapi.infer('open-closed-eye', left_eyes, eyes_inputs)
eyesr_outputs = cv.gapi.infer('open-closed-eye', right_eyes, eyes_inputs)
eyesl = eyesl_outputs.at('19')
eyesr = eyesr_outputs.at('19')
# Process eyes states
l_eye_st, r_eye_st = GGetStates.on(eyesl, eyesr)
# Gaze estimation
gaze_inputs = cv.GInferListInputs()
gaze_inputs.setInput('left_eye_image', left_eyes)
gaze_inputs.setInput('right_eye_image', right_eyes)
gaze_inputs.setInput('head_pose_angles', heads_pos)
gaze_outputs = cv.gapi.infer2('gaze-estimation', g_in, gaze_inputs)
gaze_vectors = gaze_outputs.at('gaze_vector')
out = cv.gapi.copy(g_in)
# ------------------------End of graph------------------------
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(out,
faces_rc,
left_eyes,
right_eyes,
gaze_vectors,
angles_y,
angles_p,
angles_r,
l_eye_st,
r_eye_st,
mids,
lmarks))
# Networks
face_net = cv.gapi.ie.params('face-detection', ARGUMENTS.facem,
weight_path(ARGUMENTS.facem), ARGUMENTS.faced)
head_pose_net = cv.gapi.ie.params('head-pose', ARGUMENTS.headm,
weight_path(ARGUMENTS.headm), ARGUMENTS.headd)
landmarks_net = cv.gapi.ie.params('facial-landmarks', ARGUMENTS.landm,
weight_path(ARGUMENTS.landm), ARGUMENTS.landd)
gaze_net = cv.gapi.ie.params('gaze-estimation', ARGUMENTS.gazem,
weight_path(ARGUMENTS.gazem), ARGUMENTS.gazed)
eye_net = cv.gapi.ie.params('open-closed-eye', ARGUMENTS.eyem,
weight_path(ARGUMENTS.eyem), ARGUMENTS.eyed)
nets = cv.gapi.networks(face_net, head_pose_net, landmarks_net, gaze_net, eye_net)
# Kernels pack
kernels = cv.gapi.kernels(GParseEyesImpl, GProcessPosesImpl, GGetStatesImpl)
# ------------------------Execution part------------------------
ccomp = comp.compileStreaming(args=cv.gapi.compile_args(kernels, nets))
source = cv.gapi.wip.make_capture_src(ARGUMENTS.input)
ccomp.setSource(cv.gin(source))
ccomp.start()
frames = 0
fps = 0
print('Processing')
START_TIME = time.time()
while True:
start_time_cycle = time.time()
has_frame, (oimg,
outr,
l_eyes,
r_eyes,
outg,
out_y,
out_p,
out_r,
out_st_l,
out_st_r,
out_mids,
outl) = ccomp.pull()
if not has_frame:
break
# Draw
GREEN = (0, 255, 0)
RED = (0, 0, 255)
WHITE = (255, 255, 255)
BLUE = (255, 0, 0)
PINK = (255, 0, 255)
YELLOW = (0, 255, 255)
M_PI_180 = np.pi / 180
M_PI_2 = np.pi / 2
M_PI = np.pi
FACES_SIZE = len(outr)
for i, out_rect in enumerate(outr):
# Face box
cv.rectangle(oimg, out_rect, WHITE, 1)
rx, ry, rwidth, rheight = out_rect
# Landmarks
lm_radius = int(0.01 * rwidth + 1)
lmsize = int(len(outl) / FACES_SIZE)
for j in range(lmsize):
cv.circle(oimg, outl[j + i * lmsize], lm_radius, YELLOW, -1)
# Headposes
yaw = out_y[i]
pitch = out_p[i]
roll = out_r[i]
sin_y = np.sin(yaw[:] * M_PI_180)
sin_p = np.sin(pitch[:] * M_PI_180)
sin_r = np.sin(roll[:] * M_PI_180)
cos_y = np.cos(yaw[:] * M_PI_180)
cos_p = np.cos(pitch[:] * M_PI_180)
cos_r = np.cos(roll[:] * M_PI_180)
axis_length = 0.4 * rwidth
x_center = int(rx + rwidth / 2)
y_center = int(ry + rheight / 2)
# center to right
cv.line(oimg, [x_center, y_center],
[int(x_center + axis_length * (cos_r * cos_y + sin_y * sin_p * sin_r)),
int(y_center + axis_length * cos_p * sin_r)],
RED, 2)
# center to top
cv.line(oimg, [x_center, y_center],
[int(x_center + axis_length * (cos_r * sin_y * sin_p + cos_y * sin_r)),
int(y_center - axis_length * cos_p * cos_r)],
GREEN, 2)
# center to forward
cv.line(oimg, [x_center, y_center],
[int(x_center + axis_length * sin_y * cos_p),
int(y_center + axis_length * sin_p)],
PINK, 2)
scale_box = 0.002 * rwidth
cv.putText(oimg, "head pose: (y=%0.0f, p=%0.0f, r=%0.0f)" %
(np.round(yaw), np.round(pitch), np.round(roll)),
[int(rx), int(ry + rheight + 5 * rwidth / 100)],
cv.FONT_HERSHEY_PLAIN, scale_box * 2, WHITE, 1)
# Eyes boxes
color_l = GREEN if out_st_l[i] else RED
cv.rectangle(oimg, l_eyes[i], color_l, 1)
color_r = GREEN if out_st_r[i] else RED
cv.rectangle(oimg, r_eyes[i], color_r, 1)
# Gaze vectors
norm_gazes = np.linalg.norm(outg[i][0])
gaze_vector = outg[i][0] / norm_gazes
arrow_length = 0.4 * rwidth
gaze_arrow = [arrow_length * gaze_vector[0], -arrow_length * gaze_vector[1]]
left_arrow = [int(a+b) for a, b in zip(out_mids[0 + i * 2], gaze_arrow)]
right_arrow = [int(a+b) for a, b in zip(out_mids[1 + i * 2], gaze_arrow)]
if out_st_l[i]:
cv.arrowedLine(oimg, out_mids[0 + i * 2], left_arrow, BLUE, 2)
if out_st_r[i]:
cv.arrowedLine(oimg, out_mids[1 + i * 2], right_arrow, BLUE, 2)
v0, v1, v2 = outg[i][0]
gaze_angles = [180 / M_PI * (M_PI_2 + np.arctan2(v2, v0)),
180 / M_PI * (M_PI_2 - np.arccos(v1 / norm_gazes))]
cv.putText(oimg, "gaze angles: (h=%0.0f, v=%0.0f)" %
(np.round(gaze_angles[0]), np.round(gaze_angles[1])),
[int(rx), int(ry + rheight + 12 * rwidth / 100)],
cv.FONT_HERSHEY_PLAIN, scale_box * 2, WHITE, 1)
# Add FPS value to frame
cv.putText(oimg, "FPS: %0i" % (fps), [int(20), int(40)],
cv.FONT_HERSHEY_PLAIN, 2, RED, 2)
# Show result
cv.imshow('Gaze Estimation', oimg)
cv.waitKey(1)
fps = int(1. / (time.time() - start_time_cycle))
frames += 1
EXECUTION_TIME = time.time() - START_TIME
print('Execution successful')
print('Mean FPS is ', int(frames / EXECUTION_TIME))

View File

@ -0,0 +1,83 @@
#error This is a shadow header file, which is not intended for processing by any compiler. \
Only bindings parser should handle this file.
namespace cv
{
struct GAPI_EXPORTS_W_SIMPLE GCompileArg
{
GAPI_WRAP GCompileArg(gapi::GKernelPackage arg);
GAPI_WRAP GCompileArg(gapi::GNetPackage arg);
GAPI_WRAP GCompileArg(gapi::streaming::queue_capacity arg);
};
class GAPI_EXPORTS_W_SIMPLE GInferInputs
{
public:
GAPI_WRAP GInferInputs();
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GMat& value);
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GFrame& value);
};
class GAPI_EXPORTS_W_SIMPLE GInferListInputs
{
public:
GAPI_WRAP GInferListInputs();
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::GMat>& value);
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::Rect>& value);
};
class GAPI_EXPORTS_W_SIMPLE GInferOutputs
{
public:
GAPI_WRAP GInferOutputs();
GAPI_WRAP cv::GMat at(const std::string& name);
};
class GAPI_EXPORTS_W_SIMPLE GInferListOutputs
{
public:
GAPI_WRAP GInferListOutputs();
GAPI_WRAP cv::GArray<cv::GMat> at(const std::string& name);
};
namespace gapi
{
namespace wip
{
class GAPI_EXPORTS_W IStreamSource { };
namespace draw
{
// NB: These render primitives are partially wrapped in shadow file
// because cv::Rect conflicts with cv::gapi::wip::draw::Rect in python generator
// and cv::Rect2i breaks standalone mode.
struct Rect
{
GAPI_WRAP Rect(const cv::Rect2i& rect_,
const cv::Scalar& color_,
int thick_ = 1,
int lt_ = 8,
int shift_ = 0);
};
struct Mosaic
{
GAPI_WRAP Mosaic(const cv::Rect2i& mos_, int cellSz_, int decim_);
};
} // namespace draw
} // namespace wip
namespace streaming
{
// FIXME: Extend to work with an arbitrary G-type.
cv::GOpaque<int64_t> GAPI_EXPORTS_W timestamp(cv::GMat);
cv::GOpaque<int64_t> GAPI_EXPORTS_W seqNo(cv::GMat);
cv::GOpaque<int64_t> GAPI_EXPORTS_W seq_id(cv::GMat);
GAPI_EXPORTS_W cv::GMat desync(const cv::GMat &g);
} // namespace streaming
} // namespace gapi
namespace detail
{
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::ie::PyParams params);
} // namespace detail
} // namespace cv

View File

@ -0,0 +1,212 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
# 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_core_test(NewOpenCVTests):
def test_add(self):
# TODO: Extend to use any type and size here
sz = (720, 1280)
in1 = np.full(sz, 100)
in2 = np.full(sz, 50)
# 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.gapi.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_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.gapi.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):
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)
# G-API
g_in = cv.GMat()
g_out = cv.gapi.mean(g_in)
comp = cv.GComputation(g_in, g_out)
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
# Comparison
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.gapi.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.gapi.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')
def test_kmeans(self):
# K-means params
count = 100
sz = (count, 2)
in_mat = np.random.random(sz).astype(np.float32)
K = 5
flags = cv.KMEANS_RANDOM_CENTERS
attempts = 1
criteria = (cv.TERM_CRITERIA_MAX_ITER + cv.TERM_CRITERIA_EPS, 30, 0)
# G-API
g_in = cv.GMat()
compactness, out_labels, centers = cv.gapi.kmeans(g_in, K, criteria, attempts, flags)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(compactness, out_labels, centers))
compact, labels, centers = comp.apply(cv.gin(in_mat))
# Assert
self.assertTrue(compact >= 0)
self.assertEqual(sz[0], labels.shape[0])
self.assertEqual(1, labels.shape[1])
self.assertTrue(labels.size != 0)
self.assertEqual(centers.shape[1], sz[1])
self.assertEqual(centers.shape[0], K)
self.assertTrue(centers.size != 0)
def generate_random_points(self, sz):
arr = np.random.random(sz).astype(np.float32).T
return list(zip(arr[0], arr[1]))
def test_kmeans_2d(self):
# K-means 2D params
count = 100
sz = (count, 2)
amount = sz[0]
K = 5
flags = cv.KMEANS_RANDOM_CENTERS
attempts = 1
criteria = (cv.TERM_CRITERIA_MAX_ITER + cv.TERM_CRITERIA_EPS, 30, 0)
in_vector = self.generate_random_points(sz)
in_labels = []
# G-API
data = cv.GArrayT(cv.gapi.CV_POINT2F)
best_labels = cv.GArrayT(cv.gapi.CV_INT)
compactness, out_labels, centers = cv.gapi.kmeans(data, K, best_labels, criteria, attempts, flags)
comp = cv.GComputation(cv.GIn(data, best_labels), cv.GOut(compactness, out_labels, centers))
compact, labels, centers = comp.apply(cv.gin(in_vector, in_labels))
# Assert
self.assertTrue(compact >= 0)
self.assertEqual(amount, len(labels))
self.assertEqual(K, len(centers))
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,127 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
# 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.gapi.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(),
np.array(actual, dtype=np.float32).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.gapi.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
def test_bounding_rect(self):
sz = 1280
fscale = 256
def sample_value(fscale):
return np.random.uniform(0, 255 * fscale) / fscale
points = np.array([(sample_value(fscale), sample_value(fscale)) for _ in range(1280)], np.float32)
# OpenCV
expected = cv.boundingRect(points)
# G-API
g_in = cv.GMat()
g_out = cv.gapi.boundingRect(g_in)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
for pkg_name, pkg in pkgs:
actual = comp.apply(cv.gin(points), args=cv.gapi.compile_args(pkg))
# Comparison
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
'Failed on ' + pkg_name + ' backend')
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,341 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
class test_gapi_infer(NewOpenCVTests):
def infer_reference_network(self, model_path, weights_path, img):
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)
return net.forward(net.getUnconnectedOutLayersNames())
def make_roi(self, img, roi):
return img[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2], ...]
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')])
device_id = 'CPU'
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
img = cv.resize(cv.imread(img_path), (62,62))
# OpenCV DNN
dnn_age, dnn_gender = self.infer_reference_network(model_path, weights_path, img)
# 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)
gapi_age, gapi_gender = comp.apply(cv.gin(img), args=cv.gapi.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))
def test_age_gender_infer_roi(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')])
device_id = 'CPU'
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
img = cv.imread(img_path)
roi = (10, 10, 62, 62)
# OpenCV DNN
dnn_age, dnn_gender = self.infer_reference_network(model_path,
weights_path,
self.make_roi(img, roi))
# OpenCV G-API
g_in = cv.GMat()
g_roi = cv.GOpaqueT(cv.gapi.CV_RECT)
inputs = cv.GInferInputs()
inputs.setInput('data', g_in)
outputs = cv.gapi.infer("net", g_roi, inputs)
age_g = outputs.at("age_conv3")
gender_g = outputs.at("prob")
comp = cv.GComputation(cv.GIn(g_in, g_roi), cv.GOut(age_g, gender_g))
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
gapi_age, gapi_gender = comp.apply(cv.gin(img, roi), args=cv.gapi.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))
def test_age_gender_infer_roi_list(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')])
device_id = 'CPU'
rois = [(10, 15, 62, 62), (23, 50, 62, 62), (14, 100, 62, 62), (80, 50, 62, 62)]
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
img = cv.imread(img_path)
# OpenCV DNN
dnn_age_list = []
dnn_gender_list = []
for roi in rois:
age, gender = self.infer_reference_network(model_path,
weights_path,
self.make_roi(img, roi))
dnn_age_list.append(age)
dnn_gender_list.append(gender)
# OpenCV G-API
g_in = cv.GMat()
g_rois = cv.GArrayT(cv.gapi.CV_RECT)
inputs = cv.GInferInputs()
inputs.setInput('data', g_in)
outputs = cv.gapi.infer("net", g_rois, inputs)
age_g = outputs.at("age_conv3")
gender_g = outputs.at("prob")
comp = cv.GComputation(cv.GIn(g_in, g_rois), cv.GOut(age_g, gender_g))
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
gapi_age_list, gapi_gender_list = comp.apply(cv.gin(img, rois),
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
# Check
for gapi_age, gapi_gender, dnn_age, dnn_gender in zip(gapi_age_list,
gapi_gender_list,
dnn_age_list,
dnn_gender_list):
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))
def test_age_gender_infer2_roi(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')])
device_id = 'CPU'
rois = [(10, 15, 62, 62), (23, 50, 62, 62), (14, 100, 62, 62), (80, 50, 62, 62)]
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
img = cv.imread(img_path)
# OpenCV DNN
dnn_age_list = []
dnn_gender_list = []
for roi in rois:
age, gender = self.infer_reference_network(model_path,
weights_path,
self.make_roi(img, roi))
dnn_age_list.append(age)
dnn_gender_list.append(gender)
# OpenCV G-API
g_in = cv.GMat()
g_rois = cv.GArrayT(cv.gapi.CV_RECT)
inputs = cv.GInferListInputs()
inputs.setInput('data', g_rois)
outputs = cv.gapi.infer2("net", g_in, inputs)
age_g = outputs.at("age_conv3")
gender_g = outputs.at("prob")
comp = cv.GComputation(cv.GIn(g_in, g_rois), cv.GOut(age_g, gender_g))
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
gapi_age_list, gapi_gender_list = comp.apply(cv.gin(img, rois),
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
# Check
for gapi_age, gapi_gender, dnn_age, dnn_gender in zip(gapi_age_list,
gapi_gender_list,
dnn_age_list,
dnn_gender_list):
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))
def test_person_detection_retail_0013(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/person-detection-retail-0013/FP32/person-detection-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('gpu/lbpcascade/er.png', [os.environ.get('OPENCV_TEST_DATA_PATH')])
device_id = 'CPU'
img = cv.resize(cv.imread(img_path), (544, 320))
# 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)
def parseSSD(detections, size):
h, w = size
bboxes = []
detections = detections.reshape(-1, 7)
for sample_id, class_id, confidence, xmin, ymin, xmax, ymax in detections:
if confidence >= 0.5:
x = int(xmin * w)
y = int(ymin * h)
width = int(xmax * w - x)
height = int(ymax * h - y)
bboxes.append((x, y, width, height))
return bboxes
net.setInput(blob)
dnn_detections = net.forward()
dnn_boxes = parseSSD(np.array(dnn_detections), img.shape[:2])
# OpenCV G-API
g_in = cv.GMat()
inputs = cv.GInferInputs()
inputs.setInput('data', g_in)
g_sz = cv.gapi.streaming.size(g_in)
outputs = cv.gapi.infer("net", inputs)
detections = outputs.at("detection_out")
bboxes = cv.gapi.parseSSD(detections, g_sz, 0.5, False, False)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(bboxes))
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
gapi_boxes = comp.apply(cv.gin(img.astype(np.float32)),
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
# Comparison
self.assertEqual(0.0, cv.norm(np.array(dnn_boxes).flatten(),
np.array(gapi_boxes).flatten(),
cv.NORM_INF))
def test_person_detection_retail_0013(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/person-detection-retail-0013/FP32/person-detection-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('gpu/lbpcascade/er.png', [os.environ.get('OPENCV_TEST_DATA_PATH')])
device_id = 'CPU'
img = cv.resize(cv.imread(img_path), (544, 320))
# 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)
def parseSSD(detections, size):
h, w = size
bboxes = []
detections = detections.reshape(-1, 7)
for sample_id, class_id, confidence, xmin, ymin, xmax, ymax in detections:
if confidence >= 0.5:
x = int(xmin * w)
y = int(ymin * h)
width = int(xmax * w - x)
height = int(ymax * h - y)
bboxes.append((x, y, width, height))
return bboxes
net.setInput(blob)
dnn_detections = net.forward()
dnn_boxes = parseSSD(np.array(dnn_detections), img.shape[:2])
# OpenCV G-API
g_in = cv.GMat()
inputs = cv.GInferInputs()
inputs.setInput('data', g_in)
g_sz = cv.gapi.streaming.size(g_in)
outputs = cv.gapi.infer("net", inputs)
detections = outputs.at("detection_out")
bboxes = cv.gapi.parseSSD(detections, g_sz, 0.5, False, False)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(bboxes))
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
gapi_boxes = comp.apply(cv.gin(img.astype(np.float32)),
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
# Comparison
self.assertEqual(0.0, cv.norm(np.array(dnn_boxes).flatten(),
np.array(gapi_boxes).flatten(),
cv.NORM_INF))
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,227 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
# FIXME: FText isn't supported yet.
class gapi_render_test(NewOpenCVTests):
def __init__(self, *args):
super().__init__(*args)
self.size = (300, 300, 3)
# Rect
self.rect = (30, 30, 50, 50)
self.rcolor = (0, 255, 0)
self.rlt = cv.LINE_4
self.rthick = 2
self.rshift = 3
# Text
self.text = 'Hello, world!'
self.org = (100, 100)
self.ff = cv.FONT_HERSHEY_SIMPLEX
self.fs = 1.0
self.tthick = 2
self.tlt = cv.LINE_8
self.tcolor = (255, 255, 255)
self.blo = False
# Circle
self.center = (200, 200)
self.radius = 200
self.ccolor = (255, 255, 0)
self.cthick = 2
self.clt = cv.LINE_4
self.cshift = 1
# Line
self.pt1 = (50, 50)
self.pt2 = (200, 200)
self.lcolor = (0, 255, 128)
self.lthick = 5
self.llt = cv.LINE_8
self.lshift = 2
# Poly
self.pts = [(50, 100), (100, 200), (25, 250)]
self.pcolor = (0, 0, 255)
self.pthick = 3
self.plt = cv.LINE_4
self.pshift = 1
# Image
self.iorg = (150, 150)
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
self.img = cv.resize(cv.imread(img_path), (50, 50))
self.alpha = np.full(self.img.shape[:2], 0.8, dtype=np.float32)
# Mosaic
self.mos = (100, 100, 100, 100)
self.cell_sz = 25
self.decim = 0
# Render primitives
self.prims = [cv.gapi.wip.draw.Rect(self.rect, self.rcolor, self.rthick, self.rlt, self.rshift),
cv.gapi.wip.draw.Text(self.text, self.org, self.ff, self.fs, self.tcolor, self.tthick, self.tlt, self.blo),
cv.gapi.wip.draw.Circle(self.center, self.radius, self.ccolor, self.cthick, self.clt, self.cshift),
cv.gapi.wip.draw.Line(self.pt1, self.pt2, self.lcolor, self.lthick, self.llt, self.lshift),
cv.gapi.wip.draw.Mosaic(self.mos, self.cell_sz, self.decim),
cv.gapi.wip.draw.Image(self.iorg, self.img, self.alpha),
cv.gapi.wip.draw.Poly(self.pts, self.pcolor, self.pthick, self.plt, self.pshift)]
def cvt_nv12_to_yuv(self, y, uv):
h,w,_ = uv.shape
upsample_uv = cv.resize(uv, (h * 2, w * 2))
return cv.merge([y, upsample_uv])
def cvt_yuv_to_nv12(self, yuv, y_out, uv_out):
chs = cv.split(yuv, [y_out, None, None])
uv = cv.merge([chs[1], chs[2]])
uv_out = cv.resize(uv, (uv.shape[0] // 2, uv.shape[1] // 2), dst=uv_out)
return y_out, uv_out
def cvt_bgr_to_yuv_color(self, bgr):
y = bgr[2] * 0.299000 + bgr[1] * 0.587000 + bgr[0] * 0.114000;
u = bgr[2] * -0.168736 + bgr[1] * -0.331264 + bgr[0] * 0.500000 + 128;
v = bgr[2] * 0.500000 + bgr[1] * -0.418688 + bgr[0] * -0.081312 + 128;
return (y, u, v)
def blend_img(self, background, org, img, alpha):
x, y = org
h, w, _ = img.shape
roi_img = background[x:x+w, y:y+h, :]
img32f_w = cv.merge([alpha] * 3).astype(np.float32)
roi32f_w = np.full(roi_img.shape, 1.0, dtype=np.float32)
roi32f_w -= img32f_w
img32f = (img / 255).astype(np.float32)
roi32f = (roi_img / 255).astype(np.float32)
cv.multiply(img32f, img32f_w, dst=img32f)
cv.multiply(roi32f, roi32f_w, dst=roi32f)
roi32f += img32f
roi_img[...] = np.round(roi32f * 255)
# This is quite naive implementations used as a simple reference
# doesn't consider corner cases.
def draw_mosaic(self, img, mos, cell_sz, decim):
x,y,w,h = mos
mosaic_area = img[x:x+w, y:y+h, :]
for i in range(0, mosaic_area.shape[0], cell_sz):
for j in range(0, mosaic_area.shape[1], cell_sz):
cell_roi = mosaic_area[j:j+cell_sz, i:i+cell_sz, :]
s0, s1, s2 = cv.mean(cell_roi)[:3]
mosaic_area[j:j+cell_sz, i:i+cell_sz] = (round(s0), round(s1), round(s2))
def render_primitives_bgr_ref(self, img):
cv.rectangle(img, self.rect, self.rcolor, self.rthick, self.rlt, self.rshift)
cv.putText(img, self.text, self.org, self.ff, self.fs, self.tcolor, self.tthick, self.tlt, self.blo)
cv.circle(img, self.center, self.radius, self.ccolor, self.cthick, self.clt, self.cshift)
cv.line(img, self.pt1, self.pt2, self.lcolor, self.lthick, self.llt, self.lshift)
cv.fillPoly(img, np.expand_dims(np.array([self.pts]), axis=0), self.pcolor, self.plt, self.pshift)
self.draw_mosaic(img, self.mos, self.cell_sz, self.decim)
self.blend_img(img, self.iorg, self.img, self.alpha)
def render_primitives_nv12_ref(self, y_plane, uv_plane):
yuv = self.cvt_nv12_to_yuv(y_plane, uv_plane)
cv.rectangle(yuv, self.rect, self.cvt_bgr_to_yuv_color(self.rcolor), self.rthick, self.rlt, self.rshift)
cv.putText(yuv, self.text, self.org, self.ff, self.fs, self.cvt_bgr_to_yuv_color(self.tcolor), self.tthick, self.tlt, self.blo)
cv.circle(yuv, self.center, self.radius, self.cvt_bgr_to_yuv_color(self.ccolor), self.cthick, self.clt, self.cshift)
cv.line(yuv, self.pt1, self.pt2, self.cvt_bgr_to_yuv_color(self.lcolor), self.lthick, self.llt, self.lshift)
cv.fillPoly(yuv, np.expand_dims(np.array([self.pts]), axis=0), self.cvt_bgr_to_yuv_color(self.pcolor), self.plt, self.pshift)
self.draw_mosaic(yuv, self.mos, self.cell_sz, self.decim)
self.blend_img(yuv, self.iorg, cv.cvtColor(self.img, cv.COLOR_BGR2YUV), self.alpha)
self.cvt_yuv_to_nv12(yuv, y_plane, uv_plane)
def test_render_primitives_on_bgr_graph(self):
expected = np.zeros(self.size, dtype=np.uint8)
actual = np.array(expected, copy=True)
# OpenCV
self.render_primitives_bgr_ref(expected)
# G-API
g_in = cv.GMat()
g_prims = cv.GArray.Prim()
g_out = cv.gapi.wip.draw.render3ch(g_in, g_prims)
comp = cv.GComputation(cv.GIn(g_in, g_prims), cv.GOut(g_out))
actual = comp.apply(cv.gin(actual, self.prims))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_render_primitives_on_bgr_function(self):
expected = np.zeros(self.size, dtype=np.uint8)
actual = np.array(expected, copy=True)
# OpenCV
self.render_primitives_bgr_ref(expected)
# G-API
cv.gapi.wip.draw.render(actual, self.prims)
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_render_primitives_on_nv12_graph(self):
y_expected = np.zeros((self.size[0], self.size[1], 1), dtype=np.uint8)
uv_expected = np.zeros((self.size[0] // 2, self.size[1] // 2, 2), dtype=np.uint8)
y_actual = np.array(y_expected, copy=True)
uv_actual = np.array(uv_expected, copy=True)
# OpenCV
self.render_primitives_nv12_ref(y_expected, uv_expected)
# G-API
g_y = cv.GMat()
g_uv = cv.GMat()
g_prims = cv.GArray.Prim()
g_out_y, g_out_uv = cv.gapi.wip.draw.renderNV12(g_y, g_uv, g_prims)
comp = cv.GComputation(cv.GIn(g_y, g_uv, g_prims), cv.GOut(g_out_y, g_out_uv))
y_actual, uv_actual = comp.apply(cv.gin(y_actual, uv_actual, self.prims))
self.assertEqual(0.0, cv.norm(y_expected, y_actual, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(uv_expected, uv_actual, cv.NORM_INF))
def test_render_primitives_on_nv12_function(self):
y_expected = np.zeros((self.size[0], self.size[1], 1), dtype=np.uint8)
uv_expected = np.zeros((self.size[0] // 2, self.size[1] // 2, 2), dtype=np.uint8)
y_actual = np.array(y_expected, copy=True)
uv_actual = np.array(uv_expected, copy=True)
# OpenCV
self.render_primitives_nv12_ref(y_expected, uv_expected)
# G-API
cv.gapi.wip.draw.render(y_actual, uv_actual, self.prims)
self.assertEqual(0.0, cv.norm(y_expected, y_actual, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(uv_expected, uv_actual, cv.NORM_INF))
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,681 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
# 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())
]
@cv.gapi.op('custom.add', in_types=[cv.GMat, cv.GMat, int], out_types=[cv.GMat])
class GAdd:
"""Calculates sum of two matrices."""
@staticmethod
def outMeta(desc1, desc2, depth):
return desc1
@cv.gapi.kernel(GAdd)
class GAddImpl:
"""Implementation for GAdd operation."""
@staticmethod
def run(img1, img2, dtype):
return cv.add(img1, img2)
@cv.gapi.op('custom.split3', in_types=[cv.GMat], out_types=[cv.GMat, cv.GMat, cv.GMat])
class GSplit3:
"""Divides a 3-channel matrix into 3 single-channel matrices."""
@staticmethod
def outMeta(desc):
out_desc = desc.withType(desc.depth, 1)
return out_desc, out_desc, out_desc
@cv.gapi.kernel(GSplit3)
class GSplit3Impl:
"""Implementation for GSplit3 operation."""
@staticmethod
def run(img):
# NB: cv.split return list but g-api requires tuple in multiple output case
return tuple(cv.split(img))
@cv.gapi.op('custom.mean', in_types=[cv.GMat], out_types=[cv.GScalar])
class GMean:
"""Calculates the mean value M of matrix elements."""
@staticmethod
def outMeta(desc):
return cv.empty_scalar_desc()
@cv.gapi.kernel(GMean)
class GMeanImpl:
"""Implementation for GMean operation."""
@staticmethod
def run(img):
# NB: cv.split return list but g-api requires tuple in multiple output case
return cv.mean(img)
@cv.gapi.op('custom.addC', in_types=[cv.GMat, cv.GScalar, int], out_types=[cv.GMat])
class GAddC:
"""Adds a given scalar value to each element of given matrix."""
@staticmethod
def outMeta(mat_desc, scalar_desc, dtype):
return mat_desc
@cv.gapi.kernel(GAddC)
class GAddCImpl:
"""Implementation for GAddC operation."""
@staticmethod
def run(img, sc, dtype):
# NB: dtype is just ignored in this implementation.
# Moreover from G-API kernel got scalar as tuples with 4 elements
# where the last element is equal to zero, just cut him for broadcasting.
return img + np.array(sc, dtype=np.uint8)[:-1]
@cv.gapi.op('custom.size', in_types=[cv.GMat], out_types=[cv.GOpaque.Size])
class GSize:
"""Gets dimensions from input matrix."""
@staticmethod
def outMeta(mat_desc):
return cv.empty_gopaque_desc()
@cv.gapi.kernel(GSize)
class GSizeImpl:
"""Implementation for GSize operation."""
@staticmethod
def run(img):
# NB: Take only H, W, because the operation should return cv::Size which is 2D.
return img.shape[:2]
@cv.gapi.op('custom.sizeR', in_types=[cv.GOpaque.Rect], out_types=[cv.GOpaque.Size])
class GSizeR:
"""Gets dimensions from rectangle."""
@staticmethod
def outMeta(opaq_desc):
return cv.empty_gopaque_desc()
@cv.gapi.kernel(GSizeR)
class GSizeRImpl:
"""Implementation for GSizeR operation."""
@staticmethod
def run(rect):
# NB: rect - is tuple (x, y, h, w)
return (rect[2], rect[3])
@cv.gapi.op('custom.boundingRect', in_types=[cv.GArray.Point], out_types=[cv.GOpaque.Rect])
class GBoundingRect:
"""Calculates minimal up-right bounding rectangle for the specified
9 point set or non-zero pixels of gray-scale image."""
@staticmethod
def outMeta(arr_desc):
return cv.empty_gopaque_desc()
@cv.gapi.kernel(GBoundingRect)
class GBoundingRectImpl:
"""Implementation for GBoundingRect operation."""
@staticmethod
def run(array):
# NB: OpenCV - numpy array (n_points x 2).
# G-API - array of tuples (n_points).
return cv.boundingRect(np.array(array))
@cv.gapi.op('custom.goodFeaturesToTrack',
in_types=[cv.GMat, int, float, float, int, bool, float],
out_types=[cv.GArray.Point2f])
class GGoodFeatures:
"""Finds the most prominent corners in the image
or in the specified image region."""
@staticmethod
def outMeta(desc, max_corners, quality_lvl,
min_distance, block_sz,
use_harris_detector, k):
return cv.empty_array_desc()
@cv.gapi.kernel(GGoodFeatures)
class GGoodFeaturesImpl:
"""Implementation for GGoodFeatures operation."""
@staticmethod
def run(img, max_corners, quality_lvl,
min_distance, block_sz,
use_harris_detector, k):
features = cv.goodFeaturesToTrack(img, max_corners, quality_lvl,
min_distance, mask=None,
blockSize=block_sz,
useHarrisDetector=use_harris_detector, k=k)
# NB: The operation output is cv::GArray<cv::Pointf>, so it should be mapped
# to python paramaters like this: [(1.2, 3.4), (5.2, 3.2)], because the cv::Point2f
# according to opencv rules mapped to the tuple and cv::GArray<> mapped to the list.
# OpenCV returns np.array with shape (n_features, 1, 2), so let's to convert it to list
# tuples with size == n_features.
features = list(map(tuple, features.reshape(features.shape[0], -1)))
return features
# To validate invalid cases
def create_op(in_types, out_types):
@cv.gapi.op('custom.op', in_types=in_types, out_types=out_types)
class Op:
"""Custom operation for testing."""
@staticmethod
def outMeta(desc):
raise NotImplementedError("outMeta isn't imlemented")
return Op
class gapi_sample_pipelines(NewOpenCVTests):
def test_custom_op_add(self):
sz = (3, 3)
in_mat1 = np.full(sz, 45, dtype=np.uint8)
in_mat2 = np.full(sz, 50, dtype=np.uint8)
# OpenCV
expected = cv.add(in_mat1, in_mat2)
# G-API
g_in1 = cv.GMat()
g_in2 = cv.GMat()
g_out = GAdd.on(g_in1, g_in2, cv.CV_8UC1)
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
pkg = cv.gapi.kernels(GAddImpl)
actual = comp.apply(cv.gin(in_mat1, in_mat2), args=cv.gapi.compile_args(pkg))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_custom_op_split3(self):
sz = (4, 4)
in_ch1 = np.full(sz, 1, dtype=np.uint8)
in_ch2 = np.full(sz, 2, dtype=np.uint8)
in_ch3 = np.full(sz, 3, dtype=np.uint8)
# H x W x C
in_mat = np.stack((in_ch1, in_ch2, in_ch3), axis=2)
# G-API
g_in = cv.GMat()
g_ch1, g_ch2, g_ch3 = GSplit3.on(g_in)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_ch1, g_ch2, g_ch3))
pkg = cv.gapi.kernels(GSplit3Impl)
ch1, ch2, ch3 = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
self.assertEqual(0.0, cv.norm(in_ch1, ch1, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(in_ch2, ch2, cv.NORM_INF))
self.assertEqual(0.0, cv.norm(in_ch3, ch3, cv.NORM_INF))
def test_custom_op_mean(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.mean(in_mat)
# G-API
g_in = cv.GMat()
g_out = GMean.on(g_in)
comp = cv.GComputation(g_in, g_out)
pkg = cv.gapi.kernels(GMeanImpl)
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
# Comparison
self.assertEqual(expected, actual)
def test_custom_op_addC(self):
sz = (3, 3, 3)
in_mat = np.full(sz, 45, dtype=np.uint8)
sc = (50, 10, 20)
# Numpy reference, make array from sc to keep uint8 dtype.
expected = in_mat + np.array(sc, dtype=np.uint8)
# G-API
g_in = cv.GMat()
g_sc = cv.GScalar()
g_out = GAddC.on(g_in, g_sc, cv.CV_8UC1)
comp = cv.GComputation(cv.GIn(g_in, g_sc), cv.GOut(g_out))
pkg = cv.gapi.kernels(GAddCImpl)
actual = comp.apply(cv.gin(in_mat, sc), args=cv.gapi.compile_args(pkg))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_custom_op_size(self):
sz = (100, 150, 3)
in_mat = np.full(sz, 45, dtype=np.uint8)
# Open_cV
expected = (100, 150)
# G-API
g_in = cv.GMat()
g_sz = GSize.on(g_in)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_sz))
pkg = cv.gapi.kernels(GSizeImpl)
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_custom_op_sizeR(self):
# x, y, h, w
roi = (10, 15, 100, 150)
expected = (100, 150)
# G-API
g_r = cv.GOpaque.Rect()
g_sz = GSizeR.on(g_r)
comp = cv.GComputation(cv.GIn(g_r), cv.GOut(g_sz))
pkg = cv.gapi.kernels(GSizeRImpl)
actual = comp.apply(cv.gin(roi), args=cv.gapi.compile_args(pkg))
# cv.norm works with tuples ?
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_custom_op_boundingRect(self):
points = [(0,0), (0,1), (1,0), (1,1)]
# OpenCV
expected = cv.boundingRect(np.array(points))
# G-API
g_pts = cv.GArray.Point()
g_br = GBoundingRect.on(g_pts)
comp = cv.GComputation(cv.GIn(g_pts), cv.GOut(g_br))
pkg = cv.gapi.kernels(GBoundingRectImpl)
actual = comp.apply(cv.gin(points), args=cv.gapi.compile_args(pkg))
# cv.norm works with tuples ?
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
def test_custom_op_goodFeaturesToTrack(self):
# G-API
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)
# NB: goodFeaturesToTrack configuration
max_corners = 50
quality_lvl = 0.01
min_distance = 10.0
block_sz = 3
use_harris_detector = True
k = 0.04
# OpenCV
expected = cv.goodFeaturesToTrack(in_mat, max_corners, quality_lvl,
min_distance, mask=None,
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
# G-API
g_in = cv.GMat()
g_out = GGoodFeatures.on(g_in, max_corners, quality_lvl,
min_distance, block_sz, use_harris_detector, k)
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
pkg = cv.gapi.kernels(GGoodFeaturesImpl)
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
# NB: OpenCV & G-API have different output types.
# OpenCV - numpy array with shape (num_points, 1, 2)
# G-API - list of tuples with size - num_points
# Comparison
self.assertEqual(0.0, cv.norm(expected.flatten(),
np.array(actual, dtype=np.float32).flatten(), cv.NORM_INF))
def test_invalid_op(self):
# NB: Empty input types list
with self.assertRaises(Exception): create_op(in_types=[], out_types=[cv.GMat])
# NB: Empty output types list
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[])
# Invalid output types
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[int])
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[cv.GMat, int])
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[str, cv.GScalar])
def test_invalid_op_input(self):
# NB: Check GMat/GScalar
with self.assertRaises(Exception): create_op([cv.GMat] , [cv.GScalar]).on(cv.GScalar())
with self.assertRaises(Exception): create_op([cv.GScalar], [cv.GScalar]).on(cv.GMat())
# NB: Check GOpaque
op = create_op([cv.GOpaque.Rect], [cv.GMat])
with self.assertRaises(Exception): op.on(cv.GOpaque.Bool())
with self.assertRaises(Exception): op.on(cv.GOpaque.Int())
with self.assertRaises(Exception): op.on(cv.GOpaque.Double())
with self.assertRaises(Exception): op.on(cv.GOpaque.Float())
with self.assertRaises(Exception): op.on(cv.GOpaque.String())
with self.assertRaises(Exception): op.on(cv.GOpaque.Point())
with self.assertRaises(Exception): op.on(cv.GOpaque.Point2f())
with self.assertRaises(Exception): op.on(cv.GOpaque.Size())
# NB: Check GArray
op = create_op([cv.GArray.Rect], [cv.GMat])
with self.assertRaises(Exception): op.on(cv.GArray.Bool())
with self.assertRaises(Exception): op.on(cv.GArray.Int())
with self.assertRaises(Exception): op.on(cv.GArray.Double())
with self.assertRaises(Exception): op.on(cv.GArray.Float())
with self.assertRaises(Exception): op.on(cv.GArray.String())
with self.assertRaises(Exception): op.on(cv.GArray.Point())
with self.assertRaises(Exception): op.on(cv.GArray.Point2f())
with self.assertRaises(Exception): op.on(cv.GArray.Size())
# Check other possible invalid options
with self.assertRaises(Exception): op.on(cv.GMat())
with self.assertRaises(Exception): op.on(cv.GScalar())
with self.assertRaises(Exception): op.on(1)
with self.assertRaises(Exception): op.on('foo')
with self.assertRaises(Exception): op.on(False)
with self.assertRaises(Exception): create_op([cv.GMat, int], [cv.GMat]).on(cv.GMat(), 'foo')
with self.assertRaises(Exception): create_op([cv.GMat, int], [cv.GMat]).on(cv.GMat())
def test_stateful_kernel(self):
@cv.gapi.op('custom.sum', in_types=[cv.GArray.Int], out_types=[cv.GOpaque.Int])
class GSum:
@staticmethod
def outMeta(arr_desc):
return cv.empty_gopaque_desc()
@cv.gapi.kernel(GSum)
class GSumImpl:
last_result = 0
@staticmethod
def run(arr):
GSumImpl.last_result = sum(arr)
return GSumImpl.last_result
g_in = cv.GArray.Int()
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(GSum.on(g_in)))
s = comp.apply(cv.gin([1, 2, 3, 4]), args=cv.gapi.compile_args(cv.gapi.kernels(GSumImpl)))
self.assertEqual(10, s)
s = comp.apply(cv.gin([1, 2, 8, 7]), args=cv.gapi.compile_args(cv.gapi.kernels(GSumImpl)))
self.assertEqual(18, s)
self.assertEqual(18, GSumImpl.last_result)
def test_opaq_with_custom_type(self):
@cv.gapi.op('custom.op', in_types=[cv.GOpaque.Any, cv.GOpaque.String], out_types=[cv.GOpaque.Any])
class GLookUp:
@staticmethod
def outMeta(opaq_desc0, opaq_desc1):
return cv.empty_gopaque_desc()
@cv.gapi.kernel(GLookUp)
class GLookUpImpl:
@staticmethod
def run(table, key):
return table[key]
g_table = cv.GOpaque.Any()
g_key = cv.GOpaque.String()
g_out = GLookUp.on(g_table, g_key)
comp = cv.GComputation(cv.GIn(g_table, g_key), cv.GOut(g_out))
table = {
'int': 42,
'str': 'hello, world!',
'tuple': (42, 42)
}
out = comp.apply(cv.gin(table, 'int'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
self.assertEqual(42, out)
out = comp.apply(cv.gin(table, 'str'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
self.assertEqual('hello, world!', out)
out = comp.apply(cv.gin(table, 'tuple'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
self.assertEqual((42, 42), out)
def test_array_with_custom_type(self):
@cv.gapi.op('custom.op', in_types=[cv.GArray.Any, cv.GArray.Any], out_types=[cv.GArray.Any])
class GConcat:
@staticmethod
def outMeta(arr_desc0, arr_desc1):
return cv.empty_array_desc()
@cv.gapi.kernel(GConcat)
class GConcatImpl:
@staticmethod
def run(arr0, arr1):
return arr0 + arr1
g_arr0 = cv.GArray.Any()
g_arr1 = cv.GArray.Any()
g_out = GConcat.on(g_arr0, g_arr1)
comp = cv.GComputation(cv.GIn(g_arr0, g_arr1), cv.GOut(g_out))
arr0 = ((2, 2), 2.0)
arr1 = (3, 'str')
out = comp.apply(cv.gin(arr0, arr1),
args=cv.gapi.compile_args(cv.gapi.kernels(GConcatImpl)))
self.assertEqual(arr0 + arr1, out)
def test_raise_in_kernel(self):
@cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
class GAdd:
@staticmethod
def outMeta(desc0, desc1):
return desc0
@cv.gapi.kernel(GAdd)
class GAddImpl:
@staticmethod
def run(img0, img1):
raise Exception('Error')
return img0 + img1
g_in0 = cv.GMat()
g_in1 = cv.GMat()
g_out = GAdd.on(g_in0, g_in1)
comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
img0 = np.array([1, 2, 3])
img1 = np.array([1, 2, 3])
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
args=cv.gapi.compile_args(
cv.gapi.kernels(GAddImpl)))
def test_raise_in_outMeta(self):
@cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
class GAdd:
@staticmethod
def outMeta(desc0, desc1):
raise NotImplementedError("outMeta isn't implemented")
@cv.gapi.kernel(GAdd)
class GAddImpl:
@staticmethod
def run(img0, img1):
return img0 + img1
g_in0 = cv.GMat()
g_in1 = cv.GMat()
g_out = GAdd.on(g_in0, g_in1)
comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
img0 = np.array([1, 2, 3])
img1 = np.array([1, 2, 3])
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
args=cv.gapi.compile_args(
cv.gapi.kernels(GAddImpl)))
def test_invalid_outMeta(self):
@cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
class GAdd:
@staticmethod
def outMeta(desc0, desc1):
# Invalid outMeta
return cv.empty_gopaque_desc()
@cv.gapi.kernel(GAdd)
class GAddImpl:
@staticmethod
def run(img0, img1):
return img0 + img1
g_in0 = cv.GMat()
g_in1 = cv.GMat()
g_out = GAdd.on(g_in0, g_in1)
comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
img0 = np.array([1, 2, 3])
img1 = np.array([1, 2, 3])
# FIXME: Cause Bad variant access.
# Need to provide more descriptive error messsage.
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
args=cv.gapi.compile_args(
cv.gapi.kernels(GAddImpl)))
def test_pipeline_with_custom_kernels(self):
@cv.gapi.op('custom.resize', in_types=[cv.GMat, tuple], out_types=[cv.GMat])
class GResize:
@staticmethod
def outMeta(desc, size):
return desc.withSize(size)
@cv.gapi.kernel(GResize)
class GResizeImpl:
@staticmethod
def run(img, size):
return cv.resize(img, size)
@cv.gapi.op('custom.transpose', in_types=[cv.GMat, tuple], out_types=[cv.GMat])
class GTranspose:
@staticmethod
def outMeta(desc, order):
return desc
@cv.gapi.kernel(GTranspose)
class GTransposeImpl:
@staticmethod
def run(img, order):
return np.transpose(img, order)
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
img = cv.imread(img_path)
size = (32, 32)
order = (1, 0, 2)
# Dummy pipeline just to validate this case:
# gapi -> custom -> custom -> gapi
# OpenCV
expected = cv.cvtColor(img, cv.COLOR_BGR2RGB)
expected = cv.resize(expected, size)
expected = np.transpose(expected, order)
expected = cv.mean(expected)
# G-API
g_bgr = cv.GMat()
g_rgb = cv.gapi.BGR2RGB(g_bgr)
g_resized = GResize.on(g_rgb, size)
g_transposed = GTranspose.on(g_resized, order)
g_mean = cv.gapi.mean(g_transposed)
comp = cv.GComputation(cv.GIn(g_bgr), cv.GOut(g_mean))
actual = comp.apply(cv.gin(img), args=cv.gapi.compile_args(
cv.gapi.kernels(GResizeImpl, GTransposeImpl)))
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,369 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
import time
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
@cv.gapi.op('custom.delay', in_types=[cv.GMat], out_types=[cv.GMat])
class GDelay:
"""Delay for 10 ms."""
@staticmethod
def outMeta(desc):
return desc
@cv.gapi.kernel(GDelay)
class GDelayImpl:
"""Implementation for GDelay operation."""
@staticmethod
def run(img):
time.sleep(0.01)
return img
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.gapi.descr_of(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(cv.gin(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(cv.gin(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(cv.gin(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(),
np.array(a, np.float32).flatten(),
cv.NORM_INF))
proc_num_frames += 1
if proc_num_frames == max_num_frames:
break
def test_gapi_streaming_meta(self):
ksize = 3
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
# G-API
g_in = cv.GMat()
g_ts = cv.gapi.streaming.timestamp(g_in)
g_seqno = cv.gapi.streaming.seqNo(g_in)
g_seqid = cv.gapi.streaming.seq_id(g_in)
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_ts, g_seqno, g_seqid))
ccomp = c.compileStreaming()
source = cv.gapi.wip.make_capture_src(path)
ccomp.setSource(cv.gin(source))
ccomp.start()
# Assert
max_num_frames = 10
curr_frame_number = 0
while True:
has_frame, (ts, seqno, seqid) = ccomp.pull()
if not has_frame:
break
self.assertEqual(curr_frame_number, seqno)
self.assertEqual(curr_frame_number, seqid)
curr_frame_number += 1
if curr_frame_number == max_num_frames:
break
def test_desync(self):
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
# G-API
g_in = cv.GMat()
g_out1 = cv.gapi.copy(g_in)
des = cv.gapi.streaming.desync(g_in)
g_out2 = GDelay.on(des)
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out1, g_out2))
kernels = cv.gapi.kernels(GDelayImpl)
ccomp = c.compileStreaming(args=cv.gapi.compile_args(kernels))
source = cv.gapi.wip.make_capture_src(path)
ccomp.setSource(cv.gin(source))
ccomp.start()
# Assert
max_num_frames = 10
proc_num_frames = 0
out_counter = 0
desync_out_counter = 0
none_counter = 0
while True:
has_frame, (out1, out2) = ccomp.pull()
if not has_frame:
break
if not out1 is None:
out_counter += 1
if not out2 is None:
desync_out_counter += 1
else:
none_counter += 1
proc_num_frames += 1
if proc_num_frames == max_num_frames:
ccomp.stop()
break
self.assertLess(0, proc_num_frames)
self.assertLess(desync_out_counter, out_counter)
self.assertLess(0, none_counter)
def test_compile_streaming_empty(self):
g_in = cv.GMat()
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
comp.compileStreaming()
def test_compile_streaming_args(self):
g_in = cv.GMat()
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
comp.compileStreaming(cv.gapi.compile_args(cv.gapi.streaming.queue_capacity(1)))
def test_compile_streaming_descr_of(self):
g_in = cv.GMat()
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
img = np.zeros((3,300,300), dtype=np.float32)
comp.compileStreaming(cv.gapi.descr_of(img))
def test_compile_streaming_descr_of_and_args(self):
g_in = cv.GMat()
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
img = np.zeros((3,300,300), dtype=np.float32)
comp.compileStreaming(cv.gapi.descr_of(img),
cv.gapi.compile_args(cv.gapi.streaming.queue_capacity(1)))
def test_compile_streaming_meta(self):
g_in = cv.GMat()
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
img = np.zeros((3,300,300), dtype=np.float32)
comp.compileStreaming([cv.GMatDesc(cv.CV_8U, 3, (300, 300))])
def test_compile_streaming_meta_and_args(self):
g_in = cv.GMat()
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
img = np.zeros((3,300,300), dtype=np.float32)
comp.compileStreaming([cv.GMatDesc(cv.CV_8U, 3, (300, 300))],
cv.gapi.compile_args(cv.gapi.streaming.queue_capacity(1)))
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,54 @@
#!/usr/bin/env python
import numpy as np
import cv2 as cv
import os
import sys
import unittest
from tests_common import NewOpenCVTests
try:
if sys.version_info[:2] < (3, 0):
raise unittest.SkipTest('Python 2.x is not supported')
class gapi_types_test(NewOpenCVTests):
def test_garray_type(self):
types = [cv.gapi.CV_BOOL , cv.gapi.CV_INT , cv.gapi.CV_DOUBLE , cv.gapi.CV_FLOAT,
cv.gapi.CV_STRING, cv.gapi.CV_POINT , cv.gapi.CV_POINT2F, cv.gapi.CV_SIZE ,
cv.gapi.CV_RECT , cv.gapi.CV_SCALAR, cv.gapi.CV_MAT , cv.gapi.CV_GMAT]
for t in types:
g_array = cv.GArrayT(t)
self.assertEqual(t, g_array.type())
def test_gopaque_type(self):
types = [cv.gapi.CV_BOOL , cv.gapi.CV_INT , cv.gapi.CV_DOUBLE , cv.gapi.CV_FLOAT,
cv.gapi.CV_STRING, cv.gapi.CV_POINT , cv.gapi.CV_POINT2F, cv.gapi.CV_SIZE ,
cv.gapi.CV_RECT]
for t in types:
g_opaque = cv.GOpaqueT(t)
self.assertEqual(t, g_opaque.type())
except unittest.SkipTest as e:
message = str(e)
class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)
def test_skip():
pass
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()