Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: python bindings for image_transport and publish #323

Merged
merged 27 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c4d8434
feat: python bindings for image_transport and publish
tfoldi Sep 23, 2024
ac72a10
style: reformat code
tfoldi Sep 24, 2024
4f95097
style: missing headers, copyright year
tfoldi Sep 24, 2024
ff4ffd7
build: add tests
tfoldi Sep 24, 2024
8a4250c
build: remove pluginlib (not used)
tfoldi Sep 24, 2024
898d875
style: reformat with rolling ament config
tfoldi Sep 24, 2024
4ceb2ec
WIP: before moving spin to custom class
tfoldi Sep 26, 2024
591c0fe
doc: fix repository and bugtracker url
tfoldi Sep 26, 2024
2eddcbf
feat: camera_info and subscriber support
tfoldi Sep 26, 2024
4ba43b5
Merge branch 'feat_image_transport_py' of https://github.com/tfoldi/i…
tfoldi Sep 26, 2024
1d331ab
doc: create initial version of the README.md file
tfoldi Sep 26, 2024
74e32f1
doc: move README.md to the right location
tfoldi Sep 26, 2024
f3ece7d
feat: add image_transport parameter
tfoldi Sep 26, 2024
98042aa
doc: complete documentation
tfoldi Sep 27, 2024
1cc8b23
style: remove too long line
tfoldi Sep 27, 2024
03b8e9a
style: reformat
tfoldi Sep 27, 2024
d2983f8
style: fix documentation formating
tfoldi Sep 27, 2024
6b615d2
fix: CameraSubscriber class name
tfoldi Oct 1, 2024
0f0f3c7
build: move pybind11 to build only dep
tfoldi Oct 2, 2024
9246ea6
chore: implement review suggestions
tfoldi Oct 4, 2024
e6428ae
build: add <2.9 pybind11 compatibility
tfoldi Oct 8, 2024
6b802dd
Merge branch 'feat_image_transport_py' of https://github.com/tfoldi/i…
tfoldi Oct 8, 2024
e6e71f0
build: add <2.9 pybind11 compatibility
tfoldi Oct 8, 2024
2424f26
build: add <2.9 pybind11 compatibility
tfoldi Oct 8, 2024
817ed6c
build: ament_cppcheck(LANGUAGE "c++") after ament_lint_auto_find_test…
tfoldi Oct 8, 2024
7c1ea65
build: cpp check after test dependencies
tfoldi Oct 8, 2024
bf4eae9
build: skip cppcheck on Windows
tfoldi Oct 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions image_transport/include/image_transport/image_transport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ class ImageTransport
IMAGE_TRANSPORT_PUBLIC
explicit ImageTransport(rclcpp::Node::SharedPtr node);

IMAGE_TRANSPORT_PUBLIC
ImageTransport(const ImageTransport& other);

IMAGE_TRANSPORT_PUBLIC
ImageTransport& operator=(const ImageTransport& other);

IMAGE_TRANSPORT_PUBLIC
~ImageTransport();

Expand Down Expand Up @@ -364,6 +370,11 @@ class ImageTransport
std::unique_ptr<Impl> impl_;
};

struct ImageTransport::Impl
{
rclcpp::Node::SharedPtr node_;
};

} // namespace image_transport

#endif // IMAGE_TRANSPORT__IMAGE_TRANSPORT_HPP_
6 changes: 2 additions & 4 deletions image_transport/src/image_transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ std::vector<std::string> getLoadableTransports()
return loadableTransports;
}

struct ImageTransport::Impl
{
rclcpp::Node::SharedPtr node_;
};
ImageTransport::ImageTransport(const ImageTransport& other)
: impl_(std::make_unique<Impl>(*other.impl_)) {}

ImageTransport::ImageTransport(rclcpp::Node::SharedPtr node)
: impl_(std::make_unique<ImageTransport::Impl>())
Expand Down
3 changes: 3 additions & 0 deletions image_transport_py/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Changelog for package image_transport_py
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66 changes: 66 additions & 0 deletions image_transport_py/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
cmake_minimum_required(VERSION 3.5)
project(image_transport_py)

# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()

# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# Figure out Python3 debug/release before anything else can find_package it
if(WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug")
find_package(python_cmake_module REQUIRED)
find_package(PythonExtra REQUIRED)

# Force FindPython3 to use the debug interpreter where ROS 2 expects it
set(Python3_EXECUTABLE "${PYTHON_EXECUTABLE_DEBUG}")
endif()
tfoldi marked this conversation as resolved.
Show resolved Hide resolved


find_package(ament_cmake REQUIRED)
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
find_package(ament_cmake_python REQUIRED)
find_package(ament_cmake_ros REQUIRED)
find_package(image_transport REQUIRED)
find_package(pluginlib REQUIRED)
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)

# Find python before pybind11
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)

find_package(pybind11_vendor REQUIRED)
find_package(pybind11 REQUIRED)

ament_python_install_package(${PROJECT_NAME})

pybind11_add_module(_image_transport MODULE
src/image_transport_py/pybind_image_transport.cpp
)

target_include_directories(_image_transport PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")

target_link_libraries(_image_transport PUBLIC
image_transport::image_transport
rclcpp::rclcpp
${sensor_msgs_TARGETS}
)

# Install cython modules as sub-modules of the project
install(
TARGETS
_image_transport
DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}"
)

ament_package()
30 changes: 30 additions & 0 deletions image_transport_py/image_transport_py/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright 2023 Open Source Robotics Foundation, Inc.
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from rpyutils import add_dll_directories_from_env

# Since Python 3.8, on Windows we should ensure DLL directories are explicitly added
# to the search path.
# See https://docs.python.org/3/whatsnew/3.8.html#bpo-36085-whatsnew
with add_dll_directories_from_env('PATH'):
from image_transport_py._image_transport import (
ImageTransport,
Publisher,
)


__all__ = [
'ImageTransport',
'Publisher',
]
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
161 changes: 161 additions & 0 deletions image_transport_py/include/image_transport_py/cast_image.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// File generated by gen_ros_casters.py. Do not manually change.

#ifndef IMAGE_TRANSPORT_PY__CAST_IMAGE_HPP_
#define IMAGE_TRANSPORT_PY__CAST_IMAGE_HPP_

#include <memory>
#include <string>
#include <vector>

#include "pybind11/operators.h"
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"

#include "sensor_msgs/msg/image.hpp"

static inline bool is_ros_msg_type(pybind11::handle src, const std::string & msg_type_name)
{
return pybind11::hasattr(src, "__module__") &&
src.attr("__module__").cast<std::string>() == msg_type_name;
}

