Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enable GAPI VASOT in Python #24576

Merged
merged 1 commit into from Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/gapi/include/opencv2/gapi/cpu/ot.hpp
Expand Up @@ -19,7 +19,7 @@ namespace gapi {
*/
namespace ot {
namespace cpu {
GAPI_EXPORTS GKernelPackage kernels();
GAPI_EXPORTS_W GKernelPackage kernels();
} // namespace cpu
} // namespace ot
} // namespace gapi
Expand Down
60 changes: 32 additions & 28 deletions modules/gapi/include/opencv2/gapi/ot.hpp
Expand Up @@ -24,28 +24,28 @@ namespace ot {
*
* Tracking status twin for vas::ot::TrackingStatus
*/
enum class TrackingStatus: int32_t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looked fine, why we decided to change this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be automatically convertable to int

enum TrackingStatus
{
NEW = 0, /**< The object is newly added. */
TRACKED, /**< The object is being tracked. */
LOST /**< The object gets lost now. The object can be tracked again
by specifying detected object manually. */
};

struct ObjectTrackerParams
struct GAPI_EXPORTS_W_SIMPLE ObjectTrackerParams
{
/**
* Maximum number of trackable objects in a frame.
* Valid range: 1 <= max_num_objects. Or it can be -1 if there is no limitation
* of maximum number in X86. KMB/TBH has limitation up to 1024.
* Default value is -1 which means there is no limitation in X86. KMB/TBH is -1 means 200.
*/
int32_t max_num_objects = -1;
GAPI_PROP_RW int32_t max_num_objects = -1;

/**
* Input color format. Supports 0(BGR), 1(NV12), 2(BGRX) and 4(I420)
*/
int32_t input_image_format = 0;
GAPI_PROP_RW int32_t input_image_format = 0;

/**
* Specifies whether tracker to use detection class for keeping id of an object.
Expand All @@ -60,7 +60,7 @@ struct ObjectTrackerParams
* @n
* Default value is true.
*/
bool tracking_per_class = true;
GAPI_PROP_RW bool tracking_per_class = true;

bool operator==(const ObjectTrackerParams& other) const
{
Expand All @@ -70,7 +70,7 @@ struct ObjectTrackerParams
}
};

using GTrackedInfo = std::tuple<cv::GArray<cv::Rect>, cv::GArray<int32_t>, cv::GArray<uint64_t>, cv::GArray<TrackingStatus>>;
using GTrackedInfo = std::tuple<cv::GArray<cv::Rect>, cv::GArray<int32_t>, cv::GArray<uint64_t>, cv::GArray<int>>;

G_API_OP(GTrackFromMat, <GTrackedInfo(cv::GMat, cv::GArray<cv::Rect>, cv::GArray<int32_t>, float)>, "com.intel.track_from_mat")
{
Expand Down Expand Up @@ -107,23 +107,26 @@ G_API_OP(GTrackFromFrame, <GTrackedInfo(cv::GFrame, cv::GArray<cv::Rect>, cv::GA
* @param delta Frame_delta_t Delta time between two consecutive tracking in seconds.
* The valid range is [0.005 ~ 0.5].
* @return Tracking results of target objects.
* cv::GArray<cv::Rect> Array of rectangles for tracked objects.
* cv::GArray<int32_t> Array of detected objects labels.
* cv::GArray<uint64_t> Array of tracking IDs for objects.
* Numbering sequence starts from 1.
* The value 0 means the tracking ID of this object has
* not been assigned.
* cv::GArray<TrackingStatus> Array of tracking statuses for objects.
* cv::GArray<cv::Rect> Array of rectangles for tracked objects.
* cv::GArray<int32_t> Array of detected objects labels.
* cv::GArray<uint64_t> Array of tracking IDs for objects.
* Numbering sequence starts from 1.
* The value 0 means the tracking ID of this object has
* not been assigned.
* cv::GArray<int> Array of tracking statuses for objects.
*/
GAPI_EXPORTS std::tuple<cv::GArray<cv::Rect>,
cv::GArray<int32_t>,
cv::GArray<uint64_t>,
cv::GArray<TrackingStatus>> track(const cv::GMat& mat,
const cv::GArray<cv::Rect>& detected_rects,
const cv::GArray<int>& detected_class_labels,
float delta);
GAPI_EXPORTS_W std::tuple<cv::GArray<cv::Rect>,
cv::GArray<int>,
cv::GArray<uint64_t>,
cv::GArray<int>>
track(const cv::GMat& mat,
const cv::GArray<cv::Rect>& detected_rects,
const cv::GArray<int>& detected_class_labels,
float delta);


/**
@overload
* @brief Tracks objects with video frames. Overload of track(...) for frame as GFrame.
*
* @param frame Input frame.
Expand All @@ -139,15 +142,16 @@ GAPI_EXPORTS std::tuple<cv::GArray<cv::Rect>,
* Numbering sequence starts from 1.
* The value 0 means the tracking ID of this object has
* not been assigned.
* cv::GArray<TrackingStatus> Array of tracking statuses for objects.
* cv::GArray<int> Array of tracking statuses for objects.
*/
GAPI_EXPORTS std::tuple<cv::GArray<cv::Rect>,
cv::GArray<int32_t>,
cv::GArray<uint64_t>,
cv::GArray<TrackingStatus>> track(const cv::GFrame& frame,
const cv::GArray<cv::Rect>& detected_rects,
const cv::GArray<int>& detected_class_labels,
float delta);
GAPI_EXPORTS_W std::tuple<cv::GArray<cv::Rect>,
cv::GArray<int>,
cv::GArray<uint64_t>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually doubt if we even need uint64_t there...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what inner VAS function operates with. I don't think that reinterpret_cast or copying are the best options to deal with it to return another type.

cv::GArray<int>>
track(const cv::GFrame& frame,
const cv::GArray<cv::Rect>& detected_rects,
const cv::GArray<int>& detected_class_labels,
float delta);
} // namespace ot
} // namespace gapi
} // namespace cv
Expand Down
22 changes: 22 additions & 0 deletions modules/gapi/misc/python/package/gapi/__init__.py
Expand Up @@ -56,6 +56,14 @@ class Int():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_INT)

