diff --git a/girs/GstAnalytics-1.0.gir b/girs/GstAnalytics-1.0.gir
index 7b864e6042..aab096b2ed 100644
--- a/girs/GstAnalytics-1.0.gir
+++ b/girs/GstAnalytics-1.0.gir
@@ -331,6 +331,46 @@ identified by @id is stored.
+
+ Retrieve oriented location and location confidence level.
+
+
+ TRUE on success, otherwise FALSE.
+
+
+
+
+ instance
+
+
+
+ x component of upper-left corner of the object location (pre-rotation)
+
+
+
+ y component of upper-left corner of the object location (pre-rotation)
+
+
+
+ bounding box width of the object location
+
+
+
+ bounding box height of the object location
+
+
+
+ Rotation of the bounding box in radians <0, 2xPI>
+ with respect to the bounding box center
+ (the rotation value is a clock-wise angle)
+
+
+
+ Confidence on object location
+
+
+
+
Get an id that represent object-detection metadata type
@@ -501,6 +541,54 @@ new struct sub-classing GstAnalyticsRelatableMtd.
+
+
+
+ Added successfully
+
+
+
+
+ Instance of #GstAnalyticsRelationMeta where to add classification instance
+
+
+
+ Quark of the object type
+
+
+
+ x component of bounding box upper-left corner (pre-rotation)
+
+
+
+ y component of bounding box upper-left corner (pre-rotation)
+
+
+
+ bounding box width
+
+
+
+ bounding box height
+
+
+
+ bounding box rotation in radians <0, 2xPI>
+ with respect to the bounding box center
+ (the rotation value is a clock-wise angle)
+
+
+
+ confidence level on the object location
+
+
+
+ Handle updated with newly added object detection
+ meta. Add an object-detetion metadata to @instance.
+
+
+
+
Add analytics segmentation metadata to @instance. The rectangle (@masks_loc_x,
@mask_loc_y, @mask_loc_w, @mask_loc_h) define a area of the image that
diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.c b/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.c
index fff207c144..a08ace19ca 100644
--- a/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.c
+++ b/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.c
@@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
+ * Copyright (C) 2024 Intel Corporation
*
* gstanalyticsobjectdetectionmtd.c
*
@@ -25,6 +26,7 @@
#include "gstanalyticsobjectdetectionmtd.h"
#include
+#include
/**
* SECTION:gstanalyticsobjectdetectionmtd
@@ -45,10 +47,13 @@ typedef struct _GstAnalyticsODMtdData GstAnalyticsODMtdData;
/**
* GstAnalyticsODMtdData:
* @object_type: Type of object
- * @x: x component of upper-left corner
- * @y: y component of upper-left corner
+ * @x: x component of upper-left corner (pre-rotation)
+ * @y: y component of upper-left corner (pre-rotation)
* @w: bounding box width
* @h: bounding box height
+ * @r: bounding box rotation in radians <0, 2xPI>
+ * with respect to the bounding box center
+ * (the rotation value is a clock-wise angle)
* @location_confidence_lvl: Confidence on object location
*
* Store information on results of object detection
@@ -62,6 +67,7 @@ struct _GstAnalyticsODMtdData
gint y;
gint w;
gint h;
+ gfloat r;
gfloat location_confidence_lvl;
};
@@ -150,6 +156,92 @@ gst_analytics_od_mtd_get_location (const GstAnalyticsODMtd * instance,
*w = data->w;
*h = data->h;
+ if (loc_conf_lvl)
+ *loc_conf_lvl = data->location_confidence_lvl;
+
+ gfloat r = data->r;
+ if (r != 0) {
+ gint xc = *x + *w / 2;
+ gint yc = *y + *h / 2;
+
+ gint corners[4][2] = {
+ {*x, *y},
+ {*x + *w, *y},
+ {*x + *w, *y + *h},
+ {*x, *y + *h}
+ };
+
+ gint rotated_corners[4][2];
+ for (int i = 0; i < 4; i++) {
+ gint xt = corners[i][0] - xc;
+ gint yt = corners[i][1] - yc;
+
+ gint xr = (gint) round (xt * cos (r) - yt * sin (r));
+ gint yr = (gint) round (xt * sin (r) + yt * cos (r));
+
+ rotated_corners[i][0] = xr + xc;
+ rotated_corners[i][1] = yr + yc;
+ }
+
+ *x = rotated_corners[0][0];
+ *y = rotated_corners[0][1];
+ gint max_x = rotated_corners[0][0];
+ gint max_y = rotated_corners[0][1];
+
+ for (int i = 1; i < 4; i++) {
+ if (rotated_corners[i][0] < *x)
+ *x = rotated_corners[i][0];
+ if (rotated_corners[i][1] < *y)
+ *y = rotated_corners[i][1];
+ if (rotated_corners[i][0] > max_x)
+ max_x = rotated_corners[i][0];
+ if (rotated_corners[i][1] > max_y)
+ max_y = rotated_corners[i][1];
+ }
+
+ *w = max_x - *x;
+ *h = max_y - *y;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_analytics_od_mtd_get_oriented_location:
+ * @instance: instance
+ * @x: (out): x component of upper-left corner of the object location (pre-rotation)
+ * @y: (out): y component of upper-left corner of the object location (pre-rotation)
+ * @w: (out): bounding box width of the object location
+ * @h: (out): bounding box height of the object location
+ * @r: (out): Rotation of the bounding box in radians <0, 2xPI>
+ * with respect to the bounding box center
+ * (the rotation value is a clock-wise angle)
+ * @loc_conf_lvl: (out)(optional): Confidence on object location
+
+ *
+ * Retrieve oriented location and location confidence level.
+ *
+ * Returns: TRUE on success, otherwise FALSE.
+ *
+ * Since: 1.26
+ */
+gboolean
+gst_analytics_od_mtd_get_oriented_location (const GstAnalyticsODMtd * instance,
+ gint * x, gint * y, gint * w, gint * h, gfloat * r, gfloat * loc_conf_lvl)
+{
+ GstAnalyticsODMtdData *data;
+
+ g_return_val_if_fail (instance && x && y && w && h && r, FALSE);
+ data = gst_analytics_relation_meta_get_mtd_data (instance->meta,
+ instance->id);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ *x = data->x;
+ *y = data->y;
+ *w = data->w;
+ *h = data->h;
+ *r = data->r;
+
if (loc_conf_lvl)
*loc_conf_lvl = data->location_confidence_lvl;
@@ -233,6 +325,47 @@ gst_analytics_relation_meta_add_od_mtd (GstAnalyticsRelationMeta *
od_mtd_data->y = y;
od_mtd_data->w = w;
od_mtd_data->h = h;
+ od_mtd_data->r = 0;
+ od_mtd_data->location_confidence_lvl = loc_conf_lvl;
+ od_mtd_data->object_type = type;
+ }
+ return od_mtd_data != NULL;
+}
+
+/**
+ * gst_analytics_relation_meta_add_oriented_od_mtd:
+ * @instance: Instance of #GstAnalyticsRelationMeta where to add classification instance
+ * @type: Quark of the object type
+ * @x: x component of bounding box upper-left corner (pre-rotation)
+ * @y: y component of bounding box upper-left corner (pre-rotation)
+ * @w: bounding box width
+ * @h: bounding box height
+ * @r: bounding box rotation in radians <0, 2xPI>
+ * with respect to the bounding box center
+ * (the rotation value is a clock-wise angle)
+ * @loc_conf_lvl: confidence level on the object location
+ * @od_mtd: (out)(nullable): Handle updated with newly added object detection
+ * meta. Add an object-detetion metadata to @instance.
+ *
+ * Returns: Added successfully
+ *
+ * Since: 1.26
+ */
+gboolean
+gst_analytics_relation_meta_add_oriented_od_mtd (GstAnalyticsRelationMeta *
+ instance, GQuark type, gint x, gint y, gint w, gint h, gfloat r,
+ gfloat loc_conf_lvl, GstAnalyticsODMtd * od_mtd)
+{
+ g_return_val_if_fail (instance != NULL, FALSE);
+ gsize size = sizeof (GstAnalyticsODMtdData);
+ GstAnalyticsODMtdData *od_mtd_data = (GstAnalyticsODMtdData *)
+ gst_analytics_relation_meta_add_mtd (instance, &od_impl, size, od_mtd);
+ if (od_mtd_data) {
+ od_mtd_data->x = x;
+ od_mtd_data->y = y;
+ od_mtd_data->w = w;
+ od_mtd_data->h = h;
+ od_mtd_data->r = r;
od_mtd_data->location_confidence_lvl = loc_conf_lvl;
od_mtd_data->object_type = type;
}
diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.h b/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.h
index f5b146f590..a987dd1417 100644
--- a/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.h
+++ b/subprojects/gst-plugins-bad/gst-libs/gst/analytics/gstanalyticsobjectdetectionmtd.h
@@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) 2023 Collabora Ltd
+ * Copyright (C) 2024 Intel Corporation
*
* gstanalyticsobjectdetectionmtd.h
*
@@ -51,6 +52,11 @@ GST_ANALYTICS_META_API
gboolean gst_analytics_od_mtd_get_location (const GstAnalyticsODMtd *
instance, gint * x, gint * y, gint * w, gint * h, gfloat * loc_conf_lvl);
+GST_ANALYTICS_META_API
+gboolean gst_analytics_od_mtd_get_oriented_location (const GstAnalyticsODMtd
+ * instance, gint * x, gint * y, gint * w, gint * h, gfloat * r,
+ gfloat * loc_conf_lvl);
+
GST_ANALYTICS_META_API
gboolean gst_analytics_od_mtd_get_confidence_lvl (const GstAnalyticsODMtd *
instance, gfloat * loc_conf_lvl);
@@ -63,6 +69,12 @@ gboolean gst_analytics_relation_meta_add_od_mtd (GstAnalyticsRelationMeta *
instance, GQuark type, gint x, gint y, gint w, gint h, gfloat loc_conf_lvl,
GstAnalyticsODMtd * od_mtd);
+GST_ANALYTICS_META_API
+gboolean
+gst_analytics_relation_meta_add_oriented_od_mtd (GstAnalyticsRelationMeta *
+ instance, GQuark type, gint x, gint y, gint w, gint h, gfloat r,
+ gfloat loc_conf_lvl, GstAnalyticsODMtd * od_mtd);
+
GST_ANALYTICS_META_API
gboolean
gst_analytics_relation_meta_get_od_mtd (GstAnalyticsRelationMeta * meta,
diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/analytics/meson.build b/subprojects/gst-plugins-bad/gst-libs/gst/analytics/meson.build
index 6a00c24add..367cb0d6c9 100644
--- a/subprojects/gst-plugins-bad/gst-libs/gst/analytics/meson.build
+++ b/subprojects/gst-plugins-bad/gst-libs/gst/analytics/meson.build
@@ -26,10 +26,11 @@ gstanalytics = library('gstanalytics-' + api_version,
soversion : soversion,
darwin_versions : osxversion,
install : true,
- dependencies : [gstbase_dep, gstvideo_dep])
+ dependencies : [gstbase_dep, gstvideo_dep],
+ link_args : ['-lm'])
pkgconfig.generate(gstanalytics,
- libraries : [gst_dep, gstbase_dep],
+ libraries : [gst_dep, gstbase_dep, '-lm'],
variables : pkgconfig_variables,
subdirs : pkgconfig_subdirs,
name : pkg_name,
diff --git a/subprojects/gst-plugins-bad/tests/check/libs/analyticsmeta.c b/subprojects/gst-plugins-bad/tests/check/libs/analyticsmeta.c
index 56465c6aad..23e3c8ebdb 100644
--- a/subprojects/gst-plugins-bad/tests/check/libs/analyticsmeta.c
+++ b/subprojects/gst-plugins-bad/tests/check/libs/analyticsmeta.c
@@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) 2022 Collabora Ltd
+ * Copyright (C) 2024 Intel Corporation
*
* analyticmeta.c
*
@@ -542,6 +543,34 @@ GST_START_TEST (test_add_od_meta)
GST_END_TEST;
+GST_START_TEST (test_add_oriented_od_meta)
+{
+ /* Verity we can add Oriented Object Detection relatable metadata to a relation
+ * metadata */
+ GstBuffer *buf;
+ GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
+ GstAnalyticsRelationMeta *rmeta;
+ GstAnalyticsODMtd od_mtd;
+ gboolean ret;
+ buf = gst_buffer_new ();
+
+ rmeta = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
+
+ GQuark type = g_quark_from_string ("dog");
+ gint x = 20;
+ gint y = 20;
+ gint w = 10;
+ gint h = 15;
+ gfloat r = 0.785f;
+ gfloat loc_conf_lvl = 0.6f;
+ ret = gst_analytics_relation_meta_add_oriented_od_mtd (rmeta, type, x, y,
+ w, h, r, loc_conf_lvl, &od_mtd);
+ fail_unless (ret == TRUE);
+ gst_buffer_unref (buf);
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_od_meta_fields)
{
/* Verify we can readback fields of object detection metadata */
@@ -586,6 +615,160 @@ GST_START_TEST (test_od_meta_fields)
GST_END_TEST;
+GST_START_TEST (test_oriented_od_meta_fields)
+{
+ /* Verify we can readback fields of object detection metadata */
+ GstBuffer *buf;
+ GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
+ GstAnalyticsRelationMeta *rmeta;
+ GstAnalyticsODMtd od_mtd;
+ gboolean ret;
+ buf = gst_buffer_new ();
+
+ rmeta = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
+
+ GQuark type = g_quark_from_string ("dog");
+ gint x = 21;
+ gint y = 20;
+ gint w = 10;
+ gint h = 15;
+ gfloat r = 0.785f;
+ gfloat loc_conf_lvl = 0.6f;
+ ret = gst_analytics_relation_meta_add_oriented_od_mtd (rmeta, type, x, y,
+ w, h, r, loc_conf_lvl, &od_mtd);
+
+ fail_unless (ret == TRUE);
+
+ gint _x, _y, _w, _h;
+ gfloat _r, _loc_conf_lvl;
+ gst_analytics_od_mtd_get_oriented_location (&od_mtd, &_x, &_y, &_w, &_h, &_r,
+ &_loc_conf_lvl);
+
+ fail_unless (_x == x);
+ fail_unless (_y == y);
+ fail_unless (_w == w);
+ fail_unless (_h == h);
+ fail_unless (_r == r);
+ fail_unless (_loc_conf_lvl == loc_conf_lvl);
+
+ _loc_conf_lvl = -200.0; // dirty this var by setting invalid value.
+ gst_analytics_od_mtd_get_confidence_lvl (&od_mtd, &_loc_conf_lvl);
+
+ fail_unless (_loc_conf_lvl == loc_conf_lvl);
+
+ gst_buffer_unref (buf);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_add_non_oriented_get_oriented_od_meta_fields)
+{
+ /* Verify we can readback fields of object detection metadata */
+ GstBuffer *buf;
+ GstAnalyticsRelationMetaInitParams init_params = { 5, 150 };
+ GstAnalyticsRelationMeta *rmeta;
+ GstAnalyticsODMtd od_mtd;
+ gboolean ret;
+ buf = gst_buffer_new ();
+
+ rmeta = gst_buffer_add_analytics_relation_meta_full (buf, &init_params);
+
+ GQuark type = g_quark_from_string ("dog");
+ gint x = 21;
+ gint y = 20;
+ gint w = 10;
+ gint h = 15;
+ gfloat loc_conf_lvl = 0.6f;
+ ret = gst_analytics_relation_meta_add_od_mtd (rmeta, type, x, y,
+ w, h, loc_conf_lvl, &od_mtd);
+
+ fail_unless (ret == TRUE);
+
+ gint _x, _y, _w, _h;
+ gfloat _r, _loc_conf_lvl;
+ gst_analytics_od_mtd_get_oriented_location (&od_mtd, &_x, &_y, &_w, &_h, &_r,
+ &_loc_conf_lvl);
+
+ fail_unless (_x == x);
+ fail_unless (_y == y);
+ fail_unless (_w == w);
+ fail_unless (_h == h);
+ fail_unless (_r == 0);
+ fail_unless (_loc_conf_lvl == loc_conf_lvl);
+
+ _loc_conf_lvl = -200.0; // dirty this var by setting invalid value.
+ gst_analytics_od_mtd_get_confidence_lvl (&od_mtd, &_loc_conf_lvl);
+
+ fail_unless (_loc_conf_lvl == loc_conf_lvl);
+
+ gst_buffer_unref (buf);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_add_oriented_get_non_oriented_od_meta_fields)
+{
+ /* Verify we can readback fields of object detection metadata */
+ GstBuffer *buf;
+ GstAnalyticsRelationMeta *rmeta;
+ GstAnalyticsODMtd od_mtd;
+ gboolean ret;
+ gint _x, _y, _w, _h;
+ gfloat _loc_conf_lvl;
+
+ buf = gst_buffer_new ();
+ rmeta = gst_buffer_add_analytics_relation_meta (buf);
+
+ struct
+ {
+ gint x, y, w, h;
+ gfloat r;
+ gint expected_x, expected_y, expected_w, expected_h;
+ } test_cases[] = {
+ {500, 300, 200, 100, 0.0f, 500, 300, 200, 100},
+ {600, 400, 200, 100, 0.785f, 594, 344, 212, 212},
+ {400, 400, 150, 100, 1.570f, 425, 375, 100, 150},
+ {400, 300, 200, 100, 2.268f, 397, 241, 206, 218},
+ {400, 400, 200, 100, 3.142f, 400, 400, 200, 100},
+ {300, 300, 150, 100, 4.712f, 325, 275, 100, 150},
+ {500, 400, 1, 100, 0.785f, 465, 415, 71, 71},
+ {400, 500, 100, 1, 2.268f, 417, 461, 65, 77},
+ {400, 400, 100, 100, 6.283f, 400, 400, 100, 100},
+ };
+
+ gfloat loc_conf_lvl = 0.9f;
+ for (gsize i = 0; i < G_N_ELEMENTS (test_cases); i++) {
+ gint x = test_cases[i].x;
+ gint y = test_cases[i].y;
+ gint w = test_cases[i].w;
+ gint h = test_cases[i].h;
+ gfloat r = test_cases[i].r;
+
+ gint expected_x = test_cases[i].expected_x;
+ gint expected_y = test_cases[i].expected_y;
+ gint expected_w = test_cases[i].expected_w;
+ gint expected_h = test_cases[i].expected_h;
+
+ ret =
+ gst_analytics_relation_meta_add_oriented_od_mtd (rmeta,
+ g_quark_from_string ("dog"), x, y, w, h, r, loc_conf_lvl, &od_mtd);
+ fail_unless (ret == TRUE);
+
+ gst_analytics_od_mtd_get_location (&od_mtd, &_x, &_y, &_w, &_h,
+ &_loc_conf_lvl);
+
+ fail_unless (_x == expected_x);
+ fail_unless (_y == expected_y);
+ fail_unless (_w == expected_w);
+ fail_unless (_h == expected_h);
+ fail_unless (_loc_conf_lvl == loc_conf_lvl);
+ }
+
+ gst_buffer_unref (buf);
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_od_cls_relation)
{
/* Verify we can add a object detection and classification metadata to
@@ -1432,7 +1615,13 @@ analyticmeta_suite (void)
tc_chain_od = tcase_create ("Object Detection Mtd");
suite_add_tcase (s, tc_chain_od);
tcase_add_test (tc_chain_od, test_add_od_meta);
+ tcase_add_test (tc_chain_od, test_add_oriented_od_meta);
tcase_add_test (tc_chain_od, test_od_meta_fields);
+ tcase_add_test (tc_chain_od, test_oriented_od_meta_fields);
+ tcase_add_test (tc_chain_od,
+ test_add_non_oriented_get_oriented_od_meta_fields);
+ tcase_add_test (tc_chain_od,
+ test_add_oriented_get_non_oriented_od_meta_fields);
tc_chain_od_cls = tcase_create ("Object Detection <-> Classification Mtd");
suite_add_tcase (s, tc_chain_od_cls);
diff --git a/subprojects/gst-python/testsuite/test_analytics.py b/subprojects/gst-python/testsuite/test_analytics.py
index 612806ae18..938b2b6b76 100644
--- a/subprojects/gst-python/testsuite/test_analytics.py
+++ b/subprojects/gst-python/testsuite/test_analytics.py
@@ -4,6 +4,7 @@
# gst-python - Python bindings for GStreamer
# Copyright (C) 2024 Collabora Ltd
# Author: Olivier CrĂȘte
+# Copyright (C) 2024 Intel Corporation
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -84,6 +85,36 @@ class TestAnalyticsODMtd(TestCase):
self.assertEqual(location[4], 40)
self.assertAlmostEqual(location[5], 0.3, 3)
+ location = meta.get_od_mtd(0)[1].get_oriented_location()
+ self.assertEqual(location[1], 10)
+ self.assertEqual(location[2], 20)
+ self.assertEqual(location[3], 30)
+ self.assertEqual(location[4], 40)
+ self.assertEqual(location[5], 0)
+ self.assertAlmostEqual(location[6], 0.3, 3)
+
+ (ret, mtd) = meta.add_oriented_od_mtd(qk, 600, 400, 200, 100, 0.785, 0.3)
+ self.assertTrue(ret)
+ self.assertIsNotNone(mtd)
+
+ (ret, mtd) = meta.get_od_mtd(1)
+ self.assertTrue(ret)
+ self.assertIsNotNone(mtd)
+
+ location = mtd.get_oriented_location()
+ self.assertEqual(location[1], 600)
+ self.assertEqual(location[2], 400)
+ self.assertEqual(location[3], 200)
+ self.assertEqual(location[4], 100)
+ self.assertAlmostEqual(location[5], 0.785, 3)
+ self.assertAlmostEqual(location[6], 0.3, 3)
+
+ location = mtd.get_location()
+ self.assertEqual(location[1], 594)
+ self.assertEqual(location[2], 344)
+ self.assertEqual(location[3], 212)
+ self.assertEqual(location[4], 212)
+ self.assertAlmostEqual(location[5], 0.3, 3)
class TestAnalyticsClsMtd(TestCase):
def test(self):