From 49c2effa4d7759b4c7c92b88bcabc9d0f0e5ec6d Mon Sep 17 00:00:00 2001 From: "Bangadkar, Sachin" Date: Tue, 23 Jan 2024 09:57:30 +0000 Subject: [PATCH] Feature/v3 parsing and metadata --- ChangeLog.md | 5 + modules/device/include/ifm3d/device/device.h | 2 + modules/device/include/ifm3d/device/err.h | 1 + modules/device/src/libifm3d_device/err.cpp | 3 + .../framegrabber/include/ifm3d/fg/buffer.h | 14 ++- .../include/ifm3d/fg/detail/buffer.hpp | 14 ++- modules/framegrabber/include/ifm3d/fg/frame.h | 50 +++++++-- .../framegrabber/include/ifm3d/fg/organizer.h | 2 +- .../include/ifm3d/fg/organizer_utils.h | 36 ++++--- .../src/libifm3d_framegrabber/buffer.cpp | 16 ++- .../src/libifm3d_framegrabber/frame.cpp | 21 ++-- .../frame_grabber_impl.hpp | 3 +- .../src/libifm3d_framegrabber/frame_impl.hpp | 51 ++++++--- .../libifm3d_framegrabber/o3d_organizer.cpp | 38 ++++--- .../libifm3d_framegrabber/o3r_organizer.cpp | 11 +- .../libifm3d_framegrabber/o3r_organizer3D.cpp | 46 ++++---- .../libifm3d_framegrabber/o3x_organizer.cpp | 34 +++--- .../libifm3d_framegrabber/organizer_utils.cpp | 101 +++++++++++++----- .../src/libifm3d_framegrabber/schema.cpp | 20 ++++ modules/framegrabber/test/ifm3d-fg-tests.cpp | 43 ++++++++ modules/pybind11/src/bindings/frame.h | 24 ++++- modules/pybind11/src/main.cpp | 4 +- modules/pybind11/src/util.hpp | 51 +++++++++ setup.py | 2 +- 24 files changed, 443 insertions(+), 149 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index e41a2b17..88978cbb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Parsing of V3 chunks +- Ability to access V3 chunk metadata (see Frame::Metadata) +- Ability to access multiple chunks with the same id in a frame (see Frame::GetBuffer and Frame::GetBufferCount) +- O3R_RESULT_JSON and O3R_RESULT_ARRAY2D chunk ids ### Changes - Use .deb files in Dockerfile instead of building from sources diff --git a/modules/device/include/ifm3d/device/device.h b/modules/device/include/ifm3d/device/device.h index 10654e20..a3820987 100644 --- a/modules/device/include/ifm3d/device/device.h +++ b/modules/device/include/ifm3d/device/device.h @@ -114,6 +114,8 @@ namespace ifm3d ALGO_DEBUG = 900, O3R_ODS_OCCUPANCY_GRID = 1000, O3R_ODS_INFO = 1001, + O3R_RESULT_JSON = 1002, + O3R_RESULT_ARRAY2D = 1003 }; class XMLRPCWrapper; diff --git a/modules/device/include/ifm3d/device/err.h b/modules/device/include/ifm3d/device/err.h index 25b47c48..d858b2bc 100644 --- a/modules/device/include/ifm3d/device/err.h +++ b/modules/device/include/ifm3d/device/err.h @@ -64,6 +64,7 @@ extern IFM3D_DEVICE_EXPORT const int IFM3D_CORRUPTED_STRUCT; extern IFM3D_DEVICE_EXPORT const int IFM3D_DEVICE_PORT_INCOMPATIBLE_WITH_ORGANIZER; extern IFM3D_DEVICE_EXPORT const int IFM3D_DEVICE_PORT_NOT_SUPPORTED; +extern IFM3D_DEVICE_EXPORT const int IFM3D_INDEX_OUT_OF_RANGE; // sensor errors extern IFM3D_DEVICE_EXPORT const int IFM3D_XMLRPC_OBJ_NOT_FOUND; extern IFM3D_DEVICE_EXPORT const int IFM3D_INVALID_PARAM; diff --git a/modules/device/src/libifm3d_device/err.cpp b/modules/device/src/libifm3d_device/err.cpp index c89bd67f..b29cc965 100644 --- a/modules/device/src/libifm3d_device/err.cpp +++ b/modules/device/src/libifm3d_device/err.cpp @@ -48,6 +48,7 @@ const int IFM3D_SYSTEM_ERROR = -100034; const int IFM3D_CORRUPTED_STRUCT = -100035; const int IFM3D_DEVICE_PORT_INCOMPATIBLE_WITH_ORGANIZER = -100036; const int IFM3D_DEVICE_PORT_NOT_SUPPORTED = -100037; +const int IFM3D_INDEX_OUT_OF_RANGE = -100038; // sensor errors const int IFM3D_XMLRPC_OBJ_NOT_FOUND = 100000; const int IFM3D_INVALID_PARAM = 101000; @@ -162,6 +163,8 @@ ifm3d::strerror(int errnum) "organizers"; case IFM3D_DEVICE_PORT_NOT_SUPPORTED: return "Lib: Port is not supported by the device"; + case IFM3D_INDEX_OUT_OF_RANGE: + return "Lib: index is out of range"; case IFM3D_XMLRPC_OBJ_NOT_FOUND: return "Sensor: XMLRPC obj not found - trying to access dead session?"; case IFM3D_INVALID_PARAM: diff --git a/modules/framegrabber/include/ifm3d/fg/buffer.h b/modules/framegrabber/include/ifm3d/fg/buffer.h index e1fe6bf1..9920c25b 100644 --- a/modules/framegrabber/include/ifm3d/fg/buffer.h +++ b/modules/framegrabber/include/ifm3d/fg/buffer.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -114,6 +116,8 @@ namespace ifm3d size_t bytes_per_pixel; /* @brief bytes per row */ size_t bytes_per_row; + /* @brief json formatted metadata of the chunk obtain from device*/ + json metadata_; class BufferAllocator; std::shared_ptr buffer_allocator_; @@ -132,13 +136,15 @@ namespace ifm3d @param nchannel Number of channels in Buffer @param format value from ifm3d::pixel_format releates to data type need to store one value. + @param metadata json formatted metadata of the chunk obtain from device @note This internally calls Create Method to allocates Memory */ Buffer(const std::uint32_t cols, const std::uint32_t rows, const std::uint32_t nchannel, - ifm3d::pixel_format format); + ifm3d::pixel_format format, + std::optional metadata = std::nullopt); virtual ~Buffer() = default; @@ -172,6 +178,7 @@ namespace ifm3d std::uint32_t width() const; std::uint32_t nchannels() const; ifm3d::pixel_format dataFormat() const; + ifm3d::json metadata() const; /** * @brief Return the size of the buffer in bytes @@ -321,7 +328,9 @@ namespace ifm3d /* Similar to Buffer(cols,rows,ifm3d::formatType::nchannel, * ifm3d::formatType::format ) */ - Buffer_(const std::uint32_t cols, const std::uint32_t rows); + Buffer_(const std::uint32_t cols, + const std::uint32_t rows, + std::optional metadata = std::nullopt); ~Buffer_() = default; @@ -349,6 +358,7 @@ namespace ifm3d std::uint32_t width() const; std::uint32_t nchannels() const; ifm3d::pixel_format dataFormat() const; + ifm3d::json metadata() const; /** @brief returns a pointer to the specified Buffer row. @param row number diff --git a/modules/framegrabber/include/ifm3d/fg/detail/buffer.hpp b/modules/framegrabber/include/ifm3d/fg/detail/buffer.hpp index 5d367ee9..4651908a 100644 --- a/modules/framegrabber/include/ifm3d/fg/detail/buffer.hpp +++ b/modules/framegrabber/include/ifm3d/fg/detail/buffer.hpp @@ -314,12 +314,15 @@ template ifm3d::Buffer_::Buffer_() : ifm3d::Buffer(){}; template -ifm3d::Buffer_::Buffer_(const std::uint32_t cols, const std::uint32_t rows) +ifm3d::Buffer_::Buffer_(const std::uint32_t cols, + const std::uint32_t rows, + std::optional metadata) : ifm3d::Buffer( cols, rows, static_cast(ifm3d::FormatType::nchannel), - static_cast(ifm3d::FormatType::format)) + static_cast(ifm3d::FormatType::format), + metadata) {} template @@ -390,6 +393,13 @@ ifm3d::Buffer_::dataFormat() const return Buffer::dataFormat(); } +template +ifm3d::json +ifm3d::Buffer_::metadata() const +{ + return Buffer::metadata(); +} + template Tp* ifm3d::Buffer_::ptr(const std::uint32_t row) diff --git a/modules/framegrabber/include/ifm3d/fg/frame.h b/modules/framegrabber/include/ifm3d/fg/frame.h index f8cdeceb..297de1f6 100644 --- a/modules/framegrabber/include/ifm3d/fg/frame.h +++ b/modules/framegrabber/include/ifm3d/fg/frame.h @@ -149,35 +149,55 @@ namespace ifm3d */ ALGO_DEBUG = static_cast(ifm3d::image_chunk::ALGO_DEBUG), - /** @hideinitializer + /** @hideinitializer * @brief ifm3d::ODSOccupancyGridV1 */ O3R_ODS_OCCUPANCY_GRID = static_cast(ifm3d::image_chunk::O3R_ODS_OCCUPANCY_GRID), - /** @hideinitializer + /** @hideinitializer * @brief ifm3d::ODSInfoV1 */ O3R_ODS_INFO = static_cast(ifm3d::image_chunk::O3R_ODS_INFO), + /** @hideinitializer + * @brief ifm3d::O3R_RESULT_JSON + */ + O3R_RESULT_JSON = static_cast(ifm3d::image_chunk::O3R_RESULT_JSON), + + /** @hideinitializer + * @brief ifm3d::O3R_RESULT_ARRAY2D + */ + O3R_RESULT_ARRAY2D = static_cast(ifm3d::image_chunk::O3R_RESULT_ARRAY2D), + + /** @hideinitializer * @brief The point cloud encoded as a 3 channel XYZ image */ - XYZ = std::numeric_limits::max(), + XYZ = std::numeric_limits::max(), /** @hideinitializer * @brief \c */ - EXPOSURE_TIME, + EXPOSURE_TIME, /** @hideinitializer * @brief \c */ ILLUMINATION_TEMP, + + O3R_ODS_FLAGS, + O3R_MCC_LIVE_IMAGE, + O3R_MCC_MOTION_IMAGE, + O3R_MCC_STATIC_IMAGE, + // clang-format on }; using TimePointT = std::chrono::time_point; + using BufferList = std::vector; + using BufferDataListMap = std::map; + /** @ingroup FrameGrabber * * Represent a frame of data received from the the device. @@ -187,7 +207,7 @@ namespace ifm3d public: using Ptr = std::shared_ptr; - Frame(const std::map& images, + Frame(const BufferDataListMap& images, const std::vector timestamps, uint64_t frame_count); ~Frame(); @@ -218,10 +238,17 @@ namespace ifm3d * @brief Get the image with the given id * * @param id the id of the image to get + * @param index of the image * @return Image& Reference to the requested buffer * @throw std::out_of_range if no image with the give id exists */ - Buffer& GetBuffer(buffer_id id); + Buffer& GetBuffer(buffer_id id, + std::optional index = std::nullopt); + + /** + * @brief Get the total number of image with the given id + */ + size_t GetBufferCount(buffer_id id); /** * @brief Get the frame count according to algorithm output @@ -236,12 +263,13 @@ namespace ifm3d */ std::vector GetBuffers(); - decltype(std::declval>().begin()) + decltype(std::declval>().begin()) begin() noexcept; - decltype(std::declval>().begin()) begin() - const noexcept; - decltype(std::declval>().end()) end() noexcept; - decltype(std::declval>().end()) end() + decltype(std::declval>().begin()) + begin() const noexcept; + decltype(std::declval>().end()) + end() noexcept; + decltype(std::declval>().end()) end() const noexcept; private: diff --git a/modules/framegrabber/include/ifm3d/fg/organizer.h b/modules/framegrabber/include/ifm3d/fg/organizer.h index da02cb81..b0a4fe70 100644 --- a/modules/framegrabber/include/ifm3d/fg/organizer.h +++ b/modules/framegrabber/include/ifm3d/fg/organizer.h @@ -24,7 +24,7 @@ namespace ifm3d public: struct Result { - std::map images; + std::map images; std::vector timestamps; uint32_t frame_count; }; diff --git a/modules/framegrabber/include/ifm3d/fg/organizer_utils.h b/modules/framegrabber/include/ifm3d/fg/organizer_utils.h index e87a4f9a..17769095 100644 --- a/modules/framegrabber/include/ifm3d/fg/organizer_utils.h +++ b/modules/framegrabber/include/ifm3d/fg/organizer_utils.h @@ -7,6 +7,7 @@ #define IFM3D_FG_ORGANIZER_UTILS_H #include +#include #include #include #include @@ -20,7 +21,7 @@ namespace ifm3d { constexpr std::size_t IMG_BUFF_START = 8; - std::map get_image_chunks( + std::map> get_image_chunks( const std::vector& data, std::size_t start_idx, std::optional end_idx = std::nullopt); @@ -40,7 +41,8 @@ namespace ifm3d std::size_t idx, std::size_t width, std::size_t height, - pixel_format fmt); + pixel_format fmt, + std::optional metadata = std::nullopt); Buffer create_xyz_buffer(const std::vector& data, std::size_t xidx, @@ -51,7 +53,8 @@ namespace ifm3d pixel_format fmt, const std::optional& mask); - auto find_metadata_chunk(const std::map& chunks) + auto find_metadata_chunk( + const std::map>& chunks) -> decltype(chunks.end()); std::tuple get_image_size( @@ -77,6 +80,9 @@ namespace ifm3d std::size_t get_chunk_pixeldata_size(const std::vector& data, std::size_t idx); + std::size_t get_chunk_header_version(const std::vector& data, + std::size_t idx); + void mask_buffer(Buffer& image, const Buffer& mask); bool is_probably_blob(const std::vector& data, @@ -86,18 +92,24 @@ namespace ifm3d Buffer create_pixel_mask(Buffer& confidence); - void parse_data(const std::vector& data, - const std::set& requestedImages, - const std::map& chunks, - const size_t width, - const size_t height, - std::map& data_blob, - std::map& data_image); - - void mask_images(std::map& images, + void parse_data( + const std::vector& data, + const std::set& requestedImages, + const std::map>& chunks, + const size_t width, + const size_t height, + std::map& data_blob, + std::map& data_image); + + void mask_images(std::map& images, ifm3d::Buffer& mask, std::function should_mask); + bool has_metadata(const std::vector& data, std::size_t idx); + + ifm3d::json create_metadata(const std::vector& data, + std::size_t idx); + /** * Create a value of type T from sizeof(T) bytes of the passed in byte * buffer. Given that the ifm sensors transmit data in little endian diff --git a/modules/framegrabber/src/libifm3d_framegrabber/buffer.cpp b/modules/framegrabber/src/libifm3d_framegrabber/buffer.cpp index 48d998fe..b68ae4a0 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/buffer.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/buffer.cpp @@ -90,13 +90,16 @@ ifm3d::Buffer::Buffer() data_size_in_bytes_(0), size_(0), bytes_per_pixel(0), - bytes_per_row(0) + bytes_per_row(0), + metadata_(ifm3d::json()) {} ifm3d::Buffer::Buffer(const std::uint32_t cols, const std::uint32_t rows, const std::uint32_t nchannel, - ifm3d::pixel_format format) + ifm3d::pixel_format format, + std::optional metadata) + : metadata_(metadata.value_or(ifm3d::json())) { create(cols, rows, nchannel, format); } @@ -129,8 +132,7 @@ ifm3d::Buffer::create(const std::uint32_t cols, ifm3d::Buffer ifm3d::Buffer::clone() const { - Buffer copy; - copy.create(cols_, rows_, nchannel_, data_format_); + Buffer copy(cols_, rows_, nchannel_, data_format_, metadata_); std::memcpy(copy.ptr(0), data_, size_); return copy; } @@ -163,4 +165,10 @@ size_t ifm3d::Buffer::size() const { return size_; +} + +ifm3d::json +ifm3d::Buffer::metadata() const +{ + return metadata_; } \ No newline at end of file diff --git a/modules/framegrabber/src/libifm3d_framegrabber/frame.cpp b/modules/framegrabber/src/libifm3d_framegrabber/frame.cpp index 9ad2c686..7824645d 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/frame.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/frame.cpp @@ -6,7 +6,7 @@ #include #include -ifm3d::Frame::Frame(const std::map& images, +ifm3d::Frame::Frame(const BufferDataListMap& images, const std::vector timestamps, uint64_t frame_count) : pImpl(std::make_unique(images, timestamps, frame_count)) @@ -47,9 +47,15 @@ ifm3d::Frame::HasBuffer(buffer_id id) } ifm3d::Buffer& -ifm3d::Frame::GetBuffer(buffer_id key) +ifm3d::Frame::GetBuffer(buffer_id key, std::optional index) { - return pImpl->GetBuffer(key); + return pImpl->GetBuffer(key, index); +} + +size_t +ifm3d::Frame::GetBufferCount(buffer_id id) +{ + return pImpl->GetBufferCount(id); } std::vector @@ -58,26 +64,27 @@ ifm3d::Frame::GetBuffers() return pImpl->GetBuffers(); }; -decltype(std::declval>().begin()) +decltype(std::declval>().begin()) ifm3d::Frame::begin() noexcept { return pImpl->begin(); } decltype( - std::declval>().begin()) + std::declval>().begin()) ifm3d::Frame::begin() const noexcept { return pImpl->begin(); } -decltype(std::declval>().end()) +decltype(std::declval>().end()) ifm3d::Frame::end() noexcept { return pImpl->end(); } -decltype(std::declval>().end()) +decltype( + std::declval>().end()) ifm3d::Frame::end() const noexcept { return pImpl->end(); diff --git a/modules/framegrabber/src/libifm3d_framegrabber/frame_grabber_impl.hpp b/modules/framegrabber/src/libifm3d_framegrabber/frame_grabber_impl.hpp index 42b7eb61..ac23645d 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/frame_grabber_impl.hpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/frame_grabber_impl.hpp @@ -653,7 +653,6 @@ void ifm3d::FrameGrabber::Impl::ImageHandler() { std::size_t buffer_size = this->payload_buffer_.size(); - bool buffer_valid = std::string(this->payload_buffer_.begin() + 4, this->payload_buffer_.begin() + 8) == "star" && @@ -669,6 +668,7 @@ ifm3d::FrameGrabber::Impl::ImageHandler() auto result = this->organizer_->Organize(this->payload_buffer_, this->requested_images_, this->IsMasking()); + auto frame = std::make_shared(result.images, result.timestamps, result.frame_count); @@ -687,6 +687,7 @@ ifm3d::FrameGrabber::Impl::ImageHandler() this->new_frame_callback_(frame); } } + catch (std::exception ex) { LOG_WARNING("Bad image: {}", ex.what()); diff --git a/modules/framegrabber/src/libifm3d_framegrabber/frame_impl.hpp b/modules/framegrabber/src/libifm3d_framegrabber/frame_impl.hpp index 847503e0..c8a5c7e4 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/frame_impl.hpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/frame_impl.hpp @@ -21,7 +21,7 @@ namespace ifm3d class IFM3D_FRAME_GRABBER_LOCAL Frame::Impl { public: - Impl(const std::map& images, + Impl(const BufferDataListMap& images, const std::vector timestamps, uint64_t frame_count); @@ -29,25 +29,27 @@ namespace ifm3d bool HasBuffer(buffer_id id); - Buffer& GetBuffer(buffer_id id); + Buffer& GetBuffer(buffer_id id, std::optional index); + size_t GetBufferCount(buffer_id id); std::vector GetBuffers(); uint64_t FrameCount(); - decltype(std::declval>().begin()) + decltype(std::declval>().begin()) begin() noexcept; - decltype(std::declval>().begin()) begin() - const noexcept; - decltype(std::declval>().end()) end() noexcept; - decltype(std::declval>().end()) end() + decltype(std::declval>().begin()) + begin() const noexcept; + decltype(std::declval>().end()) + end() noexcept; + decltype(std::declval>().end()) end() const noexcept; protected: //--------------------- // State //--------------------- - std::map images_; + BufferDataListMap images_; std::vector timestamps_; uint32_t frame_count_; @@ -55,7 +57,7 @@ namespace ifm3d } // end: namespace ifm3d -ifm3d::Frame::Impl::Impl(const std::map& images, +ifm3d::Frame::Impl::Impl(const BufferDataListMap& images, const std::vector timestamps, uint64_t frame_count) : images_(images), @@ -76,17 +78,35 @@ ifm3d::Frame::Impl::HasBuffer(buffer_id id) } ifm3d::Buffer& -ifm3d::Frame::Impl::GetBuffer(buffer_id id) +ifm3d::Frame::Impl::GetBuffer(buffer_id id, std::optional index) { if (HasBuffer(id)) { - return images_.at(id); + auto buffer_list = images_.at(id); + auto index_value = index.value_or(0); + if (index_value < buffer_list.size()) + { + return images_.at(id)[index_value]; + } + else + { + throw ifm3d::Error(IFM3D_INDEX_OUT_OF_RANGE, + fmt::format("buffer_id: {}, index = {}", + std::to_string(static_cast(id)), + index_value)); + } } throw ifm3d::Error( IFM3D_BUFFER_ID_NOT_AVAILABLE, fmt::format("buffer_id: {}", std::to_string(static_cast(id)))); } +size_t +ifm3d::Frame::Impl::GetBufferCount(ifm3d::buffer_id id) +{ + return images_.at(id).size(); +} + std::vector ifm3d::Frame::Impl::GetBuffers() { @@ -106,26 +126,27 @@ ifm3d::Frame::Impl::FrameCount() return frame_count_; } -decltype(std::declval>().begin()) +decltype(std::declval>().begin()) ifm3d::Frame::Impl::begin() noexcept { return images_.begin(); } decltype( - std::declval>().begin()) + std::declval>().begin()) ifm3d::Frame::Impl::begin() const noexcept { return images_.begin(); } -decltype(std::declval>().end()) +decltype(std::declval>().end()) ifm3d::Frame::Impl::end() noexcept { return images_.end(); } -decltype(std::declval>().end()) +decltype( + std::declval>().end()) ifm3d::Frame::Impl::end() const noexcept { return images_.end(); diff --git a/modules/framegrabber/src/libifm3d_framegrabber/o3d_organizer.cpp b/modules/framegrabber/src/libifm3d_framegrabber/o3d_organizer.cpp index be948c70..9e69f839 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/o3d_organizer.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/o3d_organizer.cpp @@ -34,7 +34,7 @@ ifm3d::O3DOrganizer::Organize(const std::vector& data, const std::set& requested_images, const bool masking) { - std::map images; + ifm3d::BufferDataListMap images; size_t end_idx = data.size() - 6; // iilumination temperature data if present will always come last as it last // data in schema Note : this is automatically done with sorting provided by @@ -51,7 +51,7 @@ ifm3d::O3DOrganizer::Organize(const std::vector& data, ifm3d::SIZE_OF_O3D_ILLUMINATION_TEMPERATURE_VALUE, 1, ifm3d::pixel_format::FORMAT_8U); - images[ifm3d::buffer_id::ILLUMINATION_TEMP] = illumination_temp_buffer; + images[ifm3d::buffer_id::ILLUMINATION_TEMP] = {illumination_temp_buffer}; end_idx = illumination_temp_idx; } @@ -68,7 +68,7 @@ ifm3d::O3DOrganizer::Organize(const std::vector& data, ifm3d::SIZE_OF_O3D_EXPOSURE_TIME_VALUES, 1, ifm3d::pixel_format::FORMAT_8U); - images[ifm3d::buffer_id::EXPOSURE_TIME] = exposure_time_buffer; + images[ifm3d::buffer_id::EXPOSURE_TIME] = {exposure_time_buffer}; end_idx = exposure_time_idx; } @@ -85,28 +85,28 @@ ifm3d::O3DOrganizer::Organize(const std::vector& data, } // get the image dimensions - auto [width, height] = get_image_size(data, metachunk->second); + auto [width, height] = get_image_size(data, *(metachunk->second.begin())); std::uint32_t npts = width * height; - auto timestamps = get_chunk_timestamps(data, metachunk->second); - auto frame_count = get_chunk_frame_count(data, metachunk->second); + auto timestamps = get_chunk_timestamps(data, *(metachunk->second.begin())); + auto frame_count = get_chunk_frame_count(data, *(metachunk->second.begin())); if (chunks.find(image_chunk::CARTESIAN_ALL) != chunks.end()) { - size_t cart_all_idx = chunks[image_chunk::CARTESIAN_ALL]; + size_t cart_all_idx = *(chunks[image_chunk::CARTESIAN_ALL].begin()); size_t x_idx = cart_all_idx + get_chunk_pixeldata_offset(data, cart_all_idx); size_t y_idx = x_idx + get_chunk_size(data, x_idx); size_t z_idx = y_idx + get_chunk_size(data, y_idx); - chunks[image_chunk::CARTESIAN_X_COMPONENT] = x_idx; - chunks[image_chunk::CARTESIAN_Y_COMPONENT] = y_idx; - chunks[image_chunk::CARTESIAN_Z_COMPONENT] = z_idx; + chunks[image_chunk::CARTESIAN_X_COMPONENT] = {x_idx}; + chunks[image_chunk::CARTESIAN_Y_COMPONENT] = {y_idx}; + chunks[image_chunk::CARTESIAN_Z_COMPONENT] = {z_idx}; chunks.erase(image_chunk::CARTESIAN_ALL); } - std::map data_blob, data_image; + std::map data_blob, data_image; ifm3d::parse_data(data, requested_images, chunks, @@ -121,7 +121,8 @@ ifm3d::O3DOrganizer::Organize(const std::vector& data, { if (images.find(buffer_id::CONFIDENCE_IMAGE) != images.end()) { - mask = create_pixel_mask(images[ifm3d::buffer_id::CONFIDENCE_IMAGE]); + mask = + create_pixel_mask(images[ifm3d::buffer_id::CONFIDENCE_IMAGE][0]); mask_images(data_image, mask.value(), std::bind(&ifm3d::O3DOrganizer::ShouldMask, @@ -143,17 +144,20 @@ ifm3d::O3DOrganizer::Organize(const std::vector& data, if (x != chunks.end() && y != chunks.end() && z != chunks.end()) { - auto fmt = get_chunk_format(data, x->second); + auto fmt = get_chunk_format(data, *(x->second.begin())); auto xyz = create_xyz_buffer( data, - x->second + get_chunk_pixeldata_offset(data, x->second), - y->second + get_chunk_pixeldata_offset(data, y->second), - z->second + get_chunk_pixeldata_offset(data, z->second), + *(x->second.begin()) + + get_chunk_pixeldata_offset(data, *(x->second.begin())), + *(y->second.begin()) + + get_chunk_pixeldata_offset(data, *(y->second.begin())), + *(z->second.begin()) + + get_chunk_pixeldata_offset(data, *(z->second.begin())), width, height, fmt, mask); - images[static_cast(buffer_id::XYZ)] = xyz; + images[static_cast(buffer_id::XYZ)] = {xyz}; } } return {images, timestamps, frame_count}; diff --git a/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer.cpp b/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer.cpp index e066a8b5..b082e93e 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer.cpp @@ -15,10 +15,9 @@ ifm3d::O3ROrganizer::Organize(const std::vector& data, const std::set& requested_images, const bool masking) { - std::map images; + std::map images; auto chunks = get_image_chunks(data, IMG_BUFF_START); - auto metachunk = find_metadata_chunk(chunks); // if we do not have a meta chunk we cannot go further @@ -29,13 +28,13 @@ ifm3d::O3ROrganizer::Organize(const std::vector& data, } // get the image dimensions - auto [width, height] = get_image_size(data, metachunk->second); + auto [width, height] = get_image_size(data, *(metachunk->second.begin())); std::uint32_t npts = width * height; - auto timestamps = get_chunk_timestamps(data, metachunk->second); - auto frame_count = get_chunk_frame_count(data, metachunk->second); + auto timestamps = get_chunk_timestamps(data, *(metachunk->second.begin())); + auto frame_count = get_chunk_frame_count(data, *(metachunk->second.begin())); - std::map data_blob, data_image; + std::map data_blob, data_image; ifm3d::parse_data(data, requested_images, chunks, diff --git a/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer3D.cpp b/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer3D.cpp index 8624f562..b724e38b 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer3D.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/o3r_organizer3D.cpp @@ -15,7 +15,7 @@ ifm3d::O3ROrganizer3D::Organize(const std::vector& data, const std::set& requested_images, const bool masking) { - std::map images; + std::map images; auto chunks = get_image_chunks(data, IMG_BUFF_START); @@ -29,11 +29,11 @@ ifm3d::O3ROrganizer3D::Organize(const std::vector& data, } // get the image dimensions - auto [width, height] = get_image_size(data, metachunk->second); + auto [width, height] = get_image_size(data, *(metachunk->second.begin())); std::uint32_t npts = width * height; - auto timestamps = get_chunk_timestamps(data, metachunk->second); - auto frame_count = get_chunk_frame_count(data, metachunk->second); + auto timestamps = get_chunk_timestamps(data, *(metachunk->second.begin())); + auto frame_count = get_chunk_frame_count(data, *(metachunk->second.begin())); // for an O3R device, a distance_image_info object will be created // for others a nullptr is returned @@ -42,19 +42,19 @@ ifm3d::O3ROrganizer3D::Organize(const std::vector& data, chunks.find(image_chunk::RADIAL_DISTANCE_IMAGE) != chunks.end() && chunks.find(image_chunk::NORM_AMPLITUDE_IMAGE) != chunks.end()) { - distance_image_info = - CreateDistanceImageInfo(data, - chunks.at(image_chunk::TOF_INFO), - chunks.at(image_chunk::RADIAL_DISTANCE_IMAGE), - chunks.at(image_chunk::NORM_AMPLITUDE_IMAGE), - width, - height); + distance_image_info = CreateDistanceImageInfo( + data, + *(chunks.at(image_chunk::TOF_INFO).begin()), + *(chunks.at(image_chunk::RADIAL_DISTANCE_IMAGE).begin()), + *(chunks.at(image_chunk::NORM_AMPLITUDE_IMAGE).begin()), + width, + height); chunks.erase(image_chunk::NORM_AMPLITUDE_IMAGE); chunks.erase(image_chunk::RADIAL_DISTANCE_IMAGE); } - std::map data_blob, data_image; + std::map data_blob, data_image; ifm3d::parse_data(data, requested_images, chunks, @@ -71,7 +71,8 @@ ifm3d::O3ROrganizer3D::Organize(const std::vector& data, { if (images.find(buffer_id::CONFIDENCE_IMAGE) != images.end()) { - mask = create_pixel_mask(images[ifm3d::buffer_id::CONFIDENCE_IMAGE]); + mask = + create_pixel_mask(images[ifm3d::buffer_id::CONFIDENCE_IMAGE][0]); mask_images(data_image, mask.value(), std::bind(&ifm3d::O3ROrganizer3D::ShouldMask, @@ -83,17 +84,20 @@ ifm3d::O3ROrganizer3D::Organize(const std::vector& data, if (distance_image_info != nullptr) { auto extracted = ExtractDistanceImageInfo(distance_image_info, mask); - images.insert(extracted.begin(), extracted.end()); + for (auto& itr : extracted) + { + images.insert({itr.first, {itr.second}}); + } if (images.find(ifm3d::buffer_id::RADIAL_DISTANCE_NOISE) != images.end()) { auto dist_noise_buffer = distance_image_info->applyDistanceResolution( images[static_cast( - ifm3d::image_chunk::RADIAL_DISTANCE_NOISE)]); + ifm3d::image_chunk::RADIAL_DISTANCE_NOISE)][0]); images[static_cast( - ifm3d::buffer_id::RADIAL_DISTANCE_NOISE)] = dist_noise_buffer; + ifm3d::buffer_id::RADIAL_DISTANCE_NOISE)] = {dist_noise_buffer}; } } else if (requested_images.empty() || @@ -106,17 +110,17 @@ ifm3d::O3ROrganizer3D::Organize(const std::vector& data, if (x != chunks.end() && y != chunks.end() && z != chunks.end()) { - auto fmt = get_chunk_format(data, x->second); + auto fmt = get_chunk_format(data, *(x->second.begin())); auto xyz = create_xyz_buffer(data, - x->second, - y->second, - z->second, + *(x->second.begin()), + *(y->second.begin()), + *(z->second.begin()), width, height, fmt, mask); - images[static_cast(buffer_id::XYZ)] = xyz; + images[static_cast(buffer_id::XYZ)] = {xyz}; } } diff --git a/modules/framegrabber/src/libifm3d_framegrabber/o3x_organizer.cpp b/modules/framegrabber/src/libifm3d_framegrabber/o3x_organizer.cpp index 8616e4e9..786bfd72 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/o3x_organizer.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/o3x_organizer.cpp @@ -15,7 +15,7 @@ ifm3d::O3XOrganizer::Organize(const std::vector& data, const std::set& requested_images, const bool masking) { - std::map images; + std::map images; auto chunks = get_image_chunks(data, IMG_BUFF_START); @@ -29,28 +29,28 @@ ifm3d::O3XOrganizer::Organize(const std::vector& data, } // get the image dimensions - auto [width, height] = get_image_size(data, metachunk->second); + auto [width, height] = get_image_size(data, *(metachunk->second.begin())); std::uint32_t npts = width * height; - auto timestamps = get_chunk_timestamps(data, metachunk->second); - auto frame_count = get_chunk_frame_count(data, metachunk->second); + auto timestamps = get_chunk_timestamps(data, *(metachunk->second.begin())); + auto frame_count = get_chunk_frame_count(data, *(metachunk->second.begin())); if (chunks.find(image_chunk::CARTESIAN_ALL) != chunks.end()) { - size_t cart_all_idx = chunks[image_chunk::CARTESIAN_ALL]; + size_t cart_all_idx = *(chunks[image_chunk::CARTESIAN_ALL].begin()); size_t x_idx = cart_all_idx + get_chunk_pixeldata_offset(data, cart_all_idx); size_t y_idx = x_idx + get_chunk_size(data, x_idx); size_t z_idx = y_idx + get_chunk_size(data, y_idx); - chunks[image_chunk::CARTESIAN_X_COMPONENT] = x_idx; - chunks[image_chunk::CARTESIAN_Y_COMPONENT] = y_idx; - chunks[image_chunk::CARTESIAN_Z_COMPONENT] = z_idx; + chunks[image_chunk::CARTESIAN_X_COMPONENT] = {x_idx}; + chunks[image_chunk::CARTESIAN_Y_COMPONENT] = {y_idx}; + chunks[image_chunk::CARTESIAN_Z_COMPONENT] = {z_idx}; chunks.erase(image_chunk::CARTESIAN_ALL); } - std::map data_blob, data_image; + std::map data_blob, data_image; ifm3d::parse_data(data, requested_images, chunks, @@ -65,7 +65,8 @@ ifm3d::O3XOrganizer::Organize(const std::vector& data, { if (images.find(buffer_id::CONFIDENCE_IMAGE) != images.end()) { - mask = create_pixel_mask(images[ifm3d::buffer_id::CONFIDENCE_IMAGE]); + mask = + create_pixel_mask(images[ifm3d::buffer_id::CONFIDENCE_IMAGE][0]); mask_images(data_image, mask.value(), std::bind(&ifm3d::O3XOrganizer::ShouldMask, @@ -87,17 +88,20 @@ ifm3d::O3XOrganizer::Organize(const std::vector& data, if (x != chunks.end() && y != chunks.end() && z != chunks.end()) { - auto fmt = get_chunk_format(data, x->second); + auto fmt = get_chunk_format(data, *(x->second.begin())); auto xyz = create_xyz_buffer( data, - x->second + get_chunk_pixeldata_offset(data, x->second), - y->second + get_chunk_pixeldata_offset(data, y->second), - z->second + get_chunk_pixeldata_offset(data, z->second), + *(x->second.begin()) + + get_chunk_pixeldata_offset(data, *(x->second.begin())), + *(y->second.begin()) + + get_chunk_pixeldata_offset(data, *(y->second.begin())), + *(z->second.begin()) + + get_chunk_pixeldata_offset(data, *(z->second.begin())), width, height, fmt, mask); - images[static_cast(buffer_id::XYZ)] = xyz; + images[static_cast(buffer_id::XYZ)] = {xyz}; } } diff --git a/modules/framegrabber/src/libifm3d_framegrabber/organizer_utils.cpp b/modules/framegrabber/src/libifm3d_framegrabber/organizer_utils.cpp index 478ef959..c1e94f78 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/organizer_utils.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/organizer_utils.cpp @@ -1,3 +1,4 @@ + #include #include #include @@ -12,6 +13,7 @@ constexpr auto CHUNK_OFFSET_TIME_STAMP = 0x001C; constexpr auto CHUNK_OFFSET_FRAME_COUNT = 0x0020; constexpr auto CHUNK_OFFSET_TIME_STAMP_SEC = 0x0028; constexpr auto CHUNK_OFFSET_TIME_STAMP_NSEC = 0x002C; +constexpr auto CHUNK_OFFSET_META_DATA = 0x0030; std::size_t ifm3d::get_format_size(ifm3d::pixel_format fmt) @@ -76,12 +78,13 @@ ifm3d::create_1d_buffer(const std::vector& data, std::size_t idx) { std::size_t pixeldata_offset = ifm3d::get_chunk_pixeldata_offset(data, idx); auto size = ifm3d::get_chunk_pixeldata_size(data, idx); - + auto metadata = create_metadata(data, idx); return create_buffer(data, idx + pixeldata_offset, size, 1, - pixel_format::FORMAT_8U); + pixel_format::FORMAT_8U, + metadata); } ifm3d::Buffer @@ -92,11 +95,13 @@ ifm3d::create_buffer(const std::vector& data, { auto fmt = get_chunk_format(data, idx); std::size_t pixeldata_offset = get_chunk_pixeldata_offset(data, idx); + auto metadata = create_metadata(data, idx); return ifm3d::create_buffer(data, idx + pixeldata_offset, width, height, - fmt); + fmt, + metadata); } ifm3d::Buffer @@ -104,12 +109,12 @@ ifm3d::create_buffer(const std::vector& data, std::size_t idx, std::size_t width, std::size_t height, - pixel_format fmt) + pixel_format fmt, + std::optional metadata) { uint32_t nchan = get_format_channels(fmt); std::size_t fsize = get_format_size(fmt); - - ifm3d::Buffer image(width, height, nchan, fmt); + ifm3d::Buffer image(width, height, nchan, fmt, metadata); std::size_t incr = fsize * nchan; std::size_t npts = width * height; @@ -288,12 +293,12 @@ ifm3d::create_xyz_buffer(const std::vector& data, } } -std::map +std::map> ifm3d::get_image_chunks(const std::vector& data, std::size_t start_idx, std::optional end_idx) { - std::map chunks; + std::map> chunks; std::size_t idx = start_idx; // start of first chunk std::size_t size = (end_idx.has_value() ? end_idx.value() : data.size()) - 6; @@ -302,8 +307,8 @@ ifm3d::get_image_chunks(const std::vector& data, { image_chunk chunk = static_cast(mkval(data.data() + idx)); - - chunks[chunk] = idx; + std::cout << static_cast(chunk) << "," << idx << " " << std::endl; + chunks[chunk].insert(idx); // move to the beginning of the next chunk std::uint32_t incr = mkval(data.data() + idx + 4); @@ -322,7 +327,7 @@ ifm3d::get_image_chunks(const std::vector& data, auto ifm3d::find_metadata_chunk( - const std::map& chunks) + const std::map>& chunks) -> decltype(chunks.end()) { // to get the metadata we use the confidence image for 3d and @@ -377,6 +382,13 @@ ifm3d::get_chunk_frame_count(const std::vector& data, return mkval(data.data() + idx + CHUNK_OFFSET_FRAME_COUNT); } +std::size_t +ifm3d::get_chunk_header_version(const std::vector& data, + std::size_t idx) +{ + return mkval(data.data() + idx + CHUNK_OFFSET_HEADER_VERSION); +} + std::vector ifm3d::get_chunk_timestamps(const std::vector& data, std::size_t idx) { @@ -539,13 +551,14 @@ ifm3d::create_pixel_mask(ifm3d::Buffer& confidence) } void -ifm3d::parse_data(const std::vector& data, - const std::set& requested_images, - const std::map& chunks, - const size_t width, - const size_t height, - std::map& data_blob, - std::map& data_image) +ifm3d::parse_data( + const std::vector& data, + const std::set& requested_images, + const std::map>& chunks, + const size_t width, + const size_t height, + std::map& data_blob, + std::map& data_image) { for (const auto& chunk : chunks) @@ -554,30 +567,60 @@ ifm3d::parse_data(const std::vector& data, requested_images.find(static_cast(chunk.first)) != requested_images.end()) { - if (is_probably_blob(data, chunk.second, width, height)) - { - auto buffer = create_1d_buffer(data, chunk.second); - data_blob[static_cast(chunk.first)] = buffer; - } - else + for (auto& index : chunk.second) { - auto image = create_buffer(data, chunk.second, width, height); - data_image[static_cast(chunk.first)] = image; + if (is_probably_blob(data, index, width, height)) + { + auto buffer = create_1d_buffer(data, index); + data_blob[static_cast(chunk.first)].push_back( + buffer); + } + else + { + auto image = create_buffer(data, index, width, height); + data_image[static_cast(chunk.first)].push_back( + image); + } } } } } void -ifm3d::mask_images(std::map& images, +ifm3d::mask_images(std::map& images, ifm3d::Buffer& mask, std::function should_mask) { - for (auto& [buffer_id_value, buffer] : images) + for (auto& [buffer_id_value, buffers] : images) { if (should_mask(buffer_id_value)) { - mask_buffer(buffer, mask); + for (auto& buffer : buffers) + { + mask_buffer(buffer, mask); + } } } +} + +bool +ifm3d::has_metadata(const std::vector& data, std::size_t idx) +{ + auto version = get_chunk_header_version(data, idx); + return version >= 3; +} + +ifm3d::json +ifm3d::create_metadata(const std::vector& data, std::size_t idx) +{ + if (has_metadata(data, idx)) + { + std::string metadata( + std::string((char*)(data.data() + idx + CHUNK_OFFSET_META_DATA), + get_chunk_pixeldata_offset(data, idx) - + CHUNK_OFFSET_META_DATA) + .c_str()); + return ifm3d::json::parse(metadata); + } + return {}; } \ No newline at end of file diff --git a/modules/framegrabber/src/libifm3d_framegrabber/schema.cpp b/modules/framegrabber/src/libifm3d_framegrabber/schema.cpp index f33b0bb4..634ad19d 100644 --- a/modules/framegrabber/src/libifm3d_framegrabber/schema.cpp +++ b/modules/framegrabber/src/libifm3d_framegrabber/schema.cpp @@ -88,6 +88,26 @@ const std::map o3r_schema_map{ {ifm3d::buffer_id::O3R_ODS_INFO, {{"type", "blob"}, {"id", "O3R_ODS_INFO"}}}, {ifm3d::buffer_id::O3R_ODS_OCCUPANCY_GRID, {{"type", "blob"}, {"id", "O3R_ODS_OCCUPANCY_GRID"}}}, + {ifm3d::buffer_id::O3R_RESULT_JSON, + {{"type", "blob"}, {"id", "O3R_RESULT_JSON"}}}, + {ifm3d::buffer_id::O3R_RESULT_ARRAY2D, + {{"type", "blob"}, {"id", "O3R_RESULT_ARRAY2D"}}}, + {ifm3d::buffer_id::O3R_ODS_FLAGS, + {{"type", "records"}, + {"id", "O3R_ODS_FLAGS"}, + {"elements", {{{"type", "blob"}, {"id", "O3R_RESULT_ARRAY2D"}}}}}}, + {ifm3d::buffer_id::O3R_MCC_LIVE_IMAGE, + {{"type", "records"}, + {"id", "O3R_MCC_LIVE_IMAGE"}, + {"elements", {{{"type", "blob"}, {"id", "O3R_RESULT_ARRAY2D"}}}}}}, + {ifm3d::buffer_id::O3R_MCC_MOTION_IMAGE, + {{"type", "records"}, + {"id", "O3R_MCC_MOTION_IMAGE"}, + {"elements", {{{"type", "blob"}, {"id", "O3R_RESULT_ARRAY2D"}}}}}}, + {ifm3d::buffer_id::O3R_MCC_STATIC_IMAGE, + {{"type", "records"}, + {"id", "O3R_MCC_STATIC_IMAGE"}, + {"elements", {{{"type", "blob"}, {"id", "O3R_RESULT_ARRAY2D"}}}}}}, }; ifm3d::json diff --git a/modules/framegrabber/test/ifm3d-fg-tests.cpp b/modules/framegrabber/test/ifm3d-fg-tests.cpp index 07f22a27..a91a76d2 100644 --- a/modules/framegrabber/test/ifm3d-fg-tests.cpp +++ b/modules/framegrabber/test/ifm3d-fg-tests.cpp @@ -577,3 +577,46 @@ TEST_F(FrameGrabberTest, digonistic_data_grabber) LOG_INFO("digonistic_data_grabber test"); EXPECT_NO_THROW(std::make_shared(dev_, 50009)); } + +TEST_F(FrameGrabberTest, metadata) +{ + LOG_INFO("PDS_CHUNKS test"); + using namespace ifm3d::literals; + + auto o3r = std::dynamic_pointer_cast(this->dev_); + + // setup device for PDS application + ifm3d::json json_command_extrinsic = + "{ \"ports\":{\"port2\":{\"processing\":{\"extrinsicHeadToUser\":{\"rotX\":1.57,\"rotY\" : -1.57,\"rotZ\" : 0,\"transX\" : 0,\"transY\" : 0,\"transZ\" : 0}}}} }"_json; + + o3r->Set(json_command_extrinsic); + + ifm3d::json json_command_testMethod = + "{\"applications\":{\"instances\":{\"app0\":{\"class\":\"pds\", \"ports\" : [\"port2\"] , \"state\" : \"IDLE\", \"configuration\" : {\"parameter\":{\"testMode\":1}}}}}}"_json; + o3r->Set(json_command_testMethod); + + const auto FG_PCIC_PORT = + o3r->Get()["/applications/instances/app0/data/pcicTCPPort"_json_pointer]; + + auto fg = std::make_shared(o3r, FG_PCIC_PORT); + + // Set Schema and start the grabber + fg->Start( + {ifm3d::buffer_id::O3R_RESULT_JSON, ifm3d::buffer_id::O3R_RESULT_ARRAY2D}); + + ifm3d::json json_command = + "{ \"applications\":{\"instances\":{\"app0\":{\"configuration\":{\"customization\":{\"command\":\"getPallet\"}}}}} }"_json; + + o3r->Set(json_command); + + auto frame = fg->WaitForFrame().get(); + + EXPECT_NO_THROW(frame->GetBuffer(ifm3d::buffer_id::O3R_RESULT_JSON)); + + auto buffer = frame->GetBuffer( + static_cast(ifm3d::buffer_id::O3R_RESULT_JSON)); + + EXPECT_TRUE(buffer.metadata().size() > 0); + EXPECT_TRUE(frame->GetBufferCount(static_cast( + ifm3d::buffer_id::O3R_RESULT_JSON)) > 0); +} \ No newline at end of file diff --git a/modules/pybind11/src/bindings/frame.h b/modules/pybind11/src/bindings/frame.h index 4cfe0d04..b07f0228 100644 --- a/modules/pybind11/src/bindings/frame.h +++ b/modules/pybind11/src/bindings/frame.h @@ -10,8 +10,9 @@ #include #include +#define PYBIND11_DETAILED_ERROR_MESSAGES void -bind_frame(pybind11::module_& m) +bind_frame(pybind11::module_& m, pybind11::module_& ifm3dpy) { // clang-format off py::class_ frame( @@ -79,14 +80,31 @@ bind_frame(pybind11::module_& m) frame.def( "get_buffer", - [](const ifm3d::Frame::Ptr& frame, ifm3d::buffer_id id){ - return ifm3d::image_to_array(frame->GetBuffer(id)); + [ifm3dpy](const ifm3d::Frame::Ptr& frame, ifm3d::buffer_id id, size_t index) + { + auto instance = ifm3dpy.attr("buffer"); + auto ifm3d_buffer = frame->GetBuffer(id, index); + py::object json_loads = py::module::import("json").attr("loads"); + py::gil_scoped_acquire acquire; + return instance(ifm3d::image_to_array(ifm3d_buffer),json_loads(ifm3d_buffer.metadata().dump())); }, py::arg("id"), + py::arg("index") = 0, R"( Get the buffer with the given id )"); + frame.def( + "get_buffer_count", + [](const ifm3d::Frame::Ptr& frame, ifm3d::buffer_id id) + { + return frame->GetBufferCount(id); + }, + py::arg("id"), + R"( + Get the total number of image with the given id + )"); + frame.def( "get_buffers", &ifm3d::Frame::GetBuffers, diff --git a/modules/pybind11/src/main.cpp b/modules/pybind11/src/main.cpp index 7dd77041..44419653 100644 --- a/modules/pybind11/src/main.cpp +++ b/modules/pybind11/src/main.cpp @@ -209,7 +209,7 @@ PYBIND11_MODULE(ifm3dpy, m) "logging", R"(Provides access for configuring the logging facilities of ifm3d.)"); bind_logging(logging_module); - + bind_numpy(m); auto device_module = m.def_submodule( "device", R"(Provides an implementation of the XMLRPC protocol for configuring the camera and pmd imager settings.)"); @@ -224,7 +224,7 @@ PYBIND11_MODULE(ifm3dpy, m) auto framegrabber_module = m.def_submodule( "framegrabber", R"(Provides an implementation of the PCIC protocol for streaming pixel data and triggered image acquisition.)"); - bind_frame(framegrabber_module); + bind_frame(framegrabber_module, m); bind_future( m, "FrameAwaitable", diff --git a/modules/pybind11/src/util.hpp b/modules/pybind11/src/util.hpp index 9c9d0ced..de2ff728 100644 --- a/modules/pybind11/src/util.hpp +++ b/modules/pybind11/src/util.hpp @@ -12,8 +12,59 @@ #include #include +using namespace pybind11::literals; + namespace py = pybind11; +void +bind_numpy(pybind11::module_& m) +{ + py::options options; + options.disable_function_signatures(); + py::object view_class = + py::module::import("numpy").attr("ndarray").attr("view"); + py::object parent_class = py::module::import("numpy").attr("ndarray"); + py::object parent_metaclass = + py::reinterpret_borrow((PyObject*)&PyType_Type)(parent_class); + py::dict attributes; + + py::object wrapper_class = parent_metaclass("ifm3d_ndarray", + py::make_tuple(parent_class), + attributes); + + wrapper_class.attr("__new__") = py::cpp_function( + [parent_class, view_class](py::object self, + const py::array& data, + const py::dict& metadata, + py::args args, + py::kwargs kwargs + + ) { + auto obj = view_class(data, self); + obj.attr("metadata") = metadata; + + return obj; + }, + // py::arg("data"), + // py::arg("metadada"), + py::is_method(wrapper_class), + py::doc(R"( + __new__(self, data: ndarray, metada: dict) -> ndarray + Create a buffer as numpy.ndarray with metadata. + )")); + + attributes["__array_finalize__"] = py::cpp_function( + [](py::object self, py::object obj) { + if (obj == Py_None) + { + return; + } + self.attr("metadata") = obj.attr("metadata"); + }, + py::is_method(wrapper_class)); + m.attr("buffer") = wrapper_class; +}; + namespace ifm3d { template diff --git a/setup.py b/setup.py index a7634497..8efd30d9 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,7 @@ def build_extension(self, ext): '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, '-DPYTHON_ARCHIVE_OUTPUT_DIRECTORY=' + extdir, '-DPYTHON_EXECUTABLE=' + sys.executable, - '-DCREATE_PYTHON_STUBS=ON'] + '-DCREATE_PYTHON_STUBS=OFF'] cfg = 'Debug' if self.debug else 'Release' build_args = ['--config', cfg]