class Int64():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any usage of both Int64() and UInt64() propose to remove this unless it's really needed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the return types of OT I guess.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UInt64 will be used if we want to create custom kernel in python and accept output from track operation.

def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_INT64)

class UInt64():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_UINT64)

class Double():
def __new__(self):
return cv.GOpaqueT(cv.gapi.CV_DOUBLE)
Expand Down Expand Up @@ -111,6 +119,14 @@ class Int():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_INT)

class Int64():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_INT64)

class UInt64():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_UINT64)

class Double():
def __new__(self):
return cv.GArrayT(cv.gapi.CV_DOUBLE)
Expand Down Expand Up @@ -170,6 +186,8 @@ 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.Int64: cv.gapi.CV_INT64,
cv.GArray.UInt64: cv.gapi.CV_UINT64,
cv.GArray.Double: cv.gapi.CV_DOUBLE,
cv.GArray.Float: cv.gapi.CV_FLOAT,
cv.GArray.String: cv.gapi.CV_STRING,
Expand All @@ -190,6 +208,8 @@ def op(op_id, in_types, out_types):
cv.GOpaque.Rect: cv.gapi.CV_RECT,
cv.GOpaque.Bool: cv.gapi.CV_BOOL,
cv.GOpaque.Int: cv.gapi.CV_INT,
cv.GOpaque.Int64: cv.gapi.CV_INT64,
cv.GOpaque.UInt64: cv.gapi.CV_UINT64,
cv.GOpaque.Double: cv.gapi.CV_DOUBLE,
cv.GOpaque.Float: cv.gapi.CV_FLOAT,
cv.GOpaque.String: cv.gapi.CV_STRING,
Expand All @@ -205,6 +225,8 @@ def op(op_id, in_types, out_types):
type2str = {
cv.gapi.CV_BOOL: 'cv.gapi.CV_BOOL' ,
cv.gapi.CV_INT: 'cv.gapi.CV_INT' ,
cv.gapi.CV_INT64: 'cv.gapi.CV_INT64' ,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do we use int64_t? I can only see uint64_t

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was exposed in the bindings already. I decided to just add it here also.

cv.gapi.CV_UINT64: 'cv.gapi.CV_UINT64' ,
cv.gapi.CV_DOUBLE: 'cv.gapi.CV_DOUBLE' ,
cv.gapi.CV_FLOAT: 'cv.gapi.CV_FLOAT' ,
cv.gapi.CV_STRING: 'cv.gapi.CV_STRING' ,
Expand Down
14 changes: 7 additions & 7 deletions modules/gapi/misc/python/pyopencv_gapi.hpp
Expand Up @@ -246,6 +246,7 @@ PyObject* pyopencv_from(const cv::GArg& value)
HANDLE_CASE(BOOL, bool);
HANDLE_CASE(INT, int);
HANDLE_CASE(INT64, int64_t);
HANDLE_CASE(UINT64, uint64_t);
HANDLE_CASE(DOUBLE, double);
HANDLE_CASE(FLOAT, float);
HANDLE_CASE(STRING, std::string);
Expand All @@ -258,7 +259,6 @@ PyObject* pyopencv_from(const cv::GArg& value)
HANDLE_CASE(MAT, cv::Mat);
HANDLE_CASE(UNKNOWN, cv::detail::PyObjectHolder);
HANDLE_CASE(DRAW_PRIM, cv::gapi::wip::draw::Prim);
UNSUPPORTED(UINT64);
#undef HANDLE_CASE
#undef UNSUPPORTED
}
Expand Down Expand Up @@ -304,6 +304,7 @@ PyObject* pyopencv_from(const cv::detail::OpaqueRef& o)
case cv::detail::OpaqueKind::CV_BOOL : return pyopencv_from(o.rref<bool>());
case cv::detail::OpaqueKind::CV_INT : return pyopencv_from(o.rref<int>());
case cv::detail::OpaqueKind::CV_INT64 : return pyopencv_from(o.rref<int64_t>());
case cv::detail::OpaqueKind::CV_UINT64 : return pyopencv_from(o.rref<uint64_t>());
case cv::detail::OpaqueKind::CV_DOUBLE : return pyopencv_from(o.rref<double>());
case cv::detail::OpaqueKind::CV_FLOAT : return pyopencv_from(o.rref<float>());
case cv::detail::OpaqueKind::CV_STRING : return pyopencv_from(o.rref<std::string>());
Expand All @@ -314,7 +315,6 @@ PyObject* pyopencv_from(const cv::detail::OpaqueRef& o)
case cv::detail::OpaqueKind::CV_RECT : return pyopencv_from(o.rref<cv::Rect>());
case cv::detail::OpaqueKind::CV_UNKNOWN : return pyopencv_from(o.rref<cv::GArg>());
case cv::detail::OpaqueKind::CV_DRAW_PRIM : return pyopencv_from(o.rref<cv::gapi::wip::draw::Prim>());
case cv::detail::OpaqueKind::CV_UINT64 : break;
case cv::detail::OpaqueKind::CV_SCALAR : break;
case cv::detail::OpaqueKind::CV_MAT : break;
}
Expand All @@ -331,6 +331,7 @@ PyObject* pyopencv_from(const cv::detail::VectorRef& v)
case cv::detail::OpaqueKind::CV_BOOL : return pyopencv_from_generic_vec(v.rref<bool>());
case cv::detail::OpaqueKind::CV_INT : return pyopencv_from_generic_vec(v.rref<int>());
case cv::detail::OpaqueKind::CV_INT64 : return pyopencv_from_generic_vec(v.rref<int64_t>());
case cv::detail::OpaqueKind::CV_UINT64 : return pyopencv_from_generic_vec(v.rref<uint64_t>());
case cv::detail::OpaqueKind::CV_DOUBLE : return pyopencv_from_generic_vec(v.rref<double>());
case cv::detail::OpaqueKind::CV_FLOAT : return pyopencv_from_generic_vec(v.rref<float>());
case cv::detail::OpaqueKind::CV_STRING : return pyopencv_from_generic_vec(v.rref<std::string>());
Expand All @@ -343,7 +344,6 @@ PyObject* pyopencv_from(const cv::detail::VectorRef& v)
case cv::detail::OpaqueKind::CV_MAT : return pyopencv_from_generic_vec(v.rref<cv::Mat>());
case cv::detail::OpaqueKind::CV_UNKNOWN : return pyopencv_from_generic_vec(v.rref<cv::GArg>());
case cv::detail::OpaqueKind::CV_DRAW_PRIM : return pyopencv_from_generic_vec(v.rref<cv::gapi::wip::draw::Prim>());
case cv::detail::OpaqueKind::CV_UINT64 : break;
}

