From 7ba27e79e03862f684897291bcf70d3c3b87862a Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Tue, 23 Sep 2025 14:52:05 +1200 Subject: [PATCH 1/2] adds nanobind scaffolding for future python bindinds Signed-off-by: Anton Dukhovnikov --- .github/workflows/ci.yml | 2 ++ CMakeLists.txt | 11 ++++++- README.md | 1 + build_scripts/install_deps_linux.bash | 3 +- build_scripts/install_deps_mac.bash | 2 +- build_scripts/install_deps_windows.bash | 3 +- configure.cmake | 16 ++++++++++ src/bindings/CMakeLists.txt | 40 +++++++++++++++++++++++++ src/bindings/py_core.cpp | 9 ++++++ src/bindings/py_core.h | 6 ++++ src/bindings/py_module.cpp | 11 +++++++ src/bindings/py_util.cpp | 39 ++++++++++++++++++++++++ src/bindings/py_util.h | 6 ++++ src/rawtoaces_util/CMakeLists.txt | 2 +- 14 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 src/bindings/CMakeLists.txt create mode 100644 src/bindings/py_core.cpp create mode 100644 src/bindings/py_core.h create mode 100644 src/bindings/py_module.cpp create mode 100644 src/bindings/py_util.cpp create mode 100644 src/bindings/py_util.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a704639..a099566b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,7 @@ jobs: shell: bash run: | sudo yum install --setopt=tsflags=nodocs -y eigen3-devel ceres-solver-devel json-devel + sudo python -m pip install nanobind - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. @@ -152,6 +153,7 @@ jobs: shell: bash run: | sudo yum install --setopt=tsflags=nodocs -y eigen3-devel ceres-solver-devel json-devel + sudo python -m pip install nanobind - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. diff --git a/CMakeLists.txt b/CMakeLists.txt index 45b82bd1..bfe34dbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,11 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX /EHsc") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX") add_compile_definitions( NOMINMAX ) -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +elseif ( + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" +) # GCC/Clang strict flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -pedantic") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wextra -pedantic") @@ -69,6 +73,7 @@ endforeach() option( ENABLE_SHARED "Enable Shared Libraries" ON ) option( RTA_CENTOS7_CERES_HACK "Work around broken config in ceres-solver 1.12" OFF ) +option( RTA_BUILD_PYTHON_BINDINGS "Build python bindings" ON ) option( ENABLE_COVERAGE "Enable code coverage reporting" OFF ) if ( ENABLE_SHARED ) @@ -93,6 +98,10 @@ add_subdirectory("src/${RAWTOACES_CORE_LIB}") add_subdirectory("src/${RAWTOACES_UTIL_LIB}") add_subdirectory("src/rawtoaces") +if ( RTA_BUILD_PYTHON_BINDINGS ) + add_subdirectory(src/bindings) +endif ( RTA_BUILD_PYTHON_BINDINGS ) + enable_testing() add_subdirectory(tests) diff --git a/README.md b/README.md index 00ecc74a..57f1cc65 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ To build `rawtoaces` you would need to satisfy these dependencies: | `ceres` | `1.12.0` | Ceres Solver is an open source library for solving Non-linear Least Squares problems with bounds constraints and unconstrained optimization problems. It processes non-linear regression for rawtoaces. | [Ceres Solver installation](http://ceres-solver.org/installation.html)| | `boost` | `1.76.0` | Boost has multiple C++ libraries that support tasks related to linear algebra, multithreading, image processing, unit testing, etc. It unit testing for rawtoaces. | [Boost download](http://www.boost.org/) | | `OpenImageIO` | `3.0` | OpenImageIO is an open source library providing vast functionality for image processing. rawtoaces relies on OpenImageIO for reading raw files, saving AcesContainer files, and also all pixel operations. | [OpenImageIO installation](https://github.com/AcademySoftwareFoundation/OpenImageIO/blob/main/INSTALL.md) | +| `nanobind` | `1.9` | nanobind is a small binding library that exposes C++ types in Python and vice versa. | [nanobind installation](https://nanobind.readthedocs.io/en/latest/installing.html) | ### MacOS diff --git a/build_scripts/install_deps_linux.bash b/build_scripts/install_deps_linux.bash index 03338536..40e11401 100755 --- a/build_scripts/install_deps_linux.bash +++ b/build_scripts/install_deps_linux.bash @@ -8,4 +8,5 @@ time sudo apt-get -q -f install -y \ libceres-dev \ nlohmann-json3-dev \ libopencv-dev \ - openimageio-tools libopenimageio-dev + openimageio-tools libopenimageio-dev \ + nanobind-dev diff --git a/build_scripts/install_deps_mac.bash b/build_scripts/install_deps_mac.bash index f7504e57..ff616a9c 100755 --- a/build_scripts/install_deps_mac.bash +++ b/build_scripts/install_deps_mac.bash @@ -2,4 +2,4 @@ set -ex -brew install ceres-solver nlohmann-json openimageio +brew install ceres-solver nlohmann-json openimageio nanobind robin-map diff --git a/build_scripts/install_deps_windows.bash b/build_scripts/install_deps_windows.bash index aaea37d3..19a08fb9 100755 --- a/build_scripts/install_deps_windows.bash +++ b/build_scripts/install_deps_windows.bash @@ -5,4 +5,5 @@ set -ex vcpkg install \ ceres:x64-windows \ nlohmann-json:x64-windows \ - openimageio:x64-windows + openimageio:x64-windows \ + nanobind:x64-windows diff --git a/configure.cmake b/configure.cmake index 5ebc3399..02f79586 100644 --- a/configure.cmake +++ b/configure.cmake @@ -11,3 +11,19 @@ if (RTA_CENTOS7_CERES_HACK) else () find_package ( Ceres CONFIG REQUIRED ) endif () + +if (RTA_BUILD_PYTHON_BINDINGS) + + if ( CMAKE_VERSION VERSION_LESS 3.18 ) + set( DEV_MODULE Development ) + else () + set( DEV_MODULE Development.Module ) + endif () + + find_package ( Python 3.8 COMPONENTS Interpreter ${DEV_MODULE} REQUIRED ) + + execute_process ( + COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT) + find_package ( nanobind CONFIG REQUIRED ) +endif () diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt new file mode 100644 index 00000000..41c2ca24 --- /dev/null +++ b/src/bindings/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required ( VERSION 3.12 ) +include_directories ( "${CMAKE_CURRENT_SOURCE_DIR}" ) + +nanobind_add_module( rawtoaces_bindings + py_util.cpp py_util.h + py_core.cpp py_core.h + py_module.cpp +) + +target_link_libraries( rawtoaces_bindings + PUBLIC + ${RAWTOACES_UTIL_LIB} +) + +if ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) + target_compile_options ( nanobind-static PRIVATE -Wno-pedantic ) + target_compile_options ( rawtoaces_bindings PRIVATE -Wno-pedantic ) + if ( CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0 ) + target_compile_options ( nanobind-static PRIVATE -Wno-error=zero-length-bounds ) + target_compile_options ( rawtoaces_bindings PRIVATE -Wno-error=zero-length-bounds ) + endif () +elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" ) + target_compile_options ( nanobind-static PRIVATE -Wno-error=zero-length-array ) + target_compile_options ( rawtoaces_bindings PRIVATE -Wno-error=zero-length-array ) +endif() + +set_target_properties( rawtoaces_bindings PROPERTIES + OUTPUT_NAME "rawtoaces" + #EXPORT_NAME "rawtoaces" + #SOVERSION ${RAWTOACES_MAJOR_VERSION}.${RAWTOACES_MINOR_VERSION}.${RAWTOACES_PATCH_VERSION} + #VERSION ${RAWTOACES_VERSION} +) + +install( + TARGETS rawtoaces_bindings + EXPORT RAWTOACESTargets + LIBRARY DESTINATION ${INSTALL_LIB_DIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + PUBLIC_HEADER DESTINATION include/rawtoaces +) diff --git a/src/bindings/py_core.cpp b/src/bindings/py_core.cpp new file mode 100644 index 00000000..657da1ab --- /dev/null +++ b/src/bindings/py_core.cpp @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Contributors to the rawtoaces Project. + +#include "py_core.h" + +void core_bindings( nanobind::module_ & /*m - unused*/) +{ + // TODO: add the core lib bindings here +} diff --git a/src/bindings/py_core.h b/src/bindings/py_core.h new file mode 100644 index 00000000..c43825f7 --- /dev/null +++ b/src/bindings/py_core.h @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Contributors to the rawtoaces Project. + +#include + +void core_bindings( nanobind::module_ &m ); diff --git a/src/bindings/py_module.cpp b/src/bindings/py_module.cpp new file mode 100644 index 00000000..e3356e78 --- /dev/null +++ b/src/bindings/py_module.cpp @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Contributors to the rawtoaces Project. + +#include "py_core.h" +#include "py_util.h" + +NB_MODULE( rawtoaces, m ) +{ + core_bindings( m ); + util_bindings( m ); +} diff --git a/src/bindings/py_util.cpp b/src/bindings/py_util.cpp new file mode 100644 index 00000000..c9419a66 --- /dev/null +++ b/src/bindings/py_util.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Contributors to the rawtoaces Project. + +#include "py_util.h" +#include +#include + +using namespace rta::util; + +void util_bindings( nanobind::module_ &m ) +{ + nanobind::class_ image_converter( m, "ImageConverter" ); + + image_converter.def( nanobind::init<>() ); + + // TODO: add the rest of the ImageConverter methods and properties + image_converter + .def_rw( + "settings", + &ImageConverter::settings ) // The Settings class is described below + .def( "process_image", &ImageConverter::process_image ); + + nanobind::class_ settings( + image_converter, "Settings" ); + + // TODO: add the rest of the Settings' properties + settings.def( nanobind::init<>() ) + .def_rw( + "WB_Method", + &ImageConverter::Settings:: + WB_method ) // The WBMethod enum is described below + .def_rw( "illuminant", &ImageConverter::Settings::illuminant ); + + // TODO: add the rest of WBMethod values, add other enums following this example + nanobind::enum_( settings, "WBMethod" ) + .value( "Metadata", ImageConverter::Settings::WBMethod::Metadata ) + .value( "Illuminant", ImageConverter::Settings::WBMethod::Illuminant ) + .export_values(); +} diff --git a/src/bindings/py_util.h b/src/bindings/py_util.h new file mode 100644 index 00000000..c584632d --- /dev/null +++ b/src/bindings/py_util.h @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Contributors to the rawtoaces Project. + +#include + +void util_bindings( nanobind::module_ &m ); diff --git a/src/rawtoaces_util/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index 08bca6b9..f68a259d 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -50,4 +50,4 @@ install( TARGETS ${RAWTOACES_UTIL_LIB} LIBRARY DESTINATION ${INSTALL_LIB_DIR} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} PUBLIC_HEADER DESTINATION include/rawtoaces -) +) \ No newline at end of file From c3b8e0576589f82e58cacb8332879522d2a345be Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Tue, 23 Sep 2025 20:54:45 +1200 Subject: [PATCH 2/2] fix formatting Signed-off-by: Anton Dukhovnikov --- src/bindings/py_core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings/py_core.cpp b/src/bindings/py_core.cpp index 657da1ab..e343ac1e 100644 --- a/src/bindings/py_core.cpp +++ b/src/bindings/py_core.cpp @@ -3,7 +3,7 @@ #include "py_core.h" -void core_bindings( nanobind::module_ & /*m - unused*/) +void core_bindings( nanobind::module_ & /*m - unused*/ ) { // TODO: add the core lib bindings here }