From 18e255128158a458f378fc84f765ecbba137c2ab Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Tue, 21 Jan 2025 09:01:42 +0100 Subject: [PATCH 01/14] model loading --- src/cpp/py_bindings/py_classification.cpp | 91 +++++++++++++++++++ .../py_bindings/py_instance_segmentation.cpp | 59 ++++++++++++ src/cpp/py_bindings/py_keypoint_detection.cpp | 54 +++++++++++ src/cpp/py_bindings/py_segmentation.cpp | 59 ++++++++++++ src/cpp/py_bindings/py_vision_api.cpp | 9 +- 5 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 src/cpp/py_bindings/py_classification.cpp create mode 100644 src/cpp/py_bindings/py_instance_segmentation.cpp create mode 100644 src/cpp/py_bindings/py_keypoint_detection.cpp create mode 100644 src/cpp/py_bindings/py_segmentation.cpp diff --git a/src/cpp/py_bindings/py_classification.cpp b/src/cpp/py_bindings/py_classification.cpp new file mode 100644 index 00000000..33b48851 --- /dev/null +++ b/src/cpp/py_bindings/py_classification.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "models/classification_model.h" +#include "models/results.h" +#include "py_utils.hpp" + +namespace pyutils = vision::nanobind::utils; + +void init_classification(nb::module_& m) { + nb::class_(m, "Classification") + .def(nb::init()) + .def_rw("id", &ClassificationResult::Classification::id) + .def_rw("label", &ClassificationResult::Classification::label) + .def_rw("score", &ClassificationResult::Classification::score); + + nb::class_(m, "ClassificationResult") + .def(nb::init<>()) + .def_ro("topLabels", &ClassificationResult::topLabels) + .def("__repr__", &ClassificationResult::operator std::string) + .def_prop_ro( + "feature_vector", + [](ClassificationResult& r) { + if (!r.feature_vector) { + return nb::ndarray(); + } + + return nb::ndarray(r.feature_vector.data(), + r.feature_vector.get_shape().size(), + r.feature_vector.get_shape().data()); + }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "saliency_map", + [](ClassificationResult& r) { + if (!r.saliency_map) { + return nb::ndarray(); + } + + return nb::ndarray(r.saliency_map.data(), + r.saliency_map.get_shape().size(), + r.saliency_map.get_shape().data()); + }, + nb::rv_policy::reference_internal); + + nb::class_(m, "ClassificationModel") + .def_static( + "create_model", + [](const std::string& model_path, + const std::map& configuration, + bool preload, + const std::string& device) { + auto ov_any_config = ov::AnyMap(); + for (const auto& item : configuration) { + ov_any_config[item.first] = pyutils::py_object_to_any(item.second, item.first); + } + + return ClassificationModel::create_model(model_path, ov_any_config, preload, device); + }, + nb::arg("model_path"), + nb::arg("configuration") = ov::AnyMap({}), + nb::arg("preload") = true, + nb::arg("device") = "AUTO") + + .def("__call__", + [](ClassificationModel& self, const nb::ndarray<>& input) { + return self.infer(pyutils::wrap_np_mat(input)); + }) + .def("infer_batch", [](ClassificationModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }) + .def_prop_ro_static("__model__", [](nb::object) { + return ClassificationModel::ModelType; + }); +} diff --git a/src/cpp/py_bindings/py_instance_segmentation.cpp b/src/cpp/py_bindings/py_instance_segmentation.cpp new file mode 100644 index 00000000..0b03665c --- /dev/null +++ b/src/cpp/py_bindings/py_instance_segmentation.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "models/instance_segmentation.h" +#include "models/results.h" +#include "py_utils.hpp" + +namespace pyutils = vision::nanobind::utils; + +void init_instance_segmentation(nb::module_& m) { + nb::class_(m, "MaskRCNNModel") + .def_static( + "create_model", + [](const std::string& model_path, + const std::map& configuration, + bool preload, + const std::string& device) { + auto ov_any_config = ov::AnyMap(); + for (const auto& item : configuration) { + ov_any_config[item.first] = pyutils::py_object_to_any(item.second, item.first); + } + + return MaskRCNNModel::create_model(model_path, ov_any_config, preload, device); + }, + nb::arg("model_path"), + nb::arg("configuration") = ov::AnyMap({}), + nb::arg("preload") = true, + nb::arg("device") = "AUTO") + + .def("__call__", + [](MaskRCNNModel& self, const nb::ndarray<>& input) { + return self.infer(pyutils::wrap_np_mat(input)); + }) + .def("infer_batch", [](MaskRCNNModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }) + .def("postprocess", [](MaskRCNNModel& self, InferenceResult& infResult) { + return self.postprocess(infResult); + }) + .def_prop_ro_static("__model__", [](nb::object) { + return MaskRCNNModel::ModelType; + }); +} diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp new file mode 100644 index 00000000..d2797e30 --- /dev/null +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include + +#include "models/keypoint_detection.h" +#include "models/results.h" +#include "py_utils.hpp" + +namespace pyutils = vision::nanobind::utils; + +void init_keypoint_detection(nb::module_& m) { + nb::class_(m, "KeypointDetectionModel") + .def_static( + "create_model", + [](const std::string& model_path, + const std::map& configuration, + bool preload, + const std::string& device) { + auto ov_any_config = ov::AnyMap(); + for (const auto& item : configuration) { + ov_any_config[item.first] = pyutils::py_object_to_any(item.second, item.first); + } + + return KeypointDetectionModel::create_model(model_path, ov_any_config, preload, device); + }, + nb::arg("model_path"), + nb::arg("configuration") = ov::AnyMap({}), + nb::arg("preload") = true, + nb::arg("device") = "AUTO") + + .def("__call__", + [](KeypointDetectionModel& self, const nb::ndarray<>& input) { + return self.infer(pyutils::wrap_np_mat(input)); + }) + .def("infer_batch", [](KeypointDetectionModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }) + .def("postprocess", [](KeypointDetectionModel& self, InferenceResult& infResult) { + return self.postprocess(infResult); + }) + .def_prop_ro_static("__model__", [](nb::object) { + return KeypointDetectionModel::ModelType; + }); +} \ No newline at end of file diff --git a/src/cpp/py_bindings/py_segmentation.cpp b/src/cpp/py_bindings/py_segmentation.cpp new file mode 100644 index 00000000..88cd434e --- /dev/null +++ b/src/cpp/py_bindings/py_segmentation.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "models/segmentation_model.h" +#include "models/results.h" +#include "py_utils.hpp" + +namespace pyutils = vision::nanobind::utils; + +void init_segmentation(nb::module_& m) { + nb::class_(m, "SegmentationModel") + .def_static( + "create_model", + [](const std::string& model_path, + const std::map& configuration, + bool preload, + const std::string& device) { + auto ov_any_config = ov::AnyMap(); + for (const auto& item : configuration) { + ov_any_config[item.first] = pyutils::py_object_to_any(item.second, item.first); + } + + return SegmentationModel::create_model(model_path, ov_any_config, preload, device); + }, + nb::arg("model_path"), + nb::arg("configuration") = ov::AnyMap({}), + nb::arg("preload") = true, + nb::arg("device") = "AUTO") + + .def("__call__", + [](SegmentationModel& self, const nb::ndarray<>& input) { + return self.infer(pyutils::wrap_np_mat(input)); + }) + .def("infer_batch", [](SegmentationModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }) + .def("postprocess", [](SegmentationModel& self, InferenceResult& infResult) { + return self.postprocess(infResult); + }) + .def_prop_ro_static("__model__", [](nb::object) { + return SegmentationModel::ModelType; + }); +} \ No newline at end of file diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/py_vision_api.cpp index c10e6486..5a9973bc 100644 --- a/src/cpp/py_bindings/py_vision_api.cpp +++ b/src/cpp/py_bindings/py_vision_api.cpp @@ -7,11 +7,18 @@ namespace nb = nanobind; -void init_classification(nb::module_& m); void init_base_modules(nb::module_& m); +void init_classification(nb::module_& m); +void init_segmentation(nb::module_& m); +void init_instance_segmentation(nb::module_& m); +void init_keypoint_detection(nb::module_& m); + NB_MODULE(py_model_api, m) { m.doc() = "Nanobind binding for OpenVINO Vision API library"; init_base_modules(m); init_classification(m); + init_keypoint_detection(m); + init_segmentation(m); + init_instance_segmentation(m); } From 6e8dca85c8b43ef551805fddf187f4f0d892b194 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Tue, 21 Jan 2025 09:02:30 +0100 Subject: [PATCH 02/14] renamed --- src/cpp/py_bindings/py_classificaiton.cpp | 88 ----------------------- 1 file changed, 88 deletions(-) delete mode 100644 src/cpp/py_bindings/py_classificaiton.cpp diff --git a/src/cpp/py_bindings/py_classificaiton.cpp b/src/cpp/py_bindings/py_classificaiton.cpp deleted file mode 100644 index 19e2b4eb..00000000 --- a/src/cpp/py_bindings/py_classificaiton.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2025 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#include "models/classification_model.h" -#include "models/results.h" -#include "py_utils.hpp" - -namespace pyutils = vision::nanobind::utils; - -void init_classification(nb::module_& m) { - nb::class_(m, "Classification") - .def(nb::init()) - .def_rw("id", &ClassificationResult::Classification::id) - .def_rw("label", &ClassificationResult::Classification::label) - .def_rw("score", &ClassificationResult::Classification::score); - - nb::class_(m, "ClassificationResult") - .def(nb::init<>()) - .def_ro("topLabels", &ClassificationResult::topLabels) - .def("__repr__", &ClassificationResult::operator std::string) - .def_prop_ro( - "feature_vector", - [](ClassificationResult& r) { - if (!r.feature_vector) { - return nb::ndarray(); - } - - return nb::ndarray(r.feature_vector.data(), - r.feature_vector.get_shape().size(), - r.feature_vector.get_shape().data()); - }, - nb::rv_policy::reference_internal) - .def_prop_ro( - "saliency_map", - [](ClassificationResult& r) { - if (!r.saliency_map) { - return nb::ndarray(); - } - - return nb::ndarray(r.saliency_map.data(), - r.saliency_map.get_shape().size(), - r.saliency_map.get_shape().data()); - }, - nb::rv_policy::reference_internal); - - nb::class_(m, "ClassificationModel") - .def_static( - "create_model", - [](const std::string& model_path, - const std::map& configuration, - bool preload, - const std::string& device) { - auto ov_any_config = ov::AnyMap(); - for (const auto& item : configuration) { - ov_any_config[item.first] = pyutils::py_object_to_any(item.second, item.first); - } - - return ClassificationModel::create_model(model_path, ov_any_config, preload, device); - }, - nb::arg("model_path"), - nb::arg("configuration") = ov::AnyMap({}), - nb::arg("preload") = true, - nb::arg("device") = "AUTO") - - .def("__call__", - [](ClassificationModel& self, const nb::ndarray<>& input) { - return self.infer(pyutils::wrap_np_mat(input)); - }) - .def("infer_batch", [](ClassificationModel& self, const std::vector> inputs) { - std::vector input_mats; - input_mats.reserve(inputs.size()); - - for (const auto& input : inputs) { - input_mats.push_back(pyutils::wrap_np_mat(input)); - } - - return self.inferBatch(input_mats); - }); -} From 9ec7c686ad2cd6d7b37c883c5b17ee5df1c75ee7 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Tue, 21 Jan 2025 13:17:16 +0100 Subject: [PATCH 03/14] changes --- .../py_bindings/py_instance_segmentation.cpp | 47 ++++++++++++++----- src/cpp/py_bindings/py_keypoint_detection.cpp | 39 ++++++++++----- src/cpp/py_bindings/py_results.cpp | 37 +++++++++++++++ src/cpp/py_bindings/py_segmentation.cpp | 15 +++++- src/cpp/py_bindings/py_vision_api.cpp | 2 + 5 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 src/cpp/py_bindings/py_results.cpp diff --git a/src/cpp/py_bindings/py_instance_segmentation.cpp b/src/cpp/py_bindings/py_instance_segmentation.cpp index 0b03665c..73faa7ba 100644 --- a/src/cpp/py_bindings/py_instance_segmentation.cpp +++ b/src/cpp/py_bindings/py_instance_segmentation.cpp @@ -40,20 +40,41 @@ void init_instance_segmentation(nb::module_& m) { [](MaskRCNNModel& self, const nb::ndarray<>& input) { return self.infer(pyutils::wrap_np_mat(input)); }) - .def("infer_batch", [](MaskRCNNModel& self, const std::vector> inputs) { - std::vector input_mats; - input_mats.reserve(inputs.size()); - - for (const auto& input : inputs) { - input_mats.push_back(pyutils::wrap_np_mat(input)); - } - - return self.inferBatch(input_mats); - }) - .def("postprocess", [](MaskRCNNModel& self, InferenceResult& infResult) { - return self.postprocess(infResult); - }) + .def("infer_batch", + [](MaskRCNNModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }) + .def("postprocess", + [](MaskRCNNModel& self, InferenceResult& infResult) { + return self.postprocess(infResult); + }) .def_prop_ro_static("__model__", [](nb::object) { return MaskRCNNModel::ModelType; }); + + + nb::class_(m, "InstanceSegmentationResult") + .def(nb::init>(), + nb::arg("frameId") = -1, + nb::arg("metaData") = nullptr) + .def_ro("segmentedObjects", &InstanceSegmentationResult::segmentedObjects) + .def_prop_ro( + "feature_vector", + [](InstanceSegmentationResult& r) { + if (!r.feature_vector) { + return nb::ndarray(); + } + + return nb::ndarray(r.feature_vector.data(), + r.feature_vector.get_shape().size(), + r.feature_vector.get_shape().data()); + }, + nb::rv_policy::reference_internal); } diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp index d2797e30..9f56dbd3 100644 --- a/src/cpp/py_bindings/py_keypoint_detection.cpp +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -35,20 +35,33 @@ void init_keypoint_detection(nb::module_& m) { [](KeypointDetectionModel& self, const nb::ndarray<>& input) { return self.infer(pyutils::wrap_np_mat(input)); }) - .def("infer_batch", [](KeypointDetectionModel& self, const std::vector> inputs) { - std::vector input_mats; - input_mats.reserve(inputs.size()); - - for (const auto& input : inputs) { - input_mats.push_back(pyutils::wrap_np_mat(input)); - } - - return self.inferBatch(input_mats); - }) - .def("postprocess", [](KeypointDetectionModel& self, InferenceResult& infResult) { - return self.postprocess(infResult); - }) + .def("infer_batch", + [](KeypointDetectionModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }) + .def("postprocess", + [](KeypointDetectionModel& self, InferenceResult& infResult) { + return self.postprocess(infResult); + }) .def_prop_ro_static("__model__", [](nb::object) { return KeypointDetectionModel::ModelType; }); + + nb::class_(m, "KeypointDetectionResult") + .def(nb::init>(), + nb::arg("frameId") = -1, + nb::arg("metaData") = nullptr) + .def_ro("poses", &KeypointDetectionResult::poses); + + nb::class_(m, "DetectedKeypoints") + .def(nb::init<>()) + .def_ro("keypoints", &DetectedKeypoints::keypoints) + .def_ro("scores", &DetectedKeypoints::scores); } \ No newline at end of file diff --git a/src/cpp/py_bindings/py_results.cpp b/src/cpp/py_bindings/py_results.cpp new file mode 100644 index 00000000..6b03ad60 --- /dev/null +++ b/src/cpp/py_bindings/py_results.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#include "models/results.h" + +namespace nb = nanobind; + +void init_results_modules(nb::module_& m) { + + nb::class_(m, "DetectedObject") + .def(nb::init<>()) + .def_rw("labelID", &DetectedObject::labelID) + .def_rw("label", &DetectedObject::label) + .def_rw("confidence", &DetectedObject::confidence); + + nb::class_(m, "SegmentedObject") + .def(nb::init<>()) + .def_prop_ro( + "mask", + [](SegmentedObject& s) { + return nb::ndarray(s.mask.data, + { + static_cast(s.mask.rows), + static_cast(s.mask.cols), + static_cast(s.mask.channels()) + }); + }, + nb::rv_policy::reference_internal + ); +} diff --git a/src/cpp/py_bindings/py_segmentation.cpp b/src/cpp/py_bindings/py_segmentation.cpp index 88cd434e..7a5393b1 100644 --- a/src/cpp/py_bindings/py_segmentation.cpp +++ b/src/cpp/py_bindings/py_segmentation.cpp @@ -56,4 +56,17 @@ void init_segmentation(nb::module_& m) { .def_prop_ro_static("__model__", [](nb::object) { return SegmentationModel::ModelType; }); -} \ No newline at end of file + + nb::class_(m, "ImageResult") + .def(nb::init>(), + nb::arg("frameId") = -1, + nb::arg("metaData") = nullptr) + .def_prop_ro( + "resultImage", + [](ImageResult& r) { + return nb::ndarray(r.resultImage.data, + {static_cast(r.resultImage.rows), static_cast(r.resultImage.cols), static_cast(r.resultImage.channels())}); + }, + nb::rv_policy::reference_internal + ); +} diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/py_vision_api.cpp index 5a9973bc..24076307 100644 --- a/src/cpp/py_bindings/py_vision_api.cpp +++ b/src/cpp/py_bindings/py_vision_api.cpp @@ -8,6 +8,7 @@ namespace nb = nanobind; void init_base_modules(nb::module_& m); +void init_results_modules(nb::module_& m); void init_classification(nb::module_& m); void init_segmentation(nb::module_& m); void init_instance_segmentation(nb::module_& m); @@ -17,6 +18,7 @@ void init_keypoint_detection(nb::module_& m); NB_MODULE(py_model_api, m) { m.doc() = "Nanobind binding for OpenVINO Vision API library"; init_base_modules(m); + init_results_modules(m); init_classification(m); init_keypoint_detection(m); init_segmentation(m); From 6cbfc27ca128729e973414353129d07cbbd44f82 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Wed, 22 Jan 2025 13:41:50 +0100 Subject: [PATCH 04/14] change --- src/cpp/py_bindings/py_instance_segmentation.cpp | 1 - src/cpp/py_bindings/py_vision_api.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/cpp/py_bindings/py_instance_segmentation.cpp b/src/cpp/py_bindings/py_instance_segmentation.cpp index 73faa7ba..2a36ae99 100644 --- a/src/cpp/py_bindings/py_instance_segmentation.cpp +++ b/src/cpp/py_bindings/py_instance_segmentation.cpp @@ -64,7 +64,6 @@ void init_instance_segmentation(nb::module_& m) { .def(nb::init>(), nb::arg("frameId") = -1, nb::arg("metaData") = nullptr) - .def_ro("segmentedObjects", &InstanceSegmentationResult::segmentedObjects) .def_prop_ro( "feature_vector", [](InstanceSegmentationResult& r) { diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/py_vision_api.cpp index 24076307..5a9973bc 100644 --- a/src/cpp/py_bindings/py_vision_api.cpp +++ b/src/cpp/py_bindings/py_vision_api.cpp @@ -8,7 +8,6 @@ namespace nb = nanobind; void init_base_modules(nb::module_& m); -void init_results_modules(nb::module_& m); void init_classification(nb::module_& m); void init_segmentation(nb::module_& m); void init_instance_segmentation(nb::module_& m); @@ -18,7 +17,6 @@ void init_keypoint_detection(nb::module_& m); NB_MODULE(py_model_api, m) { m.doc() = "Nanobind binding for OpenVINO Vision API library"; init_base_modules(m); - init_results_modules(m); init_classification(m); init_keypoint_detection(m); init_segmentation(m); From 6c78d651e15754f633b2e9aca252138dfa6bede0 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Wed, 22 Jan 2025 13:43:53 +0100 Subject: [PATCH 05/14] license header --- src/cpp/py_bindings/py_keypoint_detection.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp index 9f56dbd3..b6bf5570 100644 --- a/src/cpp/py_bindings/py_keypoint_detection.cpp +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -1,3 +1,7 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ #include #include #include From 745fdcf7a424890f3d8fa850aa47e009bc713ecc Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Thu, 23 Jan 2025 08:32:34 +0100 Subject: [PATCH 06/14] clang-format --- src/cpp/py_bindings/py_classification.cpp | 17 +++++---- .../py_bindings/py_instance_segmentation.cpp | 5 +-- src/cpp/py_bindings/py_keypoint_detection.cpp | 4 +- src/cpp/py_bindings/py_results.cpp | 37 ------------------- src/cpp/py_bindings/py_segmentation.cpp | 37 ++++++++++--------- src/cpp/py_bindings/py_vision_api.cpp | 3 +- 6 files changed, 31 insertions(+), 72 deletions(-) delete mode 100644 src/cpp/py_bindings/py_results.cpp diff --git a/src/cpp/py_bindings/py_classification.cpp b/src/cpp/py_bindings/py_classification.cpp index 33b48851..cc7cd11d 100644 --- a/src/cpp/py_bindings/py_classification.cpp +++ b/src/cpp/py_bindings/py_classification.cpp @@ -75,16 +75,17 @@ void init_classification(nb::module_& m) { [](ClassificationModel& self, const nb::ndarray<>& input) { return self.infer(pyutils::wrap_np_mat(input)); }) - .def("infer_batch", [](ClassificationModel& self, const std::vector> inputs) { - std::vector input_mats; - input_mats.reserve(inputs.size()); + .def("infer_batch", + [](ClassificationModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); - for (const auto& input : inputs) { - input_mats.push_back(pyutils::wrap_np_mat(input)); - } + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } - return self.inferBatch(input_mats); - }) + return self.inferBatch(input_mats); + }) .def_prop_ro_static("__model__", [](nb::object) { return ClassificationModel::ModelType; }); diff --git a/src/cpp/py_bindings/py_instance_segmentation.cpp b/src/cpp/py_bindings/py_instance_segmentation.cpp index 2a36ae99..52a21dd8 100644 --- a/src/cpp/py_bindings/py_instance_segmentation.cpp +++ b/src/cpp/py_bindings/py_instance_segmentation.cpp @@ -59,11 +59,8 @@ void init_instance_segmentation(nb::module_& m) { return MaskRCNNModel::ModelType; }); - nb::class_(m, "InstanceSegmentationResult") - .def(nb::init>(), - nb::arg("frameId") = -1, - nb::arg("metaData") = nullptr) + .def(nb::init>(), nb::arg("frameId") = -1, nb::arg("metaData") = nullptr) .def_prop_ro( "feature_vector", [](InstanceSegmentationResult& r) { diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp index b6bf5570..bcc5e534 100644 --- a/src/cpp/py_bindings/py_keypoint_detection.cpp +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -59,9 +59,7 @@ void init_keypoint_detection(nb::module_& m) { }); nb::class_(m, "KeypointDetectionResult") - .def(nb::init>(), - nb::arg("frameId") = -1, - nb::arg("metaData") = nullptr) + .def(nb::init>(), nb::arg("frameId") = -1, nb::arg("metaData") = nullptr) .def_ro("poses", &KeypointDetectionResult::poses); nb::class_(m, "DetectedKeypoints") diff --git a/src/cpp/py_bindings/py_results.cpp b/src/cpp/py_bindings/py_results.cpp deleted file mode 100644 index 6b03ad60..00000000 --- a/src/cpp/py_bindings/py_results.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2025 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include - -#include "models/results.h" - -namespace nb = nanobind; - -void init_results_modules(nb::module_& m) { - - nb::class_(m, "DetectedObject") - .def(nb::init<>()) - .def_rw("labelID", &DetectedObject::labelID) - .def_rw("label", &DetectedObject::label) - .def_rw("confidence", &DetectedObject::confidence); - - nb::class_(m, "SegmentedObject") - .def(nb::init<>()) - .def_prop_ro( - "mask", - [](SegmentedObject& s) { - return nb::ndarray(s.mask.data, - { - static_cast(s.mask.rows), - static_cast(s.mask.cols), - static_cast(s.mask.channels()) - }); - }, - nb::rv_policy::reference_internal - ); -} diff --git a/src/cpp/py_bindings/py_segmentation.cpp b/src/cpp/py_bindings/py_segmentation.cpp index 7a5393b1..befc7cf8 100644 --- a/src/cpp/py_bindings/py_segmentation.cpp +++ b/src/cpp/py_bindings/py_segmentation.cpp @@ -10,8 +10,8 @@ #include #include -#include "models/segmentation_model.h" #include "models/results.h" +#include "models/segmentation_model.h" #include "py_utils.hpp" namespace pyutils = vision::nanobind::utils; @@ -40,33 +40,34 @@ void init_segmentation(nb::module_& m) { [](SegmentationModel& self, const nb::ndarray<>& input) { return self.infer(pyutils::wrap_np_mat(input)); }) - .def("infer_batch", [](SegmentationModel& self, const std::vector> inputs) { - std::vector input_mats; - input_mats.reserve(inputs.size()); + .def("infer_batch", + [](SegmentationModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); - for (const auto& input : inputs) { - input_mats.push_back(pyutils::wrap_np_mat(input)); - } + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } - return self.inferBatch(input_mats); - }) - .def("postprocess", [](SegmentationModel& self, InferenceResult& infResult) { - return self.postprocess(infResult); - }) + return self.inferBatch(input_mats); + }) + .def("postprocess", + [](SegmentationModel& self, InferenceResult& infResult) { + return self.postprocess(infResult); + }) .def_prop_ro_static("__model__", [](nb::object) { return SegmentationModel::ModelType; }); nb::class_(m, "ImageResult") - .def(nb::init>(), - nb::arg("frameId") = -1, - nb::arg("metaData") = nullptr) + .def(nb::init>(), nb::arg("frameId") = -1, nb::arg("metaData") = nullptr) .def_prop_ro( "resultImage", [](ImageResult& r) { return nb::ndarray(r.resultImage.data, - {static_cast(r.resultImage.rows), static_cast(r.resultImage.cols), static_cast(r.resultImage.channels())}); + {static_cast(r.resultImage.rows), + static_cast(r.resultImage.cols), + static_cast(r.resultImage.channels())}); }, - nb::rv_policy::reference_internal - ); + nb::rv_policy::reference_internal); } diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/py_vision_api.cpp index 5a9973bc..8ee144d6 100644 --- a/src/cpp/py_bindings/py_vision_api.cpp +++ b/src/cpp/py_bindings/py_vision_api.cpp @@ -11,8 +11,7 @@ void init_base_modules(nb::module_& m); void init_classification(nb::module_& m); void init_segmentation(nb::module_& m); void init_instance_segmentation(nb::module_& m); -void init_keypoint_detection(nb::module_& m); - +void init_keypoint_detection(nb::module_& m); NB_MODULE(py_model_api, m) { m.doc() = "Nanobind binding for OpenVINO Vision API library"; From d7061079982a35c9861a7898a5b4bbdfc90be838 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Thu, 23 Jan 2025 08:38:45 +0100 Subject: [PATCH 07/14] EOL fix for precommits --- src/cpp/py_bindings/py_keypoint_detection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp index bcc5e534..ec03169b 100644 --- a/src/cpp/py_bindings/py_keypoint_detection.cpp +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -66,4 +66,4 @@ void init_keypoint_detection(nb::module_& m) { .def(nb::init<>()) .def_ro("keypoints", &DetectedKeypoints::keypoints) .def_ro("scores", &DetectedKeypoints::scores); -} \ No newline at end of file +} From 5ce76c391b9b6acb8024fd684d1de32e85a58349 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Fri, 24 Jan 2025 15:23:24 +0100 Subject: [PATCH 08/14] match API to python version, classification, keypoint detection --- src/cpp/py_bindings/py_classification.cpp | 14 +++++++- src/cpp/py_bindings/py_keypoint_detection.cpp | 33 +++++++++++++------ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/cpp/py_bindings/py_classification.cpp b/src/cpp/py_bindings/py_classification.cpp index cc7cd11d..21e699cf 100644 --- a/src/cpp/py_bindings/py_classification.cpp +++ b/src/cpp/py_bindings/py_classification.cpp @@ -20,7 +20,7 @@ void init_classification(nb::module_& m) { nb::class_(m, "Classification") .def(nb::init()) .def_rw("id", &ClassificationResult::Classification::id) - .def_rw("label", &ClassificationResult::Classification::label) + .def_rw("name", &ClassificationResult::Classification::label) .def_rw("score", &ClassificationResult::Classification::score); nb::class_(m, "ClassificationResult") @@ -39,6 +39,18 @@ void init_classification(nb::module_& m) { r.feature_vector.get_shape().data()); }, nb::rv_policy::reference_internal) + .def_prop_ro( + "raw_scores", + [](ClassificationResult& r) { + if (!r.raw_scores) { + return nb::ndarray(); + } + + return nb::ndarray(r.raw_scores.data(), + r.raw_scores.get_shape().size(), + r.raw_scores.get_shape().data()); + }, + nb::rv_policy::reference_internal) .def_prop_ro( "saliency_map", [](ClassificationResult& r) { diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp index ec03169b..54d392bf 100644 --- a/src/cpp/py_bindings/py_keypoint_detection.cpp +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -50,20 +50,33 @@ void init_keypoint_detection(nb::module_& m) { return self.inferBatch(input_mats); }) - .def("postprocess", - [](KeypointDetectionModel& self, InferenceResult& infResult) { - return self.postprocess(infResult); - }) .def_prop_ro_static("__model__", [](nb::object) { return KeypointDetectionModel::ModelType; }); nb::class_(m, "KeypointDetectionResult") .def(nb::init>(), nb::arg("frameId") = -1, nb::arg("metaData") = nullptr) - .def_ro("poses", &KeypointDetectionResult::poses); - - nb::class_(m, "DetectedKeypoints") - .def(nb::init<>()) - .def_ro("keypoints", &DetectedKeypoints::keypoints) - .def_ro("scores", &DetectedKeypoints::scores); + .def_prop_ro("keypoints", [](const KeypointDetectionResult& result) { + if (!result.poses.empty()) { + std::vector shape = {result.poses[0].keypoints.size(), 2}; + return nb::ndarray( + const_cast(static_cast(result.poses[0].keypoints.data())), + shape.size(), + shape.data()); + } + return nb::ndarray(); + }, + nb::rv_policy::reference_internal) + .def_prop_ro("scores", [](const KeypointDetectionResult& result) { + if (!result.poses.empty()) { + std::vector shape = {result.poses[0].scores.size()}; + return nb::ndarray( + const_cast(static_cast(result.poses[0].scores.data())), + shape.size(), + shape.data()); + } + return nb::ndarray(); + }, + nb::rv_policy::reference_internal + ); } From b54f76947a859b82a84128ad636eff6bfeb4e060 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Mon, 27 Jan 2025 10:04:46 +0100 Subject: [PATCH 09/14] anomaly --- src/cpp/py_bindings/py_anomaly.cpp | 80 +++++++++++++++++++ src/cpp/py_bindings/py_keypoint_detection.cpp | 45 +++++------ src/cpp/py_bindings/py_segmentation.cpp | 4 - src/cpp/py_bindings/py_vision_api.cpp | 2 + 4 files changed, 104 insertions(+), 27 deletions(-) create mode 100644 src/cpp/py_bindings/py_anomaly.cpp diff --git a/src/cpp/py_bindings/py_anomaly.cpp b/src/cpp/py_bindings/py_anomaly.cpp new file mode 100644 index 00000000..0561356f --- /dev/null +++ b/src/cpp/py_bindings/py_anomaly.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +#include "models/anomaly_model.h" +#include "models/results.h" +#include "py_utils.hpp" + +namespace pyutils = vision::nanobind::utils; + +void init_anomaly_detection(nb::module_& m) { + nb::class_(m, "AnomalyDetection") + .def_static( + "create_model", + [](const std::string& model_path, + const std::map& configuration, + bool preload, + const std::string& device) { + auto ov_any_config = ov::AnyMap(); + for (const auto& item : configuration) { + ov_any_config[item.first] = pyutils::py_object_to_any(item.second, item.first); + } + + return AnomalyModel::create_model(model_path, ov_any_config, preload, device); + }, + nb::arg("model_path"), + nb::arg("configuration") = ov::AnyMap({}), + nb::arg("preload") = true, + nb::arg("device") = "AUTO") + + .def("__call__", + [](AnomalyModel& self, const nb::ndarray<>& input) { + return self.infer(pyutils::wrap_np_mat(input)); + }) + .def("infer_batch", + [](AnomalyModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }) + .def_prop_ro_static("__model__", [](nb::object) { + return AnomalyModel::ModelType; + }); + + nb::class_(m, "AnomalyResult") + .def(nb::init>(), nb::arg("frameId") = -1, nb::arg("metaData") = nullptr) + .def_prop_ro( + "anomaly_map", + [](AnomalyResult& r) { + return nb::ndarray(r.anomaly_map.data, + {static_cast(r.anomaly_map.rows), + static_cast(r.anomaly_map.cols), + static_cast(r.anomaly_map.channels())}); + }, + nb::rv_policy::reference_internal) + .def_ro("pred_boxes", &AnomalyResult::pred_boxes) + .def_ro("pred_label", &AnomalyResult::pred_label) + .def_prop_ro( + "pred_mask", + [](AnomalyResult& r) { + return nb::ndarray(r.pred_mask.data, + {static_cast(r.pred_mask.rows), + static_cast(r.pred_mask.cols), + static_cast(r.pred_mask.channels())}); + }, + nb::rv_policy::reference_internal) + .def_ro("pred_score", &AnomalyResult::pred_score); +} \ No newline at end of file diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp index 54d392bf..43e40cfa 100644 --- a/src/cpp/py_bindings/py_keypoint_detection.cpp +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -56,27 +56,26 @@ void init_keypoint_detection(nb::module_& m) { nb::class_(m, "KeypointDetectionResult") .def(nb::init>(), nb::arg("frameId") = -1, nb::arg("metaData") = nullptr) - .def_prop_ro("keypoints", [](const KeypointDetectionResult& result) { - if (!result.poses.empty()) { - std::vector shape = {result.poses[0].keypoints.size(), 2}; - return nb::ndarray( - const_cast(static_cast(result.poses[0].keypoints.data())), - shape.size(), - shape.data()); - } - return nb::ndarray(); - }, - nb::rv_policy::reference_internal) - .def_prop_ro("scores", [](const KeypointDetectionResult& result) { - if (!result.poses.empty()) { - std::vector shape = {result.poses[0].scores.size()}; - return nb::ndarray( - const_cast(static_cast(result.poses[0].scores.data())), - shape.size(), - shape.data()); - } - return nb::ndarray(); - }, - nb::rv_policy::reference_internal - ); + .def_prop_ro( + "keypoints", + [](const KeypointDetectionResult& result) { + if (!result.poses.empty()) { + return nb::ndarray( + const_cast(static_cast(result.poses[0].keypoints.data())), + {static_cast(result.poses[0].keypoints.size()), 2}); + } + return nb::ndarray(); + }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "scores", + [](const KeypointDetectionResult& result) { + if (!result.poses.empty()) { + return nb::ndarray( + const_cast(static_cast(result.poses[0].scores.data())), + {static_cast(result.poses[0].scores.size())}); + } + return nb::ndarray(); + }, + nb::rv_policy::reference_internal); } diff --git a/src/cpp/py_bindings/py_segmentation.cpp b/src/cpp/py_bindings/py_segmentation.cpp index befc7cf8..f9aa3ae2 100644 --- a/src/cpp/py_bindings/py_segmentation.cpp +++ b/src/cpp/py_bindings/py_segmentation.cpp @@ -51,10 +51,6 @@ void init_segmentation(nb::module_& m) { return self.inferBatch(input_mats); }) - .def("postprocess", - [](SegmentationModel& self, InferenceResult& infResult) { - return self.postprocess(infResult); - }) .def_prop_ro_static("__model__", [](nb::object) { return SegmentationModel::ModelType; }); diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/py_vision_api.cpp index 8ee144d6..84bded10 100644 --- a/src/cpp/py_bindings/py_vision_api.cpp +++ b/src/cpp/py_bindings/py_vision_api.cpp @@ -12,6 +12,7 @@ void init_classification(nb::module_& m); void init_segmentation(nb::module_& m); void init_instance_segmentation(nb::module_& m); void init_keypoint_detection(nb::module_& m); +void init_anomaly_detection(nb::module_& m); NB_MODULE(py_model_api, m) { m.doc() = "Nanobind binding for OpenVINO Vision API library"; @@ -20,4 +21,5 @@ NB_MODULE(py_model_api, m) { init_keypoint_detection(m); init_segmentation(m); init_instance_segmentation(m); + init_anomaly_detection(m); } From 00f8593a49dd3cb321c1408a016e80254201ddc7 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Mon, 27 Jan 2025 10:05:37 +0100 Subject: [PATCH 10/14] no postprocess in instance seg --- src/cpp/py_bindings/py_instance_segmentation.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cpp/py_bindings/py_instance_segmentation.cpp b/src/cpp/py_bindings/py_instance_segmentation.cpp index 52a21dd8..1ea846d8 100644 --- a/src/cpp/py_bindings/py_instance_segmentation.cpp +++ b/src/cpp/py_bindings/py_instance_segmentation.cpp @@ -51,10 +51,6 @@ void init_instance_segmentation(nb::module_& m) { return self.inferBatch(input_mats); }) - .def("postprocess", - [](MaskRCNNModel& self, InferenceResult& infResult) { - return self.postprocess(infResult); - }) .def_prop_ro_static("__model__", [](nb::object) { return MaskRCNNModel::ModelType; }); From bafaa5fc11812c8e57b55ce53bd52d4d19b9c1ad Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Mon, 27 Jan 2025 10:13:13 +0100 Subject: [PATCH 11/14] end of line --- src/cpp/py_bindings/py_anomaly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp/py_bindings/py_anomaly.cpp b/src/cpp/py_bindings/py_anomaly.cpp index 0561356f..987f1709 100644 --- a/src/cpp/py_bindings/py_anomaly.cpp +++ b/src/cpp/py_bindings/py_anomaly.cpp @@ -77,4 +77,4 @@ void init_anomaly_detection(nb::module_& m) { }, nb::rv_policy::reference_internal) .def_ro("pred_score", &AnomalyResult::pred_score); -} \ No newline at end of file +} From ecef0fa41f4d4dc729f50014bd4b749cda8be54c Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Tue, 28 Jan 2025 09:03:47 +0100 Subject: [PATCH 12/14] add pred_boxes --- src/cpp/py_bindings/py_anomaly.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cpp/py_bindings/py_anomaly.cpp b/src/cpp/py_bindings/py_anomaly.cpp index 987f1709..09d94d04 100644 --- a/src/cpp/py_bindings/py_anomaly.cpp +++ b/src/cpp/py_bindings/py_anomaly.cpp @@ -65,7 +65,13 @@ void init_anomaly_detection(nb::module_& m) { static_cast(r.anomaly_map.channels())}); }, nb::rv_policy::reference_internal) - .def_ro("pred_boxes", &AnomalyResult::pred_boxes) + .def_prop_ro( + "pred_boxes", + [](AnomalyResult& r) { + return nb::ndarray(r.pred_boxes.data(), + {static_cast(r.pred_boxes.size()), 4}); + }, + nb::rv_policy::reference_internal) .def_ro("pred_label", &AnomalyResult::pred_label) .def_prop_ro( "pred_mask", From 752647bf96776d04b2a2d09955172119c89a53be Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Tue, 28 Jan 2025 10:20:20 +0100 Subject: [PATCH 13/14] segmentation properties --- src/cpp/py_bindings/py_segmentation.cpp | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/cpp/py_bindings/py_segmentation.cpp b/src/cpp/py_bindings/py_segmentation.cpp index f9aa3ae2..30804638 100644 --- a/src/cpp/py_bindings/py_segmentation.cpp +++ b/src/cpp/py_bindings/py_segmentation.cpp @@ -65,5 +65,39 @@ void init_segmentation(nb::module_& m) { static_cast(r.resultImage.cols), static_cast(r.resultImage.channels())}); }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "feature_vector", + [](ResultBase& r) { + ImageResultWithSoftPrediction ir = r.asRef(); + if (!ir.feature_vector) { + return nb::ndarray(); + } + + return nb::ndarray(ir.feature_vector.data(), + ir.feature_vector.get_shape().size(), + ir.feature_vector.get_shape().data()); + }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "soft_prediction", + [](ResultBase& r) { + ImageResultWithSoftPrediction ir = r.asRef(); + return nb::ndarray( + ir.soft_prediction.data, + {static_cast(ir.soft_prediction.rows), + static_cast(ir.soft_prediction.cols), + static_cast(ir.soft_prediction.channels())}); + }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "saliency_map", + [](ResultBase& r) { + ImageResultWithSoftPrediction ir = r.asRef(); + return nb::ndarray(ir.saliency_map.data, + {static_cast(ir.saliency_map.rows), + static_cast(ir.saliency_map.cols), + static_cast(ir.saliency_map.channels())}); + }, nb::rv_policy::reference_internal); } From 605ab88decb0af2270f1a5c2b7a1393485466881 Mon Sep 17 00:00:00 2001 From: Mariusz Gumowski Date: Thu, 30 Jan 2025 11:34:56 +0100 Subject: [PATCH 14/14] detection --- src/cpp/py_bindings/py_anomaly.cpp | 3 +- src/cpp/py_bindings/py_detection.cpp | 134 ++++++++++++++++++ src/cpp/py_bindings/py_keypoint_detection.cpp | 4 +- src/cpp/py_bindings/py_vision_api.cpp | 2 + 4 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/cpp/py_bindings/py_detection.cpp diff --git a/src/cpp/py_bindings/py_anomaly.cpp b/src/cpp/py_bindings/py_anomaly.cpp index 09d94d04..d0def857 100644 --- a/src/cpp/py_bindings/py_anomaly.cpp +++ b/src/cpp/py_bindings/py_anomaly.cpp @@ -68,8 +68,7 @@ void init_anomaly_detection(nb::module_& m) { .def_prop_ro( "pred_boxes", [](AnomalyResult& r) { - return nb::ndarray(r.pred_boxes.data(), - {static_cast(r.pred_boxes.size()), 4}); + return nb::ndarray(r.pred_boxes.data(), {r.pred_boxes.size(), 4}); }, nb::rv_policy::reference_internal) .def_ro("pred_label", &AnomalyResult::pred_label) diff --git a/src/cpp/py_bindings/py_detection.cpp b/src/cpp/py_bindings/py_detection.cpp new file mode 100644 index 00000000..1013bc7b --- /dev/null +++ b/src/cpp/py_bindings/py_detection.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +#include "models/detection_model.h" +#include "models/results.h" +#include "py_utils.hpp" + +namespace pyutils = vision::nanobind::utils; + +void init_detection(nb::module_& m) { + nb::class_(m, "DetectionModel") + .def_static( + "create_model", + [](const std::string& model_path, + const std::map& configuration, + std::string model_type, + bool preload, + const std::string& device) { + auto ov_any_config = ov::AnyMap(); + for (const auto& item : configuration) { + ov_any_config[item.first] = pyutils::py_object_to_any(item.second, item.first); + } + + return DetectionModel::create_model(model_path, ov_any_config, model_type, preload, device); + }, + nb::arg("model_path"), + nb::arg("configuration") = ov::AnyMap({}), + nb::arg("model_type") = "", + nb::arg("preload") = true, + nb::arg("device") = "AUTO") + + .def("__call__", + [](DetectionModel& self, const nb::ndarray<>& input) { + return self.infer(pyutils::wrap_np_mat(input)); + }) + .def("infer_batch", [](DetectionModel& self, const std::vector> inputs) { + std::vector input_mats; + input_mats.reserve(inputs.size()); + + for (const auto& input : inputs) { + input_mats.push_back(pyutils::wrap_np_mat(input)); + } + + return self.inferBatch(input_mats); + }); + + nb::class_(m, "DetectionResult") + .def(nb::init<>()) + .def_prop_ro( + "saliency_map", + [](DetectionResult& r) { + if (!r.saliency_map) { + return nb::ndarray(); + } + + return nb::ndarray(r.saliency_map.data(), + r.saliency_map.get_shape().size(), + r.saliency_map.get_shape().data()); + }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "feature_vector", + [](DetectionResult& r) { + if (!r.feature_vector) { + return nb::ndarray(); + } + + return nb::ndarray(r.feature_vector.data(), + r.feature_vector.get_shape().size(), + r.feature_vector.get_shape().data()); + }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "label_names", + [](DetectionResult& r) { + std::vector labels; + std::transform(r.objects.begin(), + r.objects.end(), + std::back_inserter(labels), + [](const DetectedObject& obj) { + return obj.label; + }); + + return labels; + }, + nb::rv_policy::reference_internal) + .def_prop_ro( + "scores", + [](DetectionResult& r) { + std::vector scores; + std::transform(r.objects.begin(), + r.objects.end(), + std::back_inserter(scores), + [](const DetectedObject& obj) { + return obj.confidence; + }); + return nb::ndarray(scores.data(), {scores.size()}).cast(); + }, + nb::rv_policy::move) + .def_prop_ro( + "labels", + [](DetectionResult& r) { + std::vector labels; + std::transform(r.objects.begin(), + r.objects.end(), + std::back_inserter(labels), + [](const DetectedObject& obj) { + return obj.labelID; + }); + return nb::ndarray(labels.data(), {labels.size()}).cast(); + }, + nb::rv_policy::move) + .def_prop_ro( + "bboxes", + [](DetectionResult& r) { + std::vector bboxes; + std::transform(r.objects.begin(), + r.objects.end(), + std::back_inserter(bboxes), + [](const DetectedObject& obj) { + return cv::Rect2f(obj.x, obj.y, obj.width, obj.height); + }); + return nb::ndarray(bboxes.data(), {bboxes.size(), 4}).cast(); + }, + nb::rv_policy::move); +} diff --git a/src/cpp/py_bindings/py_keypoint_detection.cpp b/src/cpp/py_bindings/py_keypoint_detection.cpp index 43e40cfa..27b1c0a5 100644 --- a/src/cpp/py_bindings/py_keypoint_detection.cpp +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -62,7 +62,7 @@ void init_keypoint_detection(nb::module_& m) { if (!result.poses.empty()) { return nb::ndarray( const_cast(static_cast(result.poses[0].keypoints.data())), - {static_cast(result.poses[0].keypoints.size()), 2}); + {result.poses[0].keypoints.size(), 2}); } return nb::ndarray(); }, @@ -73,7 +73,7 @@ void init_keypoint_detection(nb::module_& m) { if (!result.poses.empty()) { return nb::ndarray( const_cast(static_cast(result.poses[0].scores.data())), - {static_cast(result.poses[0].scores.size())}); + {result.poses[0].scores.size()}); } return nb::ndarray(); }, diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/py_vision_api.cpp index 84bded10..cc2ec207 100644 --- a/src/cpp/py_bindings/py_vision_api.cpp +++ b/src/cpp/py_bindings/py_vision_api.cpp @@ -13,6 +13,7 @@ void init_segmentation(nb::module_& m); void init_instance_segmentation(nb::module_& m); void init_keypoint_detection(nb::module_& m); void init_anomaly_detection(nb::module_& m); +void init_detection(nb::module_& m); NB_MODULE(py_model_api, m) { m.doc() = "Nanobind binding for OpenVINO Vision API library"; @@ -22,4 +23,5 @@ NB_MODULE(py_model_api, m) { init_segmentation(m); init_instance_segmentation(m); init_anomaly_detection(m); + init_detection(m); }