Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * GStreamer / NNStreamer tensor-decoder bounding box properties
4 : * Copyright (C) 2024 Yelin Jeong <yelini.jeong@samsung.com>
5 : */
6 : /**
7 : * @file ovdetection.cc
8 : * @date 13 May 2024
9 : * @brief NNStreamer tensor-decoder bounding box properties
10 : *
11 : * @see https://github.com/nnstreamer/nnstreamer
12 : * @author Yelin Jeong <yelini.jeong@samsung.com>
13 : * @bug No known bugs except for NYI items
14 : *
15 : */
16 :
17 : #include "../tensordec-boundingbox.h"
18 :
19 : #define OV_PERSON_DETECTION_CONF_THRESHOLD (0.8)
20 : #define DETECTION_MAX (200U)
21 : #define DEFAULT_MAX_TENSORS (1)
22 : #define DEFAULT_SIZE_DETECTION_DESC (7)
23 :
24 : /**
25 : * @brief Class for OVDetection box properties
26 : */
27 : class OVDetection : public BoxProperties
28 : {
29 : public:
30 : OVDetection ();
31 : ~OVDetection ();
32 0 : int setOptionInternal (const char *param)
33 : {
34 : UNUSED (param);
35 0 : return TRUE;
36 : }
37 : int checkCompatible (const GstTensorsConfig *config);
38 : GArray *decode (const GstTensorsConfig *config, const GstTensorMemory *input);
39 : };
40 :
41 : /**
42 : * @brief C++-Template-like box location calculation for OpenVino Person Detection Model
43 : * @param[in] type The tensor type of inputptr
44 : * @param[in] intputptr Input tensor Data
45 : * @param[in] typename nnstreamer enum corresponding to the type
46 : * @param[out] results The object returned. (GArray with detectedObject)
47 : */
48 : #define _get_persons_ov(type, inputptr, typename, results) \
49 : case typename: \
50 : { \
51 : type *typed_inputptr = (type *) inputptr; \
52 : guint d; \
53 : \
54 : for (d = 1; d <= DETECTION_MAX; ++d) { \
55 : struct { \
56 : type image_id; \
57 : type label; \
58 : type conf; \
59 : type x_min; \
60 : type y_min; \
61 : type x_max; \
62 : type y_max; \
63 : } desc; \
64 : \
65 : memcpy (&desc, typed_inputptr, sizeof (desc)); \
66 : typed_inputptr += (sizeof (desc) / sizeof (type)); \
67 : \
68 : if ((int) desc.image_id < 0) { \
69 : max_detection = (d - 1); \
70 : break; \
71 : } \
72 : if ((double) desc.conf < OV_PERSON_DETECTION_CONF_THRESHOLD) \
73 : continue; \
74 : \
75 : detectedObject object = { \
76 : .valid = FALSE, \
77 : .class_id = 0, \
78 : .x = 0, \
79 : .y = 0, \
80 : .width = 0, \
81 : .height = 0, \
82 : .angle = 0, \
83 : .prob = .0, \
84 : .tracking_id = 0, \
85 : }; \
86 : object.class_id = -1; \
87 : object.x = (int) (desc.x_min * (type) i_width); \
88 : object.y = (int) (desc.y_min * (type) i_height); \
89 : object.width = (int) ((desc.x_max - desc.x_min) * (type) i_width); \
90 : object.height = (int) ((desc.y_max - desc.y_min) * (type) i_height); \
91 : object.prob = 1; \
92 : object.valid = TRUE; \
93 : g_array_append_val (results, object); \
94 : } \
95 : } \
96 : break
97 :
98 : static BoxProperties *ov_detection = nullptr;
99 :
100 : #ifdef __cplusplus
101 : extern "C" {
102 : #endif /* __cplusplus */
103 : void init_properties_ovdetection (void) __attribute__ ((constructor));
104 : void fini_properties_ovdetection (void) __attribute__ ((destructor));
105 : #ifdef __cplusplus
106 : }
107 : #endif /* __cplusplus */
108 :
109 : /** @brief Constructor of OVDetection */
110 15 : OVDetection::OVDetection ()
111 : {
112 15 : name = g_strdup_printf ("ov-person-detection");
113 15 : }
114 :
115 : /** @brief Destructor of OVDetection */
116 30 : OVDetection::~OVDetection ()
117 : {
118 15 : g_free (name);
119 30 : }
120 :
121 : /** @brief Check compatibility of given tensors config */
122 : int
123 0 : OVDetection::checkCompatible (const GstTensorsConfig *config)
124 : {
125 : const guint *dim;
126 : int i;
127 0 : GstTensorInfo *info = nullptr;
128 : UNUSED (total_labels);
129 :
130 0 : if (!check_tensors (config, DEFAULT_MAX_TENSORS))
131 0 : return FALSE;
132 :
133 : /**
134 : * The shape of the output tensor is [7, N, 1, 1], where N is the maximum
135 : * number (i.e., 200) of detected bounding boxes.
136 : */
137 0 : info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) &config->info, 0);
138 0 : dim = info->dimension;
139 0 : g_return_val_if_fail (dim[0] == DEFAULT_SIZE_DETECTION_DESC, FALSE);
140 0 : g_return_val_if_fail (dim[1] == DETECTION_MAX, FALSE);
141 0 : for (i = 2; i < NNS_TENSOR_RANK_LIMIT; ++i)
142 0 : g_return_val_if_fail (dim[i] == 0 || dim[i] == 1, FALSE);
143 :
144 0 : return TRUE;
145 : }
146 :
147 : /**
148 : * @brief Decode input memory to out buffer
149 : * @param[in] config The structure of input tensor info.
150 : * @param[in] input The array of input tensor data. The maximum array size of input data is NNS_TENSOR_SIZE_LIMIT.
151 : */
152 : GArray *
153 0 : OVDetection::decode (const GstTensorsConfig *config, const GstTensorMemory *input)
154 : {
155 0 : GArray *results = NULL;
156 0 : const guint num_tensors = config->info.num_tensors;
157 0 : GstTensorInfo *info = nullptr;
158 :
159 : /* Already checked with getOutCaps. Thus, this is an internal bug */
160 0 : g_assert (num_tensors >= DEFAULT_MAX_TENSORS);
161 :
162 0 : results = g_array_sized_new (FALSE, TRUE, sizeof (detectedObject), DETECTION_MAX);
163 0 : info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) &config->info, 0);
164 0 : switch (info->type) {
165 0 : _get_persons_ov (uint8_t, input[0].data, _NNS_UINT8, results);
166 0 : _get_persons_ov (int8_t, input[0].data, _NNS_INT8, results);
167 0 : _get_persons_ov (uint16_t, input[0].data, _NNS_UINT16, results);
168 0 : _get_persons_ov (int16_t, input[0].data, _NNS_INT16, results);
169 0 : _get_persons_ov (uint32_t, input[0].data, _NNS_UINT32, results);
170 0 : _get_persons_ov (int32_t, input[0].data, _NNS_INT32, results);
171 0 : _get_persons_ov (uint64_t, input[0].data, _NNS_UINT64, results);
172 0 : _get_persons_ov (int64_t, input[0].data, _NNS_INT64, results);
173 0 : _get_persons_ov (float, input[0].data, _NNS_FLOAT32, results);
174 0 : _get_persons_ov (double, input[0].data, _NNS_FLOAT64, results);
175 0 : default:
176 0 : g_assert (0);
177 : }
178 0 : return results;
179 : }
180 :
181 : /** @brief Initialize this object for tensor decoder bounding box */
182 : void
183 15 : init_properties_ovdetection ()
184 : {
185 15 : ov_detection = new OVDetection ();
186 15 : BoundingBox::addProperties (ov_detection);
187 15 : }
188 :
189 : /** @brief Destruct this object for tensor decoder bounding box */
190 : void
191 15 : fini_properties_ovdetection ()
192 : {
193 15 : delete ov_detection;
194 15 : }
|