Update orbbec_camera package to be compatible with cuvslam

This commit is contained in:
jj
2025-04-26 18:12:18 +08:00
parent 3c4764f8ca
commit 5bd616cb90
213 changed files with 2964 additions and 7751 deletions
+3 -16
View File
@@ -217,7 +217,7 @@ add_orbbec_executable(list_camera_profile_mode_node tools/list_camera_profile.cp
add_orbbec_executable(topic_statistics_node tools/topic_statistics.cpp)
add_orbbec_executable(metadata_save_files_node tools/metadata_save_files.cpp)
add_orbbec_executable(metadata_export_files_node tools/metadata_export_files.cpp)
add_orbbec_executable(ob_benchmark_node tools/ob_benchmark.cpp)
add_orbbec_executable(multi_save_cloud_node tools/multi_save_cloud_node.cpp)
add_library(frame_latency SHARED tools/frame_latency.cpp)
target_include_directories(frame_latency PUBLIC ${COMMON_INCLUDE_DIRS})
@@ -229,16 +229,6 @@ rclcpp_components_register_node(frame_latency
EXECUTABLE frame_latency_node
)
add_library(start_benchmark SHARED tools/start_benchmark.cpp)
target_include_directories(start_benchmark PUBLIC ${COMMON_INCLUDE_DIRS})
target_link_libraries(start_benchmark ${COMMON_LIBRARIES})
ament_target_dependencies(start_benchmark ${dependencies})
rclcpp_components_register_node(start_benchmark
PLUGIN "orbbec_camera::tools::StartBenchmark"
EXECUTABLE start_benchmark_node
)
add_library(multi_save_rgbir SHARED tools/multi_save_rgbir.cpp)
target_include_directories(multi_save_rgbir PUBLIC ${COMMON_INCLUDE_DIRS} )
target_link_libraries(multi_save_rgbir ${COMMON_LIBRARIES})
@@ -248,10 +238,8 @@ rclcpp_components_register_node(multi_save_rgbir
PLUGIN "orbbec_camera::tools::MultiCameraSubscriber"
EXECUTABLE multi_save_rgbir_node
)
# Install rules
install(TARGETS ${PROJECT_NAME} frame_latency
start_benchmark
multi_save_rgbir
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
@@ -261,7 +249,6 @@ install(TARGETS ${PROJECT_NAME} frame_latency
install(DIRECTORY include/ DESTINATION include)
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}/)
install(DIRECTORY config DESTINATION share/${PROJECT_NAME}/)
install(DIRECTORY examples DESTINATION share/${PROJECT_NAME}/)
install(DIRECTORY ${ORBBEC_INCLUDE_DIR} DESTINATION include)
install(DIRECTORY ${ORBBEC_LIBS_DIR}/ DESTINATION lib/ FILES_MATCHING PATTERN "*.so*")
install(DIRECTORY ${ORBBEC_LIBS_DIR}/extensions DESTINATION lib/)
@@ -278,7 +265,7 @@ install(TARGETS list_devices_node
topic_statistics_node
metadata_save_files_node
metadata_export_files_node
ob_benchmark_node
multi_save_cloud_node
DESTINATION lib/${PROJECT_NAME}/)
if (BUILD_TESTING)
@@ -290,4 +277,4 @@ ament_export_include_directories(include ${ORBBEC_INCLUDE_DIR})
ament_export_libraries(${PROJECT_NAME})
ament_export_dependencies(${dependencies} ${ORBBEC_LIBS})
ament_package()
ament_package()
@@ -20,4 +20,4 @@
#include <libobsensor/h/StreamProfile.h>
#include <libobsensor/h/Version.h>
#include <libobsensor/h/TypeHelper.h>
#include <libobsensor/h/RecordPlayback.h>
@@ -14,8 +14,9 @@
#include <libobsensor/hpp/Filter.hpp>
#include <libobsensor/hpp/Frame.hpp>
#include <libobsensor/hpp/Pipeline.hpp>
#include <libobsensor/hpp/RecordPlayback.hpp>
// #include <libobsensor/hpp/RecordPlayback.hpp>
#include <libobsensor/hpp/Sensor.hpp>
#include <libobsensor/hpp/StreamProfile.hpp>
#include <libobsensor/hpp/Version.hpp>
#include <libobsensor/hpp/TypeHelper.hpp>
@@ -155,7 +155,7 @@ OB_EXPORT void ob_set_logger_to_console(ob_log_severity severity, ob_error **err
/**
* @brief Set the extensions directory
* @brief The extensions directory is used to search for dynamic libraries that provide additional functionality to the SDK, such as the Frame filters.
* @brief The extensions directory is used to search for dynamic libraries that provide additional functionality to the SDK, such as the Frame filters.
*
* @attention Should be called before creating the context and pipeline, otherwise the default extensions directory (./extensions) will be used.
*
@@ -388,7 +388,7 @@ OB_EXPORT const char *ob_device_info_get_firmware_version(const ob_device_info *
*
* @param[in] info Device Information
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return const char* The connection type, currently supports: "USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1", "USB3.2", "Ethernet"
* @return const char* The connection type,currently supports:"USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1", "USB3.2", "Ethernet"
*/
OB_EXPORT const char *ob_device_info_get_connection_type(const ob_device_info *info, ob_error **error);
@@ -399,7 +399,7 @@ OB_EXPORT const char *ob_device_info_get_connection_type(const ob_device_info *i
*
* @param info Device Information
* @param error Pointer to an error object that will be set if an error occurs.
* @return const char* The IP address, such as "192.168.1.10"
* @return const char* The IP address,such as "192.168.1.10"
*/
OB_EXPORT const char *ob_device_info_get_ip_address(const ob_device_info *info, ob_error **error);
@@ -533,7 +533,7 @@ OB_EXPORT const char *ob_device_list_get_device_serial_number(const ob_device_li
* @param[in] list Device list object
* @param[in] index Device index
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return const char* returns the device connection type, currently supports: "USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1", "USB3.2",
* @return const char* returns the device connection type,currently supports:"USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1", "USB3.2",
* "Ethernet"
*/
OB_EXPORT const char *ob_device_list_get_device_connection_type(const ob_device_list *list, uint32_t index, ob_error **error);
@@ -546,22 +546,10 @@ OB_EXPORT const char *ob_device_list_get_device_connection_type(const ob_device_
* @param list Device list object
* @param index Device index
* @param error Pointer to an error object that will be set if an error occurs.
* @return const char* returns the device ip address, such as "192.168.1.10"
* @return const char* returns the device ip address,such as "192.168.1.10"
*/
OB_EXPORT const char *ob_device_list_get_device_ip_address(const ob_device_list *list, uint32_t index, ob_error **error);
/**
* @brief Get device local mac address
*
* @attention Only valid for network devices, otherwise it will return "0:0:0:0:0:0".
*
* @param list Device list object
* @param index Device index
* @param error Pointer to an error object that will be set if an error occurs.
* @return const char* returns the device mac address
*/
OB_EXPORT const char *ob_device_list_get_device_local_mac(const ob_device_list *list, uint32_t index, ob_error **error);
/**
* @brief Create a device.
*
@@ -592,7 +580,7 @@ OB_EXPORT ob_device *ob_device_list_get_device_by_serial_number(const ob_device_
* @brief On Linux platform, for usb device, the uid of the device is composed of bus-port-dev, for example 1-1.2-1. But the SDK will remove the dev number and
* only keep the bus-port as the uid to create the device, for example 1-1.2, so that we can create a device connected to the specified USB port. Similarly,
* users can also directly pass in bus-port as uid to create device.
* @brief For GMSL device, the uid is GMSL port with "gmsl2-" prefix, for example gmsl2-1.
* @brief For GMSL device,the uid is GMSL port with “gmsl2-” prefix, for example gmsl2-1.
*
* @attention If the device has already been acquired and created elsewhere, repeated acquisitions will return an error.
*
@@ -68,7 +68,7 @@ OB_EXPORT ob_exception_type ob_error_get_exception_type(const ob_error *error);
/**
* @brief Delete the error object.
*
* @param[in] error The error object to delete, you should set the pointer to NULL after calling this function.
* @param[in] error The error object to delete.
*/
OB_EXPORT void ob_delete_error(ob_error *error);
@@ -148,7 +148,7 @@ OB_EXPORT void ob_delete_frame(const ob_frame *frame, ob_error **error);
/**
* @brief Copy the information of the source frame object to the destination frame object.
* @brief Including the index, timestamp, system timestamp, global timestamp and metadata will be copied.
* @brief Including the index,timestamp,system timestamp,global timestamp and metadata will be copied.
*
* @param[in] src_frame Source frame object to copy the information from.
* @param[in] dst_frame Destination frame object to copy the information to.
@@ -224,7 +224,7 @@ OB_EXPORT void ob_frame_set_system_timestamp_us(ob_frame *frame, uint64_t system
/**
* @brief Get the global timestamp of the frame in microseconds.
* @brief The global timestamp is the time point when the frame was captured by the device, and has been converted to the host clock domain. The
* @brief The global timestamp is the time point when the frame was was captured by the device, and has been converted to the host clock domain. The
* conversion process base on the frame timestamp and can eliminate the timer drift of the device
*
* @attention The global timestamp is disabled by default. If global timestamp is not enabled, the function will return 0. To enable it, call @ref
@@ -603,24 +603,6 @@ OB_EXPORT ob_frame *ob_frameset_get_frame_by_index(const ob_frame *frameset, uin
*/
OB_EXPORT void ob_frameset_push_frame(ob_frame *frameset, const ob_frame *frame, ob_error **error);
/**
* @brief Get point cloud frame width
*
* @param[in] frame point cloud Frame object
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return uint32_t return the point cloud frame width
*/
OB_EXPORT uint32_t ob_point_cloud_frame_get_width(const ob_frame *frame, ob_error **error);
/**
* @brief Get point cloud frame height
*
* @param[in] frame point cloud Frame object
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return uint32_t return the point cloud frame height
*/
OB_EXPORT uint32_t ob_point_cloud_frame_get_height(const ob_frame *frame, ob_error **error);
// The following interfaces are deprecated and are retained here for compatibility purposes.
#define ob_frame_index ob_frame_get_index
#define ob_frame_format ob_frame_get_format
@@ -62,7 +62,7 @@ OB_EXPORT ob_multi_device_sync_config ob_device_get_multi_device_sync_config(con
*
* @attention The frequency of the user call this function multiplied by the number of frames per trigger should be less than the frame rate of the stream. The
* number of frames per trigger can be set by @ref framesPerTrigger.
* @attention For some models, receive and execute the capture command will have a certain delay and performance consumption, so the frequency of calling this
* @attention For some models,receive and execute the capture command will have a certain delay and performance consumption, so the frequency of calling this
* function should not be too high, please refer to the product manual for the specific supported frequency.
* @attention If the device is not in the @ref OB_MULTI_DEVICE_SYNC_MODE_HARDWARE_TRIGGERING mode, device will ignore the capture command.
*
@@ -23,8 +23,6 @@ typedef struct ob_context_t ob_context;
typedef struct ob_device_t ob_device;
typedef struct ob_device_info_t ob_device_info;
typedef struct ob_device_list_t ob_device_list;
typedef struct ob_record_device_t ob_record_device;
typedef struct ob_playback_device_t ob_playback_device;
typedef struct ob_camera_param_list_t ob_camera_param_list;
typedef struct ob_sensor_t ob_sensor;
typedef struct ob_sensor_list_t ob_sensor_list;
@@ -497,15 +495,6 @@ typedef enum {
} OBAlignMode,
ob_align_mode;
/**
* @brief Camera performance mode
*/
typedef enum {
ADAPTIVE_PERFORMANCE_MODE, /**< Camera adaptive mode */
HIGH_PERFORMANCE_MODE, /**< High Performance Mode */
} OBCameraPerformanceMode,
ob_camera_performance_mode;
/**
* @brief Rectangle
*/
@@ -725,14 +714,14 @@ typedef struct {
double zpps; // zpps=z0/fx
float baseline; // baseline length, for monocular camera,it means the distance of laser to the center of IR-CMOS
double fx; // focus
uint8_t bitSize; // disparity bit size (raw disp bit size, for example: MX6000 is 12, MX6600 is 14)
float unit; // reference units: unit=10 denote 1cm; unit=1 denote 1mm; unit=0.5 denote 0.5mm; and so on
uint8_t bitSize; // disparity bit size(raw disp bit size,for example: MX6000 is 12, MX6600 is 14)
float unit; // reference units:unit=10 denote 1cm; unit=1 denote 1mm; unit=0.5 denote 0.5mm; and so on
float minDisparity; // dual disparity coefficient
uint8_t packMode; // data pack mode
float dispOffset; // disparity offset, actual disp=chip disp + disp_offset
int32_t invalidDisp; // invalid disparity, usually is 0, dual IR add a auxiliary value.
int32_t dispIntPlace; // disp integer digits, default is 8, Gemini2 XL is 10
uint8_t isDualCamera; // 0 monocular camera, 1 dual camera
float dispOffset; // disparity offset,actual disp=chip disp + disp_offset
int32_t invalidDisp; // invalid disparity,usually is 0,dual IR add a auxiliary value.
int32_t dispIntPlace; // disp integer digits,default is 8,Gemini2 XL is 10
uint8_t isDualCamera; // 0 monocular camera,1 dual camera
} OBDisparityParam, ob_disparity_param;
/**
@@ -837,7 +826,7 @@ typedef enum {
/**
* @brief Secondary synchronize mode
* @brief Secondary device. Both process input trigger signal and output trigger signal to other devices.
* @brief Different sensors in a single devices receive trigger signals respectively: ext trigger -> RGB && ext trigger -> IR/Depth/TOF
* @brief Different sensors in a single devices receive trigger signals respectively:ext trigger -> RGB && ext trigger -> IR/Depth/TOF
*
* @attention With the current Gemini 2 device set to this mode, each Sensor receives the first external trigger signal
* after the stream is turned on and starts timing self-triggering at the set frame rate until the stream is turned off
@@ -871,7 +860,7 @@ typedef enum {
* @brief Software trigger synchronize mode as secondary device
* @brief The slave receives the external trigger signal (the external trigger signal comes from the soft trigger host) and outputs the trigger signal to
* the external relay.
* @brief Different sensors in a single machine receive trigger signals respectively: ext trigger -> RGB && ext trigger -> IR/Depth/TOF
* @brief Different sensors in a single machine receive trigger signals respectively:ext trigger -> RGB && ext trigger -> IR/Depth/TOF
*/
OB_SYNC_MODE_SECONDARY_SOFT_TRIGGER = 0x07,
@@ -1306,14 +1295,14 @@ typedef struct {
/**
* @brief The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
*
* @attention This parameter is only valid for some models, please refer to the product manual for details.
* @attention This parameter is only valid for some models, please refer to the product manual for details.
*/
int depthDelayUs;
/**
* @brief The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
*
* @attention This parameter is only valid for some models, please refer to the product manual for details.
* @attention This parameter is only valid for some models, please refer to the product manual for details.
*/
int colorDelayUs;
@@ -1559,14 +1548,14 @@ typedef enum {
/**
* @brief Power line frequency
* @brief For anti-flickering, 0: Close, 1: 50Hz, 2: 60Hz, 3: Auto
* @brief For anti-flickering, 0:Close, 1: 50Hz, 2: 60Hz, 3: Auto
*/
OB_FRAME_METADATA_TYPE_POWER_LINE_FREQUENCY = 15,
/**
* @brief Low light compensation
*
* @attention The low light compensation is a feature inside the device, and can not manually control it.
* @attention The low light compensation is a feature inside the device,and can not manually control it.
*/
OB_FRAME_METADATA_TYPE_LOW_LIGHT_COMPENSATION = 16,
@@ -1689,26 +1678,9 @@ typedef enum {
*
*/
OB_UVC_BACKEND_TYPE_V4L2,
/**
* @brief Use MSMF backend to access the UVC device
*/
OB_UVC_BACKEND_TYPE_MSMF,
} ob_uvc_backend_type,
OBUvcBackendType;
/**
* @brief The playback status of the media
*/
typedef enum {
OB_PLAYBACK_UNKNOWN ,
OB_PLAYBACK_PLAYING, /**< The media is playing */
OB_PLAYBACK_PAUSED, /**< The media is paused */
OB_PLAYBACK_STOPPED, /**< The media is stopped */
OB_PLAYBACK_COUNT,
} ob_playback_status, OBPlaybackStatus;
// For compatibility
#define OB_FRAME_METADATA_TYPE_LASER_POWER_MODE OB_FRAME_METADATA_TYPE_LASER_POWER_LEVEL
#define OB_FRAME_METADATA_TYPE_EMITTER_MODE OB_FRAME_METADATA_TYPE_LASER_STATUS
@@ -1815,7 +1787,6 @@ typedef void(ob_frame_destroy_callback)(uint8_t *buffer, void *user_data);
*/
typedef void(ob_log_callback)(ob_log_severity severity, const char *message, void *user_data);
typedef void(*ob_playback_status_changed_callback)(ob_playback_status status, void *user_data);
/**
* @brief Check if the sensor_type is a video sensor
*
@@ -306,7 +306,7 @@ typedef enum {
OB_PROP_DEPTH_ROTATE_INT = 118,
/**
* @brief Get hardware laser power actual level which real state of laser element. OB_PROP_LASER_POWER_LEVEL_CONTROL_INT99 will effect this command
* @brief Get hardware laser power actual level which real state of laser element. OB_PROP_LASER_POWER_LEVEL_CONTROL_INT99)will effect this command
* which it setting and changed the hardware laser energy level.
*/
OB_PROP_LASER_POWER_ACTUAL_LEVEL_INT = 119,
@@ -501,14 +501,6 @@ typedef enum {
* @brief hardware noise remove filter threshold ,range [0.0 - 1.0]
*/
OB_PROP_HW_NOISE_REMOVE_FILTER_THRESHOLD_FLOAT = 212,
/**
* @brief soft trigger auto capture enable, use in OB_MULTI_DEVICE_SYNC_MODE_SOFTWARE_TRIGGERING mode
*/
OB_DEVICE_AUTO_CAPTURE_ENABLE_BOOL = 216,
/**
* @brief soft trigger auto capture interval time, use in OB_MULTI_DEVICE_SYNC_MODE_SOFTWARE_TRIGGERING mode
*/
OB_DEVICE_AUTO_CAPTURE_INTERVAL_TIME_INT = 217,
/**
* @brief Baseline calibration parameters
*/
@@ -561,7 +553,7 @@ typedef enum {
/**
* @brief Device network static ip config record
* @brief Using for get last static ip config, witch is record in device flash when user set static ip config
* @brief Using for get last static ip config,witch is record in device flash when user set static ip config
*
* @attention read only
*/
@@ -808,11 +800,6 @@ typedef enum {
*/
OB_PROP_NETWORK_BANDWIDTH_TYPE_INT = 3027,
/**
* @brief Switch device performance mode, currently available in Adaptive Mode and High Performance Mode, such as G335LE.
*/
OB_PROP_DEVICE_PERFORMANCE_MODE_INT = 3028,
/**
* @brief Calibration JSON file read from device (Femto Mega, read only)
*/
@@ -1,135 +0,0 @@
// Copyright (c) Orbbec Inc. All Rights Reserved.
// Licensed under the MIT License.
/**
* @file RecordPlayback.hpp
* @brief Record and playback device-related types, including interfaces to create recording and playback devices,
record and playback streaming data, etc.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "Device.h"
/**
* @brief Create a recording device for the specified device with a specified file path and compression enabled.
*
* @param[in] device The device to record.
* @param[in] file_path The file path to record to.
* @param[in] compression_enabled Whether to enable compression for the recording.
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return A pointer to the newly created recording device, or NULL if an error occurred.
*/
OB_EXPORT ob_record_device *ob_create_record_device(ob_device *device, const char *file_path, bool compression_enabled, ob_error **error);
/**
* @brief Delete a recording device.
*
* @param[in] recorder The recording device to delete.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_delete_record_device(ob_record_device *recorder, ob_error **error);
/**
* @brief Pause recording on the specified recording device.
*
* @param[in] recorder The recording device to pause.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_record_device_pause(ob_record_device *recorder, ob_error **error);
/**
* @brief Resume recording on the specified recording device.
*
* @param[in] recorder The recording device to resume.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_record_device_resume(ob_record_device *recorder, ob_error **error);
/**
* @brief Create a playback device for the specified file path.
*
* @param[in] file_path The file path to playback from.
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return A pointer to the newly created playback device, or NULL if an error occurred.
*/
OB_EXPORT ob_device *ob_create_playback_device(const char *file_path, ob_error **error);
/**
* @brief Pause playback on the specified playback device.
*
* @param[in] player The playback device to pause.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_playback_device_pause(ob_device *player, ob_error **error);
/**
* @brief Resume playback on the specified playback device.
*
* @param[in] player The playback device to resume.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_playback_device_resume(ob_device *player, ob_error **error);
/**
* @brief Set the playback to a specified time point of the played data.
*
* @param[in] player The playback device to set the position for.
* @param[in] timestamp The position to set the playback to, in milliseconds.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_playback_device_seek(ob_device *player, const uint64_t timestamp, ob_error **error);
/**
* @brief Set the playback to a specified time point of the played data.
*
* @param[in] player The playback device to set the position for.
* @param[in] rate The playback rate to set.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_playback_device_set_playback_rate(ob_device *player, const float rate, ob_error **error);
/**
* @brief Get the current playback status of the played data.
*
* @param[in] player The playback device to get the status for.
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return The current playback status of the played data.
*/
OB_EXPORT ob_playback_status ob_playback_device_get_current_playback_status(ob_device *player, ob_error **error);
/**
* @brief Set a callback function to receive playback status updates.
*
* @param[in] player The playback device to set the callback for.
* @param[in] callback The callback function to receive playback status updates.
* @param[out] error Pointer to an error object that will be set if an error occurs.
*/
OB_EXPORT void ob_playback_device_set_playback_status_changed_callback(ob_device *player, ob_playback_status_changed_callback callback, void *user_data,
ob_error **error);
/**
* @brief Get the current playback position of the played data.
*
* @param[in] player The playback device to get the position for.
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return The current playback position of the played data, in milliseconds.
*/
OB_EXPORT uint64_t ob_playback_device_get_position(ob_device *player, ob_error **error);
/**
* @brief Get the duration of the played data.
*
* @param[in] player The playback device to get the duration for.
* @param[out] error Pointer to an error object that will be set if an error occurs.
* @return The duration of the played data, in milliseconds.
*/
OB_EXPORT uint64_t ob_playback_device_get_duration(ob_device *player, ob_error **error);
#ifdef __cplusplus
} // extern "C"
#endif
+26 -37
View File
@@ -19,7 +19,8 @@ extern "C" {
*
* @return bool Transform result
*/
OB_EXPORT bool ob_transformation_3d_to_3d(const OBPoint3f source_point3f, OBExtrinsic extrinsic, OBPoint3f *target_point3f, ob_error **error);
OB_EXPORT bool ob_transformation_3d_to_3d(const OBPoint3f source_point3f, OBExtrinsic extrinsic, OBPoint3f *target_point3f, ob_error **error) ;
/**
* @brief Transform a 2d pixel coordinate with an associated depth value of the source camera into a 3d point of the target coordinate system.
@@ -34,8 +35,9 @@ OB_EXPORT bool ob_transformation_3d_to_3d(const OBPoint3f source_point3f, OBExtr
*
* @return bool Transform result
*/
OB_EXPORT bool ob_transformation_2d_to_3d(const OBPoint2f source_point2f, const float source_depth_pixel_value, const OBCameraIntrinsic source_intrinsic,
OBExtrinsic extrinsic, OBPoint3f *target_point3f, ob_error **error);
OB_EXPORT bool ob_transformation_2d_to_3d(const OBPoint2f source_point2f, const float source_depth_pixel_value, const OBCameraIntrinsic source_intrinsic,
OBExtrinsic extrinsic, OBPoint3f *target_point3f, ob_error **error);
/**
* @brief Transform a 3d point of a source coordinate system into a 2d pixel coordinate of the target camera.
@@ -67,59 +69,46 @@ OB_EXPORT bool ob_transformation_3d_to_2d(const OBPoint3f source_point3f, const
*
* @return bool Transform result
*/
OB_EXPORT bool ob_transformation_2d_to_2d(const OBPoint2f source_point2f, const float source_depth_pixel_value, const OBCameraIntrinsic source_intrinsic,
const OBCameraDistortion source_distortion, const OBCameraIntrinsic target_intrinsic,
const OBCameraDistortion target_distortion, OBExtrinsic extrinsic, OBPoint2f *target_point2f, ob_error **error);
OB_EXPORT bool ob_transformation_2d_to_2d(const OBPoint2f source_point2f, const float source_depth_pixel_value, const OBCameraIntrinsic source_intrinsic,
const OBCameraDistortion source_distortion, const OBCameraIntrinsic target_intrinsic, const OBCameraDistortion target_distortion,
OBExtrinsic extrinsic, OBPoint2f *target_point2f, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
// \deprecated This function is deprecated and will be removed in a future version.
OB_EXPORT ob_frame *transformation_depth_frame_to_color_camera(ob_device *device, ob_frame *depth_frame, uint32_t target_color_camera_width,
uint32_t target_color_camera_height, ob_error **error);
uint32_t target_color_camera_height, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
// \deprecated This function is deprecated and will be removed in a future version.
OB_EXPORT bool transformation_init_xy_tables(const ob_calibration_param calibration_param, const ob_sensor_type sensor_type, float *data, uint32_t *data_size,
ob_xy_tables *xy_tables, ob_error **error);
ob_xy_tables *xy_tables, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
// \deprecated This function is deprecated and will be removed in a future version.
OB_EXPORT void transformation_depth_to_pointcloud(ob_xy_tables *xy_tables, const void *depth_image_data, void *pointcloud_data, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
OB_EXPORT void transformation_depth_to_rgbd_pointcloud(ob_xy_tables *xy_tables, const void *depth_image_data, const void *color_image_data,
void *pointcloud_data, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
OB_EXPORT void transformation_depth_to_rgbd_pointcloud(ob_xy_tables *xy_tables, const void *depth_image_data, const void *color_image_data, void *pointcloud_data,
ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
// \deprecated This function is deprecated and will be removed in a future version.
// Use the ob_transformation_3d_to_3d instead.
OB_EXPORT bool ob_calibration_3d_to_3d(const ob_calibration_param calibration_param, const ob_point3f source_point3f, const ob_sensor_type source_sensor_type,
const ob_sensor_type target_sensor_type, ob_point3f *target_point3f, ob_error **error);
const ob_sensor_type target_sensor_type, ob_point3f *target_point3f, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
// \deprecated This function is deprecated and will be removed in a future version.
// Use the ob_transformation_2d_to_3d instead.
OB_EXPORT bool ob_calibration_2d_to_3d(const ob_calibration_param calibration_param, const ob_point2f source_point2f, const float source_depth_pixel_value,
const ob_sensor_type source_sensor_type, const ob_sensor_type target_sensor_type, ob_point3f *target_point3f,
ob_error **error);
const ob_sensor_type source_sensor_type, const ob_sensor_type target_sensor_type, ob_point3f *target_point3f, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
// \deprecated This function is deprecated and will be removed in a future version.
// Use the ob_transformation_3d_to_2d instead.
OB_EXPORT bool ob_calibration_3d_to_2d(const ob_calibration_param calibration_param, const ob_point3f source_point3f, const ob_sensor_type source_sensor_type,
const ob_sensor_type target_sensor_type, ob_point2f *target_point2f, ob_error **error);
const ob_sensor_type target_sensor_type, ob_point2f *target_point2f, ob_error **error);
// \deprecated This function is deprecated and will be removed in a future version.
// \deprecated This function is deprecated and will be removed in a future version.
// Use the ob_transformation_2d_to_2d instead.
OB_EXPORT bool ob_calibration_2d_to_2d(const ob_calibration_param calibration_param, const ob_point2f source_point2f, const float source_depth_pixel_value,
const ob_sensor_type source_sensor_type, const ob_sensor_type target_sensor_type, ob_point2f *target_point2f,
ob_error **error);
/**
* @brief save point cloud to ply file.
*
* @param[in] file_name Point cloud save path
* @param[in] frame Point cloud frame
* @param[in] save_binary Binary or textual,true: binary, false: textual
* @param[in] use_mesh Save mesh or not, true: save as mesh, false: not save as mesh
* @param[in] mesh_threshold Distance threshold for creating faces in point cloud,default value :50
* @param[out] error Pointer to an error object that will be set if an error occurs.
*
* @return bool save point cloud result
*/
OB_EXPORT bool ob_save_pointcloud_to_ply(const char *file_name, ob_frame *frame, bool save_binary, bool use_mesh, float mesh_threshold, ob_error **error);
const ob_sensor_type source_sensor_type, const ob_sensor_type target_sensor_type, ob_point2f *target_point2f, ob_error **error);
#ifdef __cplusplus
}
#endif
@@ -101,7 +101,7 @@ public:
* @brief Creates a network device with the specified IP address and port.
*
* @param[in] address The IP address, ipv4 only. such as "192.168.1.10"
* @param[in] port The port number, currently only support 8090
* @param[in] port The port number, currently only support 8090
* @return std::shared_ptr<Device> The created device object.
*/
std::shared_ptr<Device> createNetDevice(const char *address, uint16_t port) const {
@@ -210,7 +210,7 @@ public:
/**
* @brief Set the extensions directory
* @brief The extensions directory is used to search for dynamic libraries that provide additional functionality to the SDK, such as the Frame filters.
* @brief The extensions directory is used to search for dynamic libraries that provide additional functionality to the SDK, such as the Frame filters.
*
* @attention Should be called before creating the context and pipeline, otherwise the default extensions directory (./extensions) will be used.
*
@@ -491,7 +491,7 @@ public:
* Please delete the object directly and obtain it again after the device is reconnected.
* Support devices: Gemini2 L
*
* @param[in] delayMs Time unit: ms. delayMs == 0: No delay; delayMs > 0, Delay millisecond connect to host device after reboot
* @param[in] delayMs Time unit:ms。delayMs == 0:No delay;delayMs > 0, Delay millisecond connect to host device after reboot
*/
void reboot(uint32_t delayMs) const {
setIntProperty(OB_PROP_DEVICE_REBOOT_DELAY_INT, delayMs);
@@ -564,7 +564,7 @@ public:
*
* @attention The frequency of the user call this function multiplied by the number of frames per trigger should be less than the frame rate of the stream.
* The number of frames per trigger can be set by @ref framesPerTrigger.
* @attention For some models, receive and execute the capture command will have a certain delay and performance consumption, so the frequency of calling
* @attention For some models,receive and execute the capture command will have a certain delay and performance consumption, so the frequency of calling
* this function should not be too high, please refer to the product manual for the specific supported frequency.
* @attention If the device is not in the @ref OB_MULTI_DEVICE_SYNC_MODE_HARDWARE_TRIGGERING mode, device will ignore the capture command.
*/
@@ -919,7 +919,7 @@ public:
/**
* @brief Get the connection type of the device
*
* @return const char* the connection type of the device, currently supports: "USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1",
* @return const char* the connection type of the device,currently supports:"USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1",
* "USB3.2", "Ethernet"
*/
const char *getConnectionType() const {
@@ -1141,7 +1141,7 @@ public:
* @brief Get device connection type
*
* @param index device index
* @return const char* returns connection type, currently supports: "USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1", "USB3.2", "Ethernet"
* @return const char* returns connection type,currently supports:"USB", "USB1.0", "USB1.1", "USB2.0", "USB2.1", "USB3.0", "USB3.1", "USB3.2", "Ethernet"
*/
const char *getConnectionType(uint32_t index) const {
ob_error *error = nullptr;
@@ -1165,21 +1165,6 @@ public:
return ip;
}
/**
* @brief get the local mac address of the device at the specified index
*
* @attention Only valid for network devices, otherwise it will return "0:0:0:0:0:0".
*
* @param index the index of the device
* @return const char* the local mac address of the device
*/
const char *getLocalMacAddress(uint32_t index) const {
ob_error *error = nullptr;
auto mac = ob_device_list_get_device_local_mac(impl_, index, &error);
Error::handle(&error);
return mac;
}
/**
* @brief Get the device object at the specified index
*
@@ -1215,7 +1200,7 @@ public:
* @brief On Linux platform, for usb device, the uid of the device is composed of bus-port-dev, for example 1-1.2-1. But the SDK will remove the dev number
* and only keep the bus-port as the uid to create the device, for example 1-1.2, so that we can create a device connected to the specified USB port.
* Similarly, users can also directly pass in bus-port as uid to create device.
* @brief For GMSL device, the uid is GMSL port with "gmsl2-" prefix, for example gmsl2-1.
* @brief For GMSL device,the uid is GMSL port with “gmsl2-” prefix, for example gmsl2-1.
*
* @attention If the device has been acquired and created elsewhere, repeated acquisition will throw an exception
*
@@ -18,7 +18,7 @@
#include <functional>
/**
* Frame classis inheritance hierarchy:
* Frame classis inheritance hierarchy:
* Frame
* |
* +-----------+----------+----------+-----------+
@@ -181,7 +181,7 @@ public:
/**
* @brief Get the global timestamp of the frame in microseconds.
* @brief The global timestamp is the time point when the frame was captured by the device, and has been converted to the host clock domain. The
* @brief The global timestamp is the time point when the frame was was captured by the device, and has been converted to the host clock domain. The
* conversion process base on the device timestamp and can eliminate the timer drift of the device
*
* @attention The global timestamp disable by default. If global timestamp is not enabled, the function will return 0. To enable the global timestamp,
@@ -593,33 +593,6 @@ public:
return scale;
}
/**
* @brief Get the width of the frame.
*
* @return uint32_t The width of the frame.
*/
uint32_t getWidth() const {
ob_error *error = nullptr;
// TODO
auto width = ob_point_cloud_frame_get_width(impl_, &error);
Error::handle(&error);
return width;
}
/**
* @brief Get the height of the frame.
*
* @return uint32_t The height of the frame.
*/
uint32_t getHeight() const {
ob_error *error = nullptr;
auto height = ob_point_cloud_frame_get_height(impl_, &error);
Error::handle(&error);
return height;
}
public:
// The following interfaces are deprecated and are retained here for compatibility purposes.
#define getPositionValueScale getCoordinateValueScale
@@ -984,7 +957,7 @@ private:
static void BufferDestroy(uint8_t *buffer, void *context) {
auto *ctx = static_cast<BufferDestroyContext *>(context);
if(ctx->callback) {
if (ctx->callback) {
ctx->callback(buffer);
}
delete ctx;
@@ -1,188 +0,0 @@
// Copyright (c) Orbbec Inc. All Rights Reserved.
// Licensed under the MIT License.
/**
* @file RecordPlayback.hpp
* @brief Record and playback device-related types, including interfaces to create recording and playback devices,
record and playback streaming data, etc.
*/
#pragma once
#include "Types.hpp"
#include "Error.hpp"
#include "libobsensor/h/RecordPlayback.h"
#include "libobsensor/hpp/Device.hpp"
namespace ob {
typedef std::function<void(OBPlaybackStatus status)> PlaybackStatusChangeCallback;
class RecordDevice {
private:
ob_record_device_t *impl_;
public:
explicit RecordDevice(std::shared_ptr<Device> device, const std::string &file, bool compressionEnabled = true) {
ob_error *error = nullptr;
impl_ = ob_create_record_device(device->getImpl(), file.c_str(), compressionEnabled, &error);
Error::handle(&error);
}
virtual ~RecordDevice() noexcept {
ob_error *error = nullptr;
ob_delete_record_device(impl_, &error);
Error::handle(&error, false);
}
RecordDevice(RecordDevice &&other) {
if(this != &other) {
impl_ = other.impl_;
other.impl_ = nullptr;
}
}
RecordDevice &operator=(RecordDevice &&other) {
if(this != &other) {
impl_ = other.impl_;
other.impl_ = nullptr;
}
return *this;
}
RecordDevice(const RecordDevice &) = delete;
RecordDevice &operator=(const RecordDevice &) = delete;
public:
void pause() {
ob_error *error = nullptr;
ob_record_device_pause(impl_, &error);
Error::handle(&error);
}
void resume() {
ob_error *error = nullptr;
ob_record_device_resume(impl_, &error);
Error::handle(&error);
}
};
class PlaybackDevice : public Device {
public:
explicit PlaybackDevice(const std::string &file) : Device(nullptr) {
ob_error *error = nullptr;
impl_ = ob_create_playback_device(file.c_str(), &error);
Error::handle(&error);
}
virtual ~PlaybackDevice() noexcept = default;
PlaybackDevice(PlaybackDevice &&other) : Device(std::move(other)) {}
PlaybackDevice &operator=(PlaybackDevice &&other) {
Device::operator=(std::move(other));
return *this;
}
PlaybackDevice(const PlaybackDevice &) = delete;
PlaybackDevice &operator=(const PlaybackDevice &) = delete;
public:
/**
* @brief Pause the streaming data from the playback device.
*/
void pause() {
ob_error *error = nullptr;
ob_playback_device_pause(impl_, &error);
Error::handle(&error);
}
/**
* @brief Resume the streaming data from the playback device.
*/
void resume() {
ob_error *error = nullptr;
ob_playback_device_resume(impl_, &error);
Error::handle(&error);
}
/**
* @brief Seek to a specific timestamp when playing back a recording.
* @param[in] timestamp The timestamp to seek to, in milliseconds.
*/
void seek(const int64_t timestamp) {
ob_error *error = nullptr;
ob_playback_device_seek(impl_, timestamp, &error);
Error::handle(&error);
}
/**
* @brief Set the playback rate of the playback device.
* @param[in] rate The playback rate to set.
*/
void setPlaybackRate(const float rate) {
ob_error *error = nullptr;
ob_playback_device_set_playback_rate(impl_, rate, &error);
Error::handle(&error);
}
/**
* @brief Set a callback function to be called when the playback status changes.
* @param[in] callback The callback function to set.
*/
void setPlaybackStatusChangeCallback(PlaybackStatusChangeCallback callback) {
callback_ = callback;
ob_error *error = nullptr;
ob_playback_device_set_playback_status_changed_callback(impl_, &PlaybackDevice::playbackStatusCallback, this, &error);
Error::handle(&error);
}
/**
* @brief Get the current playback status of the playback device.
* @return The current playback status.
*/
OBPlaybackStatus getPlaybackStatus() const {
ob_error *error = nullptr;
OBPlaybackStatus status = ob_playback_device_get_current_playback_status(impl_, &error);
Error::handle(&error);
return status;
}
/**
* @brief Get the current position of the playback device.
* @return The current position of the playback device, in milliseconds.
*/
uint64_t getPosition() const {
ob_error *error = nullptr;
uint64_t position = ob_playback_device_get_position(impl_, &error);
Error::handle(&error);
return position;
}
/**
* @brief Get the duration of the playback device.
* @return The duration of the playback device, in milliseconds.
*/
uint64_t getDuration() const {
ob_error *error = nullptr;
uint64_t duration = ob_playback_device_get_duration(impl_, &error);
Error::handle(&error);
return duration;
}
private:
static void playbackStatusCallback(OBPlaybackStatus status, void *userData) {
auto *playbackDevice = static_cast<PlaybackDevice *>(userData);
if(playbackDevice && playbackDevice->callback_) {
playbackDevice->callback_(status);
}
}
private:
PlaybackStatusChangeCallback callback_;
};
} // namespace ob
@@ -128,7 +128,7 @@ public:
* OB_STREAM_VIDEO,
* OB_STREAM_DEPTH,
* OB_STREAM_COLOR,
* OB_STREAM_IR,
* OB_STREAM_IR,
* OB_STREAM_IR_LEFT,
* OB_STREAM_IR_RIGHT,
*
@@ -17,7 +17,7 @@
namespace ob {
class Device;
class CoordinateTransformHelper {
class CoordinateTransformHelper {
public:
/**
* @brief Transform a 3d point of a source coordinate system into a 3d point of the target coordinate system.
@@ -29,8 +29,8 @@ public:
* @return bool Transform result
*/
static bool transformation3dto3d(const OBPoint3f source_point3f, OBExtrinsic extrinsic, OBPoint3f *target_point3f) {
ob_error *error = NULL;
bool result = ob_transformation_3d_to_3d(source_point3f, extrinsic, target_point3f, &error);
ob_error *error = NULL;
bool result = ob_transformation_3d_to_3d(source_point3f, extrinsic, target_point3f, &error);
Error::handle(&error);
return result;
}
@@ -48,8 +48,8 @@ public:
*/
static bool transformation2dto3d(const OBPoint2f source_point2f, const float source_depth_pixel_value, const OBCameraIntrinsic source_intrinsic,
OBExtrinsic extrinsic, OBPoint3f *target_point3f) {
ob_error *error = NULL;
bool result = ob_transformation_2d_to_3d(source_point2f, source_depth_pixel_value, source_intrinsic, extrinsic, target_point3f, &error);
ob_error *error = NULL;
bool result = ob_transformation_2d_to_3d(source_point2f, source_depth_pixel_value, source_intrinsic, extrinsic, target_point3f, &error);
Error::handle(&error);
return result;
}
@@ -66,9 +66,9 @@ public:
* @return bool Transform result
*/
static bool transformation3dto2d(const OBPoint3f source_point3f, const OBCameraIntrinsic target_intrinsic, const OBCameraDistortion target_distortion,
OBExtrinsic extrinsic, OBPoint2f *target_point2f) {
ob_error *error = NULL;
bool result = ob_transformation_3d_to_2d(source_point3f, target_intrinsic, target_distortion, extrinsic, target_point2f, &error);
OBExtrinsic extrinsic, OBPoint2f *target_point2f) {
ob_error *error = NULL;
bool result = ob_transformation_3d_to_2d(source_point3f, target_intrinsic, target_distortion, extrinsic, target_point2f, &error);
Error::handle(&error);
return result;
}
@@ -90,7 +90,7 @@ public:
static bool transformation2dto2d(const OBPoint2f source_point2f, const float source_depth_pixel_value, const OBCameraIntrinsic source_intrinsic,
const OBCameraDistortion source_distortion, const OBCameraIntrinsic target_intrinsic,
const OBCameraDistortion target_distortion, OBExtrinsic extrinsic, OBPoint2f *target_point2f) {
ob_error *error = NULL;
ob_error *error = NULL;
bool result = ob_transformation_2d_to_2d(source_point2f, source_depth_pixel_value, source_intrinsic, source_distortion, target_intrinsic,
target_distortion, extrinsic, target_point2f, &error);
Error::handle(&error);
@@ -101,8 +101,8 @@ public:
// The following interfaces are deprecated and are retained here for compatibility purposes.
static bool calibration3dTo3d(const OBCalibrationParam calibrationParam, const OBPoint3f sourcePoint3f, const OBSensorType sourceSensorType,
const OBSensorType targetSensorType, OBPoint3f *targetPoint3f) {
ob_error *error = NULL;
bool result = ob_calibration_3d_to_3d(calibrationParam, sourcePoint3f, sourceSensorType, targetSensorType, targetPoint3f, &error);
ob_error *error = NULL;
bool result = ob_calibration_3d_to_3d(calibrationParam, sourcePoint3f, sourceSensorType, targetSensorType, targetPoint3f, &error);
Error::handle(&error);
return result;
}
@@ -110,16 +110,15 @@ public:
static bool calibration2dTo3d(const OBCalibrationParam calibrationParam, const OBPoint2f sourcePoint2f, const float sourceDepthPixelValue,
const OBSensorType sourceSensorType, const OBSensorType targetSensorType, OBPoint3f *targetPoint3f) {
ob_error *error = NULL;
bool result =
ob_calibration_2d_to_3d(calibrationParam, sourcePoint2f, sourceDepthPixelValue, sourceSensorType, targetSensorType, targetPoint3f, &error);
bool result = ob_calibration_2d_to_3d(calibrationParam, sourcePoint2f, sourceDepthPixelValue, sourceSensorType, targetSensorType, targetPoint3f, &error);
Error::handle(&error);
return result;
}
static bool calibration3dTo2d(const OBCalibrationParam calibrationParam, const OBPoint3f sourcePoint3f, const OBSensorType sourceSensorType,
const OBSensorType targetSensorType, OBPoint2f *targetPoint2f) {
ob_error *error = NULL;
bool result = ob_calibration_3d_to_2d(calibrationParam, sourcePoint3f, sourceSensorType, targetSensorType, targetPoint2f, &error);
ob_error *error = NULL;
bool result = ob_calibration_3d_to_2d(calibrationParam, sourcePoint3f, sourceSensorType, targetSensorType, targetPoint2f, &error);
Error::handle(&error);
return result;
}
@@ -127,8 +126,7 @@ public:
static bool calibration2dTo2d(const OBCalibrationParam calibrationParam, const OBPoint2f sourcePoint2f, const float sourceDepthPixelValue,
const OBSensorType sourceSensorType, const OBSensorType targetSensorType, OBPoint2f *targetPoint2f) {
ob_error *error = NULL;
bool result =
ob_calibration_2d_to_2d(calibrationParam, sourcePoint2f, sourceDepthPixelValue, sourceSensorType, targetSensorType, targetPoint2f, &error);
bool result = ob_calibration_2d_to_2d(calibrationParam, sourcePoint2f, sourceDepthPixelValue, sourceSensorType, targetSensorType, targetPoint2f, &error);
Error::handle(&error);
return result;
}
@@ -140,15 +138,15 @@ public:
// unsafe operation, need to cast const to non-const
auto unConstImpl = const_cast<ob_frame *>(depthFrame->getImpl());
auto result = transformation_depth_frame_to_color_camera(device->getImpl(), unConstImpl, targetColorCameraWidth, targetColorCameraHeight, &error);
auto result = transformation_depth_frame_to_color_camera(device->getImpl() , unConstImpl, targetColorCameraWidth, targetColorCameraHeight, &error);
Error::handle(&error);
return std::make_shared<ob::Frame>(result);
}
static bool transformationInitXYTables(const OBCalibrationParam calibrationParam, const OBSensorType sensorType, float *data, uint32_t *dataSize,
OBXYTables *xyTables) {
ob_error *error = NULL;
bool result = transformation_init_xy_tables(calibrationParam, sensorType, data, dataSize, xyTables, &error);
ob_error *error = NULL;
bool result = transformation_init_xy_tables(calibrationParam, sensorType, data, dataSize, xyTables, &error);
Error::handle(&error);
return result;
}
@@ -159,32 +157,11 @@ public:
Error::handle(&error, false);
}
static void transformationDepthToRGBDPointCloud(OBXYTables *xyTables, const void *depthImageData, const void *colorImageData, void *pointCloudData) {
static void transformationDepthToRGBDPointCloud(OBXYTables *xyTables, const void *depthImageData, const void *colorImageData, void *pointCloudData){
ob_error *error = NULL;
transformation_depth_to_rgbd_pointcloud(xyTables, depthImageData, colorImageData, pointCloudData, &error);
Error::handle(&error, false);
}
};
class PointCloudHelper {
public:
/**
* @brief save point cloud to ply file.
*
* @param[in] fileName Point cloud save path
* @param[in] frame Point cloud frame
* @param[in] saveBinary Binary or textual,true: binary, false: textual
* @param[in] useMesh Save mesh or not, true: save as mesh, false: not save as mesh
* @param[in] meshThreshold Distance threshold for creating faces in point cloud,default value :50
*
* @return bool save point cloud result
*/
static bool savePointcloudToPly(const char *fileName, std::shared_ptr<ob::Frame> frame, bool saveBinary, bool useMesh, float meshThreshold) {
ob_error *error = NULL;
auto unConstImpl = const_cast<ob_frame *>(frame->getImpl());
bool result = ob_save_pointcloud_to_ply(fileName, unConstImpl, saveBinary, useMesh, meshThreshold, &error);
Error::handle(&error, false);
return result;
}
};
} // namespace ob
@@ -8,12 +8,12 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "ob::OrbbecSDK" for configuration "Release"
set_property(TARGET ob::OrbbecSDK APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(ob::OrbbecSDK PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.3.5"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.2.8"
IMPORTED_SONAME_RELEASE "libOrbbecSDK.so.2"
)
list(APPEND _cmake_import_check_targets ob::OrbbecSDK )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.3.5" )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.2.8" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
@@ -1 +0,0 @@
libdepthengine.so.2.0
@@ -1 +0,0 @@
libOrbbecSDK.so.2
Binary file not shown.
@@ -1 +0,0 @@
libOrbbecSDK.so.2.3.5
Binary file not shown.
@@ -8,12 +8,12 @@ set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "ob::OrbbecSDK" for configuration "Release"
set_property(TARGET ob::OrbbecSDK APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(ob::OrbbecSDK PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.3.5"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.2.8"
IMPORTED_SONAME_RELEASE "libOrbbecSDK.so.2"
)
list(APPEND _cmake_import_check_targets ob::OrbbecSDK )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.3.5" )
list(APPEND _cmake_import_check_files_for_ob::OrbbecSDK "${_IMPORT_PREFIX}/lib/libOrbbecSDK.so.2.2.8" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
@@ -1 +0,0 @@
libdepthengine.so.2.0
@@ -1 +0,0 @@
libOrbbecSDK.so.2
Binary file not shown.
@@ -1 +0,0 @@
libOrbbecSDK.so.2.3.5
Binary file not shown.
File diff suppressed because it is too large Load Diff
+57 -32
View File
@@ -9,78 +9,103 @@ orbbec_ros:
config_file_path: "astra2.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: ""
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 1
uvc_backend: "libuvc"
vendor_id: "0x2bc5"
product_id: ""
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 100
time_domain: "global"
enable_heartbeat: false
enable_ldp: true
color:
# If true, the color image will be enabled
enable_color: true
color_qos: "default"
color_camera_info_qos: "default"
# Width of the color image. If 0, the default width will be used
color_width: 1280
# Height of the color image. If 0, the default height will be used
color_height: 720
# Fps of the color image. If 0, the default FPS will be used
color_fps: 30
color_format: "MJPG"
enable_color_auto_white_balance: true
color_white_balance: -1
color_auto_ae:
enable_color_auto_exposure: true
color_ae_max_exposure: -1
color_manual_ae:
color_exposure: -1
color_gain: -1
color_brightness: -1
depth:
# If true, the depth image will be enabled
enable_depth: true
depth_qos: "default"
depth_camera_info_qos: "default"
# Width of the depth image. If 0, the default width will be used
depth_width: 800
# Height of the depth image. If 0, the default height will be used
depth_height: 600
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 30
# Format of the depth image.
depth_format: "RLE"
# Depth registration mode.
depth_registration: false
# The alignment mode to be used.
align_mode: "HW"
ir:
# If false, the left IR image will not be enabled
enable_ir: true
ir_qos: "default"
ir_camera_info_qos: "default"
# Width of the left IR image. If 0, the default width will be used
ir_width: 800
# Height of the left IR image. If 0, the default height will be used
ir_height: 600
# Fps of the ir image. If 0, the default FPS will be used
ir_fps: 30
# Format of the left IR image. Supported formats are 'Y8'
ir_format: "Y8"
ir_parameters:
enable_ir_auto_exposure: true
ir_ae_max_exposure: -1
ir_exposure: -1
ir_gain: -1
ir_brightness: -1
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# Rate of the
accel_rate: "100hz"
# Range of the accelerometer.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# Rate of the gyroscope.
gyro_rate: "100hz"
# Range of the gyroscope.
gyro_range: "1000dps"
enable_sync_output_accel_gyro: true
liner_accel_cov: 0.01
angular_vel_cov: 0.01
point_cloud:
# If true, the point cloud will be enabled
enable_point_cloud: true
# enable color point cloud. {fase:disable, true:enable}
enable_colored_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used
use_hardware_time: false
# If false, the host time will not be synchronized with the device time
enable_sync_host_time: false
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
+5 -1
View File
@@ -3,7 +3,7 @@
orbbec_ros:
camera_parameters:
general:
# Camera model. support product models by referencing config/*.yaml
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
# The configuration file for yaml params.
config_file_path: "gemini330_series.yaml"
@@ -21,6 +21,8 @@ orbbec_ros:
device_num: 1
# Optional values: v4l2, libuvc
uvc_backend: "libuvc"
# Usually no need to change
vendor_id: "0x2bc5"
# Usually no need to change,will be read from the device
product_id: ""
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
@@ -366,6 +368,8 @@ orbbec_ros:
ir_info_url: ""
# URL of the color image info
color_info_url: ""
# If true, the 3D reconstruction mode will be enabled
enable_3d_reconstruction_mode: false
# Diagnostic period in seconds
diagnostic_period: 1.0
+74 -30
View File
@@ -9,77 +9,121 @@ orbbec_ros:
config_file_path: "femto.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: ""
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 1
uvc_backend: "libuvc"
product_id: ""
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 100
time_domain: "global"
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the LDP will be enabled
enable_ldp: true
network_device:
# Whether to enable the function of enumerating network devices. True means enabled and false means disabled. This function is only supported by Femto Mega and Gemini 2 XL devices.
# When accessing these devices through the network, the IP address of the device needs to be preconfigured. The enable switch needs to be set to true.
enumerate_net_device: false
# Port number of the network device. If 0, a random port will be used
net_device_port: 0
# IP address of the network device.
net_device_ip: ""
color:
# If true, the color image will be enabled
enable_color: true
color_qos: "default"
color_camera_info_qos: "default"
# Width of the color image. If 0, the default width will be used
color_width: 640
# Height of the color image. If 0, the default height will be used
color_height: 480
# If 0, the default FPS will be used
color_fps: 30
# Format of the color image.
color_format: "MJPG"
enable_color_auto_white_balance: true
color_white_balance: -1
color_auto_ae:
enable_color_auto_exposure: true
color_ae_max_exposure: -1
color_manual_ae:
color_exposure: -1
color_gain: -1
color_brightness: -1
depth:
# If true, the depth image will be enabled
enable_depth: true
depth_qos: "default"
depth_camera_info_qos: "default"
# Width of the depth image. If 0, the default width will be used
depth_width: 640
depth_height: 576
# Height of the depth image. If 0, the default height will be used
depth_height: 480
# fps of the depth image. If 0, the default FPS will be used
depth_fps: 30
# Format of the depth image.
depth_format: "Y16"
# Depth registration enable
depth_registration: false
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "HW"
ir:
# If false, the left IR image will not be enabled
enable_ir: true
ir_qos: "default"
ir_camera_info_qos: "default"
# Width of the left IR image. If 0, the default width will be used
ir_width: 640
ir_height: 576
# Height of the left IR image. If 0, the default height will be used
ir_height: 480
# Fps of the left IR image. If 0, the default FPS will be used
ir_fps: 30
# Format of the left IR image. Supported formats are 'Y8'
ir_format: "Y16"
ir_parameters:
enable_ir_auto_exposure: true
ir_ae_max_exposure: -1
ir_exposure: -1
ir_gain: -1
ir_brightness: -1
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# Rate of the
accel_rate: "100hz"
# Range of the accelerometer.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# Rate of the gyroscope.
gyro_rate: "100hz"
# Range of the gyroscope.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: true
liner_accel_cov: 0.01
angular_vel_cov: 0.01
point_cloud:
# If true, the point cloud will be enabled
enable_point_cloud: true
# enable color point cloud. {fase:disable, true:enable}
enable_colored_point_cloud: false
advanced:
enable_frame_sync: true
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: false
# If true, Overlay display of color image and depth image after D2C processing will be enabled
enable_d2c_viewer: false
# If false, the hardware time will not be used
use_hardware_time: false
# If false, the host time will not be synchronized with the device time
enable_sync_host_time: false
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
-85
View File
@@ -1,85 +0,0 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "femto_bolt"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "femto_bolt.yaml"
deivce:
camera_name: "camera"
serial_number: ""
usb_port: ""
device_num: 1
uvc_backend: "libuvc"
product_id: ""
connection_delay: 100
time_domain: "global"
enable_heartbeat: false
enable_ldp: true
color:
enable_color: true
color_qos: "default"
color_camera_info_qos: "default"
color_width: 1280
color_height: 720
color_fps: 30
color_format: "MJPG"
enable_color_auto_white_balance: true
color_white_balance: -1
color_auto_ae:
enable_color_auto_exposure: true
color_ae_max_exposure: -1
color_manual_ae:
color_exposure: -1
color_gain: -1
color_brightness: -1
depth:
enable_depth: true
depth_qos: "default"
depth_camera_info_qos: "default"
depth_width: 640
depth_height: 576
depth_fps: 30
depth_format: "Y16"
depth_registration: false
align_mode: "SW"
ir:
enable_ir: true
ir_qos: "default"
ir_camera_info_qos: "default"
ir_width: 640
ir_height: 576
ir_fps: 30
ir_format: "Y16"
ir_parameters:
enable_ir_auto_exposure: true
ir_ae_max_exposure: -1
ir_exposure: -1
ir_gain: -1
ir_brightness: -1
imu:
enable_accel: false
accel_rate: "200hz"
accel_range: "4g"
enable_gyro: false
gyro_rate: "200hz"
gyro_range: "1000dps"
enable_sync_output_accel_gyro: true
liner_accel_cov: 0.01
angular_vel_cov: 0.01
point_cloud:
enable_point_cloud: false
enable_colored_point_cloud: false
advanced:
enable_frame_sync: true
enable_d2c_viewer: false
-85
View File
@@ -1,85 +0,0 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "femto_mega"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "femto_mega.yaml"
deivce:
camera_name: "camera"
serial_number: ""
usb_port: ""
device_num: 1
uvc_backend: "libuvc"
product_id: ""
connection_delay: 100
time_domain: "global"
enable_heartbeat: false
enable_ldp: true
color:
enable_color: true
color_qos: "default"
color_camera_info_qos: "default"
color_width: 1280
color_height: 720
color_fps: 30
color_format: "MJPG"
enable_color_auto_white_balance: true
color_white_balance: -1
color_auto_ae:
enable_color_auto_exposure: true
color_ae_max_exposure: -1
color_manual_ae:
color_exposure: -1
color_gain: -1
color_brightness: -1
depth:
enable_depth: true
depth_qos: "default"
depth_camera_info_qos: "default"
depth_width: 640
depth_height: 576
depth_fps: 30
depth_format: "Y16"
depth_registration: false
align_mode: "HW"
ir:
enable_ir: true
ir_qos: "default"
ir_camera_info_qos: "default"
ir_width: 640
ir_height: 576
ir_fps: 30
ir_format: "Y16"
ir_parameters:
enable_ir_auto_exposure: true
ir_ae_max_exposure: -1
ir_exposure: -1
ir_gain: -1
ir_brightness: -1
imu:
enable_accel: false
accel_rate: "100hz"
accel_range: "4g"
enable_gyro: false
gyro_rate: "100hz"
gyro_range: "1000dps"
enable_sync_output_accel_gyro: true
liner_accel_cov: 0.01
angular_vel_cov: 0.01
point_cloud:
enable_point_cloud: true
enable_colored_point_cloud: false
advanced:
enable_frame_sync: true
enable_d2c_viewer: false
+129
View File
@@ -0,0 +1,129 @@
# config/*.yaml files are used to configure the camera parameters
#
# For Femto Mega and Femto Bolt devices, Configuration of depth NFOV and WFOV modes.
# NFOV and WFOV modes are achieved by configuring the resolution of Depth and IR in the startup file.
# In the startup file, depth_width, depth_height, ir_width, ir_height represent the resolution of depth and the resolution of IR, respectively.
# The frame rate and resolution of IR must be consistent with depth. The corresponding relationship between different modes and resolution is as follows:
# • NFOV unbinned: 640 x 576.
# • NFOV binned: 320 x 288.
# • WFOV unbinned: 1024 x 1024.
# • WFOV binned: 512 x 512.
#
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "femtobolt"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "femtobolt.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: ""
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 1
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 100
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 1280
# Height of the color image. If 0, the default height will be used
color_height: 720
# If 0, the default FPS will be used
color_fps: 30
# Format of the color image.
color_format: "MJPG"
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 640
# Height of the depth image. If 0, the default height will be used
depth_height: 576
# If 0, the default FPS will be used
depth_fps: 30
# Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# Depth registration mode.
depth_registration: false
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
filter:
soft_filter:
# If false, the soft filter will not be enabled
enable_soft_filter: true
# The maximum difference between the current and previous depth frame to be considered valid
soft_filter_max_diff: -1
# The size of the speckle to be filtered out
soft_filter_speckle_size: -1
ir:
# If false, the left IR image will not be enabled
enable_ir: true
# Width of the left IR image. If 0, the default width will be used
ir_width: 640
# Height of the left IR image. If 0, the default height will be used
ir_height: 576
# If 0, the default FPS will be used
ir_fps: 30
# Format of the left IR image. Supported formats are 'Y8'
ir_format: "Y16"
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# Rate of the
accel_rate: "200hz"
# Range of the accelerometer.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# Rate of the gyroscope.
gyro_rate: "200hz"
# Range of the gyroscope.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: true
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# If true, Overlay display of color image and depth image after D2C processing will be enabled
enable_d2c_viewer: false
# If false, the hardware time will not be used
use_hardware_time: true
# If false, the host time will not be synchronized with the device time
enable_sync_host_time: false
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
+134
View File
@@ -0,0 +1,134 @@
# config/*.yaml files are used to configure the camera parameters
#
# For Femto Mega and Femto Bolt devices, Configuration of depth NFOV and WFOV modes.
# NFOV and WFOV modes are achieved by configuring the resolution of Depth and IR in the startup file.
# In the startup file, depth_width, depth_height, ir_width, ir_height represent the resolution of depth and the resolution of IR, respectively.
# The frame rate and resolution of IR must be consistent with depth. The corresponding relationship between different modes and resolution is as follows:
# • NFOV unbinned: 640 x 576.
# • NFOV binned: 320 x 288.
# • WFOV unbinned: 1024 x 1024.
# • WFOV binned: 512 x 512.
#
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "femtomega"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "femtomega.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: ""
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 1
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 100
network_device:
# Whether to enable the function of enumerating network devices. True means enabled and false means disabled. This function is only supported by Femto Mega and Gemini 2 XL devices.
# When accessing these devices through the network, the IP address of the device needs to be preconfigured. The enable switch needs to be set to true.
enumerate_net_device: false
# Port number of the network device. If 0, a random port will be used
net_device_port: 0
# IP address of the network device.
net_device_ip: ""
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 1280
# Height of the color image. If 0, the default height will be used
color_height: 720
# If 0, the default FPS will be used
color_fps: 30
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 640
# Height of the depth image. If 0, the default height will be used
depth_height: 576
# If 0, the default FPS will be used
depth_fps: 30
# Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# Depth registration mode.
depth_registration: false
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "HW"
ir:
# If false, the left IR image will not be enabled
enable_ir: true
# Width of the left IR image. If 0, the default width will be used
ir_width: 640
# Height of the left IR image. If 0, the default height will be used
ir_height: 576
# If 0, the default FPS will be used
ir_fps: 30
# Format of the left IR image. Supported formats are 'Y8'
ir_format: "Y16"
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# Rate of the
accel_rate: "100hz"
# Range of the accelerometer.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# Rate of the gyroscope.
gyro_rate: "100hz"
# Range of the gyroscope.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: true
point_cloud:
# If true, the point cloud will be enabled
enable_point_cloud: true
# enable color point cloud. {fase:disable, true:enable}
enable_colored_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used
use_hardware_time: false
# If false, the host time will not be synchronized with the device time
enable_sync_host_time: false
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
+90 -28
View File
@@ -9,78 +9,140 @@ orbbec_ros:
config_file_path: "gemini2.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: ""
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 1
uvc_backend: "libuvc"
product_id: ""
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 100
time_domain: "global"
retry_on_usb3_detection_failure: false
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the LDP will be enabled
enable_ldp: true
network_device:
# Whether to enable the function of enumerating network devices. True means enabled and false means disabled. This function is only supported by Femto Mega and Gemini 2 XL devices.
# When accessing these devices through the network, the IP address of the device needs to be preconfigured. The enable switch needs to be set to true.
enumerate_net_device: false
# Port number of the network device. If 0, a random port will be used
net_device_port: 0
# IP address of the network device.
net_device_ip: ""
color:
# If true, the color image will be enabled
enable_color: true
color_qos: "default"
color_camera_info_qos: "default"
# Width of the color image. If 0, the default width will be used
color_width: 640
# Height of the color image. If 0, the default height will be used
color_height: 360
# If 0, the default FPS will be used
color_fps: 15
# Format of the color image.
color_format: "MJPG"
enable_color_auto_white_balance: true
color_white_balance: -1
color_auto_ae:
enable_color_auto_exposure: true
color_ae_max_exposure: -1
color_manual_ae:
color_exposure: -1
color_gain: -1
color_brightness: -1
depth:
# If true, the depth image will be enabled
enable_depth: true
depth_qos: "default"
depth_camera_info_qos: "default"
# Width of the depth image. If 0, the default width will be used
depth_width: 640
# Height of the depth image. If 0, the default height will be used
depth_height: 400
# If 0, the default FPS will be used
depth_fps: 15
# Format of the depth image.
depth_format: "Y14"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "HW"
# Gemini 2, Gemini 2 L, and Gemini 2 XL cameras support deep working mode switching
# Specific camera deep working mode support types can be found in the deep mode comments.
# Deep working mode support is as follows:{"Unbinned Dense Default","Unbinned Sparse Default","Binned Sparse Default","Obstacle Avoidance"}
# Depth work mode. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation.
depth_work_mode: ""
# Configure the loading path of the deep filtering configuration file. By default, the deep filtering configuration file is located in the /config/depthfilter directory and is only supported by Gemini2.
depth_filter_config: ""
filter:
soft_filter:
# If false, the soft filter will not be enabled
enable_soft_filter: true
# The maximum difference between the current and previous depth frame to be considered valid
soft_filter_max_diff: -1
# The size of the speckle to be filtered out
soft_filter_speckle_size: -1
ir:
# enable the ir camera stream
enable_ir: true
ir_qos: "default"
ir_camera_info_qos: "default"
# Width of the left IR image. If 0, the default width will be used
ir_width: 640
# Height of the left IR image. If 0, the default height will be used
ir_height: 400
# If 0, the default FPS will be used
ir_fps: 15
# Format of the left IR image. Supported formats are 'Y8'
ir_format: "Y8"
ir_parameters:
enable_ir_auto_exposure: true
ir_ae_max_exposure: -1
ir_exposure: -1
ir_gain: -1
ir_brightness: -1
imu:
# If true, enable the IMU accelerometer data
enable_accel: false
# Rate of the accelerometer
accel_rate: "100hz"
# Range of the accelerometer.
accel_range: "4g"
# If true, enable the IMU gyroscope data
enable_gyro: false
# Rate of the gyroscope.
gyro_rate: "100hz"
# Range of the gyroscope.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: true
liner_accel_cov: 0.01
angular_vel_cov: 0.01
point_cloud:
# If true, the depth point cloud will be enabled
enable_point_cloud: true
# enable color point cloud. {fase:disable, true:enable}
enable_colored_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# If true, Overlay display of color image and depth image after D2C processing will be enabled
enable_d2c_viewer: false
# If false, the hardware time will not be used
use_hardware_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
+68 -33
View File
@@ -9,78 +9,113 @@ orbbec_ros:
config_file_path: "gemini2L.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: ""
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 1
uvc_backend: "libuvc"
product_id: ""
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 100
time_domain: "global"
retry_on_usb3_detection_failure: false
enable_heartbeat: false
enable_ldp: true
network_device:
# Whether to enable the function of enumerating network devices. True means enabled and false means disabled. This function is only supported by Femto Mega and Gemini 2 XL devices.
# When accessing these devices through the network, the IP address of the device needs to be preconfigured. The enable switch needs to be set to true.
enumerate_net_device: false
# Port number of the network device. If 0, a random port will be used
net_device_port: 0
# IP address of the network device.
net_device_ip: ""
color:
# If true, the color image will be enabled
enable_color: true
color_qos: "default"
color_camera_info_qos: "default"
# Width of the color image. If 0, the default width will be used
color_width: 1280
# Height of the color image. If 0, the default height will be used
color_height: 800
# fps of the color image. If 0, the default FPS will be used
color_fps: 30
# Format of the color image.
color_format: "MJPG"
enable_color_auto_white_balance: true
color_white_balance: -1
color_auto_ae:
enable_color_auto_exposure: true
color_ae_max_exposure: -1
color_manual_ae:
color_exposure: -1
color_gain: -1
color_brightness: -1
depth:
# If true, the depth image will be enabled
enable_depth: true
depth_qos: "default"
depth_camera_info_qos: "default"
# Width of the depth image. If 0, the default width will be used
depth_width: 1280
# Height of the depth image. If 0, the default height will be used
depth_height: 800
# If 0, the default FPS will be used
depth_fps: 30
# Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# Depth registration mode.
depth_registration: false
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "HW"
# Gemini 2, Gemini 2 L, and Gemini 2 XL cameras support deep working mode switching
# Specific camera deep working mode support types can be found in the deep mode comments.
# Deep working mode support is as follows:{"Unbinned Dense Default","Unbinned Sparse Default","Binned Sparse Default","Obstacle Avoidance"}
# Depth work mode. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation.
depth_work_mode: ""
# Configure the loading path of the deep filtering configuration file. By default, the deep filtering configuration file is located in the /config/depthfilter directory and is only supported by Gemini2.
depth_filter_config: ""
filter:
soft_filter:
# If true, the soft filter will be enabled
enable_soft_filter: true
# soft_filter_max_diff, If -1, the default value will be used
soft_filter_max_diff: -1
# soft_filter_speckle_size, If -1, the default value will be used
soft_filter_speckle_size: -1
noise_removal_filter:
# If true, the noise removal filter will be enabled
enable_noise_removal_filter: true
ir:
# enable the ir camera stream
enable_ir: true
ir_qos: "default"
ir_camera_info_qos: "default"
# Width of the left IR image. If 0, the default width will be used
ir_width: 640
# Height of the left IR image. If 0, the default height will be used
ir_height: 400
# If 0, the default FPS will be used
ir_fps: 15
# Format of the left IR image.
ir_format: "Y8"
ir_parameters:
enable_ir_auto_exposure: true
ir_ae_max_exposure: -1
ir_exposure: -1
ir_gain: -1
ir_brightness: -1
imu:
# If true, enable the IMU accelerometer data will be enabled
enable_accel: false
# Rate of the accelerometer
accel_rate: "100hz"
# Range of the accelerometer.
accel_range: "4g"
# If true, enable the IMU gyroscope data will be enabled
enable_gyro: false
# Rate of the gyroscope.
gyro_rate: "100hz"
# Range of the gyroscope.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
liner_accel_cov: 0.01
angular_vel_cov: 0.01
point_cloud:
# If true, the depth point cloud will be enabled
enable_point_cloud: true
# enable color point cloud. {fase:disable, true:enable}
enable_colored_point_cloud: false
advanced:
enable_frame_sync: true
enable_d2c_viewer: false
# If false, the hardware time will not be used
use_hardware_time: true
+108 -44
View File
@@ -4,95 +4,159 @@ orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
camera_model: "gemini330Lg_series"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "gemini330_series.yaml"
config_file_path: "gemini330Lg_series.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: ""
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 1
uvc_backend: "libuvc"
product_id: ""
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 10
time_domain: "global"
retry_on_usb3_detection_failure: false
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the camera will be reset
enable_hardware_reset: false
# If true, the LDP will be enabled
enable_ldp: true
# The preset of the device. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation
# Predefined presets doc reference: docs/source/2_installation/package_description.md
# Deep working mode support is as follows:{"Default","Hand","High Accuracy","High Density","Medium Density","Custom"}
device_preset: "Default"
color:
# If true, the color image will be enabled
enable_color: true
color_qos: "default"
color_camera_info_qos: "default"
# Width of the color image. If 0, the default width will be used
color_width: 0
# Height of the color image. If 0, the default height will be used
color_height: 0
# Fps of the color image. If 0, the default FPS will be used
color_fps: 0
color_format: "ANY"
# Format of the color image. note: GMSL device dont't support MJPG format. need modify to YUYV format
color_format: "YUYV"
# enable auto exposure for the color image
enable_color_auto_exposure: true
# enable auto white balance for the color image
enable_color_auto_white_balance: true
color_white_balance: -1
color_auto_ae:
enable_color_auto_exposure: true
color_ae_max_exposure: -1
color_manual_ae:
color_exposure: -1
color_gain: -1
color_brightness: -1
# If true, the color image will be undistorted
enable_color_undistortion: false
depth:
# If true, the depth image will be enabled
enable_depth: true
depth_qos: "default"
depth_camera_info_qos: "default"
# Width of the depth image. If 0, the default width will be used
depth_width: 0
# Height of the depth image. If 0, the default height will be used
depth_height: 0
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 0
depth_format: "ANY"
# default Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
laser:
enable_laser: true
# If true, the laser data will be enabled
enable_laser: false
# Laser On/Off mode.
laser_on_off_mode: 0
filter:
# -enable_decimation_filter
enable_decimation_filter: false
# -enable_hdr_merge
enable_hdr_merge: false
# -enable_sequence_id_filter
enable_sequence_id_filter: false
# -enable_threshold_filter
enable_threshold_filter: false
# -enable_noise_removal_filter
enable_noise_removal_filter: true
# -enable_spatial_filter
enable_spatial_filter: false
# -enable_temporal_filter
enable_temporal_filter: false
# -enable_hole_filling_filter
enable_hole_filling_filter: false
# -noise_removal_filter_min_diff
noise_removal_filter_min_diff: 256
# -noise_removal_filter_max_size
noise_removal_filter_max_size: 80
# -enable_soft_filter
enable_soft_filter: true
leftir:
enable_left_ir: false
left_ir_qos: "default"
left_ir_camera_info_qos: "default"
left_ir_width: 0
left_ir_height: 0
left_ir_fps: 0
left_ir_format: "ANY"
# the left IR image will not be enabled
enable_left_ir: true
rightir:
enable_right_ir: false
right_ir_camera_info_qos: "default"
right_ir_width: 0
right_ir_height: 0
right_ir_fps: 0
right_ir_format: "ANY"
ir_parameters:
enable_ir_auto_exposure: true
ir_ae_max_exposure: -1
ir_exposure: -1
ir_gain: -1
ir_brightness: -1
# the right IR image will not be enabled
enable_right_ir: true
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# The frequency of the accelerometer can be selected as 1.5625Hz, 3.125Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
accel_rate: "200hz"
# The range of the accelerometer, the optional values are 2g, 4g, 8g, 16g. The specific value depends on the current camera.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# The frequency of the gyroscope can be selected as 1.5625hz, 3.125hz, 6.25hz, 12.5hz, 25hz, 50hz, 100hz, 200hz, 500hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
gyro_rate: "200hz"
# The range of the gyroscope, the optional values are 16dps, 31dps, 62dps, 125dps, 250dps, 500dps, 1000dps, 2000dps. The specific value depends on the current camera.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
liner_accel_cov: 0.01
angular_vel_cov: 0.01
point_cloud:
enable_point_cloud: true
# enable point cloud. {fase:disable, true:enable}
enable_point_cloud: false
# enable color point cloud. {fase:disable, true:enable}
enable_colored_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used, true:devicetime, false:systemtime
use_hardware_time: true
# the host time will be synchronized with the device time
enable_sync_host_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
+3 -1
View File
@@ -14,11 +14,13 @@ orbbec_ros:
usb_port: ""
device_num: 1
uvc_backend: "libuvc"
vendor_id: "0x2bc5"
product_id: ""
connection_delay: 10
time_domain: "global"
time_domain: "device"
retry_on_usb3_detection_failure: false
enable_heartbeat: false
enable_hardware_reset: false
enable_ldp: true
device_preset: "Default"
+22
View File
@@ -0,0 +1,22 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
multi_camera_parameters:
launch_device_camera1:
config_file_path: "multicamera_test/gemini330_series_test1.yaml"
# default period 0.0; unit: second
period: 0.0
camera_name: "camera1"
usb_port: "2-2-4"
device_num: "2"
sync_mode: "standalone"
launch_device_camera2:
config_file_path: "multicamera_test/gemini330_series_test2.yaml"
# default period 0.0; unit: second
period: 3.0
camera_name: "camera2"
usb_port: "2-1-2"
device_num: "2"
sync_mode: "standalone"
@@ -0,0 +1,40 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
multi_camera_parameters:
launch_device_camera1:
config_file_path: "multicamera_test/gemini330_series_sync_front_camera.yaml"
# default period 0.0; unit: second
period: 3.0
camera_name: "front_camera"
usb_port: "2-5"
device_num: "3"
sync_mode: "hardware_triggering"
launch_device_camera2:
config_file_path: "multicamera_test/gemini330_series_sync_left_camera.yaml"
# default period 0.0; unit: second
period: 0.0
camera_name: "left_camera"
usb_port: "2-1"
device_num: "3"
sync_mode: "hardware_triggering"
launch_device_camera3:
config_file_path: "multicamera_test/gemini330_series_sync_rear_camera.yaml"
# default period 0.0; unit: second
period: 0.0
camera_name: "rear_camera"
usb_port: "2-3"
device_num: "3"
sync_mode: "hardware_triggering"
launch_device_camera4:
config_file_path: "multicamera_test/gemini330_series_sync_right_camera.yaml"
# default period 0.0; unit: second
period: 0.0
camera_name: "right_camera"
usb_port: "2-7"
device_num: "3"
sync_mode: "hardware_triggering"
@@ -0,0 +1,161 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "gemini330_series.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "front_camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: "2-5"
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 3
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 10
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the camera will be reset
enable_hardware_reset: false
# If true, the LDP will be enabled
enable_ldp: true
# The preset of the device. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation
# Predefined presets doc reference: docs/source/2_installation/package_description.md
# Deep working mode support is as follows:{"Default","Hand","High Accuracy","High Density","Medium Density","Custom"}
device_preset: "Default"
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 0
# Height of the color image. If 0, the default height will be used
color_height: 0
# Fps of the color image. If 0, the default FPS will be used
color_fps: 0
# default Format of the color image.
color_format: "MJPG"
# enable auto exposure for the color image
enable_color_auto_exposure: true
# enable auto white balance for the color image
enable_color_auto_white_balance: true
# If true, the color image will be undistorted
enable_color_undistortion: false
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 0
# Height of the depth image. If 0, the default height will be used
depth_height: 0
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 0
# default Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
laser:
# Whether to enable the laser. Default value is true
enable_laser: false
# Laser Switch Alternate Mode, 0: Off, 1: On-Off Alternate, 2: Off-On Alternate. Default value is 0.
laser_on_off_mode: 0
filter:
# -enable_decimation_filter
enable_decimation_filter: false
# -enable_hdr_merge
enable_hdr_merge: false
# -enable_sequence_id_filter
enable_sequence_id_filter: false
# -enable_threshold_filter
enable_threshold_filter: false
# -enable_noise_removal_filter
enable_noise_removal_filter: true
# -enable_spatial_filter
enable_spatial_filter: false
# -enable_temporal_filter
enable_temporal_filter: false
# -enable_hole_filling_filter
enable_hole_filling_filter: false
# -noise_removal_filter_min_diff
noise_removal_filter_min_diff: 256
# -noise_removal_filter_max_size
noise_removal_filter_max_size: 80
# -enable_soft_filter
enable_soft_filter: true
leftir:
# the left IR image will not be enabled
enable_left_ir: true
rightir:
# the right IR image will not be enabled
enable_right_ir: true
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# The frequency of the accelerometer can be selected as 1.5625Hz, 3.125Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
accel_rate: "200hz"
# The range of the accelerometer, the optional values are 2g, 4g, 8g, 16g. The specific value depends on the current camera.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# The frequency of the gyroscope can be selected as 1.5625hz, 3.125hz, 6.25hz, 12.5hz, 25hz, 50hz, 100hz, 200hz, 500hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
gyro_rate: "200hz"
# The range of the gyroscope, the optional values are 16dps, 31dps, 62dps, 125dps, 250dps, 500dps, 1000dps, 2000dps. The specific value depends on the current camera.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
point_cloud:
# enable point cloud. {fase:disable, true:enable}
enable_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used, true:devicetime, false:systemtime
use_hardware_time: true
# the host time will be synchronized with the device time
enable_sync_host_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "SECONDARY_SYNCED"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
@@ -0,0 +1,161 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "gemini330_series.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "left_camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: "2-1"
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 3
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 10
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the camera will be reset
enable_hardware_reset: false
# If true, the LDP will be enabled
enable_ldp: true
# The preset of the device. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation
# Predefined presets doc reference: docs/source/2_installation/package_description.md
# Deep working mode support is as follows:{"Default","Hand","High Accuracy","High Density","Medium Density","Custom"}
device_preset: "Default"
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 0
# Height of the color image. If 0, the default height will be used
color_height: 0
# Fps of the color image. If 0, the default FPS will be used
color_fps: 0
# default Format of the color image.
color_format: "MJPG"
# enable auto exposure for the color image
enable_color_auto_exposure: true
# enable auto white balance for the color image
enable_color_auto_white_balance: true
# If true, the color image will be undistorted
enable_color_undistortion: false
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 0
# Height of the depth image. If 0, the default height will be used
depth_height: 0
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 0
# default Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
laser:
# Whether to enable the laser. Default value is true
enable_laser: false
# Laser Switch Alternate Mode, 0: Off, 1: On-Off Alternate, 2: Off-On Alternate. Default value is 0.
laser_on_off_mode: 0
filter:
# -enable_decimation_filter
enable_decimation_filter: false
# -enable_hdr_merge
enable_hdr_merge: false
# -enable_sequence_id_filter
enable_sequence_id_filter: false
# -enable_threshold_filter
enable_threshold_filter: false
# -enable_noise_removal_filter
enable_noise_removal_filter: true
# -enable_spatial_filter
enable_spatial_filter: false
# -enable_temporal_filter
enable_temporal_filter: false
# -enable_hole_filling_filter
enable_hole_filling_filter: false
# -noise_removal_filter_min_diff
noise_removal_filter_min_diff: 256
# -noise_removal_filter_max_size
noise_removal_filter_max_size: 80
# -enable_soft_filter
enable_soft_filter: true
leftir:
# the left IR image will not be enabled
enable_left_ir: true
rightir:
# the right IR image will not be enabled
enable_right_ir: true
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# The frequency of the accelerometer can be selected as 1.5625Hz, 3.125Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
accel_rate: "200hz"
# The range of the accelerometer, the optional values are 2g, 4g, 8g, 16g. The specific value depends on the current camera.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# The frequency of the gyroscope can be selected as 1.5625hz, 3.125hz, 6.25hz, 12.5hz, 25hz, 50hz, 100hz, 200hz, 500hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
gyro_rate: "200hz"
# The range of the gyroscope, the optional values are 16dps, 31dps, 62dps, 125dps, 250dps, 500dps, 1000dps, 2000dps. The specific value depends on the current camera.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
point_cloud:
# enable point cloud. {fase:disable, true:enable}
enable_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used, true:devicetime, false:systemtime
use_hardware_time: true
# the host time will be synchronized with the device time
enable_sync_host_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "SECONDARY_SYNCED"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
@@ -0,0 +1,161 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "gemini330_series.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "rear_camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: "2-3"
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 3
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 10
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the camera will be reset
enable_hardware_reset: false
# If true, the LDP will be enabled
enable_ldp: true
# The preset of the device. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation
# Predefined presets doc reference: docs/source/2_installation/package_description.md
# Deep working mode support is as follows:{"Default","Hand","High Accuracy","High Density","Medium Density","Custom"}
device_preset: "Default"
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 0
# Height of the color image. If 0, the default height will be used
color_height: 0
# Fps of the color image. If 0, the default FPS will be used
color_fps: 0
# default Format of the color image.
color_format: "MJPG"
# enable auto exposure for the color image
enable_color_auto_exposure: true
# enable auto white balance for the color image
enable_color_auto_white_balance: true
# If true, the color image will be undistorted
enable_color_undistortion: false
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 0
# Height of the depth image. If 0, the default height will be used
depth_height: 0
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 0
# default Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
laser:
# Whether to enable the laser. Default value is true
enable_laser: false
# Laser Switch Alternate Mode, 0: Off, 1: On-Off Alternate, 2: Off-On Alternate. Default value is 0.
laser_on_off_mode: 0
filter:
# -enable_decimation_filter
enable_decimation_filter: false
# -enable_hdr_merge
enable_hdr_merge: false
# -enable_sequence_id_filter
enable_sequence_id_filter: false
# -enable_threshold_filter
enable_threshold_filter: false
# -enable_noise_removal_filter
enable_noise_removal_filter: true
# -enable_spatial_filter
enable_spatial_filter: false
# -enable_temporal_filter
enable_temporal_filter: false
# -enable_hole_filling_filter
enable_hole_filling_filter: false
# -noise_removal_filter_min_diff
noise_removal_filter_min_diff: 256
# -noise_removal_filter_max_size
noise_removal_filter_max_size: 80
# -enable_soft_filter
enable_soft_filter: true
leftir:
# the left IR image will not be enabled
enable_left_ir: true
rightir:
# the right IR image will not be enabled
enable_right_ir: true
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# The frequency of the accelerometer can be selected as 1.5625Hz, 3.125Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
accel_rate: "200hz"
# The range of the accelerometer, the optional values are 2g, 4g, 8g, 16g. The specific value depends on the current camera.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# The frequency of the gyroscope can be selected as 1.5625hz, 3.125hz, 6.25hz, 12.5hz, 25hz, 50hz, 100hz, 200hz, 500hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
gyro_rate: "200hz"
# The range of the gyroscope, the optional values are 16dps, 31dps, 62dps, 125dps, 250dps, 500dps, 1000dps, 2000dps. The specific value depends on the current camera.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
point_cloud:
# enable point cloud. {fase:disable, true:enable}
enable_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used, true:devicetime, false:systemtime
use_hardware_time: true
# the host time will be synchronized with the device time
enable_sync_host_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "SECONDARY_SYNCED"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
@@ -0,0 +1,161 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "gemini330_series.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "right_camera"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: "2-7"
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 3
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 10
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the camera will be reset
enable_hardware_reset: false
# If true, the LDP will be enabled
enable_ldp: true
# The preset of the device. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation
# Predefined presets doc reference: docs/source/2_installation/package_description.md
# Deep working mode support is as follows:{"Default","Hand","High Accuracy","High Density","Medium Density","Custom"}
device_preset: "Default"
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 0
# Height of the color image. If 0, the default height will be used
color_height: 0
# Fps of the color image. If 0, the default FPS will be used
color_fps: 0
# default Format of the color image.
color_format: "MJPG"
# enable auto exposure for the color image
enable_color_auto_exposure: true
# enable auto white balance for the color image
enable_color_auto_white_balance: true
# If true, the color image will be undistorted
enable_color_undistortion: false
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 0
# Height of the depth image. If 0, the default height will be used
depth_height: 0
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 0
# default Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
laser:
# Whether to enable the laser. Default value is true
enable_laser: false
# Laser Switch Alternate Mode, 0: Off, 1: On-Off Alternate, 2: Off-On Alternate. Default value is 0.
laser_on_off_mode: 0
filter:
# -enable_decimation_filter
enable_decimation_filter: false
# -enable_hdr_merge
enable_hdr_merge: false
# -enable_sequence_id_filter
enable_sequence_id_filter: false
# -enable_threshold_filter
enable_threshold_filter: false
# -enable_noise_removal_filter
enable_noise_removal_filter: true
# -enable_spatial_filter
enable_spatial_filter: false
# -enable_temporal_filter
enable_temporal_filter: false
# -enable_hole_filling_filter
enable_hole_filling_filter: false
# -noise_removal_filter_min_diff
noise_removal_filter_min_diff: 256
# -noise_removal_filter_max_size
noise_removal_filter_max_size: 80
# -enable_soft_filter
enable_soft_filter: true
leftir:
# the left IR image will not be enabled
enable_left_ir: true
rightir:
# the right IR image will not be enabled
enable_right_ir: true
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# The frequency of the accelerometer can be selected as 1.5625Hz, 3.125Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
accel_rate: "200hz"
# The range of the accelerometer, the optional values are 2g, 4g, 8g, 16g. The specific value depends on the current camera.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# The frequency of the gyroscope can be selected as 1.5625hz, 3.125hz, 6.25hz, 12.5hz, 25hz, 50hz, 100hz, 200hz, 500hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
gyro_rate: "200hz"
# The range of the gyroscope, the optional values are 16dps, 31dps, 62dps, 125dps, 250dps, 500dps, 1000dps, 2000dps. The specific value depends on the current camera.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
point_cloud:
# enable point cloud. {fase:disable, true:enable}
enable_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used, true:devicetime, false:systemtime
use_hardware_time: true
# the host time will be synchronized with the device time
enable_sync_host_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "SECONDARY_SYNCED"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
@@ -0,0 +1,161 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "gemini330_series.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera_test1"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: "2-2-3"
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 2
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 10
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the camera will be reset
enable_hardware_reset: false
# If true, the LDP will be enabled
enable_ldp: true
# The preset of the device. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation
# Predefined presets doc reference: docs/source/2_installation/package_description.md
# Deep working mode support is as follows:{"Default","Hand","High Accuracy","High Density","Medium Density","Custom"}
device_preset: "Default"
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 0
# Height of the color image. If 0, the default height will be used
color_height: 0
# Fps of the color image. If 0, the default FPS will be used
color_fps: 0
# default Format of the color image.
color_format: "MJPG"
# enable auto exposure for the color image
enable_color_auto_exposure: true
# enable auto white balance for the color image
enable_color_auto_white_balance: true
# If true, the color image will be undistorted
enable_color_undistortion: false
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 0
# Height of the depth image. If 0, the default height will be used
depth_height: 0
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 0
# default Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
laser:
# Whether to enable the laser. Default value is true
enable_laser: false
# Laser Switch Alternate Mode, 0: Off, 1: On-Off Alternate, 2: Off-On Alternate. Default value is 0.
laser_on_off_mode: 0
filter:
# -enable_decimation_filter
enable_decimation_filter: false
# -enable_hdr_merge
enable_hdr_merge: false
# -enable_sequence_id_filter
enable_sequence_id_filter: false
# -enable_threshold_filter
enable_threshold_filter: false
# -enable_noise_removal_filter
enable_noise_removal_filter: true
# -enable_spatial_filter
enable_spatial_filter: false
# -enable_temporal_filter
enable_temporal_filter: false
# -enable_hole_filling_filter
enable_hole_filling_filter: false
# -noise_removal_filter_min_diff
noise_removal_filter_min_diff: 256
# -noise_removal_filter_max_size
noise_removal_filter_max_size: 80
# -enable_soft_filter
enable_soft_filter: true
leftir:
# the left IR image will not be enabled
enable_left_ir: true
rightir:
# the right IR image will not be enabled
enable_right_ir: true
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# The frequency of the accelerometer can be selected as 1.5625Hz, 3.125Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
accel_rate: "200hz"
# The range of the accelerometer, the optional values are 2g, 4g, 8g, 16g. The specific value depends on the current camera.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# The frequency of the gyroscope can be selected as 1.5625hz, 3.125hz, 6.25hz, 12.5hz, 25hz, 50hz, 100hz, 200hz, 500hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
gyro_rate: "200hz"
# The range of the gyroscope, the optional values are 16dps, 31dps, 62dps, 125dps, 250dps, 500dps, 1000dps, 2000dps. The specific value depends on the current camera.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
point_cloud:
# enable point cloud. {fase:disable, true:enable}
enable_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used, true:devicetime, false:systemtime
use_hardware_time: true
# the host time will be synchronized with the device time
enable_sync_host_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
@@ -0,0 +1,161 @@
# config/*.yaml files are used to configure the camera parameters
---
orbbec_ros:
camera_parameters:
general:
# Camera model. upport product models by referencing config/*.yaml
camera_model: "gemini330_series"
# Path to the configuration file. If empty, default parameters will be used
config_file_path: "gemini330_series.yaml"
deivce:
# camera name, usually overwritten by launch file
camera_name: "camera_test2"
# camera serial number, usually overwritten by launch file
serial_number: ""
# The USB port of the camera. This parameter is required when using multiple cameras.
usb_port: "2-1-12"
# Number of devices. If multiple cameras are required, this parameter must be filled in launch file
device_num: 2
# The delay time for reopening the device, in milliseconds. Usually, there is no need to modify by default.
connection_delay: 10
# If true, the heartbeat will be enabled
enable_heartbeat: false
# If true, the camera will be reset
enable_hardware_reset: false
# If true, the LDP will be enabled
enable_ldp: true
# The preset of the device. #For details, Please refer to the comments in SDK/include/libobsensor/Advanced.h for a detailed explanation
# Predefined presets doc reference: docs/source/2_installation/package_description.md
# Deep working mode support is as follows:{"Default","Hand","High Accuracy","High Density","Medium Density","Custom"}
device_preset: "Default"
color:
# If true, the color image will be enabled
enable_color: true
# Width of the color image. If 0, the default width will be used
color_width: 0
# Height of the color image. If 0, the default height will be used
color_height: 0
# Fps of the color image. If 0, the default FPS will be used
color_fps: 0
# default Format of the color image.
color_format: "MJPG"
# enable auto exposure for the color image
enable_color_auto_exposure: true
# enable auto white balance for the color image
enable_color_auto_white_balance: true
# If true, the color image will be undistorted
enable_color_undistortion: false
depth:
# If true, the depth image will be enabled
enable_depth: true
# Width of the depth image. If 0, the default width will be used
depth_width: 0
# Height of the depth image. If 0, the default height will be used
depth_height: 0
# Fps of the depth image. If 0, the default FPS will be used
depth_fps: 0
# default Format of the depth image.
depth_format: "Y16"
# If false, the depth scale will not be enabled
enable_depth_scale: true
# D2C Depth registration mode.
# Enables hardware that aligns depth frames to color frames. This field is required when setting enable_colored_point_cloud to true
depth_registration: true
# The alignment mode to be used. Options are "HW" for hardware alignment and "SW" for software alignment
align_mode: "SW"
laser:
# Whether to enable the laser. Default value is true
enable_laser: false
# Laser Switch Alternate Mode, 0: Off, 1: On-Off Alternate, 2: Off-On Alternate. Default value is 0.
laser_on_off_mode: 0
filter:
# -enable_decimation_filter
enable_decimation_filter: false
# -enable_hdr_merge
enable_hdr_merge: false
# -enable_sequence_id_filter
enable_sequence_id_filter: false
# -enable_threshold_filter
enable_threshold_filter: false
# -enable_noise_removal_filter
enable_noise_removal_filter: true
# -enable_spatial_filter
enable_spatial_filter: false
# -enable_temporal_filter
enable_temporal_filter: false
# -enable_hole_filling_filter
enable_hole_filling_filter: false
# -noise_removal_filter_min_diff
noise_removal_filter_min_diff: 256
# -noise_removal_filter_max_size
noise_removal_filter_max_size: 80
# -enable_soft_filter
enable_soft_filter: true
leftir:
# the left IR image will not be enabled
enable_left_ir: true
rightir:
# the right IR image will not be enabled
enable_right_ir: true
imu:
# If true, the IMU accelerometer data will be enabled
enable_accel: false
# The frequency of the accelerometer can be selected as 1.5625Hz, 3.125Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
accel_rate: "200hz"
# The range of the accelerometer, the optional values are 2g, 4g, 8g, 16g. The specific value depends on the current camera.
accel_range: "4g"
# If true, the IMU gyroscope data will be enabled
enable_gyro: false
# The frequency of the gyroscope can be selected as 1.5625hz, 3.125hz, 6.25hz, 12.5hz, 25hz, 50hz, 100hz, 200hz, 500hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz, 32kHz.
# The specific value depends on the current camera.
gyro_rate: "200hz"
# The range of the gyroscope, the optional values are 16dps, 31dps, 62dps, 125dps, 250dps, 500dps, 1000dps, 2000dps. The specific value depends on the current camera.
gyro_range: "1000dps"
# enable_sync_output_accel_gyro
enable_sync_output_accel_gyro: false
point_cloud:
# enable point cloud. {fase:disable, true:enable}
enable_point_cloud: false
advanced:
# If true, the extrinsics publish will be enabled
enable_publish_extrinsic: false
# If true, the frame synchronization will be enabled
enable_frame_sync: true
# Publish D2C superimposed image (only for testing).
enable_d2c_viewer: false
# If false, the hardware time will not be used, true:devicetime, false:systemtime
use_hardware_time: true
# the host time will be synchronized with the device time
enable_sync_host_time: true
device_sync:
# Device synchronization mode. supports: {1.FREE_RUN 2.STANDALONE 3.PRIMARY 4.SECONDARY 5.SECONDARY_SYNCED 6.SOFTWARE_TRIGGERING 7.HARDWARE_TRIGGERING}.
# For details, Please refer to the OBMultiDeviceSyncMode-related comments in SDK/include/libobsensor/ObTypes.h for a detailed explanation of each mode.
sync_mode: "STANDALONE"
# The delay time of the depth image capture after receiving the capture command or trigger signal in microseconds.
# For details, Please refer to the OBMultiDeviceSyncConfig-related comments in SDK/include/libobsensor/ObTypes.h
depth_delay_us: 0
# The delay time of the color image capture after receiving the capture command or trigger signal in microseconds.
color_delay_us: 0
# The delay time of the image capture after receiving the capture command or trigger signal in microseconds.
trigger2image_delay_us: 0
# Trigger signal output enable flag.
trigger_out_enabled: true
# The delay time of the trigger signal output after receiving the capture command or trigger signal in microseconds.
trigger_out_delay_us: 0
# The frame number of each stream after each trigger in triggering mode.
frames_per_trigger: 2
# software trigger period in ms
software_trigger_period: 33
@@ -1,14 +0,0 @@
{
"start_benchmark_params": {
"camera_name": [
"camera_01",
"camera_02",
"camera_03",
"camera_04"
],
"process_name": "component_conta",
"switch_cycle": 60,
"test_cycle": 1,
"skip_number": 30
}
}
-31
View File
@@ -1,31 +0,0 @@
# [benchmark](./benchmark)
The goal of this tool is to benchmark the performance of various OrbbecSDK_ROS2 camera configurations. The benchmark results depend on the camera and settings used.(Currently only works with ROS2 Humble).
# [disparity_search_offset](./disparity_search_offset)
How to use disparity_search_offset in OrbbecSDK_ROS2.
# [gmsl_camera](./gmsl_camera)
How to use gmsl_camera in OrbbecSDK_ROS2.Show how to start Single GMSL camera ,Multi GMSL camera , and Multi GMSL camera synced.
# [interleave_ae_mode](./interleave_ae_mode)
How to use interleave_ae in OrbbecSDK_ROS2.Show how to use interleave_ae in Gemini 330 series cameras.
# [lower_cpu_usage](./lower_cpu_usage)
How to reduce CPU usage of one or more cameras in OrbbecSDK_ROS2.
# [multi_camera_synced](./multi_camera_synced)
How to use multi-camera synced in OrbbecSDK_ROS2.
# [multi_camera_synced_verification_tool](./multi_camera_synced_verification_tool)
How to verify the synchronization accuracy of multi-camera synced.Show how to use the save_rgbir tool and Python script to analyze the synchronization between cameras and between different cameras.
# [net_camera](./net_camera)
How to use net_camera in OrbbecSDK_ROS2.Show how to start Single Net camera ,Multi Net camera.
@@ -1,51 +0,0 @@
# Ob_benchmark tool
> The goal of this tool is to benchmark the performance of various OrbbecSDK_ROS2 camera configurations. The benchmark results depend on the camera and settings used.(Currently only works with ROS2 Humble)
## Usage Instructions
### Tool Configuration ([start_benchmark_params.json](../../config/tools/startbenchmark/start_benchmark_params.json))
```json
{
"start_benchmark_params": {
"camera_name": [
"camera_01",
"camera_02",
"camera_03",
"camera_04"
],
"process_name": "component_conta",
"switch_cycle": 300,
"test_cycle": 1,
"skip_number": 30
}
}
```
* `camera_name`: Names of the cameras to be configured. Example: `"camera_01"`, `"camera_02"`, etc.
* `process_name`: The name of the process to be monitored. For example, `"component_conta"` will monitor the data of the container process.
* `switch_cycle`: The cycle time for switching configurations, in seconds. For example, setting it to `300` means the configuration will switch every 300 seconds.
* `test_cycle`: The testing cycle, in seconds. For example, setting it to `1` means the tool will collect data for the monitored process every 1 second.
* `skip_number`: The number of data points to skip. For example, setting it to `30` means that the first 30 data points will be ignored.
### Camera configuration (launch files)
In the launch folder, there are multiple\.launch.py files (`ob_benchmark_0.launch.py`, `ob_benchmark_1.launch.py`, ..., `ob_benchmark_19.launch.py`). Each file corresponds to a different camera configuration.
### Running the ob_benchmark tool
To run the tool, use the following commands:
```bash
source install/setup.bash
ros2 run orbbec_camera ob_benchmark_node
```
### Output Data Files
The output data files will be stored in the ob_benchmark folder with filenames like `0.csv`, `1.csv`, ..., 19.csv. For example:
* `0.csv` contains data from the `ob_benchmark_0.launch.py` configuration.
* `1.csv` contains data from the `ob_benchmark_1.launch.py` configuration.
@@ -1,265 +0,0 @@
import os
import yaml
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction, GroupAction
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import PushRosNamespace, ComposableNodeContainer, Node
from launch_ros.descriptions import ComposableNode
from launch.conditions import UnlessCondition
from launch_ros.actions import LoadComposableNodes
def load_yaml(file_path):
with open(file_path, 'r') as f:
return yaml.safe_load(f)
def merge_params(default_params, yaml_params):
for key, value in yaml_params.items():
if key in default_params:
default_params[key] = value
return default_params
def convert_value(value):
if isinstance(value, str):
try:
return int(value)
except ValueError:
pass
try:
return float(value)
except ValueError:
pass
if value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
return value
def load_parameters(context, args):
default_params = {arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args}
config_file_path = LaunchConfiguration('config_file_path').perform(context)
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number'}
return {
key: (value if key in skip_convert else convert_value(value))
for key, value in default_params.items()
}
def generate_launch_description():
args = [
DeclareLaunchArgument('camera_name', default_value='camera'),
DeclareLaunchArgument('depth_registration', default_value='true'),
DeclareLaunchArgument('serial_number', default_value=''),
DeclareLaunchArgument('usb_port', default_value=''),
DeclareLaunchArgument('device_num', default_value='1'),
DeclareLaunchArgument('uvc_backend', default_value='libuvc'),#libuvc or v4l2
DeclareLaunchArgument('point_cloud_qos', default_value='default'),
DeclareLaunchArgument('enable_point_cloud', default_value='true'),
DeclareLaunchArgument('enable_colored_point_cloud', default_value='false'),
DeclareLaunchArgument('cloud_frame_id', default_value=''),
DeclareLaunchArgument('connection_delay', default_value='10'),
DeclareLaunchArgument('color_width', default_value='0'),
DeclareLaunchArgument('color_height', default_value='0'),
DeclareLaunchArgument('color_fps', default_value='0'),
DeclareLaunchArgument('color_format', default_value='ANY'),
DeclareLaunchArgument('enable_color', default_value='true'),
DeclareLaunchArgument('color_qos', default_value='default'),
DeclareLaunchArgument('color_camera_info_qos', default_value='default'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('color_ae_max_exposure', default_value='-1'),
DeclareLaunchArgument('color_brightness', default_value='-1'),
DeclareLaunchArgument('depth_width', default_value='0'),
DeclareLaunchArgument('depth_height', default_value='0'),
DeclareLaunchArgument('depth_fps', default_value='0'),
DeclareLaunchArgument('depth_format', default_value='ANY'),
DeclareLaunchArgument('enable_depth', default_value='true'),
DeclareLaunchArgument('depth_qos', default_value='default'),
DeclareLaunchArgument('depth_camera_info_qos', default_value='default'),
DeclareLaunchArgument('left_ir_width', default_value='0'),
DeclareLaunchArgument('left_ir_height', default_value='0'),
DeclareLaunchArgument('left_ir_fps', default_value='0'),
DeclareLaunchArgument('left_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_left_ir', default_value='false'),
DeclareLaunchArgument('left_ir_qos', default_value='default'),
DeclareLaunchArgument('left_ir_camera_info_qos', default_value='default'),
DeclareLaunchArgument('right_ir_width', default_value='0'),
DeclareLaunchArgument('right_ir_height', default_value='0'),
DeclareLaunchArgument('right_ir_fps', default_value='0'),
DeclareLaunchArgument('right_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_right_ir', default_value='false'),
DeclareLaunchArgument('right_ir_qos', default_value='default'),
DeclareLaunchArgument('right_ir_camera_info_qos', default_value='default'),
DeclareLaunchArgument('enable_ir_auto_exposure', default_value='true'),
DeclareLaunchArgument('ir_exposure', default_value='-1'),
DeclareLaunchArgument('ir_gain', default_value='-1'),
DeclareLaunchArgument('ir_ae_max_exposure', default_value='-1'),
DeclareLaunchArgument('ir_brightness', default_value='-1'),
DeclareLaunchArgument('enable_sync_output_accel_gyro', default_value='false'),
DeclareLaunchArgument('enable_accel', default_value='false'),
DeclareLaunchArgument('accel_rate', default_value='200hz'),
DeclareLaunchArgument('accel_range', default_value='4g'),
DeclareLaunchArgument('enable_gyro', default_value='false'),
DeclareLaunchArgument('gyro_rate', default_value='200hz'),
DeclareLaunchArgument('gyro_range', default_value='1000dps'),
DeclareLaunchArgument('liner_accel_cov', default_value='0.01'),
DeclareLaunchArgument('angular_vel_cov', default_value='0.01'),
DeclareLaunchArgument('publish_tf', default_value='true'),
DeclareLaunchArgument('tf_publish_rate', default_value='0.0'),
DeclareLaunchArgument('ir_info_url', default_value=''),
DeclareLaunchArgument('color_info_url', default_value=''),
DeclareLaunchArgument('log_level', default_value='none'),
DeclareLaunchArgument('enable_publish_extrinsic', default_value='false'),
DeclareLaunchArgument('enable_d2c_viewer', default_value='false'),
DeclareLaunchArgument('enable_hardware_d2d', default_value='true'),
DeclareLaunchArgument('enable_ldp', default_value='true'),
DeclareLaunchArgument('enable_soft_filter', default_value='true'),
DeclareLaunchArgument('soft_filter_max_diff', default_value='-1'),
DeclareLaunchArgument('soft_filter_speckle_size', default_value='-1'),
DeclareLaunchArgument('sync_mode', default_value='standalone'),
DeclareLaunchArgument('depth_delay_us', default_value='0'),
DeclareLaunchArgument('color_delay_us', default_value='0'),
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
DeclareLaunchArgument('enable_depth_scale', default_value='true'),
DeclareLaunchArgument('enable_decimation_filter', default_value='false'),
DeclareLaunchArgument('enable_hdr_merge', default_value='false'),
DeclareLaunchArgument('enable_sequence_id_filter', default_value='false'),
DeclareLaunchArgument('enable_threshold_filter', default_value='false'),
DeclareLaunchArgument('enable_hardware_noise_removal_filter', default_value='true'),
DeclareLaunchArgument('enable_noise_removal_filter', default_value='true'),
DeclareLaunchArgument('enable_spatial_filter', default_value='false'),
DeclareLaunchArgument('enable_temporal_filter', default_value='false'),
DeclareLaunchArgument('enable_hole_filling_filter', default_value='false'),
DeclareLaunchArgument('decimation_filter_scale', default_value='-1'),
DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'),
DeclareLaunchArgument('threshold_filter_max', default_value='-1'),
DeclareLaunchArgument('threshold_filter_min', default_value='-1'),
DeclareLaunchArgument('noise_removal_filter_min_diff', default_value='256'),
DeclareLaunchArgument('noise_removal_filter_max_size', default_value='80'),
DeclareLaunchArgument('spatial_filter_alpha', default_value='-1.0'),
DeclareLaunchArgument('spatial_filter_diff_threshold', default_value='-1'),
DeclareLaunchArgument('spatial_filter_magnitude', default_value='-1'),
DeclareLaunchArgument('spatial_filter_radius', default_value='-1'),
DeclareLaunchArgument('temporal_filter_diff_threshold', default_value='-1.0'),
DeclareLaunchArgument('temporal_filter_weight', default_value='-1.0'),
DeclareLaunchArgument('hole_filling_filter_mode', default_value=''),
DeclareLaunchArgument('hdr_merge_exposure_1', default_value='-1'),
DeclareLaunchArgument('hdr_merge_gain_1', default_value='-1'),
DeclareLaunchArgument('hdr_merge_exposure_2', default_value='-1'),
DeclareLaunchArgument('hdr_merge_gain_2', default_value='-1'),
DeclareLaunchArgument('align_mode', default_value='SW'),
DeclareLaunchArgument('diagnostic_period', default_value='1.0'),
DeclareLaunchArgument('enable_laser', default_value='true'),
DeclareLaunchArgument('depth_precision', default_value=''),
DeclareLaunchArgument('device_preset', default_value='Default'),
DeclareLaunchArgument('retry_on_usb3_detection_failure', default_value='false'),
DeclareLaunchArgument('laser_energy_level', default_value='-1'),
DeclareLaunchArgument('enable_sync_host_time', default_value='true'),
DeclareLaunchArgument('time_domain', default_value='global'),# global, device, system
DeclareLaunchArgument('enable_color_undistortion', default_value='false'),
DeclareLaunchArgument('config_file_path', default_value=''),
DeclareLaunchArgument('enable_heartbeat', default_value='false'),
DeclareLaunchArgument('gmsl_trigger_fps', default_value='3000'),
DeclareLaunchArgument('enable_gmsl_trigger', default_value='false'),
DeclareLaunchArgument('disparity_range_mode', default_value='-1'),
DeclareLaunchArgument('disparity_search_offset', default_value='-1'),
DeclareLaunchArgument('disparity_offset_config', default_value='false'),
DeclareLaunchArgument('offset_index0', default_value='-1'),
DeclareLaunchArgument('offset_index1', default_value='-1'),
DeclareLaunchArgument('frame_aggregate_mode', default_value='ANY'), # full_frame、color_frame、ANY or disable
DeclareLaunchArgument('interleave_ae_mode', default_value='laser'), # 'hdr' or 'laser'
DeclareLaunchArgument('interleave_frame_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_index', default_value='1'), # 0:skip pattern ir 1: skip flood ir
DeclareLaunchArgument('hdr_index1_laser_control', default_value='1'),#interleave_hdr_param
DeclareLaunchArgument('hdr_index1_depth_exposure', default_value='1'),
DeclareLaunchArgument('hdr_index1_depth_gain', default_value='16'),
DeclareLaunchArgument('hdr_index1_ir_brightness', default_value='20'),
DeclareLaunchArgument('hdr_index1_ir_ae_max_exposure', default_value='2000'),
DeclareLaunchArgument('hdr_index0_laser_control', default_value='1'),
DeclareLaunchArgument('hdr_index0_depth_exposure', default_value='7500'),
DeclareLaunchArgument('hdr_index0_depth_gain', default_value='16'),
DeclareLaunchArgument('hdr_index0_ir_brightness', default_value='60'),
DeclareLaunchArgument('hdr_index0_ir_ae_max_exposure', default_value='10000'),
DeclareLaunchArgument('laser_index1_laser_control', default_value='0'),#interleave_laser_param
DeclareLaunchArgument('laser_index1_depth_exposure', default_value='3000'),
DeclareLaunchArgument('laser_index1_depth_gain', default_value='16'),
DeclareLaunchArgument('laser_index1_ir_brightness', default_value='60'),
DeclareLaunchArgument('laser_index1_ir_ae_max_exposure', default_value='17000'),
DeclareLaunchArgument('laser_index0_laser_control', default_value='1'),
DeclareLaunchArgument('laser_index0_depth_exposure', default_value='3000'),
DeclareLaunchArgument('laser_index0_depth_gain', default_value='16'),
DeclareLaunchArgument('laser_index0_ir_brightness', default_value='60'),
DeclareLaunchArgument('laser_index0_ir_ae_max_exposure', default_value='30000'),
DeclareLaunchArgument('use_intra_process_comms', default_value='false'),
DeclareLaunchArgument('attach_component_container_enable', default_value='false'),
DeclareLaunchArgument('attach_component_container_name', default_value='orbbec_container'),
]
def get_params(context, args):
return [load_parameters(context, args)]
def create_node_action(context, args):
params = get_params(context, args)
ros_distro = os.environ.get("ROS_DISTRO", "humble")
if ros_distro == "foxy":
return [
Node(
package="orbbec_camera",
executable="orbbec_camera_node",
name="ob_camera_node",
namespace=LaunchConfiguration("camera_name"),
parameters=params,
output="screen",
)
]
else:
attach_to_shared_component_container_arg = LaunchConfiguration('attach_to_shared_component_container', default=False)
component_container_name_arg = LaunchConfiguration('component_container_name', default='orbbec_container')
orbbec_container = Node(
name=component_container_name_arg,
package='rclcpp_components',
executable='component_container_mt',
output='screen',
condition=UnlessCondition(attach_to_shared_component_container_arg)
)
return [
orbbec_container,
LoadComposableNodes(
target_container=component_container_name_arg,
composable_node_descriptions=[
ComposableNode(
namespace=LaunchConfiguration("camera_name"),
name=LaunchConfiguration("camera_name"),
package='orbbec_camera',
plugin='orbbec_camera::OBCameraNodeDriver',
parameters=params,
extra_arguments=[{'use_intra_process_comms': LaunchConfiguration("use_intra_process_comms")}],
)
]
)
]
return LaunchDescription(
args + [
OpaqueFunction(function=lambda context: create_node_action(context, args))
]
)
@@ -1,197 +0,0 @@
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node,LoadComposableNodes
from launch.actions import IncludeLaunchDescription, GroupAction, TimerAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import DeclareLaunchArgument
from launch.conditions import UnlessCondition, IfCondition
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.descriptions import ComposableNode
def load_yaml(file_path):
with open(file_path, 'r') as f:
return yaml.safe_load(f)
def merge_params(default_params, yaml_params):
for key, value in yaml_params.items():
if key in default_params:
default_params[key] = value
return default_params
def convert_value(value):
if isinstance(value, str):
try:
return int(value)
except ValueError:
pass
try:
return float(value)
except ValueError:
pass
if value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
return value
def load_parameters(context, args):
default_params = {arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args}
config_file_path = LaunchConfiguration('config_file_path').perform(context)
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number'}
return {
key: (value if key in skip_convert else convert_value(value))
for key, value in default_params.items()
}
def generate_launch_description():
# Include launch files
package_dir = get_package_share_directory("orbbec_camera")
launch_file_dir = os.path.join(package_dir, "examples/benchmark")
attach_to_shared_component_container_arg = LaunchConfiguration('attach_to_shared_component_container', default=False)
component_container_name_arg = LaunchConfiguration('component_container_name', default='shared_orbbec_container')
shared_orbbec_container = Node(
name=component_container_name_arg,
package="rclcpp_components",
executable="component_container_mt",
output="screen",
condition=UnlessCondition(attach_to_shared_component_container_arg),
)
start_benchmark = LoadComposableNodes(
target_container=component_container_name_arg,
composable_node_descriptions=[
ComposableNode(
namespace="start_benchmark",
name="start_benchmark",
package='orbbec_camera',
plugin='orbbec_camera::tools::StartBenchmark',
)
]
)
attach_to_shared_component_container_arg = TextSubstitution(text="true")
args = [
DeclareLaunchArgument('uvc_backend', default_value='libuvc'),
DeclareLaunchArgument('depth_registration', default_value='false'),
DeclareLaunchArgument('color_width', default_value='848'),
DeclareLaunchArgument('color_height', default_value='480'),
DeclareLaunchArgument('color_fps', default_value='30'),
DeclareLaunchArgument('color_format', default_value='MJPG'),
DeclareLaunchArgument('enable_color', default_value='true'),
DeclareLaunchArgument('depth_width', default_value='848'),
DeclareLaunchArgument('depth_height', default_value='480'),
DeclareLaunchArgument('depth_fps', default_value='30'),
DeclareLaunchArgument('depth_format', default_value='ANY'),
DeclareLaunchArgument('enable_depth', default_value='true'),
DeclareLaunchArgument('left_ir_width', default_value='848'),
DeclareLaunchArgument('left_ir_height', default_value='480'),
DeclareLaunchArgument('left_ir_fps', default_value='30'),
DeclareLaunchArgument('left_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_left_ir', default_value='true'),
DeclareLaunchArgument('right_ir_width', default_value='848'),
DeclareLaunchArgument('right_ir_height', default_value='480'),
DeclareLaunchArgument('right_ir_fps', default_value='30'),
DeclareLaunchArgument('right_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_right_ir', default_value='true'),
DeclareLaunchArgument('enable_point_cloud', default_value='false'),
DeclareLaunchArgument('enable_colored_point_cloud', default_value='false'),
DeclareLaunchArgument('enable_decimation_filter', default_value='false'),
DeclareLaunchArgument('enable_hdr_merge', default_value='false'),
DeclareLaunchArgument('enable_sequence_id_filter', default_value='false'),
DeclareLaunchArgument('enable_threshold_filter', default_value='false'),
DeclareLaunchArgument('enable_hardware_noise_removal_filter', default_value='false'),
DeclareLaunchArgument('enable_noise_removal_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_filter', default_value='false'),
DeclareLaunchArgument('enable_temporal_filter', default_value='false'),
DeclareLaunchArgument('enable_hole_filling_filter', default_value='false'),
]
launch1_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_01",
"usb_port": "2-7",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch2_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_02",
"usb_port": "2-2",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch3_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_03",
"usb_port": "2-1",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch4_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_04",
"usb_port": "2-3",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
delayed_left_camera = TimerAction(
period=2.0,
actions=args+[launch1_include],
)
delayed_right_camera = TimerAction(
period=4.0,
actions=args+[launch2_include],
)
delayed_rear_camera = TimerAction(
period=6.0,
actions=args+[launch3_include],
)
delayed_front_camera = TimerAction(
period=8.0,
actions=args+[launch4_include],
)
ld = LaunchDescription(
[
shared_orbbec_container,
start_benchmark,
delayed_left_camera,
delayed_right_camera,
delayed_rear_camera,
delayed_front_camera,
]
)
return ld
@@ -1,197 +0,0 @@
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node,LoadComposableNodes
from launch.actions import IncludeLaunchDescription, GroupAction, TimerAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import DeclareLaunchArgument
from launch.conditions import UnlessCondition, IfCondition
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.descriptions import ComposableNode
def load_yaml(file_path):
with open(file_path, 'r') as f:
return yaml.safe_load(f)
def merge_params(default_params, yaml_params):
for key, value in yaml_params.items():
if key in default_params:
default_params[key] = value
return default_params
def convert_value(value):
if isinstance(value, str):
try:
return int(value)
except ValueError:
pass
try:
return float(value)
except ValueError:
pass
if value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
return value
def load_parameters(context, args):
default_params = {arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args}
config_file_path = LaunchConfiguration('config_file_path').perform(context)
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number'}
return {
key: (value if key in skip_convert else convert_value(value))
for key, value in default_params.items()
}
def generate_launch_description():
# Include launch files
package_dir = get_package_share_directory("orbbec_camera")
launch_file_dir = os.path.join(package_dir, "examples/benchmark")
attach_to_shared_component_container_arg = LaunchConfiguration('attach_to_shared_component_container', default=False)
component_container_name_arg = LaunchConfiguration('component_container_name', default='shared_orbbec_container')
shared_orbbec_container = Node(
name=component_container_name_arg,
package="rclcpp_components",
executable="component_container_mt",
output="screen",
condition=UnlessCondition(attach_to_shared_component_container_arg),
)
start_benchmark = LoadComposableNodes(
target_container=component_container_name_arg,
composable_node_descriptions=[
ComposableNode(
namespace="start_benchmark",
name="start_benchmark",
package='orbbec_camera',
plugin='orbbec_camera::tools::StartBenchmark',
)
]
)
attach_to_shared_component_container_arg = TextSubstitution(text="true")
args = [
DeclareLaunchArgument('uvc_backend', default_value='libuvc'),
DeclareLaunchArgument('depth_registration', default_value='false'),
DeclareLaunchArgument('color_width', default_value='848'),
DeclareLaunchArgument('color_height', default_value='480'),
DeclareLaunchArgument('color_fps', default_value='30'),
DeclareLaunchArgument('color_format', default_value='MJPG'),
DeclareLaunchArgument('enable_color', default_value='true'),
DeclareLaunchArgument('depth_width', default_value='848'),
DeclareLaunchArgument('depth_height', default_value='480'),
DeclareLaunchArgument('depth_fps', default_value='30'),
DeclareLaunchArgument('depth_format', default_value='ANY'),
DeclareLaunchArgument('enable_depth', default_value='true'),
DeclareLaunchArgument('left_ir_width', default_value='848'),
DeclareLaunchArgument('left_ir_height', default_value='480'),
DeclareLaunchArgument('left_ir_fps', default_value='30'),
DeclareLaunchArgument('left_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_left_ir', default_value='true'),
DeclareLaunchArgument('right_ir_width', default_value='848'),
DeclareLaunchArgument('right_ir_height', default_value='480'),
DeclareLaunchArgument('right_ir_fps', default_value='30'),
DeclareLaunchArgument('right_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_right_ir', default_value='true'),
DeclareLaunchArgument('enable_point_cloud', default_value='false'),
DeclareLaunchArgument('enable_colored_point_cloud', default_value='false'),
DeclareLaunchArgument('enable_decimation_filter', default_value='false'),
DeclareLaunchArgument('enable_hdr_merge', default_value='false'),
DeclareLaunchArgument('enable_sequence_id_filter', default_value='false'),
DeclareLaunchArgument('enable_threshold_filter', default_value='false'),
DeclareLaunchArgument('enable_hardware_noise_removal_filter', default_value='true'),
DeclareLaunchArgument('enable_noise_removal_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_filter', default_value='false'),
DeclareLaunchArgument('enable_temporal_filter', default_value='false'),
DeclareLaunchArgument('enable_hole_filling_filter', default_value='false'),
]
launch1_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_01",
"usb_port": "2-7",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch2_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_02",
"usb_port": "2-2",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch3_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_03",
"usb_port": "2-1",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch4_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_benchmark.launch.py")
),
launch_arguments={
"camera_name": "camera_04",
"usb_port": "2-3",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
delayed_left_camera = TimerAction(
period=2.0,
actions=args+[launch1_include],
)
delayed_right_camera = TimerAction(
period=4.0,
actions=args+[launch2_include],
)
delayed_rear_camera = TimerAction(
period=6.0,
actions=args+[launch3_include],
)
delayed_front_camera = TimerAction(
period=8.0,
actions=args+[launch4_include],
)
ld = LaunchDescription(
[
shared_orbbec_container,
start_benchmark,
delayed_left_camera,
delayed_right_camera,
delayed_rear_camera,
delayed_front_camera,
]
)
return ld
@@ -1,47 +0,0 @@
# Disparity_search_offset
> This section describes how to use the disparity_search_offset function in the Gemini330 series cameras (minimum camera firmware version [1.4.60](https://www.orbbec.com/docs/g330-firmware-release/)).Disparity_search_offset is effective only for1280×720, 1280×800 and 640×400 resolutions of depth stream.
## Function Introduction
The definition of disparity search range: For any pixel *(u_l, v)* in the left image, by default, the corresponding disparity search range in the right image is *[ (u_l - 255, v)*, *(u_l, v) ]*, where the disparity search length is 256 and the maximum integer disparity is 255. If the starting point of the search is adjusted to *[ (u_l - 255 - offset, v)*, *(u_l - offset, v) ]*, the offset is defined as the disparity shift. Therefore, our disparity search range configuration includes both the disparity search length and the search position offset (which can also be referred to as the disparity shift).
![Depth Point Cloud Visualization](image/search_offset0.png)
## Parameter Introduction
The disparity_search_offset related parameters are set in [gemini_330_series.launch.py](../../launch/gemini_330_series.launch.py)
* `disparity_range_mode` : Disparity search length,can only be set to 64, 128 and 256.
* `disparity_search_offset` : Disparity search offset value,Disparity search offset value, can be set from 0 to 127.
* `disparity_offset_config` : Disparity search offset interleave frames.
* `offset_index0` : Frame 0 disparity search offset value.
* `offset_index1` : Frame 1 disparity search offset value.
| disparity range mode | disparity search offset | Minimum depth of inclined wall (mm) |
| :------------------: | :---------------------: | :---------------------------------: |
| 64 | 85 | Gemini 335L  388-406 |
| 64 | 127 | Gemini 335L  302-317 |
| disparity range mode | disparity search offset | Minimum depth of inclined wall (mm) |
| :------------------: | :---------------------: | :---------------------------------------------: |
| 128 | 0 | Gemini 335  233-249<br />Gemini 335L  453-475 |
| 128 | 45 | Gemini 335  172-184<br />Gemini 335L  334-349 |
| 128 | 127 | Gemini 335  117-125<br />Gemini 335L  226-236 |
| disparity range mode | disparity search offset | Minimum depth of inclined wall (mm) |
| :------------------: | :---------------------: | :---------------------------------: |
| 256 | 85 | Gemini 335L  169-178 |
| 256 | 127 | Gemini 335L  151-158 |
## Run the launch
Setting the disparity_search_offset parameter,`colcon build` again and run launch
```bash
ros2 launch orbbec_camera gemini_330_series.launch.py
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,47 +0,0 @@
# GMSL_camera
> This section describes how to use GMSL camera in OrbbecSDK_ROS2.Currently, only G335Lg GMSL devices are supported, and other GMSL devices will be supported in the near future.
## Single GMSL camera
The usage of GMSL camera in OrbbecSDK_ROS2 is the same as that of Gemini 330 series camera via USB.
```bash
ros2 launch orbbec_camera gemini_330_series.launch.py
```
## Multi GMSL camera
To get the `usb_port` of the GMSL camera, plug in the camera and run the following command in the terminal:
```bash
ros2 run orbbec_camera list_devices_node
```
For example, the obtained gmsl camera `usb_port`: `gmsl2-1`
Go to the [multi_camera.launch.py](../../launch/multi_camera.launch.py) file and change the `usb_port`.
```bash
ros2 launch orbbec_camera multi_camera.launch.py
```
## Multi GMSL camera synced
First, please see how to use [multi_camera_synced](../multi_camera_synced/README.MD).
In addition, GMSL multi-camera synced does not require Multi-Camera Sync Hub Pro, so there is no need to set the `primary` mode. Each GMSL camera is `secondary`.
### Additional Parameter Settings
* `gmsl_trigger_fps` : set hardware soc trigger source frame rate.
* `enable_gmsl_trigger` : enable hardware soc trigger.
### Run the launch
Please refer to the configuration in [multi_gmsl_camera_synced.launch.py.](multi_gmsl_camera_synced.launch.py)
```bash
ros2 launch orbbec_camera multi_gmsl_camera_synced.launch.py
```
@@ -1,57 +0,0 @@
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import IncludeLaunchDescription, GroupAction, TimerAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
def generate_launch_description():
# Include launch files
package_dir = get_package_share_directory("orbbec_camera")
launch_file_dir = os.path.join(package_dir, "launch")
config_file_dir = os.path.join(package_dir, "config")
config_file_path = os.path.join(config_file_dir, "camera_params.yaml")
launch1_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series.launch.py")
),
launch_arguments={
"camera_name": "camera_01",
"usb_port": "gmsl2-1",
"device_num": "2",
"sync_mode": "secondary_synced",
"config_file_path": config_file_path,
"trigger_out_enabled": "false",
"gmsl_trigger_fps": "3000",
"enable_gmsl_trigger": "true",
}.items(),
)
launch2_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series.launch.py")
),
launch_arguments={
"camera_name": "camera_02",
"usb_port": "gmsl2-3",
"device_num": "2",
"sync_mode": "secondary_synced",
"config_file_path": config_file_path,
"trigger_out_enabled": "false",
"enable_gmsl_trigger": "false",
}.items(),
)
# Launch description
ld = LaunchDescription(
[
# The sending the gmsl_trigger signal gsml camera should be launched at lfirst
TimerAction(period=0.0, actions=[GroupAction([launch1_include])]),
TimerAction(period=2.0, actions=[GroupAction([launch2_include])]),
]
)
return ld
@@ -1,81 +0,0 @@
# Using interleave_ae with Gemini330 series cameras
> This section describes how to use interleave_ae in Gemini 330 series cameras (minimum camera firmware version [1.4.00](https://www.orbbec.com/docs/g330-firmware-release/))
## Parameter Introduction
The interleave_ae related parameters are set in [gemini_330_series.launch.py](../../launch/gemini_330_series.launch.py)
* `interleave_ae_mode` : Set laser or hdr interleave.
* `interleave_frame_enable` : enable interleave frame mode.
* `interleave_skip_enable` : enable skip frame mode.
* `interleave_skip_index` : Set 0 for skip pattern ir, set 1 for skip flood ir.
### interleave hdr
When the `interleave_ae_mode` parameter is set to `hdr` and `interleave_frame_enable `is set to `true`, interleave hdr will be enabled
* `hdr_index1_laser_control` : Frame 1 laser switch settings.
* `hdr_index1_depth_exposure` : Frame 1 depth exposure value setting, not in AE mode.
* `hdr_index1_depth_gain` : Frame 1 depth gain value setting, not in AE mode.
* `hdr_index1_ir_brightness` : Frame 1 ir gain value setting.
* `hdr_index1_ir_ae_max_exposure` : Frame 1 ir maximum exposure value setting in AE (auto exposure).
* `hdr_index0_laser_control`: Frame 0 laser switch settings.
* `hdr_index0_depth_exposure`: Frame 0 depth exposure value setting, not in AE mode.
* `hdr_index0_depth_gain` : Frame 0 depth gain value setting, not in AE mode.
* `hdr_index0_ir_brightness` : Frame 0 ir gain value setting.
* `hdr_index0_ir_ae_max_exposure` : Frame 0 ir maximum exposure value setting in AE (auto exposure).
### interleave laser
When the `interleave_ae_mode` parameter is set to `laser` and `interleave_frame_enable `is set to `true`, interleave laser will be enabled
* `laser_index1_laser_control` : Frame 1 laser switch settings.
* `laser_index1_depth_exposure` : Frame 1 depth exposure value setting, not in AE mode.
* `laser_index1_depth_gain` : Frame 1 depth gain value setting, not in AE mode.
* `laser_index1_ir_brightness` : Frame 1 ir gain value setting.
* `laser_index1_ir_ae_max_exposure` : Frame 1 ir maximum exposure value setting in AE (auto exposure).
* `laser_index0_laser_control` : Frame 0 laser switch settings.
* `laser_index0_depth_exposure` : Frame 0 depth exposure value setting, not in AE mode.
* `laser_index0_depth_gain` : Frame 0 depth gain value setting, not in AE mode.
* `laser_index0_ir_brightness` : Frame 0 ir gain value setting.
* `laser_index0_ir_ae_max_exposure` : Frame 0 ir maximum exposure value setting in AE (auto exposure).
## Run the launch
Setting the interleave_ae parameter,`colcon build` again and run launch
```bash
ros2 launch orbbec_camera gemini_330_series.launch.py
```
#### Example Visualization
![Depth Point Cloud Visualization](image/interleave_ae0.jpeg)
![Depth Point Cloud Visualization](image/interleave_ae1.jpeg)
## Multi_camera_synced + Interleave_ae
Please refer to [multi_camera_synced](../multi_camera_synced/README.MD) and [Parameter Introduction](#parameter-introduction)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

@@ -1,99 +0,0 @@
## Using the Orbbec ROS package to get lower CPU usage
This section shows you how to reduce CPU usage for one or more cameras in a ROS 2 environment. This method only works with Gemini 330 series cameras, and the firmware version needs to be above 1.4.10(`device_preset `is set to Default).
The example launch files used in this section are `gemini_330_series_lower_cpu_usage.launch.py` and `multi_camera_lower_cpu_usage.launch.py`.
### Parameters that affect CPU usage
* `uvc_backend`:Global UVC Backend select on Linux,optional values: libuvc, v4l2.(v4l2 is lower)
* `color_format`:Color Stream coding format.(RGB is lower)
* `depth_registration`: Enables alignment of the depth frame to the color frame.(align_mode is set to HW lower)
* `enable_point_cloud`:Disables the point cloud
* `enable_colored_point_cloud`:Disables the RGB point cloud
* `filter`:decimation_filter,hdr_merge,sequenced_filter,threshold_filter,hardware_noise_removal_filter,noise_removal_filter,spatial_filter,temporal_filter,hole_filling_filter.(hardware_noise_removal_filter is lower)
### Data comparison
> Since different machines and different software environments will result in different CPU usage, the CPU improvement rate is calculated based on the device's CPU benchmark.
> A comparing B:
> `CPU improvement rate=(CPUA-CPUB)/CPUB*100`
In this example, we used two different video stream resolutions as test benchmarks to provide a performance comparison between lower and higher resolutions.(Currently, data is only provided for `uvc_backend`, `color_format`, and some `filter`)
#### Depth&Left_ir&Right_ir 424 * 266 15fps,Color 848 * 480 15fps
##### uvc_backend
libuvc comparing v4l2 In the same environment, CPU improvement rate is ***13.1%***
* libuvc is ***72.3%***
* v4l2 is ***62.8%***
##### color_format
ROS2 color stream sets MJPG encoding format and decodes it to RGB comparing RGB encoding format (including YUYV format to RGB conversion operation cost).The CPU improvement rate under the libuvc protocol is ***14.2%*** the CPU improvement rate under the v4l2 protocol is ***30.8%***
* libuvc:RGB encoding format is ***63.3%***,MJPG encoding format and decoded into RGB is ***72.3%***
* v4l2:RGB encoding format is ***48%***,MJPG encoding format and decoded into RGB is ***62.8%***
##### filter
The color stream setting RGB encoding and MJPG have no effect on filtering and are basically the same. The CPU usage of the depth stream is basically the same under the configuration of 424*266 15fps.
| Filter Configuration | libuvc(CPU improvement rate) | v4l2(CPU improvement rate) |
| :------------------------------------------: | :--------------------------: | :------------------------: |
| No filter | 63.3%(0%) | 48.0%(0%) |
| hardware_noise_removal_filter | 61.2%(-3.3%) | 47.9%(-0.2%) |
| hardware_noise_removal_filter+spatial_filter | 65.3%(3.2%) | 51.2%(6.7%) |
| noise_removal_filter | 77.0%(21.6%) | 53.3%(11.0%) |
| noise_removal_filter+spatial_filter | 78.4%(23.9%) | 54.8%(14.2%) |
#### Depth&Left_ir&Right_ir 848 * 480 30fps,Color 848 * 480 30fps
##### uvc_backend
libuvc comparing v4l2 In the same environment, CPU improvement rate is ***53.9%***
* libuvc is ***182.8%***
* v4l2 is ***118.8%***
##### color_format
ROS2 color stream sets MJPG encoding format and decodes it to RGB comparing RGB encoding format (including YUYV format to RGB conversion operation cost).The CPU improvement rate under the libuvc protocol is ***90.2%*** the CPU improvement rate under the v4l2 protocol is ***43.1%***
* libuvc:RGB encoding format is ***182.8%***,MJPG encoding format and decoded into RGB is ***347.7%***
* v4l2:RGB encoding format is ***118.8%***,MJPG encoding format and decoded into RGB is ***170.0%***
##### filter
When the depth stream is configured at 848*480 30fps, the CPU usage is significantly different.
| Filter Configuration | libuvc(CPU improvement rate) | v4l2(CPU improvement rate) |
| :------------------------------------------: | :--------------------------: | :------------------------: |
| No filter | 182.8%(0%) | 118.8%(0%) |
| hardware_noise_removal_filter | 186.3%(1.9%) | 115.4%(-2.9%) |
| hardware_noise_removal_filter+spatial_filter | 251.3%(37.5%) | 152.5%(28.4%) |
| noise_removal_filter | 218.0%(16.1%) | 128.5%(8.2%) |
| noise_removal_filter+spatial_filter | 469.6%(156.9%) | 336.7%(183.4%) |
### Example launch
This is the current example file for running the camera to achieve the lowest CPU usage, excluding the impact of filters.
Use the following command to start the single-camera configuration:
```bash
ros2 launch orbbec_camera gemini_330_series_lower_cpu_usage.launch.py
```
Use the following command to start the multi-camera configuration:
```bash
roslaunch orbbec_camera multi_camera_lower_cpu_usage.launch.py
```
@@ -1,265 +0,0 @@
import os
import yaml
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction, GroupAction
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import PushRosNamespace, ComposableNodeContainer, Node
from launch_ros.descriptions import ComposableNode
from launch.conditions import UnlessCondition
from launch_ros.actions import LoadComposableNodes
def load_yaml(file_path):
with open(file_path, 'r') as f:
return yaml.safe_load(f)
def merge_params(default_params, yaml_params):
for key, value in yaml_params.items():
if key in default_params:
default_params[key] = value
return default_params
def convert_value(value):
if isinstance(value, str):
try:
return int(value)
except ValueError:
pass
try:
return float(value)
except ValueError:
pass
if value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
return value
def load_parameters(context, args):
default_params = {arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args}
config_file_path = LaunchConfiguration('config_file_path').perform(context)
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number'}
return {
key: (value if key in skip_convert else convert_value(value))
for key, value in default_params.items()
}
def generate_launch_description():
args = [
DeclareLaunchArgument('camera_name', default_value='camera'),
DeclareLaunchArgument('depth_registration', default_value='false'),
DeclareLaunchArgument('serial_number', default_value=''),
DeclareLaunchArgument('usb_port', default_value=''),
DeclareLaunchArgument('device_num', default_value='1'),
DeclareLaunchArgument('uvc_backend', default_value='v4l2'),#libuvc or v4l2
DeclareLaunchArgument('point_cloud_qos', default_value='default'),
DeclareLaunchArgument('enable_point_cloud', default_value='false'),
DeclareLaunchArgument('enable_colored_point_cloud', default_value='false'),
DeclareLaunchArgument('cloud_frame_id', default_value=''),
DeclareLaunchArgument('connection_delay', default_value='10'),
DeclareLaunchArgument('color_width', default_value='0'),
DeclareLaunchArgument('color_height', default_value='0'),
DeclareLaunchArgument('color_fps', default_value='0'),
DeclareLaunchArgument('color_format', default_value='RGB'),
DeclareLaunchArgument('enable_color', default_value='true'),
DeclareLaunchArgument('color_qos', default_value='default'),
DeclareLaunchArgument('color_camera_info_qos', default_value='default'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('color_ae_max_exposure', default_value='-1'),
DeclareLaunchArgument('color_brightness', default_value='-1'),
DeclareLaunchArgument('depth_width', default_value='0'),
DeclareLaunchArgument('depth_height', default_value='0'),
DeclareLaunchArgument('depth_fps', default_value='0'),
DeclareLaunchArgument('depth_format', default_value='ANY'),
DeclareLaunchArgument('enable_depth', default_value='true'),
DeclareLaunchArgument('depth_qos', default_value='default'),
DeclareLaunchArgument('depth_camera_info_qos', default_value='default'),
DeclareLaunchArgument('left_ir_width', default_value='0'),
DeclareLaunchArgument('left_ir_height', default_value='0'),
DeclareLaunchArgument('left_ir_fps', default_value='0'),
DeclareLaunchArgument('left_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_left_ir', default_value='false'),
DeclareLaunchArgument('left_ir_qos', default_value='default'),
DeclareLaunchArgument('left_ir_camera_info_qos', default_value='default'),
DeclareLaunchArgument('right_ir_width', default_value='0'),
DeclareLaunchArgument('right_ir_height', default_value='0'),
DeclareLaunchArgument('right_ir_fps', default_value='0'),
DeclareLaunchArgument('right_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_right_ir', default_value='false'),
DeclareLaunchArgument('right_ir_qos', default_value='default'),
DeclareLaunchArgument('right_ir_camera_info_qos', default_value='default'),
DeclareLaunchArgument('enable_ir_auto_exposure', default_value='true'),
DeclareLaunchArgument('ir_exposure', default_value='-1'),
DeclareLaunchArgument('ir_gain', default_value='-1'),
DeclareLaunchArgument('ir_ae_max_exposure', default_value='-1'),
DeclareLaunchArgument('ir_brightness', default_value='-1'),
DeclareLaunchArgument('enable_sync_output_accel_gyro', default_value='false'),
DeclareLaunchArgument('enable_accel', default_value='false'),
DeclareLaunchArgument('accel_rate', default_value='200hz'),
DeclareLaunchArgument('accel_range', default_value='4g'),
DeclareLaunchArgument('enable_gyro', default_value='false'),
DeclareLaunchArgument('gyro_rate', default_value='200hz'),
DeclareLaunchArgument('gyro_range', default_value='1000dps'),
DeclareLaunchArgument('liner_accel_cov', default_value='0.01'),
DeclareLaunchArgument('angular_vel_cov', default_value='0.01'),
DeclareLaunchArgument('publish_tf', default_value='true'),
DeclareLaunchArgument('tf_publish_rate', default_value='0.0'),
DeclareLaunchArgument('ir_info_url', default_value=''),
DeclareLaunchArgument('color_info_url', default_value=''),
DeclareLaunchArgument('log_level', default_value='none'),
DeclareLaunchArgument('enable_publish_extrinsic', default_value='false'),
DeclareLaunchArgument('enable_d2c_viewer', default_value='false'),
DeclareLaunchArgument('enable_hardware_d2d', default_value='true'),
DeclareLaunchArgument('enable_ldp', default_value='true'),
DeclareLaunchArgument('enable_soft_filter', default_value='true'),
DeclareLaunchArgument('soft_filter_max_diff', default_value='-1'),
DeclareLaunchArgument('soft_filter_speckle_size', default_value='-1'),
DeclareLaunchArgument('sync_mode', default_value='standalone'),
DeclareLaunchArgument('depth_delay_us', default_value='0'),
DeclareLaunchArgument('color_delay_us', default_value='0'),
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
DeclareLaunchArgument('enable_depth_scale', default_value='true'),
DeclareLaunchArgument('enable_decimation_filter', default_value='false'),
DeclareLaunchArgument('enable_hdr_merge', default_value='false'),
DeclareLaunchArgument('enable_sequence_id_filter', default_value='false'),
DeclareLaunchArgument('enable_threshold_filter', default_value='false'),
DeclareLaunchArgument('enable_hardware_noise_removal_filter', default_value='true'),
DeclareLaunchArgument('enable_noise_removal_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_filter', default_value='false'),
DeclareLaunchArgument('enable_temporal_filter', default_value='false'),
DeclareLaunchArgument('enable_hole_filling_filter', default_value='false'),
DeclareLaunchArgument('decimation_filter_scale', default_value='-1'),
DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'),
DeclareLaunchArgument('threshold_filter_max', default_value='-1'),
DeclareLaunchArgument('threshold_filter_min', default_value='-1'),
DeclareLaunchArgument('noise_removal_filter_min_diff', default_value='256'),
DeclareLaunchArgument('noise_removal_filter_max_size', default_value='80'),
DeclareLaunchArgument('spatial_filter_alpha', default_value='-1.0'),
DeclareLaunchArgument('spatial_filter_diff_threshold', default_value='-1'),
DeclareLaunchArgument('spatial_filter_magnitude', default_value='-1'),
DeclareLaunchArgument('spatial_filter_radius', default_value='-1'),
DeclareLaunchArgument('temporal_filter_diff_threshold', default_value='-1.0'),
DeclareLaunchArgument('temporal_filter_weight', default_value='-1.0'),
DeclareLaunchArgument('hole_filling_filter_mode', default_value=''),
DeclareLaunchArgument('hdr_merge_exposure_1', default_value='-1'),
DeclareLaunchArgument('hdr_merge_gain_1', default_value='-1'),
DeclareLaunchArgument('hdr_merge_exposure_2', default_value='-1'),
DeclareLaunchArgument('hdr_merge_gain_2', default_value='-1'),
DeclareLaunchArgument('align_mode', default_value='SW'),
DeclareLaunchArgument('diagnostic_period', default_value='1.0'),
DeclareLaunchArgument('enable_laser', default_value='true'),
DeclareLaunchArgument('depth_precision', default_value=''),
DeclareLaunchArgument('device_preset', default_value='Default'),
DeclareLaunchArgument('retry_on_usb3_detection_failure', default_value='false'),
DeclareLaunchArgument('laser_energy_level', default_value='-1'),
DeclareLaunchArgument('enable_sync_host_time', default_value='true'),
DeclareLaunchArgument('time_domain', default_value='global'),# global, device, system
DeclareLaunchArgument('enable_color_undistortion', default_value='false'),
DeclareLaunchArgument('config_file_path', default_value=''),
DeclareLaunchArgument('enable_heartbeat', default_value='false'),
DeclareLaunchArgument('gmsl_trigger_fps', default_value='3000'),
DeclareLaunchArgument('enable_gmsl_trigger', default_value='false'),
DeclareLaunchArgument('disparity_range_mode', default_value='-1'),
DeclareLaunchArgument('disparity_search_offset', default_value='-1'),
DeclareLaunchArgument('disparity_offset_config', default_value='false'),
DeclareLaunchArgument('offset_index0', default_value='-1'),
DeclareLaunchArgument('offset_index1', default_value='-1'),
DeclareLaunchArgument('frame_aggregate_mode', default_value='ANY'), # full_frame、color_frame、ANY or disable
DeclareLaunchArgument('interleave_ae_mode', default_value='laser'), # 'hdr' or 'laser'
DeclareLaunchArgument('interleave_frame_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_index', default_value='1'), # 0:skip pattern ir 1: skip flood ir
DeclareLaunchArgument('hdr_index1_laser_control', default_value='1'),#interleave_hdr_param
DeclareLaunchArgument('hdr_index1_depth_exposure', default_value='1'),
DeclareLaunchArgument('hdr_index1_depth_gain', default_value='16'),
DeclareLaunchArgument('hdr_index1_ir_brightness', default_value='20'),
DeclareLaunchArgument('hdr_index1_ir_ae_max_exposure', default_value='2000'),
DeclareLaunchArgument('hdr_index0_laser_control', default_value='1'),
DeclareLaunchArgument('hdr_index0_depth_exposure', default_value='7500'),
DeclareLaunchArgument('hdr_index0_depth_gain', default_value='16'),
DeclareLaunchArgument('hdr_index0_ir_brightness', default_value='60'),
DeclareLaunchArgument('hdr_index0_ir_ae_max_exposure', default_value='10000'),
DeclareLaunchArgument('laser_index1_laser_control', default_value='0'),#interleave_laser_param
DeclareLaunchArgument('laser_index1_depth_exposure', default_value='3000'),
DeclareLaunchArgument('laser_index1_depth_gain', default_value='16'),
DeclareLaunchArgument('laser_index1_ir_brightness', default_value='60'),
DeclareLaunchArgument('laser_index1_ir_ae_max_exposure', default_value='17000'),
DeclareLaunchArgument('laser_index0_laser_control', default_value='1'),
DeclareLaunchArgument('laser_index0_depth_exposure', default_value='3000'),
DeclareLaunchArgument('laser_index0_depth_gain', default_value='16'),
DeclareLaunchArgument('laser_index0_ir_brightness', default_value='60'),
DeclareLaunchArgument('laser_index0_ir_ae_max_exposure', default_value='30000'),
DeclareLaunchArgument('use_intra_process_comms', default_value='false'),
DeclareLaunchArgument('attach_component_container_enable', default_value='false'),
DeclareLaunchArgument('attach_component_container_name', default_value='orbbec_container'),
]
def get_params(context, args):
return [load_parameters(context, args)]
def create_node_action(context, args):
params = get_params(context, args)
ros_distro = os.environ.get("ROS_DISTRO", "humble")
if ros_distro == "foxy":
return [
Node(
package="orbbec_camera",
executable="orbbec_camera_node",
name="ob_camera_node",
namespace=LaunchConfiguration("camera_name"),
parameters=params,
output="screen",
)
]
else:
attach_to_shared_component_container_arg = LaunchConfiguration('attach_to_shared_component_container', default=False)
component_container_name_arg = LaunchConfiguration('component_container_name', default='orbbec_container')
orbbec_container = Node(
name=component_container_name_arg,
package='rclcpp_components',
executable='component_container_mt',
output='screen',
condition=UnlessCondition(attach_to_shared_component_container_arg)
)
return [
orbbec_container,
LoadComposableNodes(
target_container=component_container_name_arg,
composable_node_descriptions=[
ComposableNode(
namespace=LaunchConfiguration("camera_name"),
name=LaunchConfiguration("camera_name"),
package='orbbec_camera',
plugin='orbbec_camera::OBCameraNodeDriver',
parameters=params,
extra_arguments=[{'use_intra_process_comms': LaunchConfiguration("use_intra_process_comms")}],
)
]
)
]
return LaunchDescription(
args + [
OpaqueFunction(function=lambda context: create_node_action(context, args))
]
)
@@ -1,150 +0,0 @@
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node,LoadComposableNodes
from launch.actions import IncludeLaunchDescription, GroupAction, TimerAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import DeclareLaunchArgument
from launch.conditions import UnlessCondition, IfCondition
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.descriptions import ComposableNode
def load_yaml(file_path):
with open(file_path, 'r') as f:
return yaml.safe_load(f)
def merge_params(default_params, yaml_params):
for key, value in yaml_params.items():
if key in default_params:
default_params[key] = value
return default_params
def convert_value(value):
if isinstance(value, str):
try:
return int(value)
except ValueError:
pass
try:
return float(value)
except ValueError:
pass
if value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
return value
def load_parameters(context, args):
default_params = {arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args}
config_file_path = LaunchConfiguration('config_file_path').perform(context)
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number'}
return {
key: (value if key in skip_convert else convert_value(value))
for key, value in default_params.items()
}
def generate_launch_description():
# Include launch files
package_dir = get_package_share_directory("orbbec_camera")
launch_file_dir = os.path.join(package_dir, "examples/lower_cpu_usage")
attach_to_shared_component_container_arg = LaunchConfiguration('attach_to_shared_component_container', default=False)
component_container_name_arg = LaunchConfiguration('component_container_name', default='shared_orbbec_container')
shared_orbbec_container = Node(
name=component_container_name_arg,
package="rclcpp_components",
executable="component_container_mt",
output="screen",
condition=UnlessCondition(attach_to_shared_component_container_arg),
)
attach_to_shared_component_container_arg = TextSubstitution(text="true")
launch1_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_lower_cpu_usage.launch.py")
),
launch_arguments={
"camera_name": "camera_01",
"usb_port": "2-7",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch2_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_lower_cpu_usage.launch.py")
),
launch_arguments={
"camera_name": "camera_02",
"usb_port": "2-2",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch3_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_lower_cpu_usage.launch.py")
),
launch_arguments={
"camera_name": "camera_03",
"usb_port": "2-6",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch4_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_lower_cpu_usage.launch.py")
),
launch_arguments={
"camera_name": "camera_04",
"usb_port": "2-3",
"device_num": "4",
"sync_mode": "standalone",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
delayed_left_camera = TimerAction(
period=2.0,
actions=[launch1_include],
)
delayed_right_camera = TimerAction(
period=4.0,
actions=[launch2_include],
)
delayed_rear_camera = TimerAction(
period=6.0,
actions=[launch3_include],
)
delayed_front_camera = TimerAction(
period=8.0,
actions=[launch4_include],
)
ld = LaunchDescription(
[
shared_orbbec_container,
TimerAction(period=0.0, actions=[GroupAction([delayed_left_camera])]),
TimerAction(period=2.0, actions=[GroupAction([delayed_right_camera])]),
TimerAction(period=4.0, actions=[GroupAction([delayed_rear_camera])]),
TimerAction(period=6.0, actions=[GroupAction([delayed_front_camera])]),
]
)
return ld
@@ -1,55 +0,0 @@
# Multi_camera synced Instructions
> The purpose of this document is to explain how to use multi-camera synced with OrbbecSDK_ROS2
## Setup instructions
* Please read the Multi-Camera Synchronization Setup Guide:[Multi-Camera Synchronization Setup](https://www.orbbec.com/docs/set-up-cameras-for-external-synchronization_v1-2/)
* Make sure the camera is correctly connected to the multi-camera synchronizer.
![Depth Point Cloud Visualization](image/multi_camera_synced1.png)
### Checking camera port with OrbbecSDK_ROS2
```bash
ros2 run orbbec_camera list_devices_node
```
### OrbbecSDK_ROS2 multi-camera synced configuration
Open multi_camera_synced.launch.py, and configure the camera settings as shown below:
![Depth Point Cloud Visualization](image/multi_camera_synced2.png)
1. `gemini_330_series.launch.py` is the launch file for starting the camera.
2. Set `camera_name` to `G330_0`. For example, the published color image topic will be `/G330_0/color/image_raw`.
3. Set `usb_port` to `2-2`, indicating that the camera device on port `2-2` is being used. This value can be found in the output of the `ros2 run orbbec_camera list_devices_node` command.
4. Set `device_num` to `2`, meaning two cameras will be used.
5. Set `sync_mode` to `primary` to indicate that the `2-7` camera device is in primary mode. The multi-camera sync mode options can be found in the figure below.
6. Parameters from the `config_file_path` can override the parameters set in `gemini_330_series.launch.py` (optional).
7. For slave cameras, set `trigger_out_enabled` to false.
| **Pattern Nam**e | **Setting effect description** |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| free_run | -Support different frame rate settings<br />The -8-pin synchronization interface does not support external output of synchronization-related signals |
| standalone(default) | ● Same as Primary by default<br />● Built-in RGBD frame synchronization<br />● 8-pin synchronous interface does not output signals to the outside by default |
| primary | ● Set as primary camera<br />● 8-pin synchronous interface output signal to external device |
| secondary | ● Set as secondary (passive synchronization; When there is a hardware continuous trigger signal input from the outside and the continuous trigger signal matches the currently set frame rate, the image is collected according to the external trigger signal; When there is no external trigger signal, the flow is stopped)<br />● 8-pin synchronous interface output signal to external device |
| secondary_synced | ● Set to secondary synchronization (passive synchronization; When there is a hardware continuous trigger signal input from the outside and the continuous trigger signal matches the currently set frame rate, the image is collected according to the external trigger signal; When there is no external trigger signal, the image is collected according to the internal trigger signal at the set frame rate)<br />● 8-pin synchronous interface output signal to external device |
| hardware_triggering | ● Set as hardware trigger (passive trigger; When there is a hardware trigger signal input from the outside and the trigger signal time interval is not less than the current upper limit, the image is collected according to the external trigger signal; When there is no external trigger signal, the image is not collected)<br />● 8-pin synchronous interface output signal to external device |
| software_triggering | ● Set as software trigger (passive trigger; When there is a trigger command input from the host computer and the trigger command time interval is not less than the current upper limit, the image is collected according to the trigger command; When there is no trigger command, the image is not collected)<br />● 8-pin synchronous interface output signal to external device |
* The master camera should be launched last.
* Ideally, there should be a 2-second delay between starting each camera.
### Run the following command to start the multi-camera synced
```bash
ros2 launch orbbec_camera multi_camera_synced.launch.py
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

@@ -1,155 +0,0 @@
# Multi_camera_synced_verification_tool
> This article will introduce how to verify the synchronization accuracy of multi-camera synchronization.
>
> First, please see how to use [multi_camera_synced](../multi_camera_synced/README.MD).
## Directory Structure
```plaintext
.
├── multicamera_sync/
│ ├── output/
│ ├──20250218102900/
│ ├──DevicesInfo.txt
│ ├──StreamProfileInfo.txt
│ ├── Python/
│ ├──Config.ini
├── gemini_330_series_synced_verify.launch.py
├── multi_camera_synced_verify.launch.py
```
### multicamera_sync
* `gemini_330_series_synced_verify.launch.py` : Single camera runs launch, which provides the camera running node for multi_camera_synced_verify.launch.py.
* `multi_camera_synced_verify.launch.py` : Multi camer synced + launch of save_rgbir tool.
#### output
> The `ouput` folder is the folder where the camera pictures are output
In the output example provided
* `20250218102900` : Represents the camera image information collected at 10:29:00 on February 18, 2025.
* `TotalModeFrames` : Camera image information storage directory.
* `results-2025-02-25_163648` : The result after analyzing and matching the image information of TotalModeFrames.
* `DevicesInfo.txt` : Camera equipment basic information (need to be modified).
* `StreamProfileInfo.txt` : Camera video stream information (no need to modify).
#### Python
* `Config.ini` : Configuration file for Python analysis script (need to be modified).
## Preparation for operation
### save_rgbir node
Edit multi_camera_synced_verify.launch.py and fill in the activated camera device,we can find that save_rgbir is started at the end.
```python
# Launch description
ld = LaunchDescription(
[
shared_orbbec_container,
TimerAction(period=0.0, actions=[GroupAction([launch2_include])]),
TimerAction(period=2.0, actions=[GroupAction([launch1_include])]),
# The primary camera should be launched at last
TimerAction(period=6.0, actions=[GroupAction([save_rgbir])]),
# save_rgbir is synced verification tool
]
)
return ld
```
save_rgbir is a tool for saving images. The configuration file of this tool is in [multi_save_rgbir_params.json](../../config/tools/multisavergbir/multi_save_rgbir_params.json).
```json
{
"save_rgbir_params": {
"time_domain": "global",
"usb_ports": [
"2-1",
"2-3"
],
"camera_name": [
"camera_01",
"camera_02"
]
}
}
```
* `time_domain` : Timestamp Type
* `usb_ports` : "primary", "secondary 1", "secondary 2", "secondary 3", fill in as many usb_ports as there are cameras
* `camera_name` : The name of the camera setting, for example: camera_01
### DevicesInfo.txt
Edit DevicesInfo.txt. Only the `primarySerialNumber`, `index` and `serialNumber` parameters need to be changed. Other parameters do not need to be changed.Refer to the example of [20250218102900](./multicamera_sync/output/20250218102900).
* `primarySerialNumber` : The SN serial number of the primary camera
* `index` : Camera index
* `serialNumber` : The SN serial number of the camera
### Config.ini
Edit Config.ini.Modify `frameRate` and `tspRangeThreshold`.
## Run this example
### Run launch and save camera pictures
* Frst terminal
```bash
ros2 launch orbbec_camera multi_camera_synced_verify.launch.py
```
* Second terminal
```bash
ros2 service call /save_rgbir/start_capture orbbec_camera_msgs/srv/SetInt32 '{data: 100}'
```
When the terminal displays "over", the image is saved.A new multicamera_sync folder will be generated under the workspace.
#### Camera pictures naming format
Take [color_SNCP1E5420006D_Index0_g1739874543227_f0_s1739874543327_e50_d16_.jpg](./multicamera_sync/output/20250218102900/TotalModeFrames/SNCP1E5420006D_Index0/color_SNCP1E5420006D_Index0_g1739874543227_f0_s1739874543327_e50_d16_.jpg) as an example
* `color` : This image is a snapshot of the color stream.
* `SNCP1E5420006D` : The camera's SN serial number is CP1E5420006D.
* `Index0` : Camera 0 (usually referred to primary camera).
* `g1739874543227` : “g” represents the global timestamp, which means the global timestamp of this frame is 1739874543227.
* `f0` : The 0th picture of the color stream acquisition of this camera.
* `s1739874543327` : "s" represents the timestamp of the current system, which means the current system timestamp of this frame is 1739874543327.
* `e50` : The exposure of this frame is 50.
* `d16` : The gain of this frame is 16.
### Analyzing camera image data
You need to copy the modified [Pyhotn folder](./multicamera_sync/Python) to the new multi_camera_synced subdirectory, and copy the modified [DevicesInfo.txt ](./multicamera_sync/output/20250218102900/DevicesInfo.txt)and [StreamProfileInfo.txt](./multicamera_sync/output/20250218102900/StreamProfileInfo.txt) to the same level directory as the TotalModeFrames folder.
* Finally everything is ready, run the python script
```bash
cd multicamera_sync/Python
python3 SyncFramesMain.py
```
After the operation is successful, you can view the synchronization effect in the r `esults folder`
## Files that need to be changed
### Analysis tools
* [multi_save_rgbir_params.json](../../config/tools/multisavergbir/multi_save_rgbir_params.json)
* [DevicesInfo.txt ](./multicamera_sync/output/20250218102900/DevicesInfo.txt)
* [Config.ini](./multicamera_sync/Python/Config.ini)
### Camera Configuration
[camera_params.yaml](../../config/camera_params.yaml)(Camera startup parameter settings)
[multi_camera_synced_verify.launch.py](./multi_camera_synced_verify.launch.py)
@@ -1,265 +0,0 @@
import os
import yaml
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction, GroupAction
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import PushRosNamespace, ComposableNodeContainer, Node
from launch_ros.descriptions import ComposableNode
from launch.conditions import UnlessCondition
from launch_ros.actions import LoadComposableNodes
def load_yaml(file_path):
with open(file_path, 'r') as f:
return yaml.safe_load(f)
def merge_params(default_params, yaml_params):
for key, value in yaml_params.items():
if key in default_params:
default_params[key] = value
return default_params
def convert_value(value):
if isinstance(value, str):
try:
return int(value)
except ValueError:
pass
try:
return float(value)
except ValueError:
pass
if value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
return value
def load_parameters(context, args):
default_params = {arg.name: LaunchConfiguration(arg.name).perform(context) for arg in args}
config_file_path = LaunchConfiguration('config_file_path').perform(context)
if config_file_path:
yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number'}
return {
key: (value if key in skip_convert else convert_value(value))
for key, value in default_params.items()
}
def generate_launch_description():
args = [
DeclareLaunchArgument('camera_name', default_value='camera'),
DeclareLaunchArgument('depth_registration', default_value='true'),
DeclareLaunchArgument('serial_number', default_value=''),
DeclareLaunchArgument('usb_port', default_value=''),
DeclareLaunchArgument('device_num', default_value='1'),
DeclareLaunchArgument('uvc_backend', default_value='libuvc'),#libuvc or v4l2
DeclareLaunchArgument('point_cloud_qos', default_value='default'),
DeclareLaunchArgument('enable_point_cloud', default_value='true'),
DeclareLaunchArgument('enable_colored_point_cloud', default_value='false'),
DeclareLaunchArgument('cloud_frame_id', default_value=''),
DeclareLaunchArgument('connection_delay', default_value='10'),
DeclareLaunchArgument('color_width', default_value='0'),
DeclareLaunchArgument('color_height', default_value='0'),
DeclareLaunchArgument('color_fps', default_value='0'),
DeclareLaunchArgument('color_format', default_value='ANY'),
DeclareLaunchArgument('enable_color', default_value='true'),
DeclareLaunchArgument('color_qos', default_value='default'),
DeclareLaunchArgument('color_camera_info_qos', default_value='default'),
DeclareLaunchArgument('enable_color_auto_exposure', default_value='true'),
DeclareLaunchArgument('color_exposure', default_value='-1'),
DeclareLaunchArgument('color_gain', default_value='-1'),
DeclareLaunchArgument('enable_color_auto_white_balance', default_value='true'),
DeclareLaunchArgument('color_white_balance', default_value='-1'),
DeclareLaunchArgument('color_ae_max_exposure', default_value='-1'),
DeclareLaunchArgument('color_brightness', default_value='-1'),
DeclareLaunchArgument('depth_width', default_value='0'),
DeclareLaunchArgument('depth_height', default_value='0'),
DeclareLaunchArgument('depth_fps', default_value='0'),
DeclareLaunchArgument('depth_format', default_value='ANY'),
DeclareLaunchArgument('enable_depth', default_value='true'),
DeclareLaunchArgument('depth_qos', default_value='default'),
DeclareLaunchArgument('depth_camera_info_qos', default_value='default'),
DeclareLaunchArgument('left_ir_width', default_value='0'),
DeclareLaunchArgument('left_ir_height', default_value='0'),
DeclareLaunchArgument('left_ir_fps', default_value='0'),
DeclareLaunchArgument('left_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_left_ir', default_value='false'),
DeclareLaunchArgument('left_ir_qos', default_value='default'),
DeclareLaunchArgument('left_ir_camera_info_qos', default_value='default'),
DeclareLaunchArgument('right_ir_width', default_value='0'),
DeclareLaunchArgument('right_ir_height', default_value='0'),
DeclareLaunchArgument('right_ir_fps', default_value='0'),
DeclareLaunchArgument('right_ir_format', default_value='ANY'),
DeclareLaunchArgument('enable_right_ir', default_value='false'),
DeclareLaunchArgument('right_ir_qos', default_value='default'),
DeclareLaunchArgument('right_ir_camera_info_qos', default_value='default'),
DeclareLaunchArgument('enable_ir_auto_exposure', default_value='true'),
DeclareLaunchArgument('ir_exposure', default_value='-1'),
DeclareLaunchArgument('ir_gain', default_value='-1'),
DeclareLaunchArgument('ir_ae_max_exposure', default_value='-1'),
DeclareLaunchArgument('ir_brightness', default_value='-1'),
DeclareLaunchArgument('enable_sync_output_accel_gyro', default_value='false'),
DeclareLaunchArgument('enable_accel', default_value='false'),
DeclareLaunchArgument('accel_rate', default_value='200hz'),
DeclareLaunchArgument('accel_range', default_value='4g'),
DeclareLaunchArgument('enable_gyro', default_value='false'),
DeclareLaunchArgument('gyro_rate', default_value='200hz'),
DeclareLaunchArgument('gyro_range', default_value='1000dps'),
DeclareLaunchArgument('liner_accel_cov', default_value='0.01'),
DeclareLaunchArgument('angular_vel_cov', default_value='0.01'),
DeclareLaunchArgument('publish_tf', default_value='true'),
DeclareLaunchArgument('tf_publish_rate', default_value='0.0'),
DeclareLaunchArgument('ir_info_url', default_value=''),
DeclareLaunchArgument('color_info_url', default_value=''),
DeclareLaunchArgument('log_level', default_value='none'),
DeclareLaunchArgument('enable_publish_extrinsic', default_value='false'),
DeclareLaunchArgument('enable_d2c_viewer', default_value='false'),
DeclareLaunchArgument('enable_hardware_d2d', default_value='true'),
DeclareLaunchArgument('enable_ldp', default_value='true'),
DeclareLaunchArgument('enable_soft_filter', default_value='true'),
DeclareLaunchArgument('soft_filter_max_diff', default_value='-1'),
DeclareLaunchArgument('soft_filter_speckle_size', default_value='-1'),
DeclareLaunchArgument('sync_mode', default_value='standalone'),
DeclareLaunchArgument('depth_delay_us', default_value='0'),
DeclareLaunchArgument('color_delay_us', default_value='0'),
DeclareLaunchArgument('trigger2image_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_delay_us', default_value='0'),
DeclareLaunchArgument('trigger_out_enabled', default_value='true'),
DeclareLaunchArgument('frames_per_trigger', default_value='2'),
DeclareLaunchArgument('software_trigger_period', default_value='33'), # ms
DeclareLaunchArgument('enable_frame_sync', default_value='true'),
DeclareLaunchArgument('ordered_pc', default_value='false'),
DeclareLaunchArgument('enable_depth_scale', default_value='true'),
DeclareLaunchArgument('enable_decimation_filter', default_value='false'),
DeclareLaunchArgument('enable_hdr_merge', default_value='false'),
DeclareLaunchArgument('enable_sequence_id_filter', default_value='false'),
DeclareLaunchArgument('enable_threshold_filter', default_value='false'),
DeclareLaunchArgument('enable_hardware_noise_removal_filter', default_value='true'),
DeclareLaunchArgument('enable_noise_removal_filter', default_value='true'),
DeclareLaunchArgument('enable_spatial_filter', default_value='false'),
DeclareLaunchArgument('enable_temporal_filter', default_value='false'),
DeclareLaunchArgument('enable_hole_filling_filter', default_value='false'),
DeclareLaunchArgument('decimation_filter_scale', default_value='-1'),
DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'),
DeclareLaunchArgument('threshold_filter_max', default_value='-1'),
DeclareLaunchArgument('threshold_filter_min', default_value='-1'),
DeclareLaunchArgument('noise_removal_filter_min_diff', default_value='256'),
DeclareLaunchArgument('noise_removal_filter_max_size', default_value='80'),
DeclareLaunchArgument('spatial_filter_alpha', default_value='-1.0'),
DeclareLaunchArgument('spatial_filter_diff_threshold', default_value='-1'),
DeclareLaunchArgument('spatial_filter_magnitude', default_value='-1'),
DeclareLaunchArgument('spatial_filter_radius', default_value='-1'),
DeclareLaunchArgument('temporal_filter_diff_threshold', default_value='-1.0'),
DeclareLaunchArgument('temporal_filter_weight', default_value='-1.0'),
DeclareLaunchArgument('hole_filling_filter_mode', default_value=''),
DeclareLaunchArgument('hdr_merge_exposure_1', default_value='-1'),
DeclareLaunchArgument('hdr_merge_gain_1', default_value='-1'),
DeclareLaunchArgument('hdr_merge_exposure_2', default_value='-1'),
DeclareLaunchArgument('hdr_merge_gain_2', default_value='-1'),
DeclareLaunchArgument('align_mode', default_value='SW'),
DeclareLaunchArgument('diagnostic_period', default_value='1.0'),
DeclareLaunchArgument('enable_laser', default_value='true'),
DeclareLaunchArgument('depth_precision', default_value=''),
DeclareLaunchArgument('device_preset', default_value='Default'),
DeclareLaunchArgument('retry_on_usb3_detection_failure', default_value='false'),
DeclareLaunchArgument('laser_energy_level', default_value='-1'),
DeclareLaunchArgument('enable_sync_host_time', default_value='true'),
DeclareLaunchArgument('time_domain', default_value='global'),# global, device, system
DeclareLaunchArgument('enable_color_undistortion', default_value='false'),
DeclareLaunchArgument('config_file_path', default_value=''),
DeclareLaunchArgument('enable_heartbeat', default_value='false'),
DeclareLaunchArgument('gmsl_trigger_fps', default_value='3000'),
DeclareLaunchArgument('enable_gmsl_trigger', default_value='false'),
DeclareLaunchArgument('disparity_range_mode', default_value='-1'),
DeclareLaunchArgument('disparity_search_offset', default_value='-1'),
DeclareLaunchArgument('disparity_offset_config', default_value='false'),
DeclareLaunchArgument('offset_index0', default_value='-1'),
DeclareLaunchArgument('offset_index1', default_value='-1'),
DeclareLaunchArgument('frame_aggregate_mode', default_value='ANY'), # full_frame、color_frame、ANY or disable
DeclareLaunchArgument('interleave_ae_mode', default_value='laser'), # 'hdr' or 'laser'
DeclareLaunchArgument('interleave_frame_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_enable', default_value='false'),
DeclareLaunchArgument('interleave_skip_index', default_value='1'), # 0:skip pattern ir 1: skip flood ir
DeclareLaunchArgument('hdr_index1_laser_control', default_value='1'),#interleave_hdr_param
DeclareLaunchArgument('hdr_index1_depth_exposure', default_value='1'),
DeclareLaunchArgument('hdr_index1_depth_gain', default_value='16'),
DeclareLaunchArgument('hdr_index1_ir_brightness', default_value='20'),
DeclareLaunchArgument('hdr_index1_ir_ae_max_exposure', default_value='2000'),
DeclareLaunchArgument('hdr_index0_laser_control', default_value='1'),
DeclareLaunchArgument('hdr_index0_depth_exposure', default_value='7500'),
DeclareLaunchArgument('hdr_index0_depth_gain', default_value='16'),
DeclareLaunchArgument('hdr_index0_ir_brightness', default_value='60'),
DeclareLaunchArgument('hdr_index0_ir_ae_max_exposure', default_value='10000'),
DeclareLaunchArgument('laser_index1_laser_control', default_value='0'),#interleave_laser_param
DeclareLaunchArgument('laser_index1_depth_exposure', default_value='3000'),
DeclareLaunchArgument('laser_index1_depth_gain', default_value='16'),
DeclareLaunchArgument('laser_index1_ir_brightness', default_value='60'),
DeclareLaunchArgument('laser_index1_ir_ae_max_exposure', default_value='17000'),
DeclareLaunchArgument('laser_index0_laser_control', default_value='1'),
DeclareLaunchArgument('laser_index0_depth_exposure', default_value='3000'),
DeclareLaunchArgument('laser_index0_depth_gain', default_value='16'),
DeclareLaunchArgument('laser_index0_ir_brightness', default_value='60'),
DeclareLaunchArgument('laser_index0_ir_ae_max_exposure', default_value='30000'),
DeclareLaunchArgument('use_intra_process_comms', default_value='false'),
DeclareLaunchArgument('attach_component_container_enable', default_value='false'),
DeclareLaunchArgument('attach_component_container_name', default_value='orbbec_container'),
]
def get_params(context, args):
return [load_parameters(context, args)]
def create_node_action(context, args):
params = get_params(context, args)
ros_distro = os.environ.get("ROS_DISTRO", "humble")
if ros_distro == "foxy":
return [
Node(
package="orbbec_camera",
executable="orbbec_camera_node",
name="ob_camera_node",
namespace=LaunchConfiguration("camera_name"),
parameters=params,
output="screen",
)
]
else:
attach_to_shared_component_container_arg = LaunchConfiguration('attach_to_shared_component_container', default=False)
component_container_name_arg = LaunchConfiguration('component_container_name', default='orbbec_container')
orbbec_container = Node(
name=component_container_name_arg,
package='rclcpp_components',
executable='component_container_mt',
output='screen',
condition=UnlessCondition(attach_to_shared_component_container_arg)
)
return [
orbbec_container,
LoadComposableNodes(
target_container=component_container_name_arg,
composable_node_descriptions=[
ComposableNode(
namespace=LaunchConfiguration("camera_name"),
name=LaunchConfiguration("camera_name"),
package='orbbec_camera',
plugin='orbbec_camera::OBCameraNodeDriver',
parameters=params,
extra_arguments=[{'use_intra_process_comms': LaunchConfiguration("use_intra_process_comms")}],
)
]
)
]
return LaunchDescription(
args + [
OpaqueFunction(function=lambda context: create_node_action(context, args))
]
)
@@ -1,126 +0,0 @@
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node, LoadComposableNodes
from launch.actions import IncludeLaunchDescription, GroupAction, TimerAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import DeclareLaunchArgument
from launch.conditions import UnlessCondition, IfCondition
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.descriptions import ComposableNode
def load_yaml(file_path):
with open(file_path, "r") as f:
return yaml.safe_load(f)
def merge_params(default_params, yaml_params):
for key, value in yaml_params.items():
if key in default_params:
default_params[key] = value
return default_params
def convert_value(value):
if isinstance(value, str):
try:
return int(value)
except ValueError:
pass
try:
return float(value)
except ValueError:
pass
if value.lower() == "true":
return True
elif value.lower() == "false":
return False
return value
def generate_launch_description():
# Include launch files
package_dir = get_package_share_directory("orbbec_camera")
launch_file_dir = os.path.join(
package_dir, "examples/multi_camera_synced_verification_tool"
)
config_file_dir = os.path.join(package_dir, "config")
config_file_path = os.path.join(config_file_dir, "camera_params.yaml")
secondary_config_file_path = os.path.join(config_file_dir, "camera_secondary_params.yaml")
attach_to_shared_component_container_arg = LaunchConfiguration(
"attach_to_shared_component_container", default=False
)
component_container_name_arg = LaunchConfiguration(
"component_container_name", default="shared_orbbec_container"
)
shared_orbbec_container = Node(
name=component_container_name_arg,
package="rclcpp_components",
executable="component_container_mt",
output="screen",
condition=UnlessCondition(attach_to_shared_component_container_arg),
)
save_rgbir = LoadComposableNodes(
target_container=component_container_name_arg,
composable_node_descriptions=[
ComposableNode(
namespace="save_rgbir",
name="save_rgbir",
package="orbbec_camera",
plugin="orbbec_camera::tools::MultiCameraSubscriber",
)
],
)
attach_to_shared_component_container_arg = TextSubstitution(text="true")
launch1_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_synced_verify.launch.py")
),
launch_arguments={
"camera_name": "camera_01",
"usb_port": "2-1",
"device_num": "2",
"sync_mode": "primary",
"config_file_path": config_file_path,
"trigger_out_enabled": "true",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
launch2_include = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(launch_file_dir, "gemini_330_series_synced_verify.launch.py")
),
launch_arguments={
"camera_name": "camera_02",
"usb_port": "2-3",
"device_num": "2",
"sync_mode": "secondary_synced",
"config_file_path": secondary_config_file_path,
"trigger_out_enabled": "false",
"attach_to_shared_component_container": attach_to_shared_component_container_arg,
"component_container_name": component_container_name_arg,
}.items(),
)
# Launch description
ld = LaunchDescription(
[
shared_orbbec_container,
TimerAction(period=0.0, actions=[GroupAction([launch2_include])]),
TimerAction(period=2.0, actions=[GroupAction([launch1_include])]),
# The primary camera should be launched at last
TimerAction(period=6.0, actions=[GroupAction([save_rgbir])]),
# save_rgbir is synced verification tool
]
)
return ld
@@ -1,6 +0,0 @@
## config_frameMatch.py
Definition of 3 folders:
matchFrames: data with card control within half frame.
notMatchFrames: data with card control not within half frame, not matched.
abnormal: data within the group that exceeds tspRangeThreshold setting
@@ -1,5 +0,0 @@
[Parameter]
# Unit: FPS, please fill in according to the actual frame rate of the dataset, otherwise it will lead to inaccurate matching
frameRate=30
# Unit: ms. When the timestamp range of a group of data frames after matching is greater than or equal to tspRangeThreshold, the file name will be marked
tspRangeThreshold=4
@@ -1,97 +0,0 @@
import os
import subprocess
import json
import platform
def list_subdirectories(path):
# 遍历指定目录
for f in os.listdir(path):
# 判断是否是子目录
if os.path.isdir(os.path.join(path, f)):
yield f
def read_pid_from_device_json(frames_dir):
file_path = frames_dir + "/DevicesInfo.txt"
if not os.path.exists(file_path):
print(file_path + " not exists. Please check it")
return ""
with open(file_path, 'r') as f:
data = json.load(f)
if not 'devicePid' in data:
print("Not found 'devicePid' in " + file_path)
return ""
return data['devicePid']
def execute_sync_width_pid(frames_dir, pid):
sync_script_file=""
if pid.lower() == "0x0675":
sync_script_file="script/config_frameMatch_Gemini2VL.py"
elif pid.lower() == "0x0670" or pid.lower() == "0x0701":
sync_script_file="script/config_frameMatch-systemTimestamp.py"
elif pid.lower() == "0x0660":
sync_script_file="script/config_frameMatch-Astra2_new.py"
elif pid.lower() == "0x0803" or pid.lower() == "0x0807" or pid.lower() == "0x0801" or pid.lower() == "0x0805" or pid.lower() == "0x080b" or pid.lower() == "0x080e":
sync_script_file="script/config_frameMatch_g330.py"
else:
sync_script_file="script/config_frameMatch.py"
if len(sync_script_file) > 0:
print(f"execute synchronize frames. script_file={sync_script_file}, frames_dir={frames_dir}")
if platform.system() == "Windows":
output = subprocess.check_output(["python", sync_script_file, os.path.abspath(f"{frames_dir}"), os.getcwd()])
print(output.decode("gbk"))
else:
output = subprocess.check_output(["python3", sync_script_file, os.path.abspath(f"{frames_dir}"), os.getcwd()])
print(output.decode("utf-8"))
else:
print("Invalid pid=" + pid + ", not match sync frame script")
def sync_frames(frames_dir):
pid = read_pid_from_device_json(frames_dir)
if len(pid) <= 0:
print("Get pid failed.")
return
execute_sync_width_pid(frames_dir, pid)
def main():
# 指定目录路径
frames_output_path = os.path.abspath("../output")
# 获取所有子目录
subdirectories = list(list_subdirectories(frames_output_path))
if not subdirectories:
print("No subdirectories found in the specified directory.")
# 打印子目录列表并让用户选择
for i, subdir in enumerate(subdirectories):
print(f"{i + 1}. {subdir}")
# 获取用户输入
choice = input("Please select a subdirectory by number (or 'q' to quit): ")
if choice.lower() == 'q':
return
# 验证用户输入
is_index_valid = False
try:
index = int(choice) - 1
if 0 <= index < len(subdirectories):
is_index_valid = True
else:
print(f"Invalid choice. index={index}. Please enter a number between 1 and the total number of subdirectories.")
except ValueError:
print("Invalid choice(ValueException). Please enter a number between 1 and the total number of subdirectories")
if is_index_valid:
selected_subdir = subdirectories[index]
print(f"You selected the subdirectory: {selected_subdir}")
sync_frames(f"{frames_output_path }/{selected_subdir}")
if __name__ == "__main__":
main()
@@ -1,385 +0,0 @@
import os.path
import argparse
import sys
import json
import shutil
import configparser
from pathlib import Path
from datetime import datetime
## Config.ini中配置
# 单位:FPS,请依据数据集实际帧率填写,否则会导致匹配不准确
frameRate = -1
# 单位:ms,当匹配后某组数据帧的时间戳极差大于等于tspRangeThreshold,文件名会增加标注
tspRangeThreshold = -1
## Python脚本自动解析, 不要修改
primaryId = '-1' #主机ID
mainPythonWorkPath = "" # SyncFramesMain.py的工作目录
sourceFramesPath = "" # 请勿修改,固定值,TotalMode目录路径
sourceRootPath = "" # 存放TotalMode的根目录
resultPath = "" # 保存sync分析结果
streamProfileDict = dict() # 保存Python结果
class PictureInfo(object):
class Struct(object):
def __init__(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
self.deviceId = deviceId
self.sensorType = sensorType
self.syncTimeStamp = syncTimeStamp
self.picturePath = picturePath
self.deviceIdFull = deviceIdFull
self.fileExt = fileExt
def make_struct(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
return self.Struct(deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt)
class StreamProfileInfo:
def __init__(self, sensorType, width, height, format, fps):
self.sensorType = sensorType
self.width = width
self.height = height
self.format = format
self.fps = fps
def initPrimaryId():
global primaryId
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Initialize primaryId failed. {deviceInfoPath} not exists")
return False
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Initialize primaryId failed. {deviceInfoPath} not contain item 'devices'")
return False
for item in data['devices']:
if 'isPrimaryDevice' in item and 'index' in item and item['isPrimaryDevice']:
primaryId = str(item['index'])
return True
return False
def initSyncConfigParams():
global frameRate, tspRangeThreshold
configPath = f"{mainPythonWorkPath}/Config.ini"
if not os.path.exists(configPath):
print(f"Initliaze synchronized config parameter failed. {configPath} not exists.")
return False
# 创建ConfigParser对象
config = configparser.ConfigParser()
# 读取ini文件
config.read(configPath, 'utf-8')
if not config.has_option('Parameter', 'frameRate'):
print(f"Initliaze synchronized config parameter failed. Not define 'frameRate' in ${configPath}")
return False
if not config.has_option('Parameter', 'tspRangeThreshold'):
print(f"Initliaze synchronized config parameter failed. Not define 'tspRangeThreshold' in ${configPath}")
return False
frameRate = config.getfloat('Parameter', 'frameRate')
if frameRate <= 0 or frameRate >= 1000:
print(f"Initliaze synchronized config parameter failed. Invalid frameRate={frameRate}")
return False
tspRangeThreshold = config.getfloat('Parameter', 'tspRangeThreshold')
if tspRangeThreshold <= 0:
print(f"Initliaze synchronized config parameter failed. Invalid tspRangeThreshold={tspRangeThreshold}")
return False
return True
def getDeviceCount():
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Get device count failed. {deviceInfoPath} not exists")
return 0
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Get device count failed. {deviceInfoPath} not contain item 'devices'")
return 0
return len(data['devices'])
def initProfileInfoDict():
global streamProfileDict
streamProfileDict = dict()
profilePath = f"{sourceRootPath}/StreamProfileInfo.txt"
if not os.path.exists(profilePath):
print(f"Initialize profile information dictionary failed. {profilePath} not exists")
return False
with open(profilePath, 'r') as f:
data = json.load(f)
if not 'streamProfiles' in data:
print(f"Initialize profile information dictionary failed. {profilePath} not contain item 'streamProfiles'")
return False
for item in data['streamProfiles']:
if 'sensorType' in item and 'width' in item and 'height' in item and 'format' in item and 'fps' in item:
profileInfo = StreamProfileInfo(item['sensorType'], item['width'], item['height'], item['format'], item['fps'])
streamProfileDict.setdefault(item['sensorType'], profileInfo)
else:
print(f"Initialize profile information dictionary. Error invalid StreamProfile, {item}")
return len(streamProfileDict.items()) > 0
def initResultDir():
global resultPath
timeText = datetime.now().strftime("%Y-%m-%d_%H%M%S")
resultPath = f"{sourceRootPath}/results-{timeText}"
if not os.path.exists(resultPath):
os.makedirs(resultPath)
def isFrameFile(fileName):
fileExt = os.path.splitext(fileName)
if len(fileExt) < 2:
return False
frameExts = {".jpeg", ".jpg", ".png", ".raw", "bmp"}
return fileExt[1] in frameExts
def initPictureInfoDictionary(rootFilePath, pictureInfoDict):
frameFileCount = 0
for dirpath, dirnames, filenames in os.walk(rootFilePath):
# print(f"dirpath={dirpath}, dirpath.basename=" + os.path.basename(dirpath))
for fileName in filenames:
filePath = os.path.join(dirpath, fileName)
if not isFrameFile(fileName):
continue
frameFileCount += 1
fileNameNoExt = os.path.splitext(fileName)[0]
pictureNameList = fileNameNoExt.split('_')
deviceId = pictureNameList[2][5:]
sensorType = pictureNameList[0].replace('#', '_')
syncTimeStamp = int(pictureNameList[3][1:])
# 创建结构体
pictureInfo = PictureInfo()
info = pictureInfo.make_struct(deviceId, sensorType, syncTimeStamp, filePath, os.path.basename(dirpath), os.path.splitext(fileName)[1])
# 格式化字典一个key对应一个数组
pictureInfoDict.setdefault(deviceId, []).append(info)
if 0 == frameFileCount:
print("initialize pictureInfoDict failed. Not found frame file")
def matchFrame(pictureInfoDict):
global primaryId, frameRate
global streamProfileDict
# 获取比较图像数组,取第一个设备的Color数组来进行比较
compareList = []
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == 'color':
compareList.append(info)
sorted_dict = dict(sorted(pictureInfoDict.items(), key=lambda x: x[1], reverse=False))
pictureInfoDict = sorted_dict
# 根据开流情况动态分析,减少循环次数
hasColorProfile = 'OB_SENSOR_COLOR' in streamProfileDict
hasDepthProfile = 'OB_SENSOR_DEPTH' in streamProfileDict
hasIRProfile = 'OB_SENSOR_IR' in streamProfileDict
# 匹配相邻帧
resultDict = {}
consumedList = []
dictIndex = 0
frameTspGap = int(1000.0/frameRate+0.5)
for comparePic in compareList:
resultDict.setdefault(dictIndex, []).append(comparePic)
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
# 对比彩色
if hasColorProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'color' and info.syncTimeStamp >= comparePic.syncTimeStamp and info.syncTimeStamp - comparePic.syncTimeStamp <= frameTspGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对Depth
if hasDepthProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'depth' and info.syncTimeStamp >= comparePic.syncTimeStamp and info.syncTimeStamp - comparePic.syncTimeStamp <= frameTspGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# IR
if hasIRProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir' and info.syncTimeStamp >= comparePic.syncTimeStamp and info.syncTimeStamp - comparePic.syncTimeStamp <= frameTspGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 计算偏差
for info in resultDict[dictIndex]:
info.tspDiff = info.syncTimeStamp - comparePic.syncTimeStamp
dictIndex += 1
return resultDict
def safe_make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
def handleSyncFrames():
global resultPath
global sourceFramesPath
global streamProfileDict
fp = open(f"{resultPath}/frameMatchLog.txt", "w")
if not initProfileInfoDict():
print("Initialize stream profile dictionary failed. exit")
return
print(f"Stream profiles: {streamProfileDict}")
streamProfileCount = len(streamProfileDict.items())
pictureInfoDict = {}
initPictureInfoDictionary(Path(sourceFramesPath), pictureInfoDict)
if len(pictureInfoDict) <= 0:
print("init pictureInfoDict failed. pictureInfoDict.len = 0")
return
# # Dump pictureInfoDict
# for key in pictureInfoDict:
# print("===================key:%s" % key)
# listTmp = list(pictureInfoDict[key])
# for info in listTmp:
# print("=====================value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (info.deviceId,info.sensorType,info.syncTimeStamp,info.picturePath))
deviceCount = getDeviceCount()
print("=================device count:%d" % deviceCount)
resultDict = {}
resultDict = matchFrame(pictureInfoDict)
for key in resultDict:
fp.write("===================result key:%s\n" % key)
print("===================result key:%s" % key)
listTmp = list(resultDict[key])
for info in listTmp:
fp.write("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s\n" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
print("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
matchPath = f"{resultPath}/matchFrames/"
safe_make_dir(matchPath)
notMatchPath = f"{resultPath}/notMatchFrames/"
abnormalPath = f"{resultPath}/abnormal/"
for key in resultDict:
listTmp = list(resultDict[key])
if (len(listTmp) == (deviceCount * streamProfileCount)):
haveAbnormalData = False
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
haveAbnormalData = True
else:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
if haveAbnormalData:
safe_make_dir(abnormalPath)
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
else:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
else:
safe_make_dir(notMatchPath)
for info in listTmp:
newFilePath = notMatchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, newFilePath)
def main():
if not initPrimaryId():
print("Initialize primaryId failed. exit.")
return
if not initSyncConfigParams():
print("Initialized Sync config parameter failed. exit.")
return
initResultDir()
print(f"PrimaryId={primaryId}, frameRate={frameRate}, tspRangeThreshold={tspRangeThreshold}")
handleSyncFrames()
return
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Synchronize frames support for 'Orbbec Astra2'")
parser.add_argument('frames_dir', type=str, help="Frames directory")
parser.add_argument('main_script_root_dir', type=str, help="SyncFramesMain.py working directory")
args = parser.parse_args()
sourceRootPath = args.frames_dir
sourceFramesPath = f"{args.frames_dir}/TotalModeFrames"
mainPythonWorkPath = args.main_script_root_dir
print(f"Start of Astra2 synchronize frame. sourceRootPath={sourceRootPath}")
main()
print("Finish of Astra2 synchronize frame.")
@@ -1,408 +0,0 @@
import os.path
import argparse
import sys
import json
import shutil
import configparser
from pathlib import Path
from datetime import datetime
## Config.ini中配置
# 单位:FPS,请依据数据集实际帧率填写,否则会导致匹配不准确
frameRate = -1
# 单位:ms,当匹配后某组数据帧的时间戳极差大于等于tspRangeThreshold,文件名会增加标注
tspRangeThreshold = -1
## Python脚本自动解析, 不要修改
primaryId = '-1' #主机ID
mainPythonWorkPath = "" # SyncFramesMain.py的工作目录
sourceFramesPath = "" # 请勿修改,固定值,TotalMode目录路径
sourceRootPath = "" # 存放TotalMode的根目录
resultPath = "" # 保存sync分析结果
streamProfileDict = dict() # 保存Python结果
class PictureInfo(object):
class Struct(object):
def __init__(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
self.deviceId = deviceId
self.sensorType = sensorType
self.syncTimeStamp = syncTimeStamp
self.picturePath = picturePath
self.deviceIdFull = deviceIdFull
self.fileExt = fileExt
def make_struct(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
return self.Struct(deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt)
class StreamProfileInfo:
def __init__(self, sensorType, width, height, format, fps):
self.sensorType = sensorType
self.width = width
self.height = height
self.format = format
self.fps = fps
def initPrimaryId():
global primaryId
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Initialize primaryId failed. {deviceInfoPath} not exists")
return False
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Initialize primaryId failed. {deviceInfoPath} not contain item 'devices'")
return False
for item in data['devices']:
if 'isPrimaryDevice' in item and 'index' in item and item['isPrimaryDevice']:
primaryId = str(item['index'])
return True
return False
def initSyncConfigParams():
global frameRate, tspRangeThreshold
configPath = f"{mainPythonWorkPath}/Config.ini"
if not os.path.exists(configPath):
print(f"Initliaze synchronized config parameter failed. {configPath} not exists.")
return False
# 创建ConfigParser对象
config = configparser.ConfigParser()
# 读取ini文件
config.read(configPath, 'utf-8')
if not config.has_option('Parameter', 'frameRate'):
print(f"Initliaze synchronized config parameter failed. Not define 'frameRate' in ${configPath}")
return False
if not config.has_option('Parameter', 'tspRangeThreshold'):
print(f"Initliaze synchronized config parameter failed. Not define 'tspRangeThreshold' in ${configPath}")
return False
frameRate = config.getfloat('Parameter', 'frameRate')
if frameRate <= 0 or frameRate >= 1000:
print(f"Initliaze synchronized config parameter failed. Invalid frameRate={frameRate}")
return False
tspRangeThreshold = config.getfloat('Parameter', 'tspRangeThreshold')
if tspRangeThreshold <= 0:
print(f"Initliaze synchronized config parameter failed. Invalid tspRangeThreshold={tspRangeThreshold}")
return False
return True
def getDeviceCount():
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Get device count failed. {deviceInfoPath} not exists")
return 0
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Get device count failed. {deviceInfoPath} not contain item 'devices'")
return 0
return len(data['devices'])
def initProfileInfoDict():
global streamProfileDict
streamProfileDict = dict()
profilePath = f"{sourceRootPath}/StreamProfileInfo.txt"
if not os.path.exists(profilePath):
print(f"Initialize profile information dictionary failed. {profilePath} not exists")
return False
with open(profilePath, 'r') as f:
data = json.load(f)
if not 'streamProfiles' in data:
print(f"Initialize profile information dictionary failed. {profilePath} not contain item 'streamProfiles'")
return False
for item in data['streamProfiles']:
if 'sensorType' in item and 'width' in item and 'height' in item and 'format' in item and 'fps' in item:
profileInfo = StreamProfileInfo(item['sensorType'], item['width'], item['height'], item['format'], item['fps'])
streamProfileDict.setdefault(item['sensorType'], profileInfo)
else:
print(f"Initialize profile information dictionary. Error invalid StreamProfile, {item}")
return len(streamProfileDict.items()) > 0
def initResultDir():
global resultPath
timeText = datetime.now().strftime("%Y-%m-%d_%H%M%S")
resultPath = f"{sourceRootPath}/results-{timeText}"
if not os.path.exists(resultPath):
os.makedirs(resultPath)
def isFrameFile(fileName):
fileExt = os.path.splitext(fileName)
if len(fileExt) < 2:
return False
frameExts = {".jpeg", ".jpg", ".png", ".raw", "bmp"}
return fileExt[1] in frameExts
def initPictureInfoDictionary(rootFilePath, pictureInfoDict):
frameFileCount = 0
for dirpath, dirnames, filenames in os.walk(rootFilePath):
# print(f"dirpath={dirpath}, dirpath.basename=" + os.path.basename(dirpath))
for fileName in filenames:
filePath = os.path.join(dirpath, fileName)
if not isFrameFile(fileName):
continue
frameFileCount += 1
fileNameNoExt = os.path.splitext(fileName)[0]
pictureNameList = fileNameNoExt.split('_')
deviceId = pictureNameList[2][5:]
sensorType = pictureNameList[0].replace('#', '_')
syncTimeStamp = int(pictureNameList[5][1:])
# 创建结构体
pictureInfo = PictureInfo()
info = pictureInfo.make_struct(deviceId, sensorType, syncTimeStamp, filePath, os.path.basename(dirpath), os.path.splitext(fileName)[1])
# 格式化字典一个key对应一个数组
pictureInfoDict.setdefault(deviceId, []).append(info)
if 0 == frameFileCount:
print("initialize pictureInfoDict failed. Not found frame file")
def matchFrame(pictureInfoDict):
global primaryId, frameRate
global streamProfileDict
# 获取比较图像数组,取第一个设备的Color数组来进行比较
compareList = []
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == 'color':
compareList.append(info)
# 根据开流情况动态分析,减少循环次数
hasColorProfile = 'OB_SENSOR_COLOR' in streamProfileDict
hasDepthProfile = 'OB_SENSOR_DEPTH' in streamProfileDict
hasIRProfile = 'OB_SENSOR_IR' in streamProfileDict
hasIRLeftProfile = 'OB_SENSOR_IR_LEFT' in streamProfileDict
hasIRRightProfile = 'OB_SENSOR_IR_RIGHT' in streamProfileDict
# 匹配相邻帧
resultDict = {}
consumedList = []
dictIndex = 0
frameTspHalfGap = int(1000.0/frameRate/2.0+0.5)
for comparePic in compareList:
resultDict.setdefault(dictIndex, []).append(comparePic)
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
# 对比彩色
if hasColorProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'color' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对Depth
if hasDepthProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'depth' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# IR
if hasIRProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 左IR
if hasIRLeftProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_left' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 右IR
if hasIRRightProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_right' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 计算偏差
minTsp = min(resultDict[dictIndex], key=lambda x: x.syncTimeStamp)
for info in resultDict[dictIndex]:
info.tspDiff = info.syncTimeStamp - minTsp.syncTimeStamp
dictIndex += 1
return resultDict
def safe_make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
def handleSyncFrames():
global resultPath
global sourceFramesPath
global streamProfileDict
fp = open(f"{resultPath}/frameMatchLog.txt", "w")
if not initProfileInfoDict():
print("Initialize stream profile dictionary failed. exit")
return
print(f"Stream profiles: {streamProfileDict}")
streamProfileCount = len(streamProfileDict.items())
pictureInfoDict = {}
initPictureInfoDictionary(Path(sourceFramesPath), pictureInfoDict)
if len(pictureInfoDict) <= 0:
print("init pictureInfoDict failed. pictureInfoDict.len = 0")
return
# # Dump pictureInfoDict
# for key in pictureInfoDict:
# print("===================key:%s" % key)
# listTmp = list(pictureInfoDict[key])
# for info in listTmp:
# print("=====================value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (info.deviceId,info.sensorType,info.syncTimeStamp,info.picturePath))
deviceCount = getDeviceCount()
print("=================device count:%d" % deviceCount)
resultDict = {}
resultDict = matchFrame(pictureInfoDict)
for key in resultDict:
fp.write("===================result key:%s\n" % key)
print("===================result key:%s" % key)
listTmp = list(resultDict[key])
for info in listTmp:
fp.write("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s\n" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
print("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
matchPath = f"{resultPath}/matchFrames/"
safe_make_dir(matchPath)
notMatchPath = f"{resultPath}/notMatchFrames/"
abnormalPath = f"{resultPath}/abnormal/"
for key in resultDict:
listTmp = list(resultDict[key])
if (len(listTmp) == (deviceCount * streamProfileCount)):
haveAbnormalData = False
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
haveAbnormalData = True
else:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
if haveAbnormalData:
safe_make_dir(abnormalPath)
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
else:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
else:
safe_make_dir(notMatchPath)
for info in listTmp:
newFilePath = notMatchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, newFilePath)
def main():
if not initPrimaryId():
print("Initialize primaryId failed. exit.")
return
if not initSyncConfigParams():
print("Initialized Sync config parameter failed. exit.")
return
initResultDir()
print(f"PrimaryId={primaryId}, frameRate={frameRate}, tspRangeThreshold={tspRangeThreshold}")
handleSyncFrames()
return
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Synchronize frames support for 'Orbbec Gemini 2'")
parser.add_argument('frames_dir', type=str, help="Frames directory")
parser.add_argument('main_script_root_dir', type=str, help="SyncFramesMain.py working directory")
args = parser.parse_args()
sourceRootPath = args.frames_dir
sourceFramesPath = f"{args.frames_dir}/TotalModeFrames"
mainPythonWorkPath = args.main_script_root_dir
print(f"Start of Gemini2 synchronize frame. sourceRootPath={sourceRootPath}")
main()
print("Finish of Gemini2 synchronize frame.")
@@ -1,430 +0,0 @@
import os.path
import argparse
import sys
import json
import shutil
import configparser
from pathlib import Path
from datetime import datetime
import os
import re
## Config.ini中配置
# 单位:FPS,请依据数据集实际帧率填写,否则会导致匹配不准确
frameRate = -1
# 单位:ms,当匹配后某组数据帧的时间戳极差大于等于tspRangeThreshold,文件名会增加标注
tspRangeThreshold = -1
## Python脚本自动解析, 不要修改
primaryId = '-1' #主机ID
mainPythonWorkPath = "" # SyncFramesMain.py的工作目录
sourceFramesPath = "" # 请勿修改,固定值,TotalMode目录路径
sourceRootPath = "" # 存放TotalMode的根目录
resultPath = "" # 保存sync分析结果
streamProfileDict = dict() # 保存Python结果
class PictureInfo(object):
class Struct(object):
def __init__(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
self.deviceId = deviceId
self.sensorType = sensorType
self.syncTimeStamp = syncTimeStamp
self.picturePath = picturePath
self.deviceIdFull = deviceIdFull
self.fileExt = fileExt
def make_struct(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
return self.Struct(deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt)
class StreamProfileInfo:
def __init__(self, sensorType, width, height, format, fps):
self.sensorType = sensorType
self.width = width
self.height = height
self.format = format
self.fps = fps
def initPrimaryId():
global primaryId
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Initialize primaryId failed. {deviceInfoPath} not exists")
return False
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Initialize primaryId failed. {deviceInfoPath} not contain item 'devices'")
return False
for item in data['devices']:
if 'isPrimaryDevice' in item and 'index' in item and item['isPrimaryDevice']:
primaryId = str(item['index'])
return True
return False
def initSyncConfigParams():
global frameRate, tspRangeThreshold
configPath = f"{mainPythonWorkPath}/Config.ini"
if not os.path.exists(configPath):
print(f"Initliaze synchronized config parameter failed. {configPath} not exists.")
return False
# 创建ConfigParser对象
config = configparser.ConfigParser()
# 读取ini文件
config.read(configPath, 'utf-8')
if not config.has_option('Parameter', 'frameRate'):
print(f"Initliaze synchronized config parameter failed. Not define 'frameRate' in ${configPath}")
return False
if not config.has_option('Parameter', 'tspRangeThreshold'):
print(f"Initliaze synchronized config parameter failed. Not define 'tspRangeThreshold' in ${configPath}")
return False
frameRate = config.getfloat('Parameter', 'frameRate')
if frameRate <= 0 or frameRate >= 1000:
print(f"Initliaze synchronized config parameter failed. Invalid frameRate={frameRate}")
return False
tspRangeThreshold = config.getfloat('Parameter', 'tspRangeThreshold')
if tspRangeThreshold <= 0:
print(f"Initliaze synchronized config parameter failed. Invalid tspRangeThreshold={tspRangeThreshold}")
return False
return True
def getDeviceCount():
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Get device count failed. {deviceInfoPath} not exists")
return 0
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Get device count failed. {deviceInfoPath} not contain item 'devices'")
return 0
return len(data['devices'])
def initProfileInfoDict():
global streamProfileDict
streamProfileDict = dict()
profilePath = f"{sourceRootPath}/StreamProfileInfo.txt"
if not os.path.exists(profilePath):
print(f"Initialize profile information dictionary failed. {profilePath} not exists")
return False
with open(profilePath, 'r') as f:
data = json.load(f)
if not 'streamProfiles' in data:
print(f"Initialize profile information dictionary failed. {profilePath} not contain item 'streamProfiles'")
return False
for item in data['streamProfiles']:
if 'sensorType' in item and 'width' in item and 'height' in item and 'format' in item and 'fps' in item:
profileInfo = StreamProfileInfo(item['sensorType'], item['width'], item['height'], item['format'], item['fps'])
streamProfileDict.setdefault(item['sensorType'], profileInfo)
else:
print(f"Initialize profile information dictionary. Error invalid StreamProfile, {item}")
return len(streamProfileDict.items()) > 0
def initResultDir():
global resultPath
timeText = datetime.now().strftime("%Y-%m-%d_%H%M%S")
resultPath = f"{sourceRootPath}/results-{timeText}"
if not os.path.exists(resultPath):
os.makedirs(resultPath)
def isFrameFile(fileName):
fileExt = os.path.splitext(fileName)
if len(fileExt) < 2:
return False
frameExts = {".jpeg", ".jpg", ".png", ".raw", "bmp"}
return fileExt[1] in frameExts
def extract_d_number(filename):
"""提取文件名中以'd'开头的数字部分"""
match_d = re.search(r'd(\d+)', filename)
if match_d:
return int(match_d.group(1))
match_g = re.search(r'g(\d+)', filename)
if match_g:
return int(match_g.group(1))
return float('inf')
def initPictureInfoDictionary(rootFilePath, pictureInfoDict):
frameFileCount = 0
for dirpath, dirnames, filenames in os.walk(rootFilePath):
filenames.sort(key=extract_d_number) # 排序,按文件名中的'd'后面的数字从小到大排序
for fileName in filenames:
filePath = os.path.join(dirpath, fileName)
if not isFrameFile(fileName):
continue
frameFileCount += 1
fileNameNoExt = os.path.splitext(fileName)[0]
pictureNameList = fileNameNoExt.split('_')
deviceId = pictureNameList[2][5:]
sensorType = pictureNameList[0].replace('#', '_')
syncTimeStamp = int(pictureNameList[3][1:])
# 创建结构体
pictureInfo = PictureInfo()
info = pictureInfo.make_struct(deviceId, sensorType, syncTimeStamp, filePath, os.path.basename(dirpath), os.path.splitext(fileName)[1])
# 格式化字典一个key对应一个数组
pictureInfoDict.setdefault(deviceId, []).append(info)
if 0 == frameFileCount:
print("initialize pictureInfoDict failed. Not found frame file")
def matchFrame(pictureInfoDict):
global primaryId, frameRate
global streamProfileDict
# 获取比较图像数组,取第一个设备的Color数组来进行比较
compareList = []
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == 'ir_left':
compareList.append(info)
# 根据开流情况动态分析,减少循环次数
hasColorProfile = 'OB_SENSOR_COLOR' in streamProfileDict
hasDepthProfile = 'OB_SENSOR_DEPTH' in streamProfileDict
hasIRProfile = 'OB_SENSOR_IR' in streamProfileDict
hasIRLeftProfile = 'OB_SENSOR_IR_LEFT' in streamProfileDict
hasIRRightProfile = 'OB_SENSOR_IR_RIGHT' in streamProfileDict
# 匹配相邻帧
resultDict = {}
consumedList = []
dictIndex = 0
frameTspHalfGap = int(1000.0/frameRate/2.0+0.5)
for comparePic in compareList:
resultDict.setdefault(dictIndex, []).append(comparePic)
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
# 对比彩色
if hasColorProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'color' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对Depth
if hasDepthProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'depth' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
print("=====================result value : jjjjjjjjjjjjjjj:%s" % (info.syncTimeStamp))
break
# IR
if hasIRProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对左IR
if hasIRLeftProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_left' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对右IR
if hasIRRightProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_right' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 计算偏差
minTsp = min(resultDict[dictIndex], key=lambda x: x.syncTimeStamp)
for info in resultDict[dictIndex]:
info.tspDiff = info.syncTimeStamp - minTsp.syncTimeStamp
dictIndex += 1
return resultDict
def safe_make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
def handleSyncFrames():
global resultPath
global sourceFramesPath
global streamProfileDict
fp = open(f"{resultPath}/frameMatchLog.txt", "w")
if not initProfileInfoDict():
print("Initialize stream profile dictionary failed. exit")
return
print(f"Stream profiles: {streamProfileDict}")
streamProfileCount = len(streamProfileDict.items())
pictureInfoDict = {}
initPictureInfoDictionary(Path(sourceFramesPath), pictureInfoDict)
if len(pictureInfoDict) <= 0:
print("init pictureInfoDict failed. pictureInfoDict.len = 0")
return
# # Dump pictureInfoDict
# for key in pictureInfoDict:
# print("===================key:%s" % key)
# listTmp = list(pictureInfoDict[key])
# for info in listTmp:
# print("=====================value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (info.deviceId,info.sensorType,info.syncTimeStamp,info.picturePath))
deviceCount = getDeviceCount()
print("=================device count:%d" % deviceCount)
resultDict = {}
resultDict = matchFrame(pictureInfoDict)
for key in resultDict:
fp.write("===================result key:%s\n" % key)
print("===================result key:%s" % key)
listTmp = list(resultDict[key])
for info in listTmp:
fp.write("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s\n" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
print("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
matchPath = f"{resultPath}/matchFrames/"
safe_make_dir(matchPath)
notMatchPath = f"{resultPath}/notMatchFrames/"
abnormalPath = f"{resultPath}/abnormal/"
for key in resultDict:
listTmp = list(resultDict[key])
# print("***********")
# print(listTmp)
if (len(listTmp) == (deviceCount * streamProfileCount)):
haveAbnormalData = False
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
haveAbnormalData = True
else:
# print("***********")
# print(info.picturePath)
# print("###########")
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
# print(path)
if haveAbnormalData:
safe_make_dir(abnormalPath)
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
else:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
else:
safe_make_dir(notMatchPath)
for info in listTmp:
newFilePath = notMatchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, newFilePath)
def main():
if not initPrimaryId():
print("Initialize primaryId failed. exit.")
return
if not initSyncConfigParams():
print("Initialized Sync config parameter failed. exit.")
return
initResultDir()
print(f"PrimaryId={primaryId}, frameRate={frameRate}, tspRangeThreshold={tspRangeThreshold}")
handleSyncFrames()
return
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Synchronize frames support for 'Orbbec Devices'")
parser.add_argument('frames_dir', type=str, help="Frames directory")
parser.add_argument('main_script_root_dir', type=str, help="SyncFramesMain.py working directory")
args = parser.parse_args()
sourceRootPath = args.frames_dir
sourceFramesPath = f"{args.frames_dir}/TotalModeFrames"
mainPythonWorkPath = args.main_script_root_dir
print(f"Start of CommonFrameMatch synchronize frame. sourceRootPath={sourceRootPath}")
main()
print("Finish of CommonFrameMatch synchronize frame.")
@@ -1,408 +0,0 @@
import os.path
import argparse
import sys
import json
import shutil
import configparser
from pathlib import Path
from datetime import datetime
## Config.ini中配置
# 单位:FPS,请依据数据集实际帧率填写,否则会导致匹配不准确
frameRate = -1
# 单位:ms,当匹配后某组数据帧的时间戳极差大于等于tspRangeThreshold,文件名会增加标注
tspRangeThreshold = -1
## Python脚本自动解析, 不要修改
primaryId = '-1' #主机ID
mainPythonWorkPath = "" # SyncFramesMain.py的工作目录
sourceFramesPath = "" # 请勿修改,固定值,TotalMode目录路径
sourceRootPath = "" # 存放TotalMode的根目录
resultPath = "" # 保存sync分析结果
streamProfileDict = dict() # 保存Python结果
class PictureInfo(object):
class Struct(object):
def __init__(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
self.deviceId = deviceId
self.sensorType = sensorType
self.syncTimeStamp = syncTimeStamp
self.picturePath = picturePath
self.deviceIdFull = deviceIdFull
self.fileExt = fileExt
def make_struct(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt):
return self.Struct(deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt)
class StreamProfileInfo:
def __init__(self, sensorType, width, height, format, fps):
self.sensorType = sensorType
self.width = width
self.height = height
self.format = format
self.fps = fps
def initPrimaryId():
global primaryId
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Initialize primaryId failed. {deviceInfoPath} not exists")
return False
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Initialize primaryId failed. {deviceInfoPath} not contain item 'devices'")
return False
for item in data['devices']:
if 'isPrimaryDevice' in item and 'index' in item and item['isPrimaryDevice']:
primaryId = str(item['index'])
return True
return False
def initSyncConfigParams():
global frameRate, tspRangeThreshold
configPath = f"{mainPythonWorkPath}/Config.ini"
if not os.path.exists(configPath):
print(f"Initliaze synchronized config parameter failed. {configPath} not exists.")
return False
# 创建ConfigParser对象
config = configparser.ConfigParser()
# 读取ini文件
config.read(configPath, 'utf-8')
if not config.has_option('Parameter', 'frameRate'):
print(f"Initliaze synchronized config parameter failed. Not define 'frameRate' in ${configPath}")
return False
if not config.has_option('Parameter', 'tspRangeThreshold'):
print(f"Initliaze synchronized config parameter failed. Not define 'tspRangeThreshold' in ${configPath}")
return False
frameRate = config.getfloat('Parameter', 'frameRate')
if frameRate <= 0 or frameRate >= 1000:
print(f"Initliaze synchronized config parameter failed. Invalid frameRate={frameRate}")
return False
tspRangeThreshold = config.getfloat('Parameter', 'tspRangeThreshold')
if tspRangeThreshold <= 0:
print(f"Initliaze synchronized config parameter failed. Invalid tspRangeThreshold={tspRangeThreshold}")
return False
return True
def getDeviceCount():
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Get device count failed. {deviceInfoPath} not exists")
return 0
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Get device count failed. {deviceInfoPath} not contain item 'devices'")
return 0
return len(data['devices'])
def initProfileInfoDict():
global streamProfileDict
streamProfileDict = dict()
profilePath = f"{sourceRootPath}/StreamProfileInfo.txt"
if not os.path.exists(profilePath):
print(f"Initialize profile information dictionary failed. {profilePath} not exists")
return False
with open(profilePath, 'r') as f:
data = json.load(f)
if not 'streamProfiles' in data:
print(f"Initialize profile information dictionary failed. {profilePath} not contain item 'streamProfiles'")
return False
for item in data['streamProfiles']:
if 'sensorType' in item and 'width' in item and 'height' in item and 'format' in item and 'fps' in item:
profileInfo = StreamProfileInfo(item['sensorType'], item['width'], item['height'], item['format'], item['fps'])
streamProfileDict.setdefault(item['sensorType'], profileInfo)
else:
print(f"Initialize profile information dictionary. Error invalid StreamProfile, {item}")
return len(streamProfileDict.items()) > 0
def initResultDir():
global resultPath
timeText = datetime.now().strftime("%Y-%m-%d_%H%M%S")
resultPath = f"{sourceRootPath}/results-{timeText}"
if not os.path.exists(resultPath):
os.makedirs(resultPath)
def isFrameFile(fileName):
fileExt = os.path.splitext(fileName)
if len(fileExt) < 2:
return False
frameExts = {".jpeg", ".jpg", ".png", ".raw", "bmp"}
return fileExt[1] in frameExts
def initPictureInfoDictionary(rootFilePath, pictureInfoDict):
frameFileCount = 0
for dirpath, dirnames, filenames in os.walk(rootFilePath):
# print(f"dirpath={dirpath}, dirpath.basename=" + os.path.basename(dirpath))
for fileName in filenames:
filePath = os.path.join(dirpath, fileName)
if not isFrameFile(fileName):
continue
frameFileCount += 1
fileNameNoExt = os.path.splitext(fileName)[0]
pictureNameList = fileNameNoExt.split('_')
deviceId = pictureNameList[2][5:]
sensorType = pictureNameList[0].replace('#', '_')
syncTimeStamp = int(pictureNameList[3][1:])
# 创建结构体
pictureInfo = PictureInfo()
info = pictureInfo.make_struct(deviceId, sensorType, syncTimeStamp, filePath, os.path.basename(dirpath), os.path.splitext(fileName)[1])
# 格式化字典一个key对应一个数组
pictureInfoDict.setdefault(deviceId, []).append(info)
if 0 == frameFileCount:
print("initialize pictureInfoDict failed. Not found frame file")
def matchFrame(pictureInfoDict):
global primaryId, frameRate
global streamProfileDict
# 获取比较图像数组,取第一个设备的Color数组来进行比较
compareList = []
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == 'color':
compareList.append(info)
# 根据开流情况动态分析,减少循环次数
hasColorProfile = 'OB_SENSOR_COLOR' in streamProfileDict
hasDepthProfile = 'OB_SENSOR_DEPTH' in streamProfileDict
hasIRProfile = 'OB_SENSOR_IR' in streamProfileDict
hasIRLeftProfile = 'OB_SENSOR_IR_LEFT' in streamProfileDict
hasIRRightProfile = 'OB_SENSOR_IR_RIGHT' in streamProfileDict
# 匹配相邻帧
resultDict = {}
consumedList = []
dictIndex = 0
frameTspHalfGap = int(1000.0/frameRate/2.0+0.5)
for comparePic in compareList:
resultDict.setdefault(dictIndex, []).append(comparePic)
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
# 对比彩色
if hasColorProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'color' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对Depth
if hasDepthProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'depth' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# IR
if hasIRProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对左IR
if hasIRLeftProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_left' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对右IR
if hasIRRightProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_right' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 计算偏差
minTsp = min(resultDict[dictIndex], key=lambda x: x.syncTimeStamp)
for info in resultDict[dictIndex]:
info.tspDiff = info.syncTimeStamp - minTsp.syncTimeStamp
dictIndex += 1
return resultDict
def safe_make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
def handleSyncFrames():
global resultPath
global sourceFramesPath
global streamProfileDict
fp = open(f"{resultPath}/frameMatchLog.txt", "w")
if not initProfileInfoDict():
print("Initialize stream profile dictionary failed. exit")
return
print(f"Stream profiles: {streamProfileDict}")
streamProfileCount = len(streamProfileDict.items())
pictureInfoDict = {}
initPictureInfoDictionary(Path(sourceFramesPath), pictureInfoDict)
if len(pictureInfoDict) <= 0:
print("init pictureInfoDict failed. pictureInfoDict.len = 0")
return
# # Dump pictureInfoDict
# for key in pictureInfoDict:
# print("===================key:%s" % key)
# listTmp = list(pictureInfoDict[key])
# for info in listTmp:
# print("=====================value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (info.deviceId,info.sensorType,info.syncTimeStamp,info.picturePath))
deviceCount = getDeviceCount()
print("=================device count:%d" % deviceCount)
resultDict = {}
resultDict = matchFrame(pictureInfoDict)
for key in resultDict:
fp.write("===================result key:%s\n" % key)
print("===================result key:%s" % key)
listTmp = list(resultDict[key])
for info in listTmp:
fp.write("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s\n" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
print("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
matchPath = f"{resultPath}/matchFrames/"
safe_make_dir(matchPath)
notMatchPath = f"{resultPath}/notMatchFrames/"
abnormalPath = f"{resultPath}/abnormal/"
for key in resultDict:
listTmp = list(resultDict[key])
if (len(listTmp) == (deviceCount * streamProfileCount)):
haveAbnormalData = False
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
haveAbnormalData = True
else:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
if haveAbnormalData:
safe_make_dir(abnormalPath)
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + info.fileExt
shutil.copy(info.picturePath, path)
else:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, path)
else:
safe_make_dir(notMatchPath)
for info in listTmp:
newFilePath = notMatchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + info.fileExt
shutil.copy(info.picturePath, newFilePath)
def main():
if not initPrimaryId():
print("Initialize primaryId failed. exit.")
return
if not initSyncConfigParams():
print("Initialized Sync config parameter failed. exit.")
return
initResultDir()
print(f"PrimaryId={primaryId}, frameRate={frameRate}, tspRangeThreshold={tspRangeThreshold}")
handleSyncFrames()
return
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Synchronize frames support for 'Orbbec Gemini 2 VL'")
parser.add_argument('frames_dir', type=str, help="Frames directory")
parser.add_argument('main_script_root_dir', type=str, help="SyncFramesMain.py working directory")
args = parser.parse_args()
sourceRootPath = args.frames_dir
sourceFramesPath = f"{args.frames_dir}/TotalModeFrames"
mainPythonWorkPath = args.main_script_root_dir
print(f"Start of Gemini2VL synchronize frame. sourceRootPath={sourceRootPath}")
main()
print("Finish of Gemini2VL synchronize frame.")
@@ -1,412 +0,0 @@
import os.path
import argparse
import sys
import json
import shutil
import configparser
from pathlib import Path
from datetime import datetime
## Config.ini中配置
# 单位:FPS,请依据数据集实际帧率填写,否则会导致匹配不准确
frameRate = -1
# 单位:ms,当匹配后某组数据帧的时间戳极差大于等于tspRangeThreshold,文件名会增加标注
tspRangeThreshold = -1
## Python脚本自动解析, 不要修改
primaryId = '-1' #主机ID
mainPythonWorkPath = "" # SyncFramesMain.py的工作目录
sourceFramesPath = "" # 请勿修改,固定值,TotalMode目录路径
sourceRootPath = "" # 存放TotalMode的根目录
resultPath = "" # 保存sync分析结果
streamProfileDict = dict() # 保存Python结果
class PictureInfo(object):
class Struct(object):
def __init__(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt, exp, gain):
self.deviceId = deviceId
self.sensorType = sensorType
self.syncTimeStamp = syncTimeStamp
self.picturePath = picturePath
self.deviceIdFull = deviceIdFull
self.fileExt = fileExt
self.exp = exp
self.gain = gain
def make_struct(self, deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt, exp, gain):
return self.Struct(deviceId, sensorType, syncTimeStamp, picturePath, deviceIdFull, fileExt, exp, gain)
class StreamProfileInfo:
def __init__(self, sensorType, width, height, format, fps):
self.sensorType = sensorType
self.width = width
self.height = height
self.format = format
self.fps = fps
def initPrimaryId():
global primaryId
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Initialize primaryId failed. {deviceInfoPath} not exists")
return False
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Initialize primaryId failed. {deviceInfoPath} not contain item 'devices'")
return False
for item in data['devices']:
if 'isPrimaryDevice' in item and 'index' in item and item['isPrimaryDevice']:
primaryId = str(item['index'])
return True
return False
def initSyncConfigParams():
global frameRate, tspRangeThreshold
configPath = f"{mainPythonWorkPath}/Config.ini"
if not os.path.exists(configPath):
print(f"Initliaze synchronized config parameter failed. {configPath} not exists.")
return False
# 创建ConfigParser对象
config = configparser.ConfigParser()
# 读取ini文件
config.read(configPath, 'utf-8')
if not config.has_option('Parameter', 'frameRate'):
print(f"Initliaze synchronized config parameter failed. Not define 'frameRate' in ${configPath}")
return False
if not config.has_option('Parameter', 'tspRangeThreshold'):
print(f"Initliaze synchronized config parameter failed. Not define 'tspRangeThreshold' in ${configPath}")
return False
frameRate = config.getfloat('Parameter', 'frameRate')
if frameRate <= 0 or frameRate >= 1000:
print(f"Initliaze synchronized config parameter failed. Invalid frameRate={frameRate}")
return False
tspRangeThreshold = config.getfloat('Parameter', 'tspRangeThreshold')
if tspRangeThreshold <= 0:
print(f"Initliaze synchronized config parameter failed. Invalid tspRangeThreshold={tspRangeThreshold}")
return False
return True
def getDeviceCount():
deviceInfoPath = f"{sourceRootPath}/DevicesInfo.txt"
if not os.path.exists(deviceInfoPath):
print(f"Get device count failed. {deviceInfoPath} not exists")
return 0
with open(deviceInfoPath, 'r') as f:
data = json.load(f)
if not 'devices' in data:
print(f"Get device count failed. {deviceInfoPath} not contain item 'devices'")
return 0
return len(data['devices'])
def initProfileInfoDict():
global streamProfileDict
streamProfileDict = dict()
profilePath = f"{sourceRootPath}/StreamProfileInfo.txt"
if not os.path.exists(profilePath):
print(f"Initialize profile information dictionary failed. {profilePath} not exists")
return False
with open(profilePath, 'r') as f:
data = json.load(f)
if not 'streamProfiles' in data:
print(f"Initialize profile information dictionary failed. {profilePath} not contain item 'streamProfiles'")
return False
for item in data['streamProfiles']:
if 'sensorType' in item and 'width' in item and 'height' in item and 'format' in item and 'fps' in item:
profileInfo = StreamProfileInfo(item['sensorType'], item['width'], item['height'], item['format'], item['fps'])
streamProfileDict.setdefault(item['sensorType'], profileInfo)
else:
print(f"Initialize profile information dictionary. Error invalid StreamProfile, {item}")
return len(streamProfileDict.items()) > 0
def initResultDir():
global resultPath
timeText = datetime.now().strftime("%Y-%m-%d_%H%M%S")
resultPath = f"{sourceRootPath}/results-{timeText}"
if not os.path.exists(resultPath):
os.makedirs(resultPath)
def isFrameFile(fileName):
fileExt = os.path.splitext(fileName)
if len(fileExt) < 2:
return False
frameExts = {".jpeg", ".jpg", ".png", ".raw", "bmp"}
return fileExt[1] in frameExts
def initPictureInfoDictionary(rootFilePath, pictureInfoDict):
frameFileCount = 0
for dirpath, dirnames, filenames in os.walk(rootFilePath):
# print(f"dirpath={dirpath}, dirpath.basename=" + os.path.basename(dirpath))
for fileName in filenames:
filePath = os.path.join(dirpath, fileName)
if not isFrameFile(fileName):
continue
frameFileCount += 1
fileNameNoExt = os.path.splitext(fileName)[0]
pictureNameList = fileNameNoExt.split('_')
deviceId = pictureNameList[2][5:]
sensorType = pictureNameList[0].replace('#', '_')
syncTimeStamp = int(pictureNameList[3][1:])
exp = str(pictureNameList[6][0:])
gain = str(pictureNameList[7][0:])
# 创建结构体
pictureInfo = PictureInfo()
info = pictureInfo.make_struct(deviceId, sensorType, syncTimeStamp, filePath, os.path.basename(dirpath), os.path.splitext(fileName)[1],exp,gain)
# 格式化字典一个key对应一个数组
pictureInfoDict.setdefault(deviceId, []).append(info)
if 0 == frameFileCount:
print("initialize pictureInfoDict failed. Not found frame file")
def matchFrame(pictureInfoDict):
global primaryId, frameRate
global streamProfileDict
# 获取比较图像数组,取第一个设备的Color数组来进行比较
compareList = []
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == 'color':
compareList.append(info)
# 根据开流情况动态分析,减少循环次数
hasColorProfile = 'OB_SENSOR_COLOR' in streamProfileDict
hasDepthProfile = 'OB_SENSOR_DEPTH' in streamProfileDict
hasIRProfile = 'OB_SENSOR_IR' in streamProfileDict
hasIRLeftProfile = 'OB_SENSOR_IR_LEFT' in streamProfileDict
hasIRRightProfile = 'OB_SENSOR_IR_RIGHT' in streamProfileDict
# 匹配相邻帧
resultDict = {}
consumedList = []
dictIndex = 0
frameTspHalfGap = int(1000.0/frameRate/2.0+0.5)
for comparePic in compareList:
resultDict.setdefault(dictIndex, []).append(comparePic)
for key in pictureInfoDict:
listTmp = list(pictureInfoDict[key])
# 对比彩色
if hasColorProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'color' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对Depth
if hasDepthProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'depth' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# IR
if hasIRProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对左IR
if hasIRLeftProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_left' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 对右IR
if hasIRRightProfile:
for info in listTmp:
if info.deviceId == primaryId and info.sensorType == comparePic.sensorType:
continue
if info in consumedList:
continue
if info.sensorType == 'ir_right' and abs(info.syncTimeStamp - comparePic.syncTimeStamp) < frameTspHalfGap:
resultDict.setdefault(dictIndex, []).append(info)
consumedList.append(info)
break
# 计算偏差
minTsp = min(resultDict[dictIndex], key=lambda x: x.syncTimeStamp)
for info in resultDict[dictIndex]:
info.tspDiff = info.syncTimeStamp - minTsp.syncTimeStamp
dictIndex += 1
return resultDict
def safe_make_dir(path):
if not os.path.exists(path):
os.makedirs(path)
def handleSyncFrames():
global resultPath
global sourceFramesPath
global streamProfileDict
fp = open(f"{resultPath}/frameMatchLog.txt", "w")
if not initProfileInfoDict():
print("Initialize stream profile dictionary failed. exit")
return
print(f"Stream profiles: {streamProfileDict}")
streamProfileCount = len(streamProfileDict.items())
pictureInfoDict = {}
initPictureInfoDictionary(Path(sourceFramesPath), pictureInfoDict)
if len(pictureInfoDict) <= 0:
print("init pictureInfoDict failed. pictureInfoDict.len = 0")
return
# # Dump pictureInfoDict
# for key in pictureInfoDict:
# print("===================key:%s" % key)
# listTmp = list(pictureInfoDict[key])
# for info in listTmp:
# print("=====================value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (info.deviceId,info.sensorType,info.syncTimeStamp,info.picturePath))
deviceCount = getDeviceCount()
print("=================device count:%d" % deviceCount)
resultDict = {}
resultDict = matchFrame(pictureInfoDict)
for key in resultDict:
fp.write("===================result key:%s\n" % key)
print("===================result key:%s" % key)
listTmp = list(resultDict[key])
for info in listTmp:
fp.write("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s\n" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
print("=====================result value : deviceId:%s\tsensorType:%s\tsyncTimeStamp:%s\tpicturePath:%s" % (
info.deviceId, info.sensorType, info.syncTimeStamp, info.picturePath))
matchPath = f"{resultPath}/matchFrames/"
safe_make_dir(matchPath)
notMatchPath = f"{resultPath}/notMatchFrames/"
abnormalPath = f"{resultPath}/abnormal/"
for key in resultDict:
listTmp = list(resultDict[key])
if (len(listTmp) == (deviceCount * streamProfileCount)):
haveAbnormalData = False
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + "_"+ str(info.exp) + "_"+ str(info.gain) + info.fileExt
shutil.copy(info.picturePath, path)
haveAbnormalData = True
else:
path = matchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_"+ str(info.exp) + "_"+ str(info.gain) + info.fileExt
shutil.copy(info.picturePath, path)
if haveAbnormalData:
safe_make_dir(abnormalPath)
for info in listTmp:
if info.tspDiff >= tspRangeThreshold:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_xxxxxx" + "_"+ str(info.exp) + "_"+ str(info.gain) + info.fileExt
shutil.copy(info.picturePath, path)
else:
path = abnormalPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_"+ str(info.exp) + "_"+ str(info.gain) + info.fileExt
shutil.copy(info.picturePath, path)
else:
safe_make_dir(notMatchPath)
for info in listTmp:
newFilePath = notMatchPath + str(key) + "_" + info.sensorType + "_" + info.deviceIdFull + "_" + str(
info.syncTimeStamp) + "_[" + str(info.tspDiff) + "]" + "_"+ str(info.exp) + "_"+ str(info.gain) + info.fileExt
shutil.copy(info.picturePath, newFilePath)
def main():
if not initPrimaryId():
print("Initialize primaryId failed. exit.")
return
if not initSyncConfigParams():
print("Initialized Sync config parameter failed. exit.")
return
initResultDir()
print(f"PrimaryId={primaryId}, frameRate={frameRate}, tspRangeThreshold={tspRangeThreshold}")
handleSyncFrames()
return
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Synchronize frames support for 'Orbbec Devices'")
parser.add_argument('frames_dir', type=str, help="Frames directory")
parser.add_argument('main_script_root_dir', type=str, help="SyncFramesMain.py working directory")
args = parser.parse_args()
sourceRootPath = args.frames_dir
sourceFramesPath = f"{args.frames_dir}/TotalModeFrames"
mainPythonWorkPath = args.main_script_root_dir
print(f"Start of CommonFrameMatch synchronize frame. sourceRootPath={sourceRootPath}")
main()
print("Finish of CommonFrameMatch synchronize frame.")
@@ -1,42 +0,0 @@
{
"deviceVid": "0x2BC5",
"devicePid": "0x0800",
"primarySerialNumber": "CP1E5420006D",
"devices": [{
"index": 0,
"isPrimaryDevice": true,
"vid": "0x2BC5",
"pid": "0x0800",
"name": "Orbbec Gemini 335",
"firmwareVersion": "1.3.64",
"serialNumber": "CP1E5420006D",
"hardwareVersion": "0.1",
"ipAddress": "0.0.0.0",
"extensionInfo": {
"ExtensionInfo": {
"IspFwVer": "20240820",
"IspNeedVer": "20240820",
"HwType": "R1",
"HwVer": "V1.1"
}
}
}, {
"index": 1,
"isPrimaryDevice": false,
"vid": "0x2BC5",
"pid": "0x0800",
"name": "Orbbec Gemini 335",
"firmwareVersion": "1.3.64",
"serialNumber": "CP1L44P00051",
"hardwareVersion": "0.1",
"ipAddress": "0.0.0.0",
"extensionInfo": {
"ExtensionInfo": {
"IspFwVer": "20240820",
"IspNeedVer": "20240820",
"HwType": "R1",
"HwVer": "V1.0"
}
}
}]
}
@@ -1,16 +0,0 @@
{
"D2CAlignMode": "ALIGN_D2C_SW_MODE",
"streamProfiles": [{
"sensorType": "OB_SENSOR_COLOR",
"width": 1280,
"height": 720,
"fps": 30,
"format": "MJPEG"
}, {
"sensorType": "OB_SENSOR_IR_LEFT",
"width": 848,
"height": 480,
"fps": 30,
"format": "Y8"
}]
}

Some files were not shown because too many files have changed in this diff Show More