PyErr_SetString(PyExc_TypeError, "Unsupported GArray type");
Expand Down Expand Up @@ -502,6 +502,8 @@ static cv::detail::OpaqueRef extract_opaque_ref(PyObject* from, cv::detail::Opaq
{
HANDLE_CASE(BOOL, bool);
HANDLE_CASE(INT, int);
HANDLE_CASE(INT64, int64_t);
HANDLE_CASE(UINT64, uint64_t);
HANDLE_CASE(DOUBLE, double);
HANDLE_CASE(FLOAT, float);
HANDLE_CASE(STRING, std::string);
Expand All @@ -511,8 +513,6 @@ static cv::detail::OpaqueRef extract_opaque_ref(PyObject* from, cv::detail::Opaq
HANDLE_CASE(SIZE, cv::Size);
HANDLE_CASE(RECT, cv::Rect);
HANDLE_CASE(UNKNOWN, cv::GArg);
UNSUPPORTED(UINT64);
UNSUPPORTED(INT64);
UNSUPPORTED(SCALAR);
UNSUPPORTED(MAT);
UNSUPPORTED(DRAW_PRIM);
Expand All @@ -535,6 +535,8 @@ static cv::detail::VectorRef extract_vector_ref(PyObject* from, cv::detail::Opaq
{
HANDLE_CASE(BOOL, bool);
HANDLE_CASE(INT, int);
HANDLE_CASE(INT64, int64_t);
HANDLE_CASE(UINT64, uint64_t);
HANDLE_CASE(DOUBLE, double);
HANDLE_CASE(FLOAT, float);
HANDLE_CASE(STRING, std::string);
Expand All @@ -547,8 +549,6 @@ static cv::detail::VectorRef extract_vector_ref(PyObject* from, cv::detail::Opaq
HANDLE_CASE(MAT, cv::Mat);
HANDLE_CASE(UNKNOWN, cv::GArg);
HANDLE_CASE(DRAW_PRIM, cv::gapi::wip::draw::Prim);
UNSUPPORTED(UINT64);
UNSUPPORTED(INT64);
#undef HANDLE_CASE
#undef UNSUPPORTED
}
Expand Down
3 changes: 3 additions & 0 deletions modules/gapi/misc/python/python_bridge.hpp
Expand Up @@ -31,6 +31,7 @@ using cv::gapi::wip::draw::Prim;
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(uint64_t , cv::gapi::ArgType::CV_UINT64, 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) \
Expand All @@ -49,6 +50,7 @@ WRAP_ARGS(cv::GMat , cv::gapi::ArgType::CV_GMAT, 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(uint64_t , cv::gapi::ArgType::CV_UINT64, 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) \
Expand All @@ -67,6 +69,7 @@ enum ArgType {
CV_BOOL,
CV_INT,
CV_INT64,
CV_UINT64,
CV_DOUBLE,
CV_FLOAT,
CV_STRING,
Expand Down
1 change: 1 addition & 0 deletions modules/gapi/misc/python/shadow_gapi.hpp
Expand Up @@ -8,6 +8,7 @@ struct GAPI_EXPORTS_W_SIMPLE GCompileArg
GAPI_WRAP GCompileArg(GKernelPackage arg);
GAPI_WRAP GCompileArg(gapi::GNetPackage arg);
GAPI_WRAP GCompileArg(gapi::streaming::queue_capacity arg);
GAPI_WRAP GCompileArg(gapi::ot::ObjectTrackerParams arg);
};

class GAPI_EXPORTS_W_SIMPLE GInferInputs
Expand Down
58 changes: 58 additions & 0 deletions modules/gapi/misc/python/test/test_gapi_ot.py
@@ -0,0 +1,58 @@
#!/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_ot_test(NewOpenCVTests):

def test_ot_smoke(self):
# Input
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
in_image = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2BGR)
in_rects = [ (138, 89, 71, 64) ]
in_rects_cls = [ 0 ]

# G-API
g_in = cv.GMat()
g_in_rects = cv.GArray.Rect()
g_in_rects_cls = cv.GArray.Int()
delta = 0.5

g_out_rects, g_out_rects_cls, g_track_ids, g_track_sts = \
cv.gapi.ot.track(g_in, g_in_rects, g_in_rects_cls, delta)


comp = cv.GComputation(cv.GIn(g_in, g_in_rects, g_in_rects_cls),
cv.GOut(g_out_rects, g_out_rects_cls,
g_track_ids, g_track_sts))

__, __, __, sts = comp.apply(cv.gin(in_image, in_rects, in_rects_cls),
args=cv.gapi.compile_args(cv.gapi.ot.cpu.kernels()))

self.assertEqual(cv.gapi.ot.NEW, sts[0])

except unittest.SkipTest as e:

message = str(e)

class TestSkip(unittest.TestCase):
def setUp(self):
self.skipTest('Skip tests: ' + message)

def test_skip():
pass


if __name__ == '__main__':
NewOpenCVTests.bootstrap()
14 changes: 7 additions & 7 deletions modules/gapi/misc/python/test/test_gapi_types.py
Expand Up @@ -17,20 +17,20 @@
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_POINT3F ,
cv.gapi.CV_SIZE , cv.gapi.CV_RECT , cv.gapi.CV_SCALAR , cv.gapi.CV_MAT ,
cv.gapi.CV_GMAT]
types = [cv.gapi.CV_BOOL , cv.gapi.CV_INT , cv.gapi.CV_INT64 , cv.gapi.CV_UINT64,
cv.gapi.CV_DOUBLE , cv.gapi.CV_FLOAT , cv.gapi.CV_STRING, cv.gapi.CV_POINT ,
cv.gapi.CV_POINT2F, cv.gapi.CV_POINT3F, 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_POINT3F,
cv.gapi.CV_SIZE , cv.gapi.CV_RECT]
types = [cv.gapi.CV_BOOL , cv.gapi.CV_INT , cv.gapi.CV_INT64 , cv.gapi.CV_UINT64,
cv.gapi.CV_DOUBLE , cv.gapi.CV_FLOAT , cv.gapi.CV_STRING, cv.gapi.CV_POINT ,
cv.gapi.CV_POINT2F, cv.gapi.CV_POINT3F, cv.gapi.CV_SIZE , cv.gapi.CV_RECT]

for t in types:
g_opaque = cv.GOpaqueT(t)
Expand Down