diff --git a/src/cpp/py_bindings/py_anomaly.cpp b/src/cpp/py_bindings/py_anomaly.cpp new file mode 100644 index 00000000..d0def857 --- /dev/null +++ b/src/cpp/py_bindings/py_anomaly.cpp @@ -0,0 +1,85 @@ +/* + * 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_prop_ro( + "pred_boxes", + [](AnomalyResult& r) { + return nb::ndarray(r.pred_boxes.data(), {r.pred_boxes.size(), 4}); + }, + nb::rv_policy::reference_internal) + .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); +} diff --git a/src/cpp/py_bindings/py_classificaiton.cpp b/src/cpp/py_bindings/py_classification.cpp similarity index 72% rename from src/cpp/py_bindings/py_classificaiton.cpp rename to src/cpp/py_bindings/py_classification.cpp index 19e2b4eb..21e699cf 100644 --- a/src/cpp/py_bindings/py_classificaiton.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) { @@ -75,14 +87,18 @@ 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_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_instance_segmentation.cpp b/src/cpp/py_bindings/py_instance_segmentation.cpp new file mode 100644 index 00000000..1ea846d8 --- /dev/null +++ b/src/cpp/py_bindings/py_instance_segmentation.cpp @@ -0,0 +1,72 @@ +/* + * 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_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_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 new file mode 100644 index 00000000..27b1c0a5 --- /dev/null +++ b/src/cpp/py_bindings/py_keypoint_detection.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ +#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_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_prop_ro( + "keypoints", + [](const KeypointDetectionResult& result) { + if (!result.poses.empty()) { + return nb::ndarray( + const_cast(static_cast(result.poses[0].keypoints.data())), + {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())), + {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 new file mode 100644 index 00000000..30804638 --- /dev/null +++ b/src/cpp/py_bindings/py_segmentation.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2025 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "models/results.h" +#include "models/segmentation_model.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_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_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) + .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); +} diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/py_vision_api.cpp index c10e6486..cc2ec207 100644 --- a/src/cpp/py_bindings/py_vision_api.cpp +++ b/src/cpp/py_bindings/py_vision_api.cpp @@ -7,11 +7,21 @@ 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); +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"; init_base_modules(m); init_classification(m); + init_keypoint_detection(m); + init_segmentation(m); + init_instance_segmentation(m); + init_anomaly_detection(m); + init_detection(m); }