namespace pybind11
{
namespace detail
{

using ContainerAllocator = std::allocator<void>;

template <>
struct type_caster<builtin_interfaces::msg::Time_<ContainerAllocator>>
{
public:
PYBIND11_TYPE_CASTER(
builtin_interfaces::msg::Time_<ContainerAllocator>,
const_name("builtin_interfaces::msg::Time_<ContainerAllocator>"));
bool load(handle src, bool)
{
if (!is_ros_msg_type(src, "builtin_interfaces.msg._time")) {
return false;
}
value.sec = src.attr("sec").cast<int32_t>();
value.nanosec = src.attr("nanosec").cast<uint32_t>();
return true;
}

static handle cast(
builtin_interfaces::msg::Time_<ContainerAllocator> cpp_msg, return_value_policy /* policy */,
handle /* parent */)
{
object mod = module::import("builtin_interfaces.msg._time");
object MsgType = mod.attr("Time");
object msg = MsgType();
msg.attr("sec") = pybind11::cast(cpp_msg.sec);
msg.attr("nanosec") = pybind11::cast(cpp_msg.nanosec);
msg.inc_ref();
return msg;
}
};

template <>
struct type_caster<std_msgs::msg::Header_<ContainerAllocator>>
{
public:
PYBIND11_TYPE_CASTER(
std_msgs::msg::Header_<ContainerAllocator>,
const_name("std_msgs::msg::Header_<ContainerAllocator>"));
bool load(handle src, bool)
{
if (!is_ros_msg_type(src, "std_msgs.msg._header")) {
return false;
}
value.stamp = src.attr("stamp").cast<builtin_interfaces::msg::Time_<ContainerAllocator>>();
value.frame_id =
src.attr("frame_id")
.cast<std::basic_string<
char, std::char_traits<char>,
typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<char>>>();
return true;
}

static handle cast(
std_msgs::msg::Header_<ContainerAllocator> cpp_msg, return_value_policy /* policy */,
handle /* parent */)
{
object mod = module::import("std_msgs.msg._header");
object MsgType = mod.attr("Header");
object msg = MsgType();
msg.attr("stamp") = pybind11::cast(cpp_msg.stamp);
msg.attr("frame_id") = pybind11::cast(cpp_msg.frame_id);
msg.inc_ref();
return msg;
}
};

template <>
struct type_caster<sensor_msgs::msg::Image_<ContainerAllocator>>
{
public:
PYBIND11_TYPE_CASTER(
sensor_msgs::msg::Image_<ContainerAllocator>,
const_name("sensor_msgs::msg::Image_<ContainerAllocator>"));
bool load(handle src, bool)
{
if (!is_ros_msg_type(src, "sensor_msgs.msg._image")) {
return false;
}
value.header = src.attr("header").cast<std_msgs::msg::Header_<ContainerAllocator>>();
value.height = src.attr("height").cast<uint32_t>();
value.width = src.attr("width").cast<uint32_t>();
value.encoding =
src.attr("encoding")
.cast<std::basic_string<
char, std::char_traits<char>,
typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<char>>>();
value.is_bigendian = src.attr("is_bigendian").cast<uint8_t>();
value.step = src.attr("step").cast<uint32_t>();
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
value.data =
src.attr("data")
.cast<std::vector<
uint8_t,
typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<uint8_t>>>();
return true;
}

static handle cast(
sensor_msgs::msg::Image_<ContainerAllocator> cpp_msg, return_value_policy /* policy */,
handle /* parent */)
{
object mod = module::import("sensor_msgs.msg._image");
object MsgType = mod.attr("Image");
object msg = MsgType();
msg.attr("header") = pybind11::cast(cpp_msg.header);
msg.attr("height") = pybind11::cast(cpp_msg.height);
msg.attr("width") = pybind11::cast(cpp_msg.width);
msg.attr("encoding") = pybind11::cast(cpp_msg.encoding);
msg.attr("is_bigendian") = pybind11::cast(cpp_msg.is_bigendian);
msg.attr("step") = pybind11::cast(cpp_msg.step);
msg.attr("data") = pybind11::cast(cpp_msg.data);
msg.inc_ref();
return msg;
}
};

} // namespace detail
} // namespace pybind11

#endif // IMAGE_TRANSPORT_PY__CAST_IMAGE_HPP_
34 changes: 34 additions & 0 deletions image_transport_py/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<package format="3">
<name>image_transport_py</name>

<version>5.0.3</version>

<description>Python API for image_transport</description>

<author>Tamas Foldi</author>

<maintainer email="[email protected]">Alejandro Hernández</maintainer>
<maintainer email="[email protected]">John D'Angelo</maintainer>

<license>BSD</license>

<url type="repository">https://github.com/ros-perception/image_transport</url>
<url type="bugtracker">https://github.com/ros-perception/image_transport/issues</url>

<buildtool_depend>ament_cmake_ros</buildtool_depend>
<buildtool_depend>ament_cmake_python</buildtool_depend>
<buildtool_depend>python_cmake_module</buildtool_depend>
tfoldi marked this conversation as resolved.
Show resolved Hide resolved

<depend>image_transport</depend>
<depend>pybind11_vendor</depend>
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
<depend>pluginlib</depend>
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
<depend>rclcpp</depend>
<depend>sensor_msgs</depend>

<exec_depend>rpyutils</exec_depend>

<export>
<build_type>ament_cmake</build_type>
</export>

</package>
31 changes: 31 additions & 0 deletions image_transport_py/src/image_transport_py/pybind11.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
tfoldi marked this conversation as resolved.
Show resolved Hide resolved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IMAGE_TRANSPORT_PY__PYBIND11_HPP_
#define IMAGE_TRANSPORT_PY__PYBIND11_HPP_

// Ignore -Wunused-value for clang.
// Based on https://github.com/pybind/pybind11/issues/2225
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
#endif
#include <pybind11/pybind11.h>
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#include <pybind11/functional.h>
#include <pybind11/stl.h>

#endif // IMAGE_TRANSPORT_PY__PYBIND11_HPP_
Loading