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):