From 7c89b2a60f6b9b471dde773ba15062862eb6cf0f Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Thu, 30 Jan 2025 02:29:13 +0900 Subject: [PATCH 01/38] Add tests for py bindings --- .github/workflows/test_accuracy.yml | 4 +++ tests/cpp/accuracy/conftest.py | 8 +++++ tests/cpp/accuracy/test_bindings.py | 56 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 tests/cpp/accuracy/conftest.py create mode 100644 tests/cpp/accuracy/test_bindings.py diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index 6cd93deb..da504c62 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -49,3 +49,7 @@ jobs: run: | build/test_accuracy -d data -p tests/python/accuracy/public_scope.json DATA=data build/test_YOLOv8 + - name: Run CPP-PY Bindings Test + run: | + source venv/bin/activate + PYTHONPATH="$PYTHONPATH:build/py_bindings" pytest --data=./data --config=./tests/python/accuracy/public_scope.json tests/cpp/accuracy/test_bindings.py diff --git a/tests/cpp/accuracy/conftest.py b/tests/cpp/accuracy/conftest.py new file mode 100644 index 00000000..2b3ab029 --- /dev/null +++ b/tests/cpp/accuracy/conftest.py @@ -0,0 +1,8 @@ +# +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +def pytest_addoption(parser): + parser.addoption("--data", action="store", help="data folder with dataset") + parser.addoption("--config", action="store", help="path to models config") diff --git a/tests/cpp/accuracy/test_bindings.py b/tests/cpp/accuracy/test_bindings.py new file mode 100644 index 00000000..314f2ac6 --- /dev/null +++ b/tests/cpp/accuracy/test_bindings.py @@ -0,0 +1,56 @@ +# +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +import pytest +import json +from pathlib import Path + +import cv2 + +from model_api.models import Model +from py_model_api import ClassificationModel + + +def read_config(models_config: str, model_type: str): + with open(models_config, "r") as f: + data = json.load(f) + for item in data: + if item["type"] == model_type: + yield item + + +@pytest.fixture(scope="session") +def data(pytestconfig) -> str: + return pytestconfig.getoption("data") + + +@pytest.fixture(scope="session") +def models_config(pytestconfig) -> str: + return pytestconfig.getoption("config") + + +@pytest.fixture() +def classification_configs(models_config: str): + return read_config(models_config, "ClassificationModel") + + +def test_classification_models(data: str, classification_configs): + for model_data in classification_configs: + name = model_data["name"] + if ".xml" not in name: + continue + if name.endswith(".xml") or name.endswith(".onnx"): + name = f"{data}/{name}" + + model = Model.create_model(name, preload=True) + cpp_model = ClassificationModel.create_model(name, preload=True) + + image_path = Path(data) / next(iter(model_data["test_data"]))["image"] + image = cv2.imread(str(image_path)) + + py_result = model(image) + cpp_result = cpp_model(image) + + assert str(py_result) == str(cpp_result) From 12c7e0db19ad03813b10a10ebba13dc94555526b Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Thu, 30 Jan 2025 02:46:51 +0900 Subject: [PATCH 02/38] Fix linter --- tests/cpp/accuracy/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cpp/accuracy/conftest.py b/tests/cpp/accuracy/conftest.py index 2b3ab029..c05e5922 100644 --- a/tests/cpp/accuracy/conftest.py +++ b/tests/cpp/accuracy/conftest.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 # + def pytest_addoption(parser): parser.addoption("--data", action="store", help="data folder with dataset") parser.addoption("--config", action="store", help="path to models config") From 18d1cb9ee8b1419b908ed36b87d599f990469dd9 Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Thu, 30 Jan 2025 03:10:55 +0900 Subject: [PATCH 03/38] Del outdated OMZ model --- tests/python/accuracy/public_scope.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/python/accuracy/public_scope.json b/tests/python/accuracy/public_scope.json index 47f0ea10..a71d2518 100644 --- a/tests/python/accuracy/public_scope.json +++ b/tests/python/accuracy/public_scope.json @@ -145,16 +145,6 @@ } ] }, - { - "name": "resnet-18-pytorch", - "type": "ClassificationModel", - "test_data": [ - { - "image": "coco128/images/train2017/000000000074.jpg", - "reference": ["254 (pug): 0.153, [0], [0], [0]"] - } - ] - }, { "name": "efficientnet-b0-pytorch", "type": "ClassificationModel", From 75ffbf853a7fca3fa958d61ed3b72a8aa80364ca Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Fri, 31 Jan 2025 00:00:21 +0900 Subject: [PATCH 04/38] Disable yolo python tests --- .github/workflows/test_accuracy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index da504c62..83dfa609 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -34,7 +34,7 @@ jobs: run: | source venv/bin/activate pytest --data=./data tests/python/accuracy/test_accuracy.py - DATA=data pytest --data=./data tests/python/accuracy/test_YOLOv8.py + # DATA=data pytest --data=./data tests/python/accuracy/test_YOLOv8.py - name: Install CPP dependencies run: | sudo bash src/cpp/install_dependencies.sh From 782974641ceb2f60ae6fc96c260063eed5340845 Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Fri, 31 Jan 2025 00:18:26 +0900 Subject: [PATCH 05/38] Disable cpp yolo tests as well --- .github/workflows/test_accuracy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index 83dfa609..cb688ccd 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -34,7 +34,7 @@ jobs: run: | source venv/bin/activate pytest --data=./data tests/python/accuracy/test_accuracy.py - # DATA=data pytest --data=./data tests/python/accuracy/test_YOLOv8.py + # DATA=data pytest --data=./data tests/python/accuracy/test_YOLOv8.py # checkpoints are not available sometimes - name: Install CPP dependencies run: | sudo bash src/cpp/install_dependencies.sh @@ -48,7 +48,7 @@ jobs: - name: Run CPP Test run: | build/test_accuracy -d data -p tests/python/accuracy/public_scope.json - DATA=data build/test_YOLOv8 + # DATA=data build/test_YOLOv8 # checkpoints are not available sometimes - name: Run CPP-PY Bindings Test run: | source venv/bin/activate From df10b258336a5a02417ef2a3aac7630e6731aabb Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Fri, 31 Jan 2025 01:04:11 +0900 Subject: [PATCH 06/38] Minor fixes in cpp samples --- examples/cpp/CMakeLists.txt | 2 +- examples/cpp/asynchronous_api/main.cpp | 2 +- examples/cpp/synchronous_api/main.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 2fe5a7fd..b1ebab76 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -92,7 +92,7 @@ endmacro() find_package(OpenCV REQUIRED COMPONENTS imgcodecs) -set (ENABLE_PY_BINDINGS OFF) +set(ENABLE_PY_BINDINGS OFF) add_subdirectory(../../src/cpp ${Samples_BINARY_DIR}/src/cpp) add_example(NAME asynchronous_api SOURCES ./asynchronous_api/main.cpp DEPENDENCIES model_api) diff --git a/examples/cpp/asynchronous_api/main.cpp b/examples/cpp/asynchronous_api/main.cpp index acd361a2..105a5150 100644 --- a/examples/cpp/asynchronous_api/main.cpp +++ b/examples/cpp/asynchronous_api/main.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/examples/cpp/synchronous_api/main.cpp b/examples/cpp/synchronous_api/main.cpp index ec4ef869..fe3f4908 100644 --- a/examples/cpp/synchronous_api/main.cpp +++ b/examples/cpp/synchronous_api/main.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include From 9dd9fcbdea4723cfbe9c255460a39efeb9584e33 Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Fri, 31 Jan 2025 01:15:04 +0900 Subject: [PATCH 07/38] Update cmake in tests --- .github/workflows/test_accuracy.yml | 2 +- tests/cpp/accuracy/CMakeLists.txt | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index cb688ccd..1ca375bb 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -52,4 +52,4 @@ jobs: - name: Run CPP-PY Bindings Test run: | source venv/bin/activate - PYTHONPATH="$PYTHONPATH:build/py_bindings" pytest --data=./data --config=./tests/python/accuracy/public_scope.json tests/cpp/accuracy/test_bindings.py + PYTHONPATH="$PYTHONPATH:build/model_api/cpp/py_bindings/" pytest --data=./data --config=./tests/python/accuracy/public_scope.json tests/cpp/accuracy/test_bindings.py diff --git a/tests/cpp/accuracy/CMakeLists.txt b/tests/cpp/accuracy/CMakeLists.txt index 57aa5705..8b4bb42a 100644 --- a/tests/cpp/accuracy/CMakeLists.txt +++ b/tests/cpp/accuracy/CMakeLists.txt @@ -63,8 +63,15 @@ FetchContent_MakeAvailable(json googletest) include(../cmake/common.cmake) +find_package(Python3 REQUIRED) +execute_process( + COMMAND ${Python3_EXECUTABLE} -c "from openvino.utils import get_cmake_path; print(get_cmake_path(), end='')" + OUTPUT_VARIABLE OpenVINO_DIR_PY + ERROR_QUIET +) + find_package(OpenCV REQUIRED COMPONENTS core highgui videoio imgproc imgcodecs) -find_package(OpenVINO REQUIRED COMPONENTS Runtime) +find_package(OpenVINO REQUIRED COMPONENTS Runtime HINTS "${OpenVINO_DIR_PY}") add_subdirectory(../../../src/cpp ${tests_BINARY_DIR}/model_api/cpp) From ae532aa271aa8412e6b457efbeb4840a3be0b84e Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Fri, 31 Jan 2025 01:38:50 +0900 Subject: [PATCH 08/38] Revert py OV in tests cmake --- tests/cpp/accuracy/CMakeLists.txt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/cpp/accuracy/CMakeLists.txt b/tests/cpp/accuracy/CMakeLists.txt index 8b4bb42a..57aa5705 100644 --- a/tests/cpp/accuracy/CMakeLists.txt +++ b/tests/cpp/accuracy/CMakeLists.txt @@ -63,15 +63,8 @@ FetchContent_MakeAvailable(json googletest) include(../cmake/common.cmake) -find_package(Python3 REQUIRED) -execute_process( - COMMAND ${Python3_EXECUTABLE} -c "from openvino.utils import get_cmake_path; print(get_cmake_path(), end='')" - OUTPUT_VARIABLE OpenVINO_DIR_PY - ERROR_QUIET -) - find_package(OpenCV REQUIRED COMPONENTS core highgui videoio imgproc imgcodecs) -find_package(OpenVINO REQUIRED COMPONENTS Runtime HINTS "${OpenVINO_DIR_PY}") +find_package(OpenVINO REQUIRED COMPONENTS Runtime) add_subdirectory(../../../src/cpp ${tests_BINARY_DIR}/model_api/cpp) From ad192abfd433ba2b6b0b7c3d7e14a8e3374710bc Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Fri, 31 Jan 2025 02:43:05 +0900 Subject: [PATCH 09/38] Use python from venv only --- .github/workflows/test_accuracy.yml | 1 + src/cpp/CMakeLists.txt | 5 +++-- src/cpp/py_bindings/CMakeLists.txt | 5 ++--- tests/cpp/accuracy/CMakeLists.txt | 12 +++++++++++- tests/cpp/cmake/common.cmake | 5 ++--- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index 1ca375bb..dab4414d 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -40,6 +40,7 @@ jobs: sudo bash src/cpp/install_dependencies.sh - name: Build CPP Test run: | + source venv/bin/activate pip install nanobind==2.4.0 pip install typing_extensions==4.12.2 mkdir build && cd build diff --git a/src/cpp/CMakeLists.txt b/src/cpp/CMakeLists.txt index 44e9b057..6d864d2c 100644 --- a/src/cpp/CMakeLists.txt +++ b/src/cpp/CMakeLists.txt @@ -35,9 +35,10 @@ find_package(OpenCV REQUIRED COMPONENTS core imgproc) # Looking for OpenVINO in the python distribution. It doesn't work for cross-compiling build if(NOT CMAKE_CROSSCOMPILING) - find_package(Python3 REQUIRED) + set(Python_FIND_VIRTUALENV ONLY) + find_package(Python COMPONENTS Interpreter Development REQUIRED) execute_process( - COMMAND ${Python3_EXECUTABLE} -c "from openvino.utils import get_cmake_path; print(get_cmake_path(), end='')" + COMMAND ${Python_EXECUTABLE} -c "from openvino.utils import get_cmake_path; print(get_cmake_path(), end='')" OUTPUT_VARIABLE OpenVINO_DIR_PY ERROR_QUIET ) diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 91eb70ce..a7c40650 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -2,9 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 # -set(DEV_MODULE Development.Module) - -find_package(Python COMPONENTS Interpreter ${DEV_MODULE} REQUIRED) +set(Python_FIND_VIRTUALENV ONLY) +find_package(Python COMPONENTS Interpreter Development REQUIRED) execute_process( COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir diff --git a/tests/cpp/accuracy/CMakeLists.txt b/tests/cpp/accuracy/CMakeLists.txt index 57aa5705..69ef04fa 100644 --- a/tests/cpp/accuracy/CMakeLists.txt +++ b/tests/cpp/accuracy/CMakeLists.txt @@ -64,7 +64,17 @@ FetchContent_MakeAvailable(json googletest) include(../cmake/common.cmake) find_package(OpenCV REQUIRED COMPONENTS core highgui videoio imgproc imgcodecs) -find_package(OpenVINO REQUIRED COMPONENTS Runtime) + +set(Python_FIND_VIRTUALENV ONLY) +find_package(Python REQUIRED) +execute_process( + COMMAND ${Python_EXECUTABLE} -c "from openvino.utils import get_cmake_path; print(get_cmake_path(), end='')" + OUTPUT_VARIABLE OpenVINO_DIR_PY + ERROR_QUIET +) +find_package(OpenVINO REQUIRED + COMPONENTS Runtime Threading + HINTS "${OpenVINO_DIR_PY}") add_subdirectory(../../../src/cpp ${tests_BINARY_DIR}/model_api/cpp) diff --git a/tests/cpp/cmake/common.cmake b/tests/cpp/cmake/common.cmake index 8a931e14..dff0a621 100644 --- a/tests/cpp/cmake/common.cmake +++ b/tests/cpp/cmake/common.cmake @@ -35,13 +35,12 @@ macro(add_test) target_include_directories(${TEST_NAME} PRIVATE ${TEST_INCLUDE_DIRECTORIES}) endif() - target_link_libraries(${TEST_NAME} PRIVATE ${OpenCV_LIBRARIES} openvino::runtime ${TEST_DEPENDENCIES}) + target_link_libraries(${TEST_NAME} PRIVATE ${OpenCV_LIBRARIES} ${TEST_DEPENDENCIES}) if(UNIX) target_link_libraries(${TEST_NAME} PRIVATE pthread) endif() - target_link_libraries(${TEST_NAME} PRIVATE gtest gtest_main) - target_link_libraries(${TEST_NAME} PRIVATE nlohmann_json::nlohmann_json) + target_link_libraries(${TEST_NAME} PRIVATE gtest_main gmock_main nlohmann_json::nlohmann_json) endmacro() From 6d2de0c1bd66028f375b2219ef660a98d9fd9c27 Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Fri, 31 Jan 2025 02:55:25 +0900 Subject: [PATCH 10/38] Specify python dir manually --- .github/workflows/test_accuracy.yml | 2 +- src/cpp/CMakeLists.txt | 2 +- src/cpp/py_bindings/CMakeLists.txt | 2 +- tests/cpp/accuracy/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index dab4414d..4c05f79f 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -44,7 +44,7 @@ jobs: pip install nanobind==2.4.0 pip install typing_extensions==4.12.2 mkdir build && cd build - cmake ../tests/cpp/accuracy/ + cmake ../tests/cpp/accuracy/ -DPython_ROOT_DIR=$(python -c "import sys; print(sys.prefix)") make -j - name: Run CPP Test run: | diff --git a/src/cpp/CMakeLists.txt b/src/cpp/CMakeLists.txt index 6d864d2c..971e650c 100644 --- a/src/cpp/CMakeLists.txt +++ b/src/cpp/CMakeLists.txt @@ -35,7 +35,7 @@ find_package(OpenCV REQUIRED COMPONENTS core imgproc) # Looking for OpenVINO in the python distribution. It doesn't work for cross-compiling build if(NOT CMAKE_CROSSCOMPILING) - set(Python_FIND_VIRTUALENV ONLY) + set(Python_FIND_VIRTUALENV FIRST) find_package(Python COMPONENTS Interpreter Development REQUIRED) execute_process( COMMAND ${Python_EXECUTABLE} -c "from openvino.utils import get_cmake_path; print(get_cmake_path(), end='')" diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index a7c40650..b955b8c4 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 # -set(Python_FIND_VIRTUALENV ONLY) +set(Python_FIND_VIRTUALENV FIRST) find_package(Python COMPONENTS Interpreter Development REQUIRED) execute_process( diff --git a/tests/cpp/accuracy/CMakeLists.txt b/tests/cpp/accuracy/CMakeLists.txt index 69ef04fa..fb79fe79 100644 --- a/tests/cpp/accuracy/CMakeLists.txt +++ b/tests/cpp/accuracy/CMakeLists.txt @@ -65,7 +65,7 @@ include(../cmake/common.cmake) find_package(OpenCV REQUIRED COMPONENTS core highgui videoio imgproc imgcodecs) -set(Python_FIND_VIRTUALENV ONLY) +set(Python_FIND_VIRTUALENV FIRST) find_package(Python REQUIRED) execute_process( COMMAND ${Python_EXECUTABLE} -c "from openvino.utils import get_cmake_path; print(get_cmake_path(), end='')" From 16c7bbd1fce7f025ec4f694dc18d1b6f2c46f5db Mon Sep 17 00:00:00 2001 From: Vladisalv Sovrasov Date: Sat, 8 Feb 2025 00:11:24 +0900 Subject: [PATCH 11/38] Enable bindings in cpp accuracy tests --- tests/cpp/accuracy/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cpp/accuracy/CMakeLists.txt b/tests/cpp/accuracy/CMakeLists.txt index c06077ba..2ccbac9a 100644 --- a/tests/cpp/accuracy/CMakeLists.txt +++ b/tests/cpp/accuracy/CMakeLists.txt @@ -65,7 +65,7 @@ include(../cmake/common.cmake) find_package(OpenCV REQUIRED COMPONENTS core highgui videoio imgproc imgcodecs) -set(ENABLE_PY_BINDINGS OFF) +set(ENABLE_PY_BINDINGS ON) add_subdirectory(../../../src/cpp ${tests_BINARY_DIR}/model_api/cpp) add_test(NAME test_accuracy SOURCES test_accuracy.cpp DEPENDENCIES model_api) From 6ef53edbbf6d4b83ff5513272931d34b7d69b26e Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Wed, 2 Apr 2025 15:20:31 +0200 Subject: [PATCH 12/38] Merge ModelBase into ImageModel Example works, but probably some missing parts. --- src/cpp/models/include/models/image_model.h | 42 +++- src/cpp/models/include/models/model_base.h | 73 ------ src/cpp/models/src/image_model.cpp | 196 +++++++++++++++- src/cpp/models/src/model_base.cpp | 221 ------------------- src/cpp/tilers/src/instance_segmentation.cpp | 4 +- src/cpp/tilers/src/tiler_base.cpp | 2 +- 6 files changed, 224 insertions(+), 314 deletions(-) delete mode 100644 src/cpp/models/include/models/model_base.h delete mode 100644 src/cpp/models/src/model_base.cpp diff --git a/src/cpp/models/include/models/image_model.h b/src/cpp/models/include/models/image_model.h index dfb274bb..74b0087a 100644 --- a/src/cpp/models/include/models/image_model.h +++ b/src/cpp/models/include/models/image_model.h @@ -9,9 +9,12 @@ #include #include +#include "adapters/inference_adapter.h" #include "models/input_data.h" -#include "models/model_base.h" +#include "models/results.h" #include "utils/image_utils.h" +#include "utils/ocv_common.hpp" +#include "utils/args_helper.hpp" namespace ov { class InferRequest; @@ -20,7 +23,7 @@ struct InputData; struct InternalModelData; // ImageModel implements preprocess(), ImageModel's direct or indirect children are expected to implement prostprocess() -class ImageModel : public ModelBase { +class ImageModel { public: /// Constructor /// @param modelFile name of model to load @@ -33,9 +36,24 @@ class ImageModel : public ModelBase { ImageModel(std::shared_ptr& model, const ov::AnyMap& configuration); ImageModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); - using ModelBase::ModelBase; - std::shared_ptr preprocess(const InputData& inputData, InferenceInput& input) override; + virtual std::shared_ptr preprocess(const InputData& inputData, InferenceInput& input); + virtual std::unique_ptr postprocess(InferenceResult& infResult) = 0; + + void load(ov::Core& core, const std::string& device, size_t num_infer_requests = 1); + + std::shared_ptr prepare(); + + virtual size_t getNumAsyncExecutors() const; + virtual bool isReady(); + virtual void awaitAll(); + virtual void awaitAny(); + virtual void setCallback( + std::function, const ov::AnyMap& callback_args)> callback); + + std::shared_ptr getModel(); + std::shared_ptr getInferenceAdapter(); + static std::vector loadLabels(const std::string& labelFilename); std::shared_ptr embedProcessing(std::shared_ptr& model, const std::string& inputName, @@ -54,7 +72,7 @@ class ImageModel : public ModelBase { protected: RESIZE_MODE selectResizeMode(const std::string& resize_type); - void updateModelInfo() override; + virtual void updateModelInfo(); void init_from_config(const ov::AnyMap& top_priority, const ov::AnyMap& mid_priority); std::string getLabelName(size_t labelID) { @@ -73,4 +91,18 @@ class ImageModel : public ModelBase { bool reverse_input_channels = false; std::vector scale_values; std::vector mean_values; + +protected: + virtual void prepareInputsOutputs(std::shared_ptr& model) = 0; + + InputTransform inputTransform = InputTransform(); + + std::shared_ptr model; + std::vector inputNames; + std::vector outputNames; + std::string modelFile; + std::shared_ptr inferenceAdapter; + std::map inputsLayouts; + ov::Layout getInputLayout(const ov::Output& input); + std::function, const ov::AnyMap&)> lastCallback; }; diff --git a/src/cpp/models/include/models/model_base.h b/src/cpp/models/include/models/model_base.h deleted file mode 100644 index 6fe3525d..00000000 --- a/src/cpp/models/include/models/model_base.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2020-2024 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -struct InferenceResult; -struct InputData; -struct InternalModelData; -struct ResultBase; - -class ModelBase { -public: - ModelBase(const std::string& modelFile, const std::string& layout = ""); - ModelBase(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); - ModelBase(std::shared_ptr& model, const ov::AnyMap& configuration); - - virtual ~ModelBase() = default; - - std::shared_ptr prepare(); - void load(ov::Core& core, const std::string& device, size_t num_infer_requests = 1); - // Modifying ov::Model doesn't affect the model wrapper - std::shared_ptr getModel(); - std::shared_ptr getInferenceAdapter(); - - virtual std::shared_ptr preprocess(const InputData& inputData, InferenceInput& input) = 0; - virtual std::unique_ptr postprocess(InferenceResult& infResult) = 0; - virtual std::unique_ptr infer(const InputData& inputData); - virtual void inferAsync(const InputData& inputData, const ov::AnyMap& callback_args = {}); - virtual std::vector> inferBatch( - const std::vector>& inputData); - virtual std::vector> inferBatch(const std::vector& inputData); - - virtual bool isReady(); - virtual void awaitAll(); - virtual void awaitAny(); - virtual void setCallback( - std::function, const ov::AnyMap& callback_args)> callback); - virtual size_t getNumAsyncExecutors() const; - - const std::vector& getoutputNames() const { - return outputNames; - } - const std::vector& getinputNames() const { - return inputNames; - } - -protected: - virtual void prepareInputsOutputs(std::shared_ptr& model) = 0; - virtual void updateModelInfo(); - - InputTransform inputTransform = InputTransform(); - - std::shared_ptr model; - std::vector inputNames; - std::vector outputNames; - std::string modelFile; - std::shared_ptr inferenceAdapter; - std::map inputsLayouts; - ov::Layout getInputLayout(const ov::Output& input); - std::function, const ov::AnyMap&)> lastCallback; -}; diff --git a/src/cpp/models/src/image_model.cpp b/src/cpp/models/src/image_model.cpp index f87d8029..9ec3fd42 100644 --- a/src/cpp/models/src/image_model.cpp +++ b/src/cpp/models/src/image_model.cpp @@ -15,17 +15,137 @@ #include #include +#include "adapters/openvino_adapter.h" #include "models/input_data.h" #include "models/internal_model_data.h" #include "models/results.h" +#include "utils/common.hpp" + +namespace { +class TmpCallbackSetter { +public: + ImageModel* model; + std::function, const ov::AnyMap&)> last_callback; + TmpCallbackSetter(ImageModel* model_, + std::function, const ov::AnyMap&)> tmp_callback, + std::function, const ov::AnyMap&)> last_callback_) + : model(model_), + last_callback(last_callback_) { + model->setCallback(tmp_callback); + } + ~TmpCallbackSetter() { + if (last_callback) { + model->setCallback(last_callback); + } else { + model->setCallback([](std::unique_ptr, const ov::AnyMap&) {}); + } + } +}; +} // namespace ImageModel::ImageModel(const std::string& modelFile, const std::string& resize_type, bool useAutoResize, const std::string& layout) - : ModelBase(modelFile, layout), - useAutoResize(useAutoResize), - resizeMode(selectResizeMode(resize_type)) {} + : useAutoResize(useAutoResize), + resizeMode(selectResizeMode(resize_type)), + modelFile(modelFile), + inputsLayouts(parseLayoutString(layout)) { + auto core = ov::Core(); + model = core.read_model(modelFile); +} + + +void ImageModel::load(ov::Core& core, const std::string& device, size_t num_infer_requests) { + if (!inferenceAdapter) { + inferenceAdapter = std::make_shared(); + } + + // Update model_info erased by pre/postprocessing + updateModelInfo(); + + inferenceAdapter->loadModel(model, core, device, {}, num_infer_requests); +} + +std::shared_ptr ImageModel::prepare() { + prepareInputsOutputs(model); + logBasicModelInfo(model); + ov::set_batch(model, 1); + + return model; +} + +ov::Layout ImageModel::getInputLayout(const ov::Output& input) { + ov::Layout layout = ov::layout::get_layout(input); + if (layout.empty()) { + if (inputsLayouts.empty()) { + layout = getLayoutFromShape(input.get_partial_shape()); + slog::warn << "Automatically detected layout '" << layout.to_string() << "' for input '" + << input.get_any_name() << "' will be used." << slog::endl; + } else if (inputsLayouts.size() == 1) { + layout = inputsLayouts.begin()->second; + } else { + layout = inputsLayouts[input.get_any_name()]; + } + } + + return layout; +} + +size_t ImageModel::getNumAsyncExecutors() const { + return inferenceAdapter->getNumAsyncExecutors(); +} + +bool ImageModel::isReady() { + return inferenceAdapter->isReady(); +} +void ImageModel::awaitAll() { + inferenceAdapter->awaitAll(); +} +void ImageModel::awaitAny() { + inferenceAdapter->awaitAny(); +} + +void ImageModel::setCallback( + std::function, const ov::AnyMap& callback_args)> callback) { + lastCallback = callback; + inferenceAdapter->setCallback([this, callback](ov::InferRequest request, CallbackData args) { + InferenceResult result; + + InferenceOutput output; + for (const auto& item : this->getInferenceAdapter()->getOutputNames()) { + output.emplace(item, request.get_tensor(item)); + } + + result.outputsData = output; + auto model_data_iter = args->find("internalModelData"); + if (model_data_iter != args->end()) { + result.internalModelData = std::move(model_data_iter->second.as>()); + } + auto retVal = this->postprocess(result); + *retVal = static_cast(result); + callback(std::move(retVal), args ? *args : ov::AnyMap()); + }); +} + +std::shared_ptr ImageModel::getModel() { + if (!model) { + throw std::runtime_error(std::string("ov::Model is not accessible for the current model adapter: ") + + typeid(inferenceAdapter).name()); + } + + updateModelInfo(); + return model; +} + +std::shared_ptr ImageModel::getInferenceAdapter() { + if (!inferenceAdapter) { + throw std::runtime_error(std::string("Model wasn't loaded")); + } + + return inferenceAdapter; +} + RESIZE_MODE ImageModel::selectResizeMode(const std::string& resize_type) { RESIZE_MODE resize = RESIZE_FILL; @@ -68,36 +188,88 @@ void ImageModel::init_from_config(const ov::AnyMap& top_priority, const ov::AnyM } ImageModel::ImageModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : ModelBase(model, configuration) { + : model(model) { + auto layout_iter = configuration.find("layout"); + std::string layout = ""; + + if (layout_iter != configuration.end()) { + layout = layout_iter->second.as(); + } else { + if (model->has_rt_info("model_info", "layout")) { + layout = model->get_rt_info("model_info", "layout"); + } + } + inputsLayouts = parseLayoutString(layout); init_from_config(configuration, model->has_rt_info("model_info") ? model->get_rt_info("model_info") : ov::AnyMap{}); } ImageModel::ImageModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : ModelBase(adapter, configuration) { + : inferenceAdapter(adapter) { + const ov::AnyMap& adapter_configuration = adapter->getModelConfig(); + + std::string layout = ""; + layout = get_from_any_maps("layout", configuration, adapter_configuration, layout); + inputsLayouts = parseLayoutString(layout); + + inputNames = adapter->getInputNames(); + outputNames = adapter->getOutputNames(); + init_from_config(configuration, adapter->getModelConfig()); } std::unique_ptr ImageModel::inferImage(const ImageInputData& inputData) { - return ModelBase::infer(static_cast(inputData)); - ; + InferenceInput inputs; + InferenceResult result; + auto internalModelData = this->preprocess(inputData, inputs); + + result.outputsData = inferenceAdapter->infer(inputs); + result.internalModelData = std::move(internalModelData); + + auto retVal = this->postprocess(result); + *retVal = static_cast(result); + return retVal; } std::vector> ImageModel::inferBatchImage(const std::vector& inputImgs) { - std::vector> inputData; + std::vector> inputData; inputData.reserve(inputImgs.size()); for (const auto& img : inputImgs) { - inputData.push_back(static_cast(img)); + inputData.push_back(img); + } + auto results = std::vector>(inputData.size()); + auto setter = TmpCallbackSetter( + this, + [&](std::unique_ptr result, const ov::AnyMap& callback_args) { + size_t id = callback_args.find("id")->second.as(); + results[id] = std::move(result); + }, + lastCallback); + size_t req_id = 0; + for (const auto& data : inputData) { + inferAsync(data, {{"id", req_id++}}); } - return ModelBase::inferBatch(inputData); + awaitAll(); + return results; } void ImageModel::inferAsync(const ImageInputData& inputData, const ov::AnyMap& callback_args) { - ModelBase::inferAsync(static_cast(inputData), callback_args); + InferenceInput inputs; + auto internalModelData = this->preprocess(inputData, inputs); + auto callback_args_ptr = std::make_shared(callback_args); + (*callback_args_ptr)["internalModelData"] = std::move(internalModelData); + inferenceAdapter->inferAsync(inputs, callback_args_ptr); } void ImageModel::updateModelInfo() { - ModelBase::updateModelInfo(); + if (!model) { + throw std::runtime_error("The ov::Model object is not accessible"); + } + + if (!inputsLayouts.empty()) { + auto layouts = formatLayouts(inputsLayouts); + model->set_rt_info(layouts, "model_info", "layout"); + } model->set_rt_info(useAutoResize, "model_info", "auto_resize"); model->set_rt_info(formatResizeMode(resizeMode), "model_info", "resize_type"); diff --git a/src/cpp/models/src/model_base.cpp b/src/cpp/models/src/model_base.cpp deleted file mode 100644 index 3e2f817f..00000000 --- a/src/cpp/models/src/model_base.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2020-2024 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "models/model_base.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include "models/input_data.h" -#include "utils/args_helper.hpp" - -namespace { -class TmpCallbackSetter { -public: - ModelBase* model; - std::function, const ov::AnyMap&)> last_callback; - TmpCallbackSetter(ModelBase* model_, - std::function, const ov::AnyMap&)> tmp_callback, - std::function, const ov::AnyMap&)> last_callback_) - : model(model_), - last_callback(last_callback_) { - model->setCallback(tmp_callback); - } - ~TmpCallbackSetter() { - if (last_callback) { - model->setCallback(last_callback); - } else { - model->setCallback([](std::unique_ptr, const ov::AnyMap&) {}); - } - } -}; -} // namespace - -ModelBase::ModelBase(const std::string& modelFile, const std::string& layout) - : modelFile(modelFile), - inputsLayouts(parseLayoutString(layout)) { - auto core = ov::Core(); - model = core.read_model(modelFile); -} - -ModelBase::ModelBase(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : inferenceAdapter(adapter) { - const ov::AnyMap& adapter_configuration = adapter->getModelConfig(); - - std::string layout = ""; - layout = get_from_any_maps("layout", configuration, adapter_configuration, layout); - inputsLayouts = parseLayoutString(layout); - - inputNames = adapter->getInputNames(); - outputNames = adapter->getOutputNames(); -} - -ModelBase::ModelBase(std::shared_ptr& model, const ov::AnyMap& configuration) : model(model) { - auto layout_iter = configuration.find("layout"); - std::string layout = ""; - - if (layout_iter != configuration.end()) { - layout = layout_iter->second.as(); - } else { - if (model->has_rt_info("model_info", "layout")) { - layout = model->get_rt_info("model_info", "layout"); - } - } - inputsLayouts = parseLayoutString(layout); -} - -void ModelBase::updateModelInfo() { - if (!model) { - throw std::runtime_error("The ov::Model object is not accessible"); - } - - if (!inputsLayouts.empty()) { - auto layouts = formatLayouts(inputsLayouts); - model->set_rt_info(layouts, "model_info", "layout"); - } -} - -void ModelBase::load(ov::Core& core, const std::string& device, size_t num_infer_requests) { - if (!inferenceAdapter) { - inferenceAdapter = std::make_shared(); - } - - // Update model_info erased by pre/postprocessing - updateModelInfo(); - - inferenceAdapter->loadModel(model, core, device, {}, num_infer_requests); -} - -std::shared_ptr ModelBase::prepare() { - prepareInputsOutputs(model); - logBasicModelInfo(model); - ov::set_batch(model, 1); - - return model; -} - -ov::Layout ModelBase::getInputLayout(const ov::Output& input) { - ov::Layout layout = ov::layout::get_layout(input); - if (layout.empty()) { - if (inputsLayouts.empty()) { - layout = getLayoutFromShape(input.get_partial_shape()); - slog::warn << "Automatically detected layout '" << layout.to_string() << "' for input '" - << input.get_any_name() << "' will be used." << slog::endl; - } else if (inputsLayouts.size() == 1) { - layout = inputsLayouts.begin()->second; - } else { - layout = inputsLayouts[input.get_any_name()]; - } - } - - return layout; -} - -std::unique_ptr ModelBase::infer(const InputData& inputData) { - InferenceInput inputs; - InferenceResult result; - auto internalModelData = this->preprocess(inputData, inputs); - - result.outputsData = inferenceAdapter->infer(inputs); - result.internalModelData = std::move(internalModelData); - - auto retVal = this->postprocess(result); - *retVal = static_cast(result); - return retVal; -} - -std::vector> ModelBase::inferBatch( - const std::vector>& inputData) { - auto results = std::vector>(inputData.size()); - auto setter = TmpCallbackSetter( - this, - [&](std::unique_ptr result, const ov::AnyMap& callback_args) { - size_t id = callback_args.find("id")->second.as(); - results[id] = std::move(result); - }, - lastCallback); - size_t req_id = 0; - for (const auto& data : inputData) { - inferAsync(data, {{"id", req_id++}}); - } - awaitAll(); - return results; -} - -std::vector> ModelBase::inferBatch(const std::vector& inputData) { - std::vector> inputRefData; - inputRefData.reserve(inputData.size()); - for (const auto& item : inputData) { - inputRefData.push_back(item); - } - return inferBatch(inputRefData); -} - -void ModelBase::inferAsync(const InputData& inputData, const ov::AnyMap& callback_args) { - InferenceInput inputs; - auto internalModelData = this->preprocess(inputData, inputs); - auto callback_args_ptr = std::make_shared(callback_args); - (*callback_args_ptr)["internalModelData"] = std::move(internalModelData); - inferenceAdapter->inferAsync(inputs, callback_args_ptr); -} - -bool ModelBase::isReady() { - return inferenceAdapter->isReady(); -} -void ModelBase::awaitAll() { - inferenceAdapter->awaitAll(); -} -void ModelBase::awaitAny() { - inferenceAdapter->awaitAny(); -} -void ModelBase::setCallback( - std::function, const ov::AnyMap& callback_args)> callback) { - lastCallback = callback; - inferenceAdapter->setCallback([this, callback](ov::InferRequest request, CallbackData args) { - InferenceResult result; - - InferenceOutput output; - for (const auto& item : this->getInferenceAdapter()->getOutputNames()) { - output.emplace(item, request.get_tensor(item)); - } - - result.outputsData = output; - auto model_data_iter = args->find("internalModelData"); - if (model_data_iter != args->end()) { - result.internalModelData = std::move(model_data_iter->second.as>()); - } - auto retVal = this->postprocess(result); - *retVal = static_cast(result); - callback(std::move(retVal), args ? *args : ov::AnyMap()); - }); -} - -size_t ModelBase::getNumAsyncExecutors() const { - return inferenceAdapter->getNumAsyncExecutors(); -} - -std::shared_ptr ModelBase::getModel() { - if (!model) { - throw std::runtime_error(std::string("ov::Model is not accessible for the current model adapter: ") + - typeid(inferenceAdapter).name()); - } - - updateModelInfo(); - return model; -} - -std::shared_ptr ModelBase::getInferenceAdapter() { - if (!inferenceAdapter) { - throw std::runtime_error(std::string("Model wasn't loaded")); - } - - return inferenceAdapter; -} diff --git a/src/cpp/tilers/src/instance_segmentation.cpp b/src/cpp/tilers/src/instance_segmentation.cpp index 7632f229..f53d6c3c 100644 --- a/src/cpp/tilers/src/instance_segmentation.cpp +++ b/src/cpp/tilers/src/instance_segmentation.cpp @@ -18,10 +18,10 @@ namespace { class MaskRCNNModelParamsSetter { public: - std::shared_ptr model; + std::shared_ptr model; bool state; MaskRCNNModel* model_ptr; - MaskRCNNModelParamsSetter(std::shared_ptr model_) : model(model_) { + MaskRCNNModelParamsSetter(std::shared_ptr model_) : model(model_) { model_ptr = static_cast(model.get()); state = model_ptr->postprocess_semantic_masks; model_ptr->postprocess_semantic_masks = false; diff --git a/src/cpp/tilers/src/tiler_base.cpp b/src/cpp/tilers/src/tiler_base.cpp index ecdd26eb..0473d705 100644 --- a/src/cpp/tilers/src/tiler_base.cpp +++ b/src/cpp/tilers/src/tiler_base.cpp @@ -75,7 +75,7 @@ std::unique_ptr TilerBase::predict_sync(const cv::Mat& image, const for (const auto& coord : tile_coords) { auto tile_img = crop_tile(image, coord); - auto tile_prediction = model->infer(ImageInputData(tile_img.clone())); + auto tile_prediction = model->inferImage(ImageInputData(tile_img.clone())); auto tile_result = postprocess_tile(std::move(tile_prediction), coord); tile_results.push_back(std::move(tile_result)); } From 7bc1bbedc8e6d3ace4b6ef12f427188078828444 Mon Sep 17 00:00:00 2001 From: "Hecker, Ronald" Date: Fri, 4 Apr 2025 13:40:18 +0200 Subject: [PATCH 13/38] Fix clang linter --- src/cpp/models/include/models/image_model.h | 2 +- src/cpp/models/src/image_model.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/cpp/models/include/models/image_model.h b/src/cpp/models/include/models/image_model.h index 74b0087a..acec8e26 100644 --- a/src/cpp/models/include/models/image_model.h +++ b/src/cpp/models/include/models/image_model.h @@ -12,9 +12,9 @@ #include "adapters/inference_adapter.h" #include "models/input_data.h" #include "models/results.h" +#include "utils/args_helper.hpp" #include "utils/image_utils.h" #include "utils/ocv_common.hpp" -#include "utils/args_helper.hpp" namespace ov { class InferRequest; diff --git a/src/cpp/models/src/image_model.cpp b/src/cpp/models/src/image_model.cpp index 9ec3fd42..e5a9651b 100644 --- a/src/cpp/models/src/image_model.cpp +++ b/src/cpp/models/src/image_model.cpp @@ -55,7 +55,6 @@ ImageModel::ImageModel(const std::string& modelFile, model = core.read_model(modelFile); } - void ImageModel::load(ov::Core& core, const std::string& device, size_t num_infer_requests) { if (!inferenceAdapter) { inferenceAdapter = std::make_shared(); @@ -146,7 +145,6 @@ std::shared_ptr ImageModel::getInferenceAdapter() { return inferenceAdapter; } - RESIZE_MODE ImageModel::selectResizeMode(const std::string& resize_type) { RESIZE_MODE resize = RESIZE_FILL; if ("crop" == resize_type) { @@ -187,8 +185,7 @@ void ImageModel::init_from_config(const ov::AnyMap& top_priority, const ov::AnyM mean_values = get_from_any_maps("mean_values", top_priority, mid_priority, mean_values); } -ImageModel::ImageModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : model(model) { +ImageModel::ImageModel(std::shared_ptr& model, const ov::AnyMap& configuration) : model(model) { auto layout_iter = configuration.find("layout"); std::string layout = ""; From ccbfcbbd60d3fcca1b83117fd20ff61a3d8c0b45 Mon Sep 17 00:00:00 2001 From: "Hecker, Ronald" Date: Mon, 7 Apr 2025 10:23:03 +0200 Subject: [PATCH 14/38] Rename ImageModel to BaseModel as opposed to ModelBase as it was. So first it was ImageModel: ModelBase. Then ModelBase merged into ImageModel now rename ImageModel to BaseModel --- src/cpp/models/include/models/anomaly_model.h | 4 +- .../models/{image_model.h => base_model.h} | 14 ++-- .../include/models/classification_model.h | 4 +- .../models/include/models/detection_model.h | 4 +- .../include/models/instance_segmentation.h | 4 +- .../include/models/keypoint_detection.h | 4 +- .../include/models/segmentation_model.h | 4 +- src/cpp/models/src/anomaly_model.cpp | 14 ++-- .../src/{image_model.cpp => base_model.cpp} | 76 +++++++++---------- src/cpp/models/src/classification_model.cpp | 12 +-- src/cpp/models/src/detection_model.cpp | 12 +-- src/cpp/models/src/detection_model_ext.cpp | 2 +- src/cpp/models/src/detection_model_ssd.cpp | 2 +- src/cpp/models/src/detection_model_yolo.cpp | 2 +- .../src/detection_model_yolov3_onnx.cpp | 2 +- src/cpp/models/src/instance_segmentation.cpp | 12 +-- src/cpp/models/src/keypoint_detection.cpp | 12 +-- src/cpp/models/src/segmentation_model.cpp | 12 +-- src/cpp/py_bindings/py_base.cpp | 8 +- ...assificaiton.cpp => py_classification.cpp} | 2 +- src/cpp/tilers/include/tilers/detection.h | 2 +- .../include/tilers/instance_segmentation.h | 2 +- .../include/tilers/semantic_segmentation.h | 2 +- src/cpp/tilers/include/tilers/tiler_base.h | 6 +- src/cpp/tilers/src/detection.cpp | 2 +- src/cpp/tilers/src/instance_segmentation.cpp | 6 +- src/cpp/tilers/src/semantic_segmentation.cpp | 2 +- src/cpp/tilers/src/tiler_base.cpp | 6 +- 28 files changed, 115 insertions(+), 119 deletions(-) rename src/cpp/models/include/models/{image_model.h => base_model.h} (91%) rename src/cpp/models/src/{image_model.cpp => base_model.cpp} (81%) rename src/cpp/py_bindings/{py_classificaiton.cpp => py_classification.cpp} (97%) diff --git a/src/cpp/models/include/models/anomaly_model.h b/src/cpp/models/include/models/anomaly_model.h index 9efa0ede..1cc5be22 100644 --- a/src/cpp/models/include/models/anomaly_model.h +++ b/src/cpp/models/include/models/anomaly_model.h @@ -4,7 +4,7 @@ */ #pragma once -#include "models/image_model.h" +#include "models/base_model.h" namespace ov { class Model; @@ -12,7 +12,7 @@ class Model; struct AnomalyResult; struct ImageInputData; -class AnomalyModel : public ImageModel { +class AnomalyModel : public BaseModel { public: AnomalyModel(std::shared_ptr& model, const ov::AnyMap& configuration); AnomalyModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); diff --git a/src/cpp/models/include/models/image_model.h b/src/cpp/models/include/models/base_model.h similarity index 91% rename from src/cpp/models/include/models/image_model.h rename to src/cpp/models/include/models/base_model.h index acec8e26..85131805 100644 --- a/src/cpp/models/include/models/image_model.h +++ b/src/cpp/models/include/models/base_model.h @@ -23,19 +23,19 @@ struct InputData; struct InternalModelData; // ImageModel implements preprocess(), ImageModel's direct or indirect children are expected to implement prostprocess() -class ImageModel { +class BaseModel { public: /// Constructor /// @param modelFile name of model to load /// @param useAutoResize - if true, image is resized by openvino /// @param layout - model input layout - ImageModel(const std::string& modelFile, - const std::string& resize_type, - bool useAutoResize, - const std::string& layout = ""); + BaseModel(const std::string& modelFile, + const std::string& resize_type, + bool useAutoResize, + const std::string& layout = ""); - ImageModel(std::shared_ptr& model, const ov::AnyMap& configuration); - ImageModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); + BaseModel(std::shared_ptr& model, const ov::AnyMap& configuration); + BaseModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); virtual std::shared_ptr preprocess(const InputData& inputData, InferenceInput& input); virtual std::unique_ptr postprocess(InferenceResult& infResult) = 0; diff --git a/src/cpp/models/include/models/classification_model.h b/src/cpp/models/include/models/classification_model.h index 5b1a1be2..88ac03bc 100644 --- a/src/cpp/models/include/models/classification_model.h +++ b/src/cpp/models/include/models/classification_model.h @@ -12,7 +12,7 @@ #include #include -#include "models/image_model.h" +#include "models/base_model.h" namespace ov { class Model; @@ -88,7 +88,7 @@ class ProbabilisticLabelsResolver : public GreedyLabelsResolver { SimpleLabelsGraph label_tree; }; -class ClassificationModel : public ImageModel { +class ClassificationModel : public BaseModel { public: ClassificationModel(std::shared_ptr& model, const ov::AnyMap& configuration); ClassificationModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); diff --git a/src/cpp/models/include/models/detection_model.h b/src/cpp/models/include/models/detection_model.h index 36bd1c8f..16ba8cf8 100644 --- a/src/cpp/models/include/models/detection_model.h +++ b/src/cpp/models/include/models/detection_model.h @@ -7,13 +7,13 @@ #include -#include "models/image_model.h" +#include "models/base_model.h" struct DetectionResult; struct ImageInputData; struct InferenceAdatper; -class DetectionModel : public ImageModel { +class DetectionModel : public BaseModel { public: DetectionModel(std::shared_ptr& model, const ov::AnyMap& configuration); DetectionModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); diff --git a/src/cpp/models/include/models/instance_segmentation.h b/src/cpp/models/include/models/instance_segmentation.h index f88b9f53..c6cadce7 100644 --- a/src/cpp/models/include/models/instance_segmentation.h +++ b/src/cpp/models/include/models/instance_segmentation.h @@ -8,7 +8,7 @@ #include #include -#include "models/image_model.h" +#include "models/base_model.h" namespace ov { class Model; @@ -19,7 +19,7 @@ struct InstanceSegmentationResult; struct ImageInputData; struct SegmentedObject; -class MaskRCNNModel : public ImageModel { +class MaskRCNNModel : public BaseModel { public: MaskRCNNModel(std::shared_ptr& model, const ov::AnyMap& configuration); MaskRCNNModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); diff --git a/src/cpp/models/include/models/keypoint_detection.h b/src/cpp/models/include/models/keypoint_detection.h index 63e4e50f..15d21cba 100644 --- a/src/cpp/models/include/models/keypoint_detection.h +++ b/src/cpp/models/include/models/keypoint_detection.h @@ -8,7 +8,7 @@ #include #include -#include "models/image_model.h" +#include "models/base_model.h" namespace ov { class Model; @@ -18,7 +18,7 @@ struct ResultBase; struct KeypointDetectionResult; struct ImageInputData; -class KeypointDetectionModel : public ImageModel { +class KeypointDetectionModel : public BaseModel { public: KeypointDetectionModel(std::shared_ptr& model, const ov::AnyMap& configuration); KeypointDetectionModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); diff --git a/src/cpp/models/include/models/segmentation_model.h b/src/cpp/models/include/models/segmentation_model.h index ed296e92..922828f7 100644 --- a/src/cpp/models/include/models/segmentation_model.h +++ b/src/cpp/models/include/models/segmentation_model.h @@ -8,7 +8,7 @@ #include #include -#include "models/image_model.h" +#include "models/base_model.h" namespace ov { class Model; @@ -20,7 +20,7 @@ struct ImageResultWithSoftPrediction; struct ImageInputData; struct Contour; -class SegmentationModel : public ImageModel { +class SegmentationModel : public BaseModel { public: SegmentationModel(std::shared_ptr& model, const ov::AnyMap& configuration); SegmentationModel(std::shared_ptr& adapter, const ov::AnyMap& configuration = {}); diff --git a/src/cpp/models/src/anomaly_model.cpp b/src/cpp/models/src/anomaly_model.cpp index 4feadb9f..eeccf08a 100644 --- a/src/cpp/models/src/anomaly_model.cpp +++ b/src/cpp/models/src/anomaly_model.cpp @@ -10,7 +10,7 @@ #include #include -#include "models/image_model.h" +#include "models/base_model.h" #include "models/input_data.h" #include "models/internal_model_data.h" #include "models/results.h" @@ -29,23 +29,23 @@ void AnomalyModel::init_from_config(const ov::AnyMap& top_priority, const ov::An } AnomalyModel::AnomalyModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : ImageModel(model, configuration) { + : BaseModel(model, configuration) { init_from_config(configuration, model->get_rt_info("model_info")); } AnomalyModel::AnomalyModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : ImageModel(adapter, configuration) { + : BaseModel(adapter, configuration) { init_from_config(configuration, adapter->getModelConfig()); } std::unique_ptr AnomalyModel::infer(const ImageInputData& inputData) { - auto result = ImageModel::inferImage(inputData); + auto result = BaseModel::inferImage(inputData); return std::unique_ptr(static_cast(result.release())); } std::vector> AnomalyModel::inferBatch(const std::vector& inputImgs) { - auto results = ImageModel::inferBatchImage(inputImgs); + auto results = BaseModel::inferBatchImage(inputImgs); std::vector> anoResults; anoResults.reserve(results.size()); for (auto& result : results) { @@ -177,7 +177,7 @@ void AnomalyModel::prepareInputsOutputs(std::shared_ptr& model) { const ov::Layout& inputLayout = getInputLayout(input); if (!embedded_processing) { - model = ImageModel::embedProcessing( + model = BaseModel::embedProcessing( model, inputNames[0], inputLayout, @@ -194,7 +194,7 @@ void AnomalyModel::prepareInputsOutputs(std::shared_ptr& model) { } void AnomalyModel::updateModelInfo() { - ImageModel::updateModelInfo(); + BaseModel::updateModelInfo(); model->set_rt_info(AnomalyModel::ModelType, "model_info", "model_type"); model->set_rt_info(task, "model_info", "task"); diff --git a/src/cpp/models/src/image_model.cpp b/src/cpp/models/src/base_model.cpp similarity index 81% rename from src/cpp/models/src/image_model.cpp rename to src/cpp/models/src/base_model.cpp index e5a9651b..6fd83d73 100644 --- a/src/cpp/models/src/image_model.cpp +++ b/src/cpp/models/src/base_model.cpp @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "models/image_model.h" +#include "models/base_model.h" #include #include @@ -24,9 +24,9 @@ namespace { class TmpCallbackSetter { public: - ImageModel* model; + BaseModel* model; std::function, const ov::AnyMap&)> last_callback; - TmpCallbackSetter(ImageModel* model_, + TmpCallbackSetter(BaseModel* model_, std::function, const ov::AnyMap&)> tmp_callback, std::function, const ov::AnyMap&)> last_callback_) : model(model_), @@ -43,10 +43,10 @@ class TmpCallbackSetter { }; } // namespace -ImageModel::ImageModel(const std::string& modelFile, - const std::string& resize_type, - bool useAutoResize, - const std::string& layout) +BaseModel::BaseModel(const std::string& modelFile, + const std::string& resize_type, + bool useAutoResize, + const std::string& layout) : useAutoResize(useAutoResize), resizeMode(selectResizeMode(resize_type)), modelFile(modelFile), @@ -55,7 +55,7 @@ ImageModel::ImageModel(const std::string& modelFile, model = core.read_model(modelFile); } -void ImageModel::load(ov::Core& core, const std::string& device, size_t num_infer_requests) { +void BaseModel::load(ov::Core& core, const std::string& device, size_t num_infer_requests) { if (!inferenceAdapter) { inferenceAdapter = std::make_shared(); } @@ -66,7 +66,7 @@ void ImageModel::load(ov::Core& core, const std::string& device, size_t num_infe inferenceAdapter->loadModel(model, core, device, {}, num_infer_requests); } -std::shared_ptr ImageModel::prepare() { +std::shared_ptr BaseModel::prepare() { prepareInputsOutputs(model); logBasicModelInfo(model); ov::set_batch(model, 1); @@ -74,7 +74,7 @@ std::shared_ptr ImageModel::prepare() { return model; } -ov::Layout ImageModel::getInputLayout(const ov::Output& input) { +ov::Layout BaseModel::getInputLayout(const ov::Output& input) { ov::Layout layout = ov::layout::get_layout(input); if (layout.empty()) { if (inputsLayouts.empty()) { @@ -91,21 +91,21 @@ ov::Layout ImageModel::getInputLayout(const ov::Output& input) { return layout; } -size_t ImageModel::getNumAsyncExecutors() const { +size_t BaseModel::getNumAsyncExecutors() const { return inferenceAdapter->getNumAsyncExecutors(); } -bool ImageModel::isReady() { +bool BaseModel::isReady() { return inferenceAdapter->isReady(); } -void ImageModel::awaitAll() { +void BaseModel::awaitAll() { inferenceAdapter->awaitAll(); } -void ImageModel::awaitAny() { +void BaseModel::awaitAny() { inferenceAdapter->awaitAny(); } -void ImageModel::setCallback( +void BaseModel::setCallback( std::function, const ov::AnyMap& callback_args)> callback) { lastCallback = callback; inferenceAdapter->setCallback([this, callback](ov::InferRequest request, CallbackData args) { @@ -127,7 +127,7 @@ void ImageModel::setCallback( }); } -std::shared_ptr ImageModel::getModel() { +std::shared_ptr BaseModel::getModel() { if (!model) { throw std::runtime_error(std::string("ov::Model is not accessible for the current model adapter: ") + typeid(inferenceAdapter).name()); @@ -137,7 +137,7 @@ std::shared_ptr ImageModel::getModel() { return model; } -std::shared_ptr ImageModel::getInferenceAdapter() { +std::shared_ptr BaseModel::getInferenceAdapter() { if (!inferenceAdapter) { throw std::runtime_error(std::string("Model wasn't loaded")); } @@ -145,7 +145,7 @@ std::shared_ptr ImageModel::getInferenceAdapter() { return inferenceAdapter; } -RESIZE_MODE ImageModel::selectResizeMode(const std::string& resize_type) { +RESIZE_MODE BaseModel::selectResizeMode(const std::string& resize_type) { RESIZE_MODE resize = RESIZE_FILL; if ("crop" == resize_type) { resize = RESIZE_CROP; @@ -162,7 +162,7 @@ RESIZE_MODE ImageModel::selectResizeMode(const std::string& resize_type) { return resize; } -void ImageModel::init_from_config(const ov::AnyMap& top_priority, const ov::AnyMap& mid_priority) { +void BaseModel::init_from_config(const ov::AnyMap& top_priority, const ov::AnyMap& mid_priority) { useAutoResize = get_from_any_maps("auto_resize", top_priority, mid_priority, useAutoResize); std::string resize_type = "standard"; @@ -185,7 +185,7 @@ void ImageModel::init_from_config(const ov::AnyMap& top_priority, const ov::AnyM mean_values = get_from_any_maps("mean_values", top_priority, mid_priority, mean_values); } -ImageModel::ImageModel(std::shared_ptr& model, const ov::AnyMap& configuration) : model(model) { +BaseModel::BaseModel(std::shared_ptr& model, const ov::AnyMap& configuration) : model(model) { auto layout_iter = configuration.find("layout"); std::string layout = ""; @@ -201,7 +201,7 @@ ImageModel::ImageModel(std::shared_ptr& model, const ov::AnyMap& conf model->has_rt_info("model_info") ? model->get_rt_info("model_info") : ov::AnyMap{}); } -ImageModel::ImageModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) +BaseModel::BaseModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) : inferenceAdapter(adapter) { const ov::AnyMap& adapter_configuration = adapter->getModelConfig(); @@ -215,7 +215,7 @@ ImageModel::ImageModel(std::shared_ptr& adapter, const ov::Any init_from_config(configuration, adapter->getModelConfig()); } -std::unique_ptr ImageModel::inferImage(const ImageInputData& inputData) { +std::unique_ptr BaseModel::inferImage(const ImageInputData& inputData) { InferenceInput inputs; InferenceResult result; auto internalModelData = this->preprocess(inputData, inputs); @@ -228,7 +228,7 @@ std::unique_ptr ImageModel::inferImage(const ImageInputData& inputDa return retVal; } -std::vector> ImageModel::inferBatchImage(const std::vector& inputImgs) { +std::vector> BaseModel::inferBatchImage(const std::vector& inputImgs) { std::vector> inputData; inputData.reserve(inputImgs.size()); for (const auto& img : inputImgs) { @@ -250,7 +250,7 @@ std::vector> ImageModel::inferBatchImage(const std:: return results; } -void ImageModel::inferAsync(const ImageInputData& inputData, const ov::AnyMap& callback_args) { +void BaseModel::inferAsync(const ImageInputData& inputData, const ov::AnyMap& callback_args) { InferenceInput inputs; auto internalModelData = this->preprocess(inputData, inputs); auto callback_args_ptr = std::make_shared(callback_args); @@ -258,7 +258,7 @@ void ImageModel::inferAsync(const ImageInputData& inputData, const ov::AnyMap& c inferenceAdapter->inferAsync(inputs, callback_args_ptr); } -void ImageModel::updateModelInfo() { +void BaseModel::updateModelInfo() { if (!model) { throw std::runtime_error("The ov::Model object is not accessible"); } @@ -280,17 +280,17 @@ void ImageModel::updateModelInfo() { model->set_rt_info(netInputHeight, "model_info", "orig_height"); } -std::shared_ptr ImageModel::embedProcessing(std::shared_ptr& model, - const std::string& inputName, - const ov::Layout& layout, - const RESIZE_MODE resize_mode, - const cv::InterpolationFlags interpolationMode, - const ov::Shape& targetShape, - uint8_t pad_value, - bool brg2rgb, - const std::vector& mean, - const std::vector& scale, - const std::type_info& dtype) { +std::shared_ptr BaseModel::embedProcessing(std::shared_ptr& model, + const std::string& inputName, + const ov::Layout& layout, + const RESIZE_MODE resize_mode, + const cv::InterpolationFlags interpolationMode, + const ov::Shape& targetShape, + uint8_t pad_value, + bool brg2rgb, + const std::vector& mean, + const std::vector& scale, + const std::type_info& dtype) { ov::preprocess::PrePostProcessor ppp(model); // Change the input type to the 8-bit image @@ -326,7 +326,7 @@ std::shared_ptr ImageModel::embedProcessing(std::shared_ptr ImageModel::preprocess(const InputData& inputData, InferenceInput& input) { +std::shared_ptr BaseModel::preprocess(const InputData& inputData, InferenceInput& input) { const auto& origImg = inputData.asRef().inputImage; auto img = inputTransform(origImg); @@ -351,7 +351,7 @@ std::shared_ptr ImageModel::preprocess(const InputData& input return std::make_shared(origImg.cols, origImg.rows); } -std::vector ImageModel::loadLabels(const std::string& labelFilename) { +std::vector BaseModel::loadLabels(const std::string& labelFilename) { std::vector labelsList; /* Read labels (if any) */ diff --git a/src/cpp/models/src/classification_model.cpp b/src/cpp/models/src/classification_model.cpp index 207c7a62..a9d281e1 100644 --- a/src/cpp/models/src/classification_model.cpp +++ b/src/cpp/models/src/classification_model.cpp @@ -221,20 +221,20 @@ void ClassificationModel::init_from_config(const ov::AnyMap& top_priority, const } ClassificationModel::ClassificationModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : ImageModel(model, configuration) { + : BaseModel(model, configuration) { init_from_config(configuration, model->has_rt_info("model_info") ? model->get_rt_info("model_info") : ov::AnyMap{}); } ClassificationModel::ClassificationModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : ImageModel(adapter, configuration) { + : BaseModel(adapter, configuration) { outputNames = get_non_xai_names(adapter->getOutputNames()); append_xai_names(adapter->getOutputNames(), outputNames); init_from_config(configuration, adapter->getModelConfig()); } void ClassificationModel::updateModelInfo() { - ImageModel::updateModelInfo(); + BaseModel::updateModelInfo(); model->set_rt_info(ClassificationModel::ModelType, "model_info", "model_type"); model->set_rt_info(topk, "model_info", "topk"); @@ -468,7 +468,7 @@ void ClassificationModel::prepareInputsOutputs(std::shared_ptr& model const ov::Layout& inputLayout = getInputLayout(input); if (!embedded_processing) { - model = ImageModel::embedProcessing( + model = BaseModel::embedProcessing( model, inputNames[0], inputLayout, @@ -536,13 +536,13 @@ void ClassificationModel::prepareInputsOutputs(std::shared_ptr& model } std::unique_ptr ClassificationModel::infer(const ImageInputData& inputData) { - auto result = ImageModel::inferImage(inputData); + auto result = BaseModel::inferImage(inputData); return std::unique_ptr(static_cast(result.release())); } std::vector> ClassificationModel::inferBatch( const std::vector& inputImgs) { - auto results = ImageModel::inferBatchImage(inputImgs); + auto results = BaseModel::inferBatchImage(inputImgs); std::vector> clsResults; clsResults.reserve(results.size()); for (auto& result : results) { diff --git a/src/cpp/models/src/detection_model.cpp b/src/cpp/models/src/detection_model.cpp index 963760d6..6b55eeba 100644 --- a/src/cpp/models/src/detection_model.cpp +++ b/src/cpp/models/src/detection_model.cpp @@ -10,17 +10,17 @@ #include #include +#include "models/base_model.h" #include "models/detection_model_ssd.h" #include "models/detection_model_yolo.h" #include "models/detection_model_yolov3_onnx.h" #include "models/detection_model_yolox.h" -#include "models/image_model.h" #include "models/input_data.h" #include "models/results.h" #include "utils/slog.hpp" DetectionModel::DetectionModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : ImageModel(model, configuration) { + : BaseModel(model, configuration) { auto confidence_threshold_iter = configuration.find("confidence_threshold"); if (confidence_threshold_iter == configuration.end()) { if (model->has_rt_info("model_info", "confidence_threshold")) { @@ -32,13 +32,13 @@ DetectionModel::DetectionModel(std::shared_ptr& model, const ov::AnyM } DetectionModel::DetectionModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : ImageModel(adapter, configuration) { + : BaseModel(adapter, configuration) { confidence_threshold = get_from_any_maps("confidence_threshold", configuration, adapter->getModelConfig(), confidence_threshold); } void DetectionModel::updateModelInfo() { - ImageModel::updateModelInfo(); + BaseModel::updateModelInfo(); model->set_rt_info(confidence_threshold, "model_info", "confidence_threshold"); } @@ -103,12 +103,12 @@ std::unique_ptr DetectionModel::create_model(std::shared_ptr DetectionModel::infer(const ImageInputData& inputData) { - auto result = ImageModel::inferImage(inputData); + auto result = BaseModel::inferImage(inputData); return std::unique_ptr(static_cast(result.release())); } std::vector> DetectionModel::inferBatch(const std::vector& inputImgs) { - auto results = ImageModel::inferBatchImage(inputImgs); + auto results = BaseModel::inferBatchImage(inputImgs); std::vector> detResults; detResults.reserve(results.size()); for (auto& result : results) { diff --git a/src/cpp/models/src/detection_model_ext.cpp b/src/cpp/models/src/detection_model_ext.cpp index 134d2a9c..d1084820 100644 --- a/src/cpp/models/src/detection_model_ext.cpp +++ b/src/cpp/models/src/detection_model_ext.cpp @@ -9,7 +9,7 @@ #include #include -#include "models/image_model.h" +#include "models/base_model.h" #include "models/input_data.h" #include "models/results.h" diff --git a/src/cpp/models/src/detection_model_ssd.cpp b/src/cpp/models/src/detection_model_ssd.cpp index 20ed396a..f6f7c818 100644 --- a/src/cpp/models/src/detection_model_ssd.cpp +++ b/src/cpp/models/src/detection_model_ssd.cpp @@ -251,7 +251,7 @@ void ModelSSD::prepareInputsOutputs(std::shared_ptr& model) { } if (!embedded_processing) { - model = ImageModel::embedProcessing( + model = BaseModel::embedProcessing( model, inputNames[0], inputLayout, diff --git a/src/cpp/models/src/detection_model_yolo.cpp b/src/cpp/models/src/detection_model_yolo.cpp index d43e903c..1698b8e6 100644 --- a/src/cpp/models/src/detection_model_yolo.cpp +++ b/src/cpp/models/src/detection_model_yolo.cpp @@ -505,7 +505,7 @@ void YOLOv5::prepareInputsOutputs(std::shared_ptr& model) { inputNames.push_back(input.get_any_name()); const ov::Layout& inputLayout = getInputLayout(input); if (!embedded_processing) { - model = ImageModel::embedProcessing( + model = BaseModel::embedProcessing( model, inputNames[0], inputLayout, diff --git a/src/cpp/models/src/detection_model_yolov3_onnx.cpp b/src/cpp/models/src/detection_model_yolov3_onnx.cpp index d7974f41..68830220 100644 --- a/src/cpp/models/src/detection_model_yolov3_onnx.cpp +++ b/src/cpp/models/src/detection_model_yolov3_onnx.cpp @@ -103,7 +103,7 @@ std::shared_ptr ModelYoloV3ONNX::preprocess(const InputData& data[0] = origImg.rows; data[1] = origImg.cols; input.emplace(inputNames[1], std::move(info)); - return ImageModel::preprocess(inputData, input); + return BaseModel::preprocess(inputData, input); } namespace { diff --git a/src/cpp/models/src/instance_segmentation.cpp b/src/cpp/models/src/instance_segmentation.cpp index 2b20e806..384fb057 100644 --- a/src/cpp/models/src/instance_segmentation.cpp +++ b/src/cpp/models/src/instance_segmentation.cpp @@ -143,13 +143,13 @@ void MaskRCNNModel::init_from_config(const ov::AnyMap& top_priority, const ov::A } MaskRCNNModel::MaskRCNNModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : ImageModel(model, configuration) { + : BaseModel(model, configuration) { init_from_config(configuration, model->has_rt_info("model_info") ? model->get_rt_info("model_info") : ov::AnyMap{}); } MaskRCNNModel::MaskRCNNModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : ImageModel(adapter, configuration) { + : BaseModel(adapter, configuration) { init_from_config(configuration, adapter->getModelConfig()); } @@ -201,7 +201,7 @@ std::unique_ptr MaskRCNNModel::create_model(std::shared_ptrset_rt_info(MaskRCNNModel::ModelType, "model_info", "model_type"); model->set_rt_info(confidence_threshold, "model_info", "confidence_threshold"); @@ -224,7 +224,7 @@ void MaskRCNNModel::prepareInputsOutputs(std::shared_ptr& model) { } if (!embedded_processing) { - model = ImageModel::embedProcessing( + model = BaseModel::embedProcessing( model, inputNames[0], inputLayout, @@ -359,13 +359,13 @@ std::unique_ptr MaskRCNNModel::postprocess(InferenceResult& infResul } std::unique_ptr MaskRCNNModel::infer(const ImageInputData& inputData) { - auto result = ImageModel::inferImage(inputData); + auto result = BaseModel::inferImage(inputData); return std::unique_ptr(static_cast(result.release())); } std::vector> MaskRCNNModel::inferBatch( const std::vector& inputImgs) { - auto results = ImageModel::inferBatchImage(inputImgs); + auto results = BaseModel::inferBatchImage(inputImgs); std::vector> isegResults; isegResults.reserve(results.size()); for (auto& result : results) { diff --git a/src/cpp/models/src/keypoint_detection.cpp b/src/cpp/models/src/keypoint_detection.cpp index af438bad..4fbe778c 100644 --- a/src/cpp/models/src/keypoint_detection.cpp +++ b/src/cpp/models/src/keypoint_detection.cpp @@ -96,14 +96,14 @@ void KeypointDetectionModel::init_from_config(const ov::AnyMap& top_priority, co } KeypointDetectionModel::KeypointDetectionModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : ImageModel(model, configuration) { + : BaseModel(model, configuration) { init_from_config(configuration, model->has_rt_info("model_info") ? model->get_rt_info("model_info") : ov::AnyMap{}); } KeypointDetectionModel::KeypointDetectionModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : ImageModel(adapter, configuration) { + : BaseModel(adapter, configuration) { init_from_config(configuration, adapter->getModelConfig()); } @@ -156,7 +156,7 @@ std::unique_ptr KeypointDetectionModel::create_model( } void KeypointDetectionModel::updateModelInfo() { - ImageModel::updateModelInfo(); + BaseModel::updateModelInfo(); model->set_rt_info(KeypointDetectionModel::ModelType, "model_info", "model_type"); model->set_rt_info(labels, "model_info", "labels"); @@ -182,7 +182,7 @@ void KeypointDetectionModel::prepareInputsOutputs(std::shared_ptr& mo } if (!embedded_processing) { - model = ImageModel::embedProcessing( + model = BaseModel::embedProcessing( model, inputNames[0], inputLayout, @@ -250,13 +250,13 @@ std::unique_ptr KeypointDetectionModel::postprocess(InferenceResult& } std::unique_ptr KeypointDetectionModel::infer(const ImageInputData& inputData) { - auto result = ImageModel::inferImage(inputData); + auto result = BaseModel::inferImage(inputData); return std::unique_ptr(static_cast(result.release())); } std::vector> KeypointDetectionModel::inferBatch( const std::vector& inputImgs) { - auto results = ImageModel::inferBatchImage(inputImgs); + auto results = BaseModel::inferBatchImage(inputImgs); std::vector> kpDetResults; kpDetResults.reserve(results.size()); for (auto& result : results) { diff --git a/src/cpp/models/src/segmentation_model.cpp b/src/cpp/models/src/segmentation_model.cpp index 25fae273..deea1c87 100644 --- a/src/cpp/models/src/segmentation_model.cpp +++ b/src/cpp/models/src/segmentation_model.cpp @@ -81,13 +81,13 @@ void SegmentationModel::init_from_config(const ov::AnyMap& top_priority, const o } SegmentationModel::SegmentationModel(std::shared_ptr& model, const ov::AnyMap& configuration) - : ImageModel(model, configuration) { + : BaseModel(model, configuration) { init_from_config(configuration, model->has_rt_info("model_info") ? model->get_rt_info("model_info") : ov::AnyMap{}); } SegmentationModel::SegmentationModel(std::shared_ptr& adapter, const ov::AnyMap& configuration) - : ImageModel(adapter, configuration) { + : BaseModel(adapter, configuration) { init_from_config(configuration, adapter->getModelConfig()); } @@ -139,7 +139,7 @@ std::unique_ptr SegmentationModel::create_model(std::shared_p } void SegmentationModel::updateModelInfo() { - ImageModel::updateModelInfo(); + BaseModel::updateModelInfo(); model->set_rt_info(SegmentationModel::ModelType, "model_info", "model_type"); model->set_rt_info(blur_strength, "model_info", "blur_strength"); @@ -182,7 +182,7 @@ void SegmentationModel::prepareInputsOutputs(std::shared_ptr& model) } if (!embedded_processing) { - model = ImageModel::embedProcessing( + model = BaseModel::embedProcessing( model, inputNames[0], inputLayout, @@ -316,12 +316,12 @@ std::vector SegmentationModel::getContours(const ImageResultWithSoftPre } std::unique_ptr SegmentationModel::infer(const ImageInputData& inputData) { - auto result = ImageModel::inferImage(inputData); + auto result = BaseModel::inferImage(inputData); return std::unique_ptr(static_cast(result.release())); } std::vector> SegmentationModel::inferBatch(const std::vector& inputImgs) { - auto results = ImageModel::inferBatchImage(inputImgs); + auto results = BaseModel::inferBatchImage(inputImgs); std::vector> segResults; segResults.reserve(results.size()); for (auto& result : results) { diff --git a/src/cpp/py_bindings/py_base.cpp b/src/cpp/py_bindings/py_base.cpp index e257991d..ecc5e4c7 100644 --- a/src/cpp/py_bindings/py_base.cpp +++ b/src/cpp/py_bindings/py_base.cpp @@ -8,7 +8,7 @@ #include -#include "models/image_model.h" +#include "models/base_model.h" #include "models/results.h" namespace nb = nanobind; @@ -16,11 +16,9 @@ namespace nb = nanobind; void init_base_modules(nb::module_& m) { nb::class_(m, "ResultBase").def(nb::init<>()); - nb::class_(m, "ModelBase") - .def("load", [](ModelBase& self, const std::string& device, size_t num_infer_requests) { + nb::class_(m, "BaseModel") + .def("load", [](BaseModel& self, const std::string& device, size_t num_infer_requests) { auto core = ov::Core(); self.load(core, device, num_infer_requests); }); - - nb::class_(m, "ImageModel"); } diff --git a/src/cpp/py_bindings/py_classificaiton.cpp b/src/cpp/py_bindings/py_classification.cpp similarity index 97% rename from src/cpp/py_bindings/py_classificaiton.cpp rename to src/cpp/py_bindings/py_classification.cpp index 19e2b4eb..d01d84f0 100644 --- a/src/cpp/py_bindings/py_classificaiton.cpp +++ b/src/cpp/py_bindings/py_classification.cpp @@ -52,7 +52,7 @@ void init_classification(nb::module_& m) { }, nb::rv_policy::reference_internal); - nb::class_(m, "ClassificationModel") + nb::class_(m, "ClassificationModel") .def_static( "create_model", [](const std::string& model_path, diff --git a/src/cpp/tilers/include/tilers/detection.h b/src/cpp/tilers/include/tilers/detection.h index 28fc14aa..8fde112b 100644 --- a/src/cpp/tilers/include/tilers/detection.h +++ b/src/cpp/tilers/include/tilers/detection.h @@ -10,7 +10,7 @@ struct DetectionResult; class DetectionTiler : public TilerBase { public: - DetectionTiler(const std::shared_ptr& model, + DetectionTiler(const std::shared_ptr& model, const ov::AnyMap& configuration, ExecutionMode exec_mode = ExecutionMode::sync); virtual ~DetectionTiler() = default; diff --git a/src/cpp/tilers/include/tilers/instance_segmentation.h b/src/cpp/tilers/include/tilers/instance_segmentation.h index 75c00f2c..3ca20dcb 100644 --- a/src/cpp/tilers/include/tilers/instance_segmentation.h +++ b/src/cpp/tilers/include/tilers/instance_segmentation.h @@ -11,7 +11,7 @@ struct InstanceSegmentationResult; class InstanceSegmentationTiler : public TilerBase { /*InstanceSegmentationTiler tiler works with MaskRCNNModel model only*/ public: - InstanceSegmentationTiler(std::shared_ptr model, + InstanceSegmentationTiler(std::shared_ptr model, const ov::AnyMap& configuration, ExecutionMode exec_mode = ExecutionMode::sync); virtual std::unique_ptr run(const ImageInputData& inputData); diff --git a/src/cpp/tilers/include/tilers/semantic_segmentation.h b/src/cpp/tilers/include/tilers/semantic_segmentation.h index 5e0966d9..4c9b9d1d 100644 --- a/src/cpp/tilers/include/tilers/semantic_segmentation.h +++ b/src/cpp/tilers/include/tilers/semantic_segmentation.h @@ -11,7 +11,7 @@ struct ImageResultWithSoftPrediction; class SemanticSegmentationTiler : public TilerBase { public: - SemanticSegmentationTiler(std::shared_ptr model, + SemanticSegmentationTiler(std::shared_ptr model, const ov::AnyMap& configuration, ExecutionMode exec_mode = ExecutionMode::sync); virtual std::unique_ptr run(const ImageInputData& inputData); diff --git a/src/cpp/tilers/include/tilers/tiler_base.h b/src/cpp/tilers/include/tilers/tiler_base.h index fcebaf7b..3fb45d1e 100644 --- a/src/cpp/tilers/include/tilers/tiler_base.h +++ b/src/cpp/tilers/include/tilers/tiler_base.h @@ -4,7 +4,7 @@ */ #pragma once -#include +#include #include #include @@ -20,7 +20,7 @@ enum class ExecutionMode { sync, async }; class TilerBase { public: - TilerBase(const std::shared_ptr& model, + TilerBase(const std::shared_ptr& model, const ov::AnyMap& configuration, ExecutionMode exec_mode = ExecutionMode::sync); @@ -38,7 +38,7 @@ class TilerBase { const cv::Size&, const std::vector&) = 0; - std::shared_ptr model; + std::shared_ptr model; size_t tile_size = 400; float tiles_overlap = 0.5f; float iou_threshold = 0.45f; diff --git a/src/cpp/tilers/src/detection.cpp b/src/cpp/tilers/src/detection.cpp index 71f65ab8..ec248664 100644 --- a/src/cpp/tilers/src/detection.cpp +++ b/src/cpp/tilers/src/detection.cpp @@ -27,7 +27,7 @@ cv::Mat non_linear_normalization(cv::Mat& class_map) { } // namespace -DetectionTiler::DetectionTiler(const std::shared_ptr& _model, +DetectionTiler::DetectionTiler(const std::shared_ptr& _model, const ov::AnyMap& configuration, ExecutionMode exec_mode) : TilerBase(_model, configuration, exec_mode) { diff --git a/src/cpp/tilers/src/instance_segmentation.cpp b/src/cpp/tilers/src/instance_segmentation.cpp index f53d6c3c..211a4761 100644 --- a/src/cpp/tilers/src/instance_segmentation.cpp +++ b/src/cpp/tilers/src/instance_segmentation.cpp @@ -18,10 +18,10 @@ namespace { class MaskRCNNModelParamsSetter { public: - std::shared_ptr model; + std::shared_ptr model; bool state; MaskRCNNModel* model_ptr; - MaskRCNNModelParamsSetter(std::shared_ptr model_) : model(model_) { + MaskRCNNModelParamsSetter(std::shared_ptr model_) : model(model_) { model_ptr = static_cast(model.get()); state = model_ptr->postprocess_semantic_masks; model_ptr->postprocess_semantic_masks = false; @@ -32,7 +32,7 @@ class MaskRCNNModelParamsSetter { }; } // namespace -InstanceSegmentationTiler::InstanceSegmentationTiler(std::shared_ptr _model, +InstanceSegmentationTiler::InstanceSegmentationTiler(std::shared_ptr _model, const ov::AnyMap& configuration, ExecutionMode exec_mode) : TilerBase(_model, configuration, exec_mode) { diff --git a/src/cpp/tilers/src/semantic_segmentation.cpp b/src/cpp/tilers/src/semantic_segmentation.cpp index b98a7d6f..6a8efc89 100644 --- a/src/cpp/tilers/src/semantic_segmentation.cpp +++ b/src/cpp/tilers/src/semantic_segmentation.cpp @@ -32,7 +32,7 @@ void normalize_soft_prediction(cv::Mat& soft_prediction, const cv::Mat& normaliz } } // namespace -SemanticSegmentationTiler::SemanticSegmentationTiler(std::shared_ptr _model, +SemanticSegmentationTiler::SemanticSegmentationTiler(std::shared_ptr _model, const ov::AnyMap& configuration, ExecutionMode exec_mode) : TilerBase(_model, configuration, exec_mode) { diff --git a/src/cpp/tilers/src/tiler_base.cpp b/src/cpp/tilers/src/tiler_base.cpp index 0473d705..6d979dea 100644 --- a/src/cpp/tilers/src/tiler_base.cpp +++ b/src/cpp/tilers/src/tiler_base.cpp @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include #include @@ -11,9 +11,7 @@ #include #include -TilerBase::TilerBase(const std::shared_ptr& _model, - const ov::AnyMap& configuration, - ExecutionMode exec_mode) +TilerBase::TilerBase(const std::shared_ptr& _model, const ov::AnyMap& configuration, ExecutionMode exec_mode) : model(_model), run_mode(exec_mode) { ov::AnyMap extra_config; From 312a2dc82bb1a0a1c7d5c8237b85eda968152fa7 Mon Sep 17 00:00:00 2001 From: "Hecker, Ronald" Date: Thu, 10 Apr 2025 12:51:01 +0200 Subject: [PATCH 15/38] Python binding compilation test area --- src/cpp/CMakeLists.txt | 8 ++--- src/cpp/py_bindings/CMakeLists.txt | 29 ++++++++++++------- src/cpp/py_bindings/README.md | 1 + src/cpp/py_bindings/pyproject.toml | 21 ++++++++++++++ src/cpp/py_bindings/{ => src}/py_base.cpp | 0 .../{ => src}/py_classification.cpp | 0 src/cpp/py_bindings/{ => src}/py_utils.cpp | 0 src/cpp/py_bindings/{ => src}/py_utils.hpp | 0 .../py_bindings/{ => src}/py_vision_api.cpp | 0 .../py_bindings/src/vision_api/__init__.py | 3 ++ 10 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 src/cpp/py_bindings/README.md create mode 100644 src/cpp/py_bindings/pyproject.toml rename src/cpp/py_bindings/{ => src}/py_base.cpp (100%) rename src/cpp/py_bindings/{ => src}/py_classification.cpp (100%) rename src/cpp/py_bindings/{ => src}/py_utils.cpp (100%) rename src/cpp/py_bindings/{ => src}/py_utils.hpp (100%) rename src/cpp/py_bindings/{ => src}/py_vision_api.cpp (100%) create mode 100644 src/cpp/py_bindings/src/vision_api/__init__.py diff --git a/src/cpp/CMakeLists.txt b/src/cpp/CMakeLists.txt index 192e145f..0bcc2721 100644 --- a/src/cpp/CMakeLists.txt +++ b/src/cpp/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.26) -option(ENABLE_PY_BINDINGS "Enables building python bindings package" ON) +# option(ENABLE_PY_BINDINGS "Enables building python bindings package" ON) # Multi config generators such as Visual Studio ignore CMAKE_BUILD_TYPE. Multi config generators are configured with # CMAKE_CONFIGURATION_TYPES, but limiting options in it completely removes such build options @@ -77,9 +77,9 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "^GNU|(Apple)?Clang$") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() -if (ENABLE_PY_BINDINGS) - add_subdirectory(py_bindings) -endif() +#if (ENABLE_PY_BINDINGS) +# add_subdirectory(py_bindings) +#endif() include(GenerateExportHeader) diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index b955b8c4..9dd0e11c 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -2,7 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 # +cmake_minimum_required(VERSION 3.26) + +add_subdirectory(../ model_api/cpp) + set(Python_FIND_VIRTUALENV FIRST) +project(vision_api LANGUAGES CXX) find_package(Python COMPONENTS Interpreter Development REQUIRED) execute_process( @@ -11,17 +16,19 @@ execute_process( find_package(nanobind CONFIG REQUIRED) -file(GLOB BINDINGS_SOURCES ./*.cpp) -file(GLOB BINDINGS_HEADERS ./*.hpp) +file(GLOB BINDINGS_SOURCES ./src/*.cpp) +file(GLOB BINDINGS_HEADERS ./src/*.hpp) + +nanobind_add_module(vision_api_impl NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) -nanobind_add_module(py_model_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) +target_link_libraries(vision_api_impl PRIVATE model_api) -target_link_libraries(py_model_api PRIVATE model_api) +install(TARGETS vision_api_impl LIBRARY DESTINATION vision_api) -nanobind_add_stub( - py_model_api_stub - MODULE py_model_api - OUTPUT py_model_api.pyi - PYTHON_PATH $ - DEPENDS py_model_api -) +# nanobind_add_stub( +# py_model_api_stub +# MODULE vision_sdk +# OUTPUT py_model_api.pyi +# PYTHON_PATH $ +# DEPENDS py_model_api +# ) diff --git a/src/cpp/py_bindings/README.md b/src/cpp/py_bindings/README.md new file mode 100644 index 00000000..3a7fa133 --- /dev/null +++ b/src/cpp/py_bindings/README.md @@ -0,0 +1 @@ +# Vision SDK diff --git a/src/cpp/py_bindings/pyproject.toml b/src/cpp/py_bindings/pyproject.toml new file mode 100644 index 00000000..1952f829 --- /dev/null +++ b/src/cpp/py_bindings/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +requires = ["scikit-build-core >=0.4.3", "nanobind >=1.3.2"] +build-backend = "scikit_build_core.build" + +[project] +name = "py_model_api" +version = "0.0.1" +description = "set of wrapper classes for particular tasks and model architectures, simplifying data preprocess and postprocess as well as routine procedures" +readme = "README.md" +requires-python = ">=3.8" +authors = [ + { name = "Ronald Hecker", email = "ronald.hecker@intel.com" }, +] +classifiers = [ + "License :: BSD", +] +# Optional: runtime dependency specification +# dependencies = [ "cryptography >=41.0" ] + +[project.urls] +Homepage = "https://github.com/open-edge-platform/model_api" diff --git a/src/cpp/py_bindings/py_base.cpp b/src/cpp/py_bindings/src/py_base.cpp similarity index 100% rename from src/cpp/py_bindings/py_base.cpp rename to src/cpp/py_bindings/src/py_base.cpp diff --git a/src/cpp/py_bindings/py_classification.cpp b/src/cpp/py_bindings/src/py_classification.cpp similarity index 100% rename from src/cpp/py_bindings/py_classification.cpp rename to src/cpp/py_bindings/src/py_classification.cpp diff --git a/src/cpp/py_bindings/py_utils.cpp b/src/cpp/py_bindings/src/py_utils.cpp similarity index 100% rename from src/cpp/py_bindings/py_utils.cpp rename to src/cpp/py_bindings/src/py_utils.cpp diff --git a/src/cpp/py_bindings/py_utils.hpp b/src/cpp/py_bindings/src/py_utils.hpp similarity index 100% rename from src/cpp/py_bindings/py_utils.hpp rename to src/cpp/py_bindings/src/py_utils.hpp diff --git a/src/cpp/py_bindings/py_vision_api.cpp b/src/cpp/py_bindings/src/py_vision_api.cpp similarity index 100% rename from src/cpp/py_bindings/py_vision_api.cpp rename to src/cpp/py_bindings/src/py_vision_api.cpp diff --git a/src/cpp/py_bindings/src/vision_api/__init__.py b/src/cpp/py_bindings/src/vision_api/__init__.py new file mode 100644 index 00000000..50ba095a --- /dev/null +++ b/src/cpp/py_bindings/src/vision_api/__init__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 + +from ._my_ext_impl import hello From fb07cb5ff295d4be37ebb058307242d58632711b Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Thu, 10 Apr 2025 15:48:35 +0200 Subject: [PATCH 16/38] Working with openvino from python package. OpenCV is using system opencv though... --- src/cpp/py_bindings/CMakeLists.txt | 17 +++++++++++------ src/cpp/py_bindings/pyproject.toml | 10 +++++++++- src/cpp/py_bindings/scratch.py | 18 ++++++++++++++++++ src/cpp/py_bindings/src/vision_api/__init__.py | 6 +++++- .../src/{ => vision_api}/py_base.cpp | 0 .../src/{ => vision_api}/py_classification.cpp | 0 .../src/{ => vision_api}/py_utils.cpp | 0 .../src/{ => vision_api}/py_utils.hpp | 0 .../src/{ => vision_api}/py_vision_api.cpp | 2 +- 9 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 src/cpp/py_bindings/scratch.py rename src/cpp/py_bindings/src/{ => vision_api}/py_base.cpp (100%) rename src/cpp/py_bindings/src/{ => vision_api}/py_classification.cpp (100%) rename src/cpp/py_bindings/src/{ => vision_api}/py_utils.cpp (100%) rename src/cpp/py_bindings/src/{ => vision_api}/py_utils.hpp (100%) rename src/cpp/py_bindings/src/{ => vision_api}/py_vision_api.cpp (92%) diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 9dd0e11c..66175c42 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.26) add_subdirectory(../ model_api/cpp) set(Python_FIND_VIRTUALENV FIRST) -project(vision_api LANGUAGES CXX) +project(_vision_api LANGUAGES CXX) find_package(Python COMPONENTS Interpreter Development REQUIRED) execute_process( @@ -16,14 +16,19 @@ execute_process( find_package(nanobind CONFIG REQUIRED) -file(GLOB BINDINGS_SOURCES ./src/*.cpp) -file(GLOB BINDINGS_HEADERS ./src/*.hpp) +file(GLOB BINDINGS_SOURCES src/vision_api/*.cpp) +file(GLOB BINDINGS_HEADERS src/vision_api/*.hpp) -nanobind_add_module(vision_api_impl NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) +message(INFO ${BINDINGS_SOURCES}) -target_link_libraries(vision_api_impl PRIVATE model_api) +nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) -install(TARGETS vision_api_impl LIBRARY DESTINATION vision_api) +set_target_properties(_vision_api PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" +) +target_link_libraries(_vision_api PRIVATE model_api) + +#install(TARGETS _vision_api_impl LIBRARY DESTINATION vision_api) # nanobind_add_stub( # py_model_api_stub diff --git a/src/cpp/py_bindings/pyproject.toml b/src/cpp/py_bindings/pyproject.toml index 1952f829..34be01b6 100644 --- a/src/cpp/py_bindings/pyproject.toml +++ b/src/cpp/py_bindings/pyproject.toml @@ -3,7 +3,7 @@ requires = ["scikit-build-core >=0.4.3", "nanobind >=1.3.2"] build-backend = "scikit_build_core.build" [project] -name = "py_model_api" +name = "vision_api" version = "0.0.1" description = "set of wrapper classes for particular tasks and model architectures, simplifying data preprocess and postprocess as well as routine procedures" readme = "README.md" @@ -19,3 +19,11 @@ classifiers = [ [project.urls] Homepage = "https://github.com/open-edge-platform/model_api" + +[tool.scikit-build] +# Protect the configuration against future changes in scikit-build-core +minimum-version = "0.4" +# Setuptools-style build caching in a local directory +build-dir = "build/{wheel_tag}" +# Build stable ABI wheels for CPython 3.12+ +wheel.py-api = "cp312" diff --git a/src/cpp/py_bindings/scratch.py b/src/cpp/py_bindings/scratch.py new file mode 100644 index 00000000..00042153 --- /dev/null +++ b/src/cpp/py_bindings/scratch.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +from vision_api import ClassificationModel, hello +import cv2 + +import sys + +hello() + +if len(sys.argv) != 3: + raise RuntimeError(f"Usage: {sys.argv[0]} ") + +model_path = sys.argv[1] +image_path = sys.argv[2] + +model = ClassificationModel.create_model(model_path) +image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB) +print(model(image)) diff --git a/src/cpp/py_bindings/src/vision_api/__init__.py b/src/cpp/py_bindings/src/vision_api/__init__.py index 50ba095a..d85a23ee 100644 --- a/src/cpp/py_bindings/src/vision_api/__init__.py +++ b/src/cpp/py_bindings/src/vision_api/__init__.py @@ -1,3 +1,7 @@ #!/usr/bin/env python3 -from ._my_ext_impl import hello +from ._vision_api import Classification, ClassificationModel + + +def hello(): + print("World!") diff --git a/src/cpp/py_bindings/src/py_base.cpp b/src/cpp/py_bindings/src/vision_api/py_base.cpp similarity index 100% rename from src/cpp/py_bindings/src/py_base.cpp rename to src/cpp/py_bindings/src/vision_api/py_base.cpp diff --git a/src/cpp/py_bindings/src/py_classification.cpp b/src/cpp/py_bindings/src/vision_api/py_classification.cpp similarity index 100% rename from src/cpp/py_bindings/src/py_classification.cpp rename to src/cpp/py_bindings/src/vision_api/py_classification.cpp diff --git a/src/cpp/py_bindings/src/py_utils.cpp b/src/cpp/py_bindings/src/vision_api/py_utils.cpp similarity index 100% rename from src/cpp/py_bindings/src/py_utils.cpp rename to src/cpp/py_bindings/src/vision_api/py_utils.cpp diff --git a/src/cpp/py_bindings/src/py_utils.hpp b/src/cpp/py_bindings/src/vision_api/py_utils.hpp similarity index 100% rename from src/cpp/py_bindings/src/py_utils.hpp rename to src/cpp/py_bindings/src/vision_api/py_utils.hpp diff --git a/src/cpp/py_bindings/src/py_vision_api.cpp b/src/cpp/py_bindings/src/vision_api/py_vision_api.cpp similarity index 92% rename from src/cpp/py_bindings/src/py_vision_api.cpp rename to src/cpp/py_bindings/src/vision_api/py_vision_api.cpp index c10e6486..13605a01 100644 --- a/src/cpp/py_bindings/src/py_vision_api.cpp +++ b/src/cpp/py_bindings/src/vision_api/py_vision_api.cpp @@ -10,7 +10,7 @@ namespace nb = nanobind; void init_classification(nb::module_& m); void init_base_modules(nb::module_& m); -NB_MODULE(py_model_api, m) { +NB_MODULE(_vision_api, m) { m.doc() = "Nanobind binding for OpenVINO Vision API library"; init_base_modules(m); init_classification(m); From 0ec186decc28d9b7ad7fd3596e89e5dc2c95374f Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Thu, 10 Apr 2025 20:59:33 +0200 Subject: [PATCH 17/38] Add Dockerfile for building the python bindings from c++ It's ugly, but its just an example to show it works --- src/cpp/install_dependencies.sh | 12 +++++++++--- src/cpp/py_bindings/Dockerfile.ubuntu | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/cpp/py_bindings/Dockerfile.ubuntu diff --git a/src/cpp/install_dependencies.sh b/src/cpp/install_dependencies.sh index caac2523..1f085cd1 100755 --- a/src/cpp/install_dependencies.sh +++ b/src/cpp/install_dependencies.sh @@ -1,16 +1,22 @@ #!/bin/bash +test -f /usr/share/doc/kitware-archive-keyring/copyright || +wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null +echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null +apt-get update +apt-get install -y cmake + # Added required keys / do the update wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB -echo "deb https://apt.repos.intel.com/openvino/2025 ubuntu22 main" | sudo tee /etc/apt/sources.list.d/intel-openvino-2025.list +echo "deb https://apt.repos.intel.com/openvino ubuntu22 main" | tee /etc/apt/sources.list.d/intel-openvino.list apt update #Install OpenCV -apt-get install libopencv-dev +apt-get install -y libopencv-dev # Install OpenVINO -sudo apt install openvino-2025.0.0 +apt install -y openvino-2025.1.0 diff --git a/src/cpp/py_bindings/Dockerfile.ubuntu b/src/cpp/py_bindings/Dockerfile.ubuntu new file mode 100644 index 00000000..5de67cad --- /dev/null +++ b/src/cpp/py_bindings/Dockerfile.ubuntu @@ -0,0 +1,27 @@ +FROM --platform=linux/amd64 ubuntu:22.04 +USER root + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y \ + clang cmake git \ + ninja-build pkg-config \ + libgtk-3-dev liblzma-dev \ + libstdc++-12-dev \ + libopencv-dev \ + curl \ + wget \ + python3.10 \ + python3-pip \ + python3.10-venv + +COPY src /build/src + +WORKDIR /build + +RUN src/cpp/install_dependencies.sh +RUN python3 -m venv /opt/venv +ENV VIRTUAL_ENV=/opt/venv +ENV PATH=/opt/venv/bin:$PATH +#RUN pip install nanobind +RUN rm -r src/cpp/py_bindings/build +RUN pip install src/cpp/py_bindings From 4decb8fede09b2a840e59bcb6e1d8a9c229385e3 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Fri, 11 Apr 2025 10:37:50 +0200 Subject: [PATCH 18/38] Working python wheel package with only opencv as dependency Currently the rpath is set to a relative path to the site-packages of python for openvino (../openvino/libs). This is maybe not great. OpenCV does not seem to be an issue --- src/cpp/py_bindings/CMakeLists.txt | 3 +++ src/cpp/py_bindings/Dockerfile_test.ubuntu | 20 ++++++++++++++++++++ src/cpp/py_bindings/README.md | 18 ++++++++++++++++++ src/cpp/py_bindings/pyproject.toml | 5 ++++- 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/cpp/py_bindings/Dockerfile_test.ubuntu diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 66175c42..0790a1b1 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -25,7 +25,10 @@ nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${B set_target_properties(_vision_api PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH "$ORIGIN/../openvino/libs" ) + target_link_libraries(_vision_api PRIVATE model_api) #install(TARGETS _vision_api_impl LIBRARY DESTINATION vision_api) diff --git a/src/cpp/py_bindings/Dockerfile_test.ubuntu b/src/cpp/py_bindings/Dockerfile_test.ubuntu new file mode 100644 index 00000000..c3356b1f --- /dev/null +++ b/src/cpp/py_bindings/Dockerfile_test.ubuntu @@ -0,0 +1,20 @@ +FROM ubuntu:22.04 + +WORKDIR /project + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y \ + python3.10 \ + python3-pip \ + python3.10-venv \ + libopencv-dev + +RUN python3 -m venv /opt/venv +ENV VIRTUAL_ENV=/opt/venv +ENV PATH=/opt/venv/bin:$PATH + +COPY vision_api-0.0.1-cp310-cp310-linux_x86_64.whl . +COPY scratch.py . + +RUN pip install vision_api-0.0.1-cp310-cp310-linux_x86_64.whl +# RUN python scratch.py /data/classification_model_with_xai_head.xml /data/sheep.jpg diff --git a/src/cpp/py_bindings/README.md b/src/cpp/py_bindings/README.md index 3a7fa133..cea25963 100644 --- a/src/cpp/py_bindings/README.md +++ b/src/cpp/py_bindings/README.md @@ -1 +1,19 @@ # Vision SDK + + +## Test building dependencies: + +``` sh +docker build -t vision-api-build -f ./Dockerfile.ubuntu . +``` + +## Test dependencies to run python package + +You can test that the python package runs by running from this path: + +``` sh +pip wheel . +docker build -t vision-api-test -f Dockerfile_test.ubuntu . +docker run --volume :/data -it vision-api-test bash +python scratch.py /data/classification_model_with_xai_head.xml /data/sheep.jpg +``` diff --git a/src/cpp/py_bindings/pyproject.toml b/src/cpp/py_bindings/pyproject.toml index 34be01b6..882a50f1 100644 --- a/src/cpp/py_bindings/pyproject.toml +++ b/src/cpp/py_bindings/pyproject.toml @@ -15,7 +15,10 @@ classifiers = [ "License :: BSD", ] # Optional: runtime dependency specification -# dependencies = [ "cryptography >=41.0" ] +dependencies = [ + "openvino>=2025.0", + "opencv-python-headless", +] [project.urls] Homepage = "https://github.com/open-edge-platform/model_api" From fbed5dd460b17241700f4ba0f8f130a7dc3377ac Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Fri, 11 Apr 2025 11:12:52 +0200 Subject: [PATCH 19/38] Clean up the Dockerfile.ubuntu for building the python package --- src/cpp/install_dependencies.sh | 12 +++--------- src/cpp/py_bindings/Dockerfile.ubuntu | 12 +++++++----- src/cpp/py_bindings/README.md | 6 +++++- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/cpp/install_dependencies.sh b/src/cpp/install_dependencies.sh index 1f085cd1..caac2523 100755 --- a/src/cpp/install_dependencies.sh +++ b/src/cpp/install_dependencies.sh @@ -1,22 +1,16 @@ #!/bin/bash -test -f /usr/share/doc/kitware-archive-keyring/copyright || -wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null -echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null -apt-get update -apt-get install -y cmake - # Added required keys / do the update wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB -echo "deb https://apt.repos.intel.com/openvino ubuntu22 main" | tee /etc/apt/sources.list.d/intel-openvino.list +echo "deb https://apt.repos.intel.com/openvino/2025 ubuntu22 main" | sudo tee /etc/apt/sources.list.d/intel-openvino-2025.list apt update #Install OpenCV -apt-get install -y libopencv-dev +apt-get install libopencv-dev # Install OpenVINO -apt install -y openvino-2025.1.0 +sudo apt install openvino-2025.0.0 diff --git a/src/cpp/py_bindings/Dockerfile.ubuntu b/src/cpp/py_bindings/Dockerfile.ubuntu index 5de67cad..65d5cfc0 100644 --- a/src/cpp/py_bindings/Dockerfile.ubuntu +++ b/src/cpp/py_bindings/Dockerfile.ubuntu @@ -2,6 +2,7 @@ FROM --platform=linux/amd64 ubuntu:22.04 USER root ENV DEBIAN_FRONTEND=noninteractive + RUN apt-get update && apt-get install -y \ clang cmake git \ ninja-build pkg-config \ @@ -14,14 +15,15 @@ RUN apt-get update && apt-get install -y \ python3-pip \ python3.10-venv +RUN python3 -m venv /opt/venv +ENV VIRTUAL_ENV=/opt/venv +ENV PATH=/opt/venv/bin:$PATH + COPY src /build/src WORKDIR /build -RUN src/cpp/install_dependencies.sh -RUN python3 -m venv /opt/venv -ENV VIRTUAL_ENV=/opt/venv -ENV PATH=/opt/venv/bin:$PATH -#RUN pip install nanobind RUN rm -r src/cpp/py_bindings/build +RUN pip install cmake +RUN pip install openvino RUN pip install src/cpp/py_bindings diff --git a/src/cpp/py_bindings/README.md b/src/cpp/py_bindings/README.md index cea25963..78b6c53d 100644 --- a/src/cpp/py_bindings/README.md +++ b/src/cpp/py_bindings/README.md @@ -3,8 +3,12 @@ ## Test building dependencies: +You can build the package in docker by running from root model_api path + ``` sh -docker build -t vision-api-build -f ./Dockerfile.ubuntu . +docker build -t vision-api-build -f src/cpp/py_bindings/Dockerfile.ubuntu . +docker run --volume :/data -it vision-api-build bash +python src/cpp/py_bindings/scratch.py /data/classification_model_with_xai_head.xml /data/sheep.jpg ``` ## Test dependencies to run python package From bc001ffbce6783a76341072e6f8a56366b128f8e Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Fri, 11 Apr 2025 11:25:46 +0200 Subject: [PATCH 20/38] Remove rpath setting --- src/cpp/py_bindings/.gitignore | 1 + src/cpp/py_bindings/CMakeLists.txt | 12 ------------ src/cpp/py_bindings/src/vision_api/__init__.py | 6 ++++++ 3 files changed, 7 insertions(+), 12 deletions(-) create mode 100644 src/cpp/py_bindings/.gitignore diff --git a/src/cpp/py_bindings/.gitignore b/src/cpp/py_bindings/.gitignore new file mode 100644 index 00000000..704d3075 --- /dev/null +++ b/src/cpp/py_bindings/.gitignore @@ -0,0 +1 @@ +*.whl diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 0790a1b1..2a750375 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -25,18 +25,6 @@ nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${B set_target_properties(_vision_api PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" - BUILD_WITH_INSTALL_RPATH TRUE - INSTALL_RPATH "$ORIGIN/../openvino/libs" ) target_link_libraries(_vision_api PRIVATE model_api) - -#install(TARGETS _vision_api_impl LIBRARY DESTINATION vision_api) - -# nanobind_add_stub( -# py_model_api_stub -# MODULE vision_sdk -# OUTPUT py_model_api.pyi -# PYTHON_PATH $ -# DEPENDS py_model_api -# ) diff --git a/src/cpp/py_bindings/src/vision_api/__init__.py b/src/cpp/py_bindings/src/vision_api/__init__.py index d85a23ee..51ea5f88 100644 --- a/src/cpp/py_bindings/src/vision_api/__init__.py +++ b/src/cpp/py_bindings/src/vision_api/__init__.py @@ -1,5 +1,11 @@ #!/usr/bin/env python3 +try: + from openvino import Core + _ = Core() # Triggers loading of shared libs like libopenvino.so +except Exception as e: + raise ImportError(f"Failed to initialize OpenVINO runtime: {e}") + from ._vision_api import Classification, ClassificationModel From ffc65ea930469897841e3962173840258ef42d6e Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 10:12:31 +0200 Subject: [PATCH 21/38] Extract opencv dependencies and setup windows part too --- src/cpp/py_bindings/.gitignore | 2 ++ src/cpp/py_bindings/CMakeLists.txt | 19 ++++++++++++++++++- src/cpp/py_bindings/OpenCVDependencies.cmake | 12 ++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/cpp/py_bindings/OpenCVDependencies.cmake diff --git a/src/cpp/py_bindings/.gitignore b/src/cpp/py_bindings/.gitignore index 704d3075..4bd229d8 100644 --- a/src/cpp/py_bindings/.gitignore +++ b/src/cpp/py_bindings/.gitignore @@ -1 +1,3 @@ *.whl +*.dll +*.so diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 2a750375..e79158ad 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -4,6 +4,9 @@ cmake_minimum_required(VERSION 3.26) +set(CMAKE_GENERATOR_TOOLSET "v142") + +get_cmake_property(_variableNames VARIABLES) add_subdirectory(../ model_api/cpp) set(Python_FIND_VIRTUALENV FIRST) @@ -24,7 +27,21 @@ message(INFO ${BINDINGS_SOURCES}) nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) set_target_properties(_vision_api PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" + # LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" ) +include(OpenCVDependencies.cmake) + +set(PYTHON_PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) +foreach(lib ${DEPENDENCIES_TO_COPY}) + add_custom_command( + TARGET _vision_api POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${lib} + ${PYTHON_PACKAGE_DIR} + COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" + ) +endforeach() + target_link_libraries(_vision_api PRIVATE model_api) diff --git a/src/cpp/py_bindings/OpenCVDependencies.cmake b/src/cpp/py_bindings/OpenCVDependencies.cmake new file mode 100644 index 00000000..182d0397 --- /dev/null +++ b/src/cpp/py_bindings/OpenCVDependencies.cmake @@ -0,0 +1,12 @@ +find_package(OpenCV REQUIRED COMPONENTS core imgproc) +if (MSVC) + set(DEPENDENCIES_TO_COPY + "${__location_release}" + ) +else() + set(DEPENDENCIES_TO_COPY + ${OpenCV_DIR}/../../libopencv_core.so.4.5d + ${OpenCV_DIR}/../../libopencv_imgproc.so.4.5d + ${TBB_DIR}/../../libtbb.so.2 + ) +endif() From 3fb1326aa00a43cd7c62c804e649579bff56fa89 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 10:40:53 +0200 Subject: [PATCH 22/38] Clean up cmakelists, sadly its been broken since last couple commits --- src/cpp/py_bindings/CMakeLists.txt | 33 +++++++------------- src/cpp/py_bindings/OpenCVDependencies.cmake | 17 +++++++++- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index e79158ad..50bfd18e 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -4,7 +4,9 @@ cmake_minimum_required(VERSION 3.26) +if (MSVC) set(CMAKE_GENERATOR_TOOLSET "v142") +endif() get_cmake_property(_variableNames VARIABLES) add_subdirectory(../ model_api/cpp) @@ -13,35 +15,24 @@ set(Python_FIND_VIRTUALENV FIRST) project(_vision_api LANGUAGES CXX) find_package(Python COMPONENTS Interpreter Development REQUIRED) -execute_process( - COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir - OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT) +#execute_process( +# COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir +# OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT) find_package(nanobind CONFIG REQUIRED) - -file(GLOB BINDINGS_SOURCES src/vision_api/*.cpp) -file(GLOB BINDINGS_HEADERS src/vision_api/*.hpp) +set(VISION_API_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) +file(GLOB BINDINGS_SOURCES ${VISION_API_SOURCE_DIR}/*.cpp) +file(GLOB BINDINGS_HEADERS ${VISION_API_SOURCE_DIR}/*.hpp) message(INFO ${BINDINGS_SOURCES}) nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) -set_target_properties(_vision_api PROPERTIES - # LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" - LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" -) - include(OpenCVDependencies.cmake) -set(PYTHON_PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) -foreach(lib ${DEPENDENCIES_TO_COPY}) - add_custom_command( - TARGET _vision_api POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${lib} - ${PYTHON_PACKAGE_DIR} - COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" - ) -endforeach() +set_target_properties(_vision_api PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${VISION_API_SOURCE_DIR} + LIBRARY_OUTPUT_DIRECTORY_RELEASE ${VISION_API_SOURCE_DIR} +) target_link_libraries(_vision_api PRIVATE model_api) diff --git a/src/cpp/py_bindings/OpenCVDependencies.cmake b/src/cpp/py_bindings/OpenCVDependencies.cmake index 182d0397..95cb7505 100644 --- a/src/cpp/py_bindings/OpenCVDependencies.cmake +++ b/src/cpp/py_bindings/OpenCVDependencies.cmake @@ -4,9 +4,24 @@ if (MSVC) "${__location_release}" ) else() + find_package(PkgConfig REQUIRED) + find_package(TBB "2021.5.0" EXACT REQUIRED) + pkg_check_modules(TBB REQUIRED tbb) + set(DEPENDENCIES_TO_COPY ${OpenCV_DIR}/../../libopencv_core.so.4.5d ${OpenCV_DIR}/../../libopencv_imgproc.so.4.5d - ${TBB_DIR}/../../libtbb.so.2 + ${pkgcfg_lib_TBB_tbb}.2 # ubuntu system package uses tbb.so.2 ) endif() + +set(PYTHON_PACKAGE_DIR ${VISION_API_SOURCE_DIR}) +foreach(lib ${DEPENDENCIES_TO_COPY}) + add_custom_command( + TARGET _vision_api POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${lib} + ${PYTHON_PACKAGE_DIR} + COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" + ) +endforeach() From 0a813034579072474e186b34c7f0fa2a09b814cc Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 10:51:31 +0200 Subject: [PATCH 23/38] Revert "Clean up cmakelists, sadly its been broken since last couple commits" This reverts commit 3fb1326aa00a43cd7c62c804e649579bff56fa89. --- src/cpp/py_bindings/CMakeLists.txt | 33 +++++++++++++------- src/cpp/py_bindings/OpenCVDependencies.cmake | 17 +--------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 50bfd18e..e79158ad 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -4,9 +4,7 @@ cmake_minimum_required(VERSION 3.26) -if (MSVC) set(CMAKE_GENERATOR_TOOLSET "v142") -endif() get_cmake_property(_variableNames VARIABLES) add_subdirectory(../ model_api/cpp) @@ -15,24 +13,35 @@ set(Python_FIND_VIRTUALENV FIRST) project(_vision_api LANGUAGES CXX) find_package(Python COMPONENTS Interpreter Development REQUIRED) -#execute_process( -# COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir -# OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT) +execute_process( + COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT) find_package(nanobind CONFIG REQUIRED) -set(VISION_API_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) -file(GLOB BINDINGS_SOURCES ${VISION_API_SOURCE_DIR}/*.cpp) -file(GLOB BINDINGS_HEADERS ${VISION_API_SOURCE_DIR}/*.hpp) + +file(GLOB BINDINGS_SOURCES src/vision_api/*.cpp) +file(GLOB BINDINGS_HEADERS src/vision_api/*.hpp) message(INFO ${BINDINGS_SOURCES}) nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) -include(OpenCVDependencies.cmake) - set_target_properties(_vision_api PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${VISION_API_SOURCE_DIR} - LIBRARY_OUTPUT_DIRECTORY_RELEASE ${VISION_API_SOURCE_DIR} + # LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" ) +include(OpenCVDependencies.cmake) + +set(PYTHON_PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) +foreach(lib ${DEPENDENCIES_TO_COPY}) + add_custom_command( + TARGET _vision_api POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${lib} + ${PYTHON_PACKAGE_DIR} + COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" + ) +endforeach() + target_link_libraries(_vision_api PRIVATE model_api) diff --git a/src/cpp/py_bindings/OpenCVDependencies.cmake b/src/cpp/py_bindings/OpenCVDependencies.cmake index 95cb7505..182d0397 100644 --- a/src/cpp/py_bindings/OpenCVDependencies.cmake +++ b/src/cpp/py_bindings/OpenCVDependencies.cmake @@ -4,24 +4,9 @@ if (MSVC) "${__location_release}" ) else() - find_package(PkgConfig REQUIRED) - find_package(TBB "2021.5.0" EXACT REQUIRED) - pkg_check_modules(TBB REQUIRED tbb) - set(DEPENDENCIES_TO_COPY ${OpenCV_DIR}/../../libopencv_core.so.4.5d ${OpenCV_DIR}/../../libopencv_imgproc.so.4.5d - ${pkgcfg_lib_TBB_tbb}.2 # ubuntu system package uses tbb.so.2 + ${TBB_DIR}/../../libtbb.so.2 ) endif() - -set(PYTHON_PACKAGE_DIR ${VISION_API_SOURCE_DIR}) -foreach(lib ${DEPENDENCIES_TO_COPY}) - add_custom_command( - TARGET _vision_api POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${lib} - ${PYTHON_PACKAGE_DIR} - COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" - ) -endforeach() From cb0020c99be3c80a72004ab6976c5243b2d9203c Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 10:51:41 +0200 Subject: [PATCH 24/38] Revert "Extract opencv dependencies and setup windows part too" This reverts commit ffc65ea930469897841e3962173840258ef42d6e. --- src/cpp/py_bindings/.gitignore | 2 -- src/cpp/py_bindings/CMakeLists.txt | 19 +------------------ src/cpp/py_bindings/OpenCVDependencies.cmake | 12 ------------ 3 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 src/cpp/py_bindings/OpenCVDependencies.cmake diff --git a/src/cpp/py_bindings/.gitignore b/src/cpp/py_bindings/.gitignore index 4bd229d8..704d3075 100644 --- a/src/cpp/py_bindings/.gitignore +++ b/src/cpp/py_bindings/.gitignore @@ -1,3 +1 @@ *.whl -*.dll -*.so diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index e79158ad..2a750375 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -4,9 +4,6 @@ cmake_minimum_required(VERSION 3.26) -set(CMAKE_GENERATOR_TOOLSET "v142") - -get_cmake_property(_variableNames VARIABLES) add_subdirectory(../ model_api/cpp) set(Python_FIND_VIRTUALENV FIRST) @@ -27,21 +24,7 @@ message(INFO ${BINDINGS_SOURCES}) nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) set_target_properties(_vision_api PROPERTIES - # LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" - LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" ) -include(OpenCVDependencies.cmake) - -set(PYTHON_PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) -foreach(lib ${DEPENDENCIES_TO_COPY}) - add_custom_command( - TARGET _vision_api POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${lib} - ${PYTHON_PACKAGE_DIR} - COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" - ) -endforeach() - target_link_libraries(_vision_api PRIVATE model_api) diff --git a/src/cpp/py_bindings/OpenCVDependencies.cmake b/src/cpp/py_bindings/OpenCVDependencies.cmake deleted file mode 100644 index 182d0397..00000000 --- a/src/cpp/py_bindings/OpenCVDependencies.cmake +++ /dev/null @@ -1,12 +0,0 @@ -find_package(OpenCV REQUIRED COMPONENTS core imgproc) -if (MSVC) - set(DEPENDENCIES_TO_COPY - "${__location_release}" - ) -else() - set(DEPENDENCIES_TO_COPY - ${OpenCV_DIR}/../../libopencv_core.so.4.5d - ${OpenCV_DIR}/../../libopencv_imgproc.so.4.5d - ${TBB_DIR}/../../libtbb.so.2 - ) -endif() From 0d655cb628e9c789163d7ccbdfb78a4ce3bb3dbf Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 10:55:17 +0200 Subject: [PATCH 25/38] Fix cmake file properly now for ubuntu Windows will come --- src/cpp/py_bindings/CMakeLists.txt | 6 ++++++ src/cpp/py_bindings/opencv.cmake | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/cpp/py_bindings/opencv.cmake diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 2a750375..93eb2bca 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -10,6 +10,10 @@ set(Python_FIND_VIRTUALENV FIRST) project(_vision_api LANGUAGES CXX) find_package(Python COMPONENTS Interpreter Development REQUIRED) +if(MSVC) + set(CMAKE_GENERATOR_TOOLSET "v142") +endif() + execute_process( COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT) @@ -28,3 +32,5 @@ set_target_properties(_vision_api PROPERTIES ) target_link_libraries(_vision_api PRIVATE model_api) + +include(opencv.cmake) diff --git a/src/cpp/py_bindings/opencv.cmake b/src/cpp/py_bindings/opencv.cmake new file mode 100644 index 00000000..0e2b45ad --- /dev/null +++ b/src/cpp/py_bindings/opencv.cmake @@ -0,0 +1,28 @@ +find_package(OpenCV REQUIRED COMPONENTS core imgproc) + +if (MSVC) + set(DEPENDENCIES_TO_COPY + "${__location_release}" + ) +else() + find_package(PkgConfig REQUIRED) + find_package(TBB "2021.5.0" EXACT REQUIRED) + pkg_check_modules(TBB REQUIRED tbb) + + set(DEPENDENCIES_TO_COPY + ${OpenCV_DIR}/../../libopencv_core.so.4.5d + ${OpenCV_DIR}/../../libopencv_imgproc.so.4.5d + ${pkgcfg_lib_TBB_tbb}.2 # ubuntu system package uses tbb.so.2 + ) +endif() + +set(PYTHON_PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) +foreach(lib ${DEPENDENCIES_TO_COPY}) + add_custom_command( + TARGET _vision_api POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${lib} + ${PYTHON_PACKAGE_DIR} + COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" + ) +endforeach() From a229e7fed142cee2660baba5ac98d57f0525905d Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 11:20:46 +0200 Subject: [PATCH 26/38] Fixing windows build again --- src/cpp/py_bindings/.gitignore | 1 + src/cpp/py_bindings/CMakeLists.txt | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cpp/py_bindings/.gitignore b/src/cpp/py_bindings/.gitignore index 704d3075..64bfb5a6 100644 --- a/src/cpp/py_bindings/.gitignore +++ b/src/cpp/py_bindings/.gitignore @@ -1 +1,2 @@ *.whl +*.dll diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index 93eb2bca..b25da694 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -4,16 +4,17 @@ cmake_minimum_required(VERSION 3.26) +if(WIN32) + set(CMAKE_GENERATOR_TOOLSET "v142") +endif() + + add_subdirectory(../ model_api/cpp) set(Python_FIND_VIRTUALENV FIRST) project(_vision_api LANGUAGES CXX) find_package(Python COMPONENTS Interpreter Development REQUIRED) -if(MSVC) - set(CMAKE_GENERATOR_TOOLSET "v142") -endif() - execute_process( COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT) From cd9bf797a4fbd98166e890001409db4ebc0a9f42 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 13:01:45 +0200 Subject: [PATCH 27/38] Fix tests for cpp-py so that they run, not working yet Seems one model is causing an issue, either via segmentation fault if trying to catch error, or a nullptr tensor --- .github/workflows/test_accuracy.yml | 3 +++ tests/cpp/accuracy/test_bindings.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index 322a7b84..00eebb1c 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -44,6 +44,9 @@ jobs: pip install typing_extensions==4.12.2 cmake ../tests/cpp/accuracy/ make -j + - name: Build CPP-PY Bindings + run: | + pip install src/cpp/py_bindings - name: Run CPP Test run: | build/test_accuracy -d data -p tests/python/accuracy/public_scope.json diff --git a/tests/cpp/accuracy/test_bindings.py b/tests/cpp/accuracy/test_bindings.py index 314f2ac6..3982765d 100644 --- a/tests/cpp/accuracy/test_bindings.py +++ b/tests/cpp/accuracy/test_bindings.py @@ -10,7 +10,7 @@ import cv2 from model_api.models import Model -from py_model_api import ClassificationModel +from vision_api import ClassificationModel def read_config(models_config: str, model_type: str): From ff67f11d1b811b854c44321f5683e71cbe618482 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 13:23:34 +0200 Subject: [PATCH 28/38] Try to fix workflow --- .github/workflows/test_accuracy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index 00eebb1c..2ea1ef2f 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -53,4 +53,4 @@ jobs: - name: Run CPP-PY Bindings Test run: | source venv/bin/activate - PYTHONPATH="$PYTHONPATH:build/model_api/cpp/py_bindings/" pytest --data=./data --config=./tests/python/accuracy/public_scope.json tests/cpp/accuracy/test_bindings.py + pytest --data=./data --config=./tests/python/accuracy/public_scope.json tests/cpp/accuracy/test_bindings.py From a263dd9dd1344961f38ccee602c683ecd7b6d5cf Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 13:34:10 +0200 Subject: [PATCH 29/38] Remove cpp tests and use venv for building package --- .github/workflows/test_accuracy.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index 2ea1ef2f..a6b33602 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -37,19 +37,10 @@ jobs: - name: Install CPP dependencies run: | sudo bash src/cpp/install_dependencies.sh - - name: Build CPP Test - run: | - mkdir build && cd build - pip install nanobind==2.4.0 - pip install typing_extensions==4.12.2 - cmake ../tests/cpp/accuracy/ - make -j - name: Build CPP-PY Bindings run: | + source venv/bin/activate pip install src/cpp/py_bindings - - name: Run CPP Test - run: | - build/test_accuracy -d data -p tests/python/accuracy/public_scope.json - name: Run CPP-PY Bindings Test run: | source venv/bin/activate From df0a3568d8df54848f67d65db542bb7b477fe991 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Mon, 14 Apr 2025 13:51:28 +0200 Subject: [PATCH 30/38] Remove the broken test and enable cpp tests again --- .github/workflows/test_accuracy.yml | 10 ++++++++++ tests/python/accuracy/public_scope.json | 12 ------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index a6b33602..a066c669 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -37,10 +37,20 @@ jobs: - name: Install CPP dependencies run: | sudo bash src/cpp/install_dependencies.sh + - name: Build CPP Test + run: | + mkdir build && cd build + pip install nanobind==2.4.0 + pip install typing_extensions==4.12.2 + cmake ../tests/cpp/accuracy/ + make -j - name: Build CPP-PY Bindings run: | source venv/bin/activate pip install src/cpp/py_bindings + - name: Run CPP Test + run: | + build/test_accuracy -d data -p tests/python/accuracy/public_scope.json - name: Run CPP-PY Bindings Test run: | source venv/bin/activate diff --git a/tests/python/accuracy/public_scope.json b/tests/python/accuracy/public_scope.json index e244ece1..f198a02f 100644 --- a/tests/python/accuracy/public_scope.json +++ b/tests/python/accuracy/public_scope.json @@ -256,18 +256,6 @@ } ] }, - { - "name": "otx_models/mobilenet_v3_large_hc_cf.xml", - "type": "ClassificationModel", - "test_data": [ - { - "image": "coco128/images/train2017/000000000081.jpg", - "reference": [ - "3 (equilateral): 0.596, 1 (multi a): 0.922, 2 (multi b): 0.696, 5 (triangle): 0.993, [0], [0], [0]" - ] - } - ] - }, { "name": "otx_models/classification_model_with_xai_head.xml", "type": "ClassificationModel", From 09765a73e3d5b3303c7587a6b743e68c93a5d9f3 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Tue, 15 Apr 2025 10:28:15 +0200 Subject: [PATCH 31/38] Clean up a bit --- src/cpp/py_bindings/.gitignore | 1 + src/cpp/py_bindings/README.md | 21 +++++++++---------- src/cpp/py_bindings/{scratch.py => run.py} | 8 +++---- .../py_bindings/src/vision_api/__init__.py | 7 +++---- 4 files changed, 17 insertions(+), 20 deletions(-) rename src/cpp/py_bindings/{scratch.py => run.py} (59%) diff --git a/src/cpp/py_bindings/.gitignore b/src/cpp/py_bindings/.gitignore index 64bfb5a6..20b07f5e 100644 --- a/src/cpp/py_bindings/.gitignore +++ b/src/cpp/py_bindings/.gitignore @@ -1,2 +1,3 @@ *.whl *.dll +*.so* diff --git a/src/cpp/py_bindings/README.md b/src/cpp/py_bindings/README.md index 78b6c53d..f0dd44b7 100644 --- a/src/cpp/py_bindings/README.md +++ b/src/cpp/py_bindings/README.md @@ -1,23 +1,22 @@ # Vision SDK +## Test building dependencies -## Test building dependencies: +You can build the package in docker by running from root model_api path. -You can build the package in docker by running from root model_api path - -``` sh +```sh docker build -t vision-api-build -f src/cpp/py_bindings/Dockerfile.ubuntu . -docker run --volume :/data -it vision-api-build bash -python src/cpp/py_bindings/scratch.py /data/classification_model_with_xai_head.xml /data/sheep.jpg +docker run --volume :/data -it vision-api-build bash +python src/cpp/py_bindings/run.py /data/classification_model_with_xai_head.xml /data/sheep.jpg ``` ## Test dependencies to run python package -You can test that the python package runs by running from this path: +You can test that the python package runs by running from this path. -``` sh +```sh pip wheel . -docker build -t vision-api-test -f Dockerfile_test.ubuntu . -docker run --volume :/data -it vision-api-test bash -python scratch.py /data/classification_model_with_xai_head.xml /data/sheep.jpg +docker build -t vision-api-test -f Dockerfile_test.ubuntu . +docker run --volume :/data -it vision-api-test bash +python run.py /data/classification_model_with_xai_head.xml /data/sheep.jpg ``` diff --git a/src/cpp/py_bindings/scratch.py b/src/cpp/py_bindings/run.py similarity index 59% rename from src/cpp/py_bindings/scratch.py rename to src/cpp/py_bindings/run.py index 00042153..16141d5b 100644 --- a/src/cpp/py_bindings/scratch.py +++ b/src/cpp/py_bindings/run.py @@ -1,18 +1,16 @@ #!/usr/bin/env python3 -from vision_api import ClassificationModel, hello +from vision_api import ClassificationModel import cv2 import sys -hello() - if len(sys.argv) != 3: - raise RuntimeError(f"Usage: {sys.argv[0]} ") + raise RuntimeError(f"Usage: {sys.argv[0]} ") model_path = sys.argv[1] image_path = sys.argv[2] model = ClassificationModel.create_model(model_path) image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB) -print(model(image)) +model(image) diff --git a/src/cpp/py_bindings/src/vision_api/__init__.py b/src/cpp/py_bindings/src/vision_api/__init__.py index 51ea5f88..663fa778 100644 --- a/src/cpp/py_bindings/src/vision_api/__init__.py +++ b/src/cpp/py_bindings/src/vision_api/__init__.py @@ -2,12 +2,11 @@ try: from openvino import Core + _ = Core() # Triggers loading of shared libs like libopenvino.so except Exception as e: raise ImportError(f"Failed to initialize OpenVINO runtime: {e}") -from ._vision_api import Classification, ClassificationModel - +from ._vision_api import ClassificationModel -def hello(): - print("World!") +__all__ = [ClassificationModel] From dd7383c7c47ec8e086277dc9f37290e27a7077dd Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Tue, 15 Apr 2025 15:03:31 +0200 Subject: [PATCH 32/38] make sure the .so's are included. Apparently scikit uses .gitignore to ignore what to add to the package --- src/cpp/py_bindings/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cpp/py_bindings/pyproject.toml b/src/cpp/py_bindings/pyproject.toml index 882a50f1..87c28f92 100644 --- a/src/cpp/py_bindings/pyproject.toml +++ b/src/cpp/py_bindings/pyproject.toml @@ -30,3 +30,4 @@ minimum-version = "0.4" build-dir = "build/{wheel_tag}" # Build stable ABI wheels for CPython 3.12+ wheel.py-api = "cp312" +sdist.include = ["*.so*"] From 35ade26fc4f074382253a4485f6ea73df9c6668d Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Tue, 15 Apr 2025 18:33:57 +0200 Subject: [PATCH 33/38] Apply feedback, remove docker files --- examples/cpp/CMakeLists.txt | 1 - src/cpp/CMakeLists.txt | 6 ---- src/cpp/py_bindings/Dockerfile.ubuntu | 29 ------------------- src/cpp/py_bindings/Dockerfile_test.ubuntu | 20 ------------- src/cpp/py_bindings/README.md | 22 -------------- src/cpp/py_bindings/pyproject.toml | 23 +++++++-------- .../py_bindings/src/vision_api/__init__.py | 3 +- tests/cpp/accuracy/CMakeLists.txt | 1 - tests/cpp/accuracy/test_bindings.py | 2 +- tests/cpp/precommit/CMakeLists.txt | 1 - 10 files changed, 14 insertions(+), 94 deletions(-) delete mode 100644 src/cpp/py_bindings/Dockerfile.ubuntu delete mode 100644 src/cpp/py_bindings/Dockerfile_test.ubuntu delete mode 100644 src/cpp/py_bindings/README.md diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index b1ebab76..fe22571f 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -92,7 +92,6 @@ endmacro() find_package(OpenCV REQUIRED COMPONENTS imgcodecs) -set(ENABLE_PY_BINDINGS OFF) add_subdirectory(../../src/cpp ${Samples_BINARY_DIR}/src/cpp) add_example(NAME asynchronous_api SOURCES ./asynchronous_api/main.cpp DEPENDENCIES model_api) diff --git a/src/cpp/CMakeLists.txt b/src/cpp/CMakeLists.txt index 0bcc2721..880f211a 100644 --- a/src/cpp/CMakeLists.txt +++ b/src/cpp/CMakeLists.txt @@ -4,8 +4,6 @@ cmake_minimum_required(VERSION 3.26) -# option(ENABLE_PY_BINDINGS "Enables building python bindings package" ON) - # Multi config generators such as Visual Studio ignore CMAKE_BUILD_TYPE. Multi config generators are configured with # CMAKE_CONFIGURATION_TYPES, but limiting options in it completely removes such build options get_property(GENERATOR_IS_MULTI_CONFIG_VAR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) @@ -77,10 +75,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "^GNU|(Apple)?Clang$") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() -#if (ENABLE_PY_BINDINGS) -# add_subdirectory(py_bindings) -#endif() - include(GenerateExportHeader) generate_export_header(model_api) diff --git a/src/cpp/py_bindings/Dockerfile.ubuntu b/src/cpp/py_bindings/Dockerfile.ubuntu deleted file mode 100644 index 65d5cfc0..00000000 --- a/src/cpp/py_bindings/Dockerfile.ubuntu +++ /dev/null @@ -1,29 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 -USER root - -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y \ - clang cmake git \ - ninja-build pkg-config \ - libgtk-3-dev liblzma-dev \ - libstdc++-12-dev \ - libopencv-dev \ - curl \ - wget \ - python3.10 \ - python3-pip \ - python3.10-venv - -RUN python3 -m venv /opt/venv -ENV VIRTUAL_ENV=/opt/venv -ENV PATH=/opt/venv/bin:$PATH - -COPY src /build/src - -WORKDIR /build - -RUN rm -r src/cpp/py_bindings/build -RUN pip install cmake -RUN pip install openvino -RUN pip install src/cpp/py_bindings diff --git a/src/cpp/py_bindings/Dockerfile_test.ubuntu b/src/cpp/py_bindings/Dockerfile_test.ubuntu deleted file mode 100644 index c3356b1f..00000000 --- a/src/cpp/py_bindings/Dockerfile_test.ubuntu +++ /dev/null @@ -1,20 +0,0 @@ -FROM ubuntu:22.04 - -WORKDIR /project - -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y \ - python3.10 \ - python3-pip \ - python3.10-venv \ - libopencv-dev - -RUN python3 -m venv /opt/venv -ENV VIRTUAL_ENV=/opt/venv -ENV PATH=/opt/venv/bin:$PATH - -COPY vision_api-0.0.1-cp310-cp310-linux_x86_64.whl . -COPY scratch.py . - -RUN pip install vision_api-0.0.1-cp310-cp310-linux_x86_64.whl -# RUN python scratch.py /data/classification_model_with_xai_head.xml /data/sheep.jpg diff --git a/src/cpp/py_bindings/README.md b/src/cpp/py_bindings/README.md deleted file mode 100644 index f0dd44b7..00000000 --- a/src/cpp/py_bindings/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Vision SDK - -## Test building dependencies - -You can build the package in docker by running from root model_api path. - -```sh -docker build -t vision-api-build -f src/cpp/py_bindings/Dockerfile.ubuntu . -docker run --volume :/data -it vision-api-build bash -python src/cpp/py_bindings/run.py /data/classification_model_with_xai_head.xml /data/sheep.jpg -``` - -## Test dependencies to run python package - -You can test that the python package runs by running from this path. - -```sh -pip wheel . -docker build -t vision-api-test -f Dockerfile_test.ubuntu . -docker run --volume :/data -it vision-api-test bash -python run.py /data/classification_model_with_xai_head.xml /data/sheep.jpg -``` diff --git a/src/cpp/py_bindings/pyproject.toml b/src/cpp/py_bindings/pyproject.toml index 87c28f92..048ee7ab 100644 --- a/src/cpp/py_bindings/pyproject.toml +++ b/src/cpp/py_bindings/pyproject.toml @@ -3,21 +3,20 @@ requires = ["scikit-build-core >=0.4.3", "nanobind >=1.3.2"] build-backend = "scikit_build_core.build" [project] -name = "vision_api" -version = "0.0.1" -description = "set of wrapper classes for particular tasks and model architectures, simplifying data preprocess and postprocess as well as routine procedures" -readme = "README.md" -requires-python = ">=3.8" +name = "openvino_model_api" +version = "0.3.0.2" +requires-python = ">=3.9" authors = [ - { name = "Ronald Hecker", email = "ronald.hecker@intel.com" }, + {name = "Intel(R) Corporation"}, ] -classifiers = [ - "License :: BSD", +maintainers = [ + {name = "Intel(R) Corporation"}, ] -# Optional: runtime dependency specification -dependencies = [ - "openvino>=2025.0", - "opencv-python-headless", +description = "Model API: model wrappers and pipelines for inference with OpenVINO" +readme = "../../python/README.md" +classifiers = [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.9" ] [project.urls] diff --git a/src/cpp/py_bindings/src/vision_api/__init__.py b/src/cpp/py_bindings/src/vision_api/__init__.py index 663fa778..0dbae48c 100644 --- a/src/cpp/py_bindings/src/vision_api/__init__.py +++ b/src/cpp/py_bindings/src/vision_api/__init__.py @@ -1,4 +1,5 @@ -#!/usr/bin/env python3 +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 try: from openvino import Core diff --git a/tests/cpp/accuracy/CMakeLists.txt b/tests/cpp/accuracy/CMakeLists.txt index d8cbdfad..e9648e91 100644 --- a/tests/cpp/accuracy/CMakeLists.txt +++ b/tests/cpp/accuracy/CMakeLists.txt @@ -67,7 +67,6 @@ include(../cmake/common.cmake) find_package(OpenCV REQUIRED COMPONENTS core highgui videoio imgproc imgcodecs) -set(ENABLE_PY_BINDINGS ON) add_subdirectory(../../../src/cpp ${tests_BINARY_DIR}/model_api/cpp) add_test(NAME test_accuracy SOURCES test_accuracy.cpp DEPENDENCIES model_api) diff --git a/tests/cpp/accuracy/test_bindings.py b/tests/cpp/accuracy/test_bindings.py index 3982765d..00b4fb3d 100644 --- a/tests/cpp/accuracy/test_bindings.py +++ b/tests/cpp/accuracy/test_bindings.py @@ -48,7 +48,7 @@ def test_classification_models(data: str, classification_configs): cpp_model = ClassificationModel.create_model(name, preload=True) image_path = Path(data) / next(iter(model_data["test_data"]))["image"] - image = cv2.imread(str(image_path)) + image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB) py_result = model(image) cpp_result = cpp_model(image) diff --git a/tests/cpp/precommit/CMakeLists.txt b/tests/cpp/precommit/CMakeLists.txt index ab8c77ff..0c56bf15 100644 --- a/tests/cpp/precommit/CMakeLists.txt +++ b/tests/cpp/precommit/CMakeLists.txt @@ -66,7 +66,6 @@ include(../cmake/common.cmake) find_package(OpenCV REQUIRED COMPONENTS core highgui videoio imgproc imgcodecs) -set(ENABLE_PY_BINDINGS OFF) add_subdirectory(../../../src/cpp ${tests_BINARY_DIR}/model_api/cpp) add_test(NAME test_sanity SOURCES test_sanity.cpp DEPENDENCIES model_api) From 831f18ba9f5ffdc45c17c82c81b8fcb7022d439f Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Wed, 16 Apr 2025 09:41:54 +0200 Subject: [PATCH 34/38] Rename the py project for py bindings to vision api --- src/cpp/py_bindings/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp/py_bindings/pyproject.toml b/src/cpp/py_bindings/pyproject.toml index 048ee7ab..1436f3e5 100644 --- a/src/cpp/py_bindings/pyproject.toml +++ b/src/cpp/py_bindings/pyproject.toml @@ -3,7 +3,7 @@ requires = ["scikit-build-core >=0.4.3", "nanobind >=1.3.2"] build-backend = "scikit_build_core.build" [project] -name = "openvino_model_api" +name = "vision_api" version = "0.3.0.2" requires-python = ">=3.9" authors = [ From 4f793e410a8f60311dfc51870d50bf9d333aea43 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Wed, 16 Apr 2025 10:10:41 +0200 Subject: [PATCH 35/38] Debug why model api is not found --- .github/workflows/test_accuracy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test_accuracy.yml b/.github/workflows/test_accuracy.yml index a066c669..0ce9dc10 100644 --- a/.github/workflows/test_accuracy.yml +++ b/.github/workflows/test_accuracy.yml @@ -54,4 +54,5 @@ jobs: - name: Run CPP-PY Bindings Test run: | source venv/bin/activate + pip list pytest --data=./data --config=./tests/python/accuracy/public_scope.json tests/cpp/accuracy/test_bindings.py From 2b249e22c83512e64b659d8884932281063a2290 Mon Sep 17 00:00:00 2001 From: "Hecker, Ronald" Date: Fri, 16 May 2025 07:48:00 +0200 Subject: [PATCH 36/38] Remove OpenCV and TBB from included dependencies for now --- src/cpp/py_bindings/CMakeLists.txt | 2 -- src/cpp/py_bindings/opencv.cmake | 28 ---------------------------- 2 files changed, 30 deletions(-) delete mode 100644 src/cpp/py_bindings/opencv.cmake diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index b25da694..fc6ab66f 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -33,5 +33,3 @@ set_target_properties(_vision_api PROPERTIES ) target_link_libraries(_vision_api PRIVATE model_api) - -include(opencv.cmake) diff --git a/src/cpp/py_bindings/opencv.cmake b/src/cpp/py_bindings/opencv.cmake deleted file mode 100644 index 0e2b45ad..00000000 --- a/src/cpp/py_bindings/opencv.cmake +++ /dev/null @@ -1,28 +0,0 @@ -find_package(OpenCV REQUIRED COMPONENTS core imgproc) - -if (MSVC) - set(DEPENDENCIES_TO_COPY - "${__location_release}" - ) -else() - find_package(PkgConfig REQUIRED) - find_package(TBB "2021.5.0" EXACT REQUIRED) - pkg_check_modules(TBB REQUIRED tbb) - - set(DEPENDENCIES_TO_COPY - ${OpenCV_DIR}/../../libopencv_core.so.4.5d - ${OpenCV_DIR}/../../libopencv_imgproc.so.4.5d - ${pkgcfg_lib_TBB_tbb}.2 # ubuntu system package uses tbb.so.2 - ) -endif() - -set(PYTHON_PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api) -foreach(lib ${DEPENDENCIES_TO_COPY}) - add_custom_command( - TARGET _vision_api POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${lib} - ${PYTHON_PACKAGE_DIR} - COMMENT "Copying ${lib} to ${PYTHON_PACKAGE_DIR}" - ) -endforeach() From f34b23353a845dbad3a2b50ef5ca4fad1871b595 Mon Sep 17 00:00:00 2001 From: Ronald Hecker Date: Fri, 16 May 2025 10:15:12 +0200 Subject: [PATCH 37/38] Install generated .so to cmake binary dir --- src/cpp/py_bindings/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cpp/py_bindings/CMakeLists.txt b/src/cpp/py_bindings/CMakeLists.txt index fc6ab66f..4ed1c5ad 100644 --- a/src/cpp/py_bindings/CMakeLists.txt +++ b/src/cpp/py_bindings/CMakeLists.txt @@ -29,7 +29,11 @@ message(INFO ${BINDINGS_SOURCES}) nanobind_add_module(_vision_api NB_STATIC STABLE_ABI LTO ${BINDINGS_SOURCES} ${BINDINGS_HEADERS}) set_target_properties(_vision_api PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/vision_api" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) target_link_libraries(_vision_api PRIVATE model_api) + +install(TARGETS _vision_api + LIBRARY DESTINATION vision_api # Same place relative to package +) From e376510563443b119ff7a370136fc1e24390898e Mon Sep 17 00:00:00 2001 From: "Hecker, Ronald" Date: Mon, 19 May 2025 10:21:28 +0200 Subject: [PATCH 38/38] Remove run.py --- src/cpp/py_bindings/run.py | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 src/cpp/py_bindings/run.py diff --git a/src/cpp/py_bindings/run.py b/src/cpp/py_bindings/run.py deleted file mode 100644 index 16141d5b..00000000 --- a/src/cpp/py_bindings/run.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 - -from vision_api import ClassificationModel -import cv2 - -import sys - -if len(sys.argv) != 3: - raise RuntimeError(f"Usage: {sys.argv[0]} ") - -model_path = sys.argv[1] -image_path = sys.argv[2] - -model = ClassificationModel.create_model(model_path) -image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB) -model(image)