图漾tycamera示例程序解析

文章目录

  • 1.Windows平台编译
    • [1.1安装Visual Studio](#1.1安装Visual Studio)
    • 1.2编译SDK
    • [1.3 成功运行标志](#1.3 成功运行标志)
  • 2.Linux平台编译
  • 3.源码说明
    • [3.1 build文件夹](#3.1 build文件夹)
    • [3.2 camport4文件夹](#3.2 camport4文件夹)
    • [3.3 include文件夹](#3.3 include文件夹)
      • [3.3.1 common.h](#3.3.1 common.h)
      • [3.3.2 tycamera.h](#3.3.2 tycamera.h)
        • [3.3.2.1 SDK生命周期管理](#3.3.2.1 SDK生命周期管理)
        • [3.3.2.2 设备管理](#3.3.2.2 设备管理)
        • [3.3.2.3 设备配置](#3.3.2.3 设备配置)
        • [3.3.2.4 回调注册](#3.3.2.4 回调注册)
        • [3.3.2.5 数据采集](#3.3.2.5 数据采集)
      • [3.3.3 TYThread.hpp](#3.3.3 TYThread.hpp)
      • [3.3.4 XmlConfig.h](#3.3.4 XmlConfig.h)
        • [3.3.4.1 配置流程](#3.3.4.1 配置流程)
    • [3.4 sample文件夹](#3.4 sample文件夹)
      • [3.4.1 文件整体结构](#3.4.1 文件整体结构)
      • [3.4.2 主函数整体流程](#3.4.2 主函数整体流程)
      • [3.4.3 主函数解析](#3.4.3 主函数解析)
    • [3.5 src文件夹](#3.5 src文件夹)
      • [3.5.1 common.cpp](#3.5.1 common.cpp)
        • [3.5.1.1 主要函数接口表](#3.5.1.1 主要函数接口表)
        • [3.5.1.2 selectDevice() - 设备选择函数](#3.5.1.2 selectDevice() - 设备选择函数)
        • [3.5.1.3 ty_image_info() - 图像格式转换函数](#3.5.1.3 ty_image_info() - 图像格式转换函数)
        • [3.5.1.4 source_init() - 相机源初始化函数](#3.5.1.4 source_init() - 相机源初始化函数)
        • [3.5.1.5 fetchSelectedSourceCalibration() - 标定数据获取函数](#3.5.1.5 fetchSelectedSourceCalibration() - 标定数据获取函数)
        • [3.5.1.6 updateDevicesParallel() - 并行设备更新函数](#3.5.1.6 updateDevicesParallel() - 并行设备更新函数)
      • [3.5.2 tycamera.cpp ---SDK主实现模块](#3.5.2 tycamera.cpp ---SDK主实现模块)
        • [3.5.2.1 ty_image类 - 图像封装类](#3.5.2.1 ty_image类 - 图像封装类)
        • [3.5.2.2 DeviceSession结构 - 设备会话结构](#3.5.2.2 DeviceSession结构 - 设备会话结构)
        • [3.5.2.3 全局变量](#3.5.2.3 全局变量)
        • [3.5.2.4 主要函数接口表](#3.5.2.4 主要函数接口表)
        • [3.5.2.5 辅助函数接口表](#3.5.2.5 辅助函数接口表)
        • [3.5.2.6 TY_CAM_Init() - SDK初始化](#3.5.2.6 TY_CAM_Init() - SDK初始化)
        • [3.5.2.7 TY_CAM_GetDeviceList() - 获取设备列表](#3.5.2.7 TY_CAM_GetDeviceList() - 获取设备列表)
        • [3.5.2.8 TY_CAM_OpenDeviceByIP() - 通过IP打开设备](#3.5.2.8 TY_CAM_OpenDeviceByIP() - 通过IP打开设备)
        • [3.5.2.9 TY_CAM_SetDeviceInitConfigFile() - 设置XML配置文件](#3.5.2.9 TY_CAM_SetDeviceInitConfigFile() - 设置XML配置文件)
        • [3.5.2.10 TY_CAM_EnableComponents() - 启用设备组件](#3.5.2.10 TY_CAM_EnableComponents() - 启用设备组件)
        • [3.5.2.11 TY_CAM_StartCapture() - 开始采集](#3.5.2.11 TY_CAM_StartCapture() - 开始采集)
        • [3.5.2.12 ReconnectDevice() - 重连设备](#3.5.2.12 ReconnectDevice() - 重连设备)
      • [3.5.3 TYThread.cpp](#3.5.3 TYThread.cpp)
        • [3.5.3.1 主要函数接口表](#3.5.3.1 主要函数接口表)
        • [3.5.3.2 使用举例](#3.5.3.2 使用举例)
      • [3.5.4 XmlConfig.cpp](#3.5.4 XmlConfig.cpp)
        • [3.5.4.1 主要函数接口表](#3.5.4.1 主要函数接口表)
        • [3.5.4.2 特性名称到特征ID映射(GigE 2.0协议)](#3.5.4.2 特性名称到特征ID映射(GigE 2.0协议))
        • [3.5.4.3 像素格式映射](#3.5.4.3 像素格式映射)
        • [3.5.4.4 parseConfigToMap() - XML解析函数](#3.5.4.4 parseConfigToMap() - XML解析函数)
        • [3.5.4.5TYCamXmlParametersGenICam::config() - GenICam设备配置](#3.5.4.5TYCamXmlParametersGenICam::config() - GenICam设备配置)
        • [3.5.4.6 TYCamXmlParametersCustom::config() - 自定义协议设备配置](#3.5.4.6 TYCamXmlParametersCustom::config() - 自定义协议设备配置)
    • [3.6 tinyxml2文件夹](#3.6 tinyxml2文件夹)
      • [3.6.1 类层次结构图](#3.6.1 类层次结构图)
      • [3.6.2 类功能对比表](#3.6.2 类功能对比表)
      • [3.6.3 XMLNode - XML节点基类](#3.6.3 XMLNode - XML节点基类)
        • [3.6.3.1 主要方法表](#3.6.3.1 主要方法表)
        • [3.6.3.2 使用举例](#3.6.3.2 使用举例)
      • [3.6.4 XMLDocument - XML文档类](#3.6.4 XMLDocument - XML文档类)
        • [3.6.4.1 主要方法表](#3.6.4.1 主要方法表)
        • [3.6.4.2 错误码枚举](#3.6.4.2 错误码枚举)
        • [3.6.4.3 使用举例](#3.6.4.3 使用举例)
      • [3.6.5 XMLElement - XML元素类](#3.6.5 XMLElement - XML元素类)
        • [3.6.5.1 主要方法表](#3.6.5.1 主要方法表)
        • [3.6.5.2 使用举例](#3.6.5.2 使用举例)
      • [3.6.6 XMLAttribute - XML属性类](#3.6.6 XMLAttribute - XML属性类)
        • [3.6.6.1 主要方法表](#3.6.6.1 主要方法表)
        • [3.6.6.2 使用举例](#3.6.6.2 使用举例)
      • [3.6.7 XMLText - XML文本类](#3.6.7 XMLText - XML文本类)
        • [3.6.7.1 主要方法表](#3.6.7.1 主要方法表)
        • [3.6.7.2 使用举例](#3.6.7.2 使用举例)
      • [3.6.8 XMLComment - XML注释类](#3.6.8 XMLComment - XML注释类)
        • [3.6.8.1 使用举例](#3.6.8.1 使用举例)
      • [3.6.9 XMLDeclaration - XML声明类](#3.6.9 XMLDeclaration - XML声明类)
        • [3.6.9.1 使用举例](#3.6.9.1 使用举例)
      • [3.6.10 XMLPrinter - XML打印类](#3.6.10 XMLPrinter - XML打印类)
        • [3.6.10.1 主要方法表](#3.6.10.1 主要方法表)
        • [3.6.10.2 使用举例](#3.6.10.2 使用举例)
      • [3.6.11 在本项目中的应用](#3.6.11 在本项目中的应用)
  • 4.补充资料

1.Windows平台编译

1.1安装Visual Studio

安装Visual Studio软件

1.2编译SDK

将开发包tycamera/camport4/lib/win/hostapp/x64路径下的tycam.dlltyimgproc.dll 拷贝到上述编译生成的文件夹build/sample/Debug或者Release文件夹中。

将build编译后,在tycamera/build/Debug或者Release路径下的tycamera.dll 拷贝到上述编译生成的文件夹build/sample/Debug或者Release文件夹中。

1.3 成功运行标志

2.Linux平台编译

2.1编译前操作

进入到tycamera/camport4/路径,根据Ubuntu控制器系统,拷贝下以下两个动态库

cpp 复制代码
sudo cp lib/linux/lib_x64/libtycam.so* /usr/lib/
sudo cp lib/linux/lib_x64/libtyimgproc.so* /usr/lib/

如果使用的时arm环境,请将lib_x64替换为lib_Aarch64

2.1.1文件结构

2.2 编译SDK

cpp 复制代码
 # tycamera
1. mkdir build
2. cd build
3. cmake ..
4. make; make install
5. ./install/bin/test

2.3 成功运行标志

正常情况下,运行程序后,生成的界面如下:

3.源码说明

3.1 build文件夹

用于存放编译生成的中间文件和最终可执行文件。这是CMake推荐的构建目录。

3.2 camport4文件夹

3.2.1 include:头文件

核心 API 头文件:包含相机的所有编程接口

TYApi.h- 设备操作的常规接口

TYDefs.h - 旧相机数据类型和定义

TYImageProc.h - 畸变校正/滤波等接口

TYParameter.h - 新相机数据类型和定义

辅助功能:

TYCoordinateMapper.h - 坐标系变换相关接口

TYFeatureList.h - 功能列表管理

PFNC.h - Pixel Format Naming Convention标准头文件,定义了机器视觉和图像处理领域中所有标准化的像素格式。

TYVer.h - SDK版本信息

3.2.2库文件目录(lib)

各类平台下的动态库文件及windows平台下sample程序

cpp 复制代码
lib_Aarch64        # ARM64架构库
lib_armv7hf        # ARMv7的32位架构带硬浮点支持
lib_i686           # 32位x86库
lib_X3M_Aarch64    # 地平线X3M专用
lib_x64            # 64位x86库

3.3 include文件夹


依赖关系图:

cpp 复制代码
TYThread.hpp
    ↓ (被使用)
tycamera.h
    ↓ (被使用)
common.h
    ↓ (被使用)
XmlConfig.h
    ↓ (依赖)
tinyxml2.h

3.3.1 common.h

提供通用的工具函数和宏定义,用于设备选择、源切换、标定数据获取等操作。

cpp 复制代码
TY_STATUS selectDevice(
    TY_INTERFACE_TYPE iface,                    // 接口类型
    const std::string& ID,                     // 设备ID
    const std::string& IP,                     // 设备IP
    uint32_t deviceNum,                        // 设备编号
    std::vector<TY_DEVICE_BASE_INFO>& out      // 输出设备列表
);


#define GenICamSourceDepth           // 深度相机源
#define GenICamSourceTexture         // 纹理(彩色)相机源
#define GenICamSourceLeft            // 左红外相机源
#define GenICamSourceRight           // 右红外相机源

//图像信息转换函数,将 TY_IMAGE_DATA 结构转换为 TYImageInfo 结构
TYImageInfo ty_image_info(const TY_IMAGE_DATA& image_data);
//源初始化函数,- 初始化指定的相机源(深度、彩色、红外等)
TY_STATUS source_init(const TY_DEV_HANDLE hDevice, const int64_t source);
//标定数据获取函数,-获取当前选中源的标定数据,用于深度图与彩色图的对齐。
TY_STATUS fetchSelectedSourceCalibration(
    const TY_DEV_HANDLE hDevice, 
    TY_CAMERA_CALIB_INFO& calib_data
);

3.3.2 tycamera.h

提供完整的相机SDK接口,包括设备管理、数据采集、回调注册等核心功能。

  1. TY_CAM_Init() // 初始化SDK
  2. TY_CAM_GetDeviceList() // 获取设备列表
  3. TY_CAM_OpenDeviceByID() // 打开设备
  4. TY_CAM_SetDeviceInitConfigFile() // 设置XML配置(可选)
  5. TY_CAM_EnableComponents() // 启用组件
  6. TY_CAM_RegisterFrameCallback() // 注册回调
  7. TY_CAM_StartCapture() // 开始采集
  8. 处理帧数据\] // 通过回调处理

  9. TY_CAM_CloseDevice() // 关闭设备
  10. TY_CAM_Deinit() // 清理SDK
cpp 复制代码
#ifndef TY_CAMERA_H
#define TY_CAMERA_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
    #ifdef PERCIPIO_API_EXPORTS
        #define PERCIPIO_API __declspec(dllexport)  // 导出(编译DLL时)
    #else
        #define PERCIPIO_API __declspec(dllimport)  // 导入(使用DLL时)
    #endif
#else
    #define PERCIPIO_API                           // Linux平台无需特殊处理
#endif

#include "TYParameter.h"
#include "TYImageProc.h"

//相机协议类型
typedef enum {
    TY_PROTOCOL_GIGE_VISION = 0,    // GigE Vision协议
    TY_PROTOCOL_USB3_VISION,         // USB3 Vision协议
    TY_PROTOCOL_CUSTOM,              // 自定义协议
    TY_PROTOCOL_UNKNOWN              // 未知协议
} TY_CAM_PROTOCOL;

// 设备状态Device status
typedef enum {
    CAM_DEVICE_STATUS_ONLINE,        // 设备在线
    CAM_DEVICE_STATUS_OFFLINE        // 设备离线
} CAM_DEVICE_STATUS;

#pragma pack(1)

//设备信息结构
typedef struct {
    char id[64];                   // 设备ID
    char ip[64];                   // 设备IP地址
    char vendor[32];               // 厂商名称
    char model[32];                // 设备型号
    TY_INTERFACE_INFO iface;         // 接口信息
    int is_online;                 // 是否在线
} CAM_DEVICE_INFO;

//图像信息结构
typedef struct TY_IMAGE_INFO {
    uint64_t timestamp;            //Timestamp in microseconds 时间戳(微秒)
    int32_t imageIndex;           // image index used in trigger mode 图像索引(触发模式)
    int32_t status;               // Status of this buffer缓冲区状态
    TY_COMPONENT_ID componentID;    // Where current data come from组件ID(数据来源)
    int32_t size;                //  Buffer size缓冲区大小
    void* buffer;                // Pointer to data buffer数据缓冲区指针
    int32_t width;               // Image width in pixels图像宽度(像素)
    int32_t height;              // Image height in pixels图像高度(像素)
    TYPixFmt pixelFormat;        // Pixel format, see TYPixFmtList像素格式
    TY_CAMERA_INTRINSIC intrinsic;  // 3x3 matrix   | fx|  0| cx| / |  0| fy| cy| / |  0|  0|  1|相机内参矩阵(3x3)
} TY_IMAGE_INFO;

//帧信息结构
typedef struct {
    void* userBuffer;             // 用户缓冲区
    int32_t bufferSize;          // 缓冲区大小
    int32_t validCount;          // 有效图像数量
    TY_IMAGE_INFO image[10];      // 图像数组(最多10个)
} TY_FRAME_INFO;

#pragma pack()

// Device status callback 设备状态回调
typedef void (*DeviceStatusCallback)(
    const char* device_id,        // 设备ID
    CAM_DEVICE_STATUS status,      // 设备状态
    void* userdata              // 用户数据
);

// Frame callback function type 帧数据回调
typedef void (*FrameCallback)(
    TY_DEV_HANDLE hDevice,        // 设备句柄
    TY_FRAME_INFO* frame,        // 帧数据
    void* userdata             // 用户数据
);

// Event callback function type 事件回调
typedef void (*EventCallback)(
    TY_DEV_HANDLE hDevice,        // 设备句柄
    TY_EVENT_INFO* event,        // 事件信息
    void* userdata             // 用户数据
);

//设备初始化回调
typedef void (*DeviceInitCallback)(
    TY_DEV_HANDLE hDevice,        // 设备句柄
    void* userdata             // 用户数据
);

/**
 * @brief Initialize the SDK
 * 
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note This function must be called before any other SDK functions
 * @note Initializes the SDK environment including necessary hardware and software resources
 */
PERCIPIO_API int TY_CAM_Init();// 初始化SDK

/**
 * @brief Clean up and release SDK resources
 * 
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note This function should be called after all devices are closed
 * @note Releases all resources occupied by the SDK, no SDK functions can be used after this call
 */

PERCIPIO_API int TY_CAM_Deinit();  // 清理SDK资源 

/**
 * @brief Set device auto-reconnect functionality
 * 
 * @param enable Enable flag: 0=disable auto-reconnect, 1=enable auto-reconnect
 * 
 * @note When enabled, SDK will automatically attempt to reconnect if device connection is abnormally lost
 * @note Should be set after calling TY_CAM_Init and before opening any device
 */
PERCIPIO_API void TY_CAM_SetAutoReconnect(int enable);  // 设置自动重连

/**
 * @brief Get the list of currently available devices
 * 
 * @param devices Output parameter, returns pointer to device information array
 * @param count Output parameter, returns number of devices
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note The returned device list must be freed using TY_CAM_FreeDeviceList
 * @note This function scans network and USB bus to find available devices
 */
PERCIPIO_API int TY_CAM_GetDeviceList(CAM_DEVICE_INFO** devices, int* count);

/**
 * @brief Free memory occupied by device list
 * 
 * @param devices Pointer to device list returned by TY_CAM_GetDeviceList
 * 
 * @note Must call this function to release memory allocated by TY_CAM_GetDeviceList
 */
PERCIPIO_API void TY_CAM_FreeDeviceList(CAM_DEVICE_INFO* devices);

/**
 * @brief Open device by IP address
 * 
 * @param ip Device IP address string
 * @param hDevice Output parameter, returns device handle
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note After opening device, components and callbacks need to be configured
 * @note For GigE Vision devices, ensure network configuration is correct
 */
PERCIPIO_API int TY_CAM_OpenDeviceByIP(const char* ip, TY_DEV_HANDLE* hDevice);

/**
 * @brief Open device by device ID
 * 
 * @param id Device unique identifier string
 * @param hDevice Output parameter, returns device handle
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note Device ID can be obtained from CAM_DEVICE_INFO structure
 * @note This method works with any connection protocol (GigE/USB)
 */
PERCIPIO_API int TY_CAM_OpenDeviceByID(const char* id, TY_DEV_HANDLE* hDevice);

/**
 * @brief Close device and release related resources
 * 
 * @param hDevice Device handle
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note If device is capturing, it will automatically stop capture
 * @note Device handle becomes invalid after closing and cannot be used further
 */
PERCIPIO_API int TY_CAM_CloseDevice(TY_DEV_HANDLE hDevice);

/**
 * @brief Get the communication protocol used by the device
 * 
 * @param hDevice Device handle
 * @param protocol Output parameter, returns protocol type
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note Protocol types include GigE Vision, USB3 Vision, and Custom.
 * @note GigE Vision and USB3 Vision devices share the same set of APIs for configuration parameters.
 *       Custom protocol devices require different APIs for configuration.
 *       It's essential to check the protocol type in your DeviceInitCallback function and use the appropriate APIs accordingly.
 *       Example usage in DeviceInitCallback:
 *       ```
 *       TY_CAM_PROTOCOL protocol;
 *       TY_CAM_GetDeviceProtocol(hDevice, &protocol);
 *       
 *       if (protocol == TY_PROTOCOL_CUSTOM) {
 *           // Use Custom protocol specific APIs
 *       } else {
 *           // Use standard GigE Vision/USB3 Vision APIs
 *       }
 *       ```
 */
PERCIPIO_API int TY_CAM_GetDeviceProtocol(TY_DEV_HANDLE hDevice, TY_CAM_PROTOCOL* protocol);

/**
 * @brief Enable specific components of the device
 * 
 * @param hDevice Device handle
 * @param depth Depth component enable flag: 0=disable, 1=enable
 * @param leftir Left infrared component enable flag: 0=disable, 1=enable
 * @param rightir Right infrared component enable flag: 0=disable, 1=enable
 * @param color RGB color component enable flag: 0=disable, 1=enable
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note This function should be called after opening device and before starting capture
 * @note Enabled components will produce data frames during capture
 * @note Some components may not be supported depending on device model and license
 */
PERCIPIO_API int TY_CAM_EnableComponents(TY_DEV_HANDLE hDevice, int depth, int leftir, int rightir, int color);

/**
 * @brief Register device initialization callback function
 * 
 * @param hDevice Device handle
 * @param callback Device initialization callback function pointer
 * @param userdata User-defined data pointer, will be passed to callback function
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note Callback function is called immediately after device initialization completes
 * @note Device parameters and stream format can be configured in the callback function
 * @note If both XML configuration file and callback are set, callback settings override XML configuration
 */
PERCIPIO_API int TY_CAM_RegisterDeviceInitCallback(TY_DEV_HANDLE hDevice, DeviceInitCallback callback, void* userdata);

/**
 * @brief Set device initialization configuration file path
 * 
 * @param hDevice Device handle
 * @param xmlFilePath Path to the XML configuration file
 * @param forceConfig If set to true, skip camera model validation and force apply configuration.
 *                    If set to false, validate camera model in XML matches the actual device before applying.
 * @return int Returns TY_STATUS_OK on success, error code on failure.
 * 
 * @note This function must be called after opening the device and before starting capture.
 * @note The XML configuration will be applied before any DeviceInitCallback registered via
 *       TY_CAM_RegisterDeviceInitCallback. If both XML configuration and DeviceInitCallback
 *       are set, the callback function will override parameters set by the XML configuration.
 */
PERCIPIO_API int TY_CAM_SetDeviceInitConfigFile(TY_DEV_HANDLE hDevice, const char* xmlFilePath, const bool forceConfig);

/**
 * @brief Register frame data callback function
 * 
 * @param hDevice Device handle
 * @param callback Frame data callback function pointer
 * @param userdata User-defined data pointer, will be passed to callback function
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note Callback function is called when complete frame data is received
 * @note Frame data contains image information from all enabled components
 * @note Callback function should process data quickly to avoid blocking capture thread
 */
PERCIPIO_API int TY_CAM_RegisterFrameCallback(TY_DEV_HANDLE hDevice, FrameCallback callback, void* userdata);

/**
 * @brief Register device event callback function
 * 
 * @param hDevice Device handle
 * @param callback Event callback function pointer
 * @param userdata User-defined data pointer, will be passed to callback function
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note Callback function is called when device generates events, such as trigger signals, errors, etc.
 * @note Event types include hardware trigger, software trigger, device errors, etc.
 * @note Can be used to implement event-driven application logic
 */
PERCIPIO_API int TY_CAM_RegisterEventCallback(TY_DEV_HANDLE hDevice, EventCallback callback, void* userdata);

/**
 * @brief Register device status change callback function
 * 
 * @param callback Device status callback function pointer
 * @param userdata User-defined data pointer, will be passed to callback function
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note This callback function is globally effective, monitoring status changes of all devices
 * @note Status changes include device online, offline, etc.
 * @note Can be used to implement device management and monitoring functionality
 */
PERCIPIO_API int TY_CAM_RegisterDeviceStatusCallback(DeviceStatusCallback callback, void* userdata);

/**
 * @brief Start data capture
 * 
 * @param hDevice Device handle
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note After starting capture, registered callback functions will begin receiving data
 * @note Ensure device is properly configured and callback functions are registered
 * @note If trigger mode is enabled, external trigger signal is required to generate data
 */
PERCIPIO_API int TY_CAM_StartCapture(TY_DEV_HANDLE hDevice);

/**
 * @brief Stop data capture
 * 
 * @param hDevice Device handle
 * @return int Returns status code, TY_STATUS_OK indicates success, others are error codes
 * 
 * @note After stopping capture, no new data frames will be generated
 * @note Can call TY_CAM_StartCapture again to resume capture
 * @note Capture will automatically stop when closing device
 */
PERCIPIO_API int TY_CAM_StopCapture(TY_DEV_HANDLE hDevice);


#ifdef __cplusplus
}
#endif
#endif
3.3.2.1 SDK生命周期管理
3.3.2.2 设备管理
3.3.2.3 设备配置
3.3.2.4 回调注册
3.3.2.5 数据采集

3.3.3 TYThread.hpp

提供跨平台的线程封装类,隐藏不同操作系统的线程实现细节,使用Pimpl模式隐藏实现。

cpp 复制代码
class TYThreadImpl;  // 前向声明,隐藏实现

class TYThread {
public:
    // 回调函数类型定义
    typedef void* (*Callback_t)(void*);
    
    // 构造函数
    TYThread();
    
    // 析构函数
    ~TYThread();
    
    // 创建线程
    int create(Callback_t cb, void* arg);
    
    // 销毁线程
    int destroy();
    
private:
    TYThreadImpl* impl;  // 实现指针(Pimpl模式)
};

3.3.4 XmlConfig.h

提供XML配置文件的解析和设备参数配置功能,支持通过XML文件批量配置相机参数。

TYCamXmlParametersBase (抽象基类)

├── TYCamXmlParametersGenICam (GenICam协议设备)

└── TYCamXmlParametersCustom (自定义协议设备)

cpp 复制代码
#pragma once

#include <map>
#include <vector>
#include "TYDefs.h"

struct FeatureConfig {
    std::string feature_name;   // 特性名称(如"ExposureTime")
    std::string feature_text;   // 特性值(如"800")
};

//XML解析函数,解析XML配置文件,将配置转换为内存中的映射表结构
bool parseConfigToMap(
    const char* xmlFilePath,                                    // XML文件路径
    std::string& deviceModel,                                  // 输出设备型号
    std::map<std::string, std::vector<FeatureConfig>>& configMap  // 输出配置映射
);

//XML参数配置基类
class TYCamXmlParametersBase {
public:
    // 构造函数
    TYCamXmlParametersBase(const TY_DEV_HANDLE dev);
    
    // 虚析构函数
    virtual ~TYCamXmlParametersBase();
    
    // 纯虚函数:配置接口
    virtual int config() = 0;
    
protected:
    TY_DEV_HANDLE hDevice;  // 设备句柄
};

//GenICam设备XML参数配置类,如GM46X相机
class TYCamXmlParametersGenICam : public TYCamXmlParametersBase {
public:
    // 构造函数
    TYCamXmlParametersGenICam(
        const TY_DEV_HANDLE dev, 
        const std::map<std::string, std::vector<FeatureConfig>>& configMap
    );    
    // 虚析构函数
    virtual ~TYCamXmlParametersGenICam();    
    // 实现配置逻辑
    virtual int config();
    
private:
    const std::map<std::string, std::vector<FeatureConfig>> xml_cfg;
};

//自定义图像格式
struct CustomImageFormat {
    int64_t Binning;           // Binning值(像素合并)
    TY_PIXEL_FORMAT FMT;        // 像素格式
};

//自定义传感器尺寸
struct CustomSensorSize {
    int32_t m_sensor_w;        // 传感器宽度
    int32_t m_sensor_h;        // 传感器高度
};

//自定义协议设备XML参数配置类,如FM854/TM26X相机
class TYCamXmlParametersCustom : public TYCamXmlParametersBase {
public:
    TYCamXmlParametersCustom(
        const TY_DEV_HANDLE dev, 
        const std::map<std::string, std::vector<FeatureConfig>>& configMap
    );
    virtual int config();         // 实现配置逻辑
    
private:
    // XML配置数据
    const std::map<std::string, std::vector<FeatureConfig>> xml_cfg;
    
    // 配置参数
    bool b_enable_color_aec_roi;      // 是否启用彩色AEC区域
    TY_AEC_ROI_PARAM color_aec_roi;  // 彩色AEC区域参数
    
    bool b_enable_frame_rate_ctrl;      // 是否启用帧率控制
    TY_TRIGGER_PARAM_EX dev_frame_rate_cfg; // 帧率配置
    
    int64_t acq_mode;                // 采集模式(单帧/多帧/连续)
    int64_t trigger_source;           // 触发源
    
    bool b_enable_trigger_mode;        // 是否启用触发模式
    TY_TRIGGER_PARAM_EX dev_trigger_cfg; // 触发配置
    
    // 传感器和图像格式映射
    std::map<TY_COMPONENT_ID, CustomSensorSize> sensor_size;
    std::map<TY_COMPONENT_ID, CustomImageFormat> image_format;
    
  
3.3.4.1 配置流程
cpp 复制代码
1. parseConfigToMap()           // 解析XML文件
2. 根据设备协议选择配置类
   ├── TYCamXmlParametersGenICam  // GenICam协议
   └── TYCamXmlParametersCustom  // 自定义协议
3. config()                    // 应用配置
4. 设备参数设置完成

3.4 sample文件夹

3.4.1 文件整体结构

main.cpp

├── 头文件引入部分

├── OpenCV辅助函数部分(条件编译)

├── 设备初始化回调函数

├── 帧数据回调函数

├── 设备状态回调函数

└── 主函数(main)

3.4.2 主函数整体流程

cpp 复制代码
main()
├── SDK初始化
├── 注册设备状态回调
├── 设备发现循环
├── 设备打开和配置
│   ├── 打开设备
│   ├── 获取设备协议
│   ├── 注册初始化回调
│   ├── 设置XML配置文件
│   ├── 启用组件
│   ├── 注册帧回调
│   └── 开始采集
├── 等待用户输入
├── 停止采集和关闭设备
└── 清理资源

使用流程图

cpp 复制代码
程序启动
    ↓
初始化SDK (TY_CAM_Init)
    ↓
注册状态回调 (TY_CAM_RegisterDeviceStatusCallback)
    ↓
循环获取设备列表 (TY_CAM_GetDeviceList)
    ↓
打开设备 (TY_CAM_OpenDeviceByIP)
    ↓
获取设备协议 (TY_CAM_GetDeviceProtocol)
    ↓
注册初始化回调 (TY_CAM_RegisterDeviceInitCallback)
    ↓
设置XML配置 (TY_CAM_SetDeviceInitConfigFile)
    ↓
启用组件 (TY_CAM_EnableComponents)
    ↓
注册帧回调 (TY_CAM_RegisterFrameCallback)
    ↓
开始采集 (TY_CAM_StartCapture)
    ↓
[异步接收帧数据]
    ↓ (frame_callback)
处理和显示图像
    ↓
用户按Enter键
    ↓
停止采集 (TY_CAM_StopCapture)
    ↓
关闭设备 (TY_CAM_CloseDevice)
    ↓
释放资源 (TY_CAM_FreeDeviceList, TY_CAM_Deinit)
    ↓
程序退出

3.4.3 主函数解析

cpp 复制代码
#include "tycamera.h"              // SDK主接口
#include <iostream>                 // 标准输入输出
#include <vector>                   // STL容器
#include <iomanip>                  // 格式化输出
#ifdef OPENCV_VIEW
#include <opencv2/opencv.hpp>      // OpenCV库(条件编译)
#endif

#ifdef OPENCV_VIEW
cv::Mat normalizeDepth(const cv::Mat& depth16u) {
    cv::Mat depth8u;
    double minVal, maxVal;
    cv::minMaxLoc(depth16u, &minVal, &maxVal);
    
    if (maxVal > minVal) {
        // 线性归一化到0-255范围
        depth16u.convertTo(depth8u, CV_8UC1, 
                         255.0 / (maxVal - minVal), 
                         -minVal * 255.0 / (maxVal - minVal));
    } else {
        // 如果最大值等于最小值,返回全0图像
        depth8u = cv::Mat::zeros(depth16u.size(), CV_8UC1);
    }
    
    return depth8u;
}

cv::Mat colorizeDepth(const cv::Mat& depth16u) {
    cv::Mat normalized = normalizeDepth(depth16u);
    cv::Mat colorized;
    
    // 应用伪彩色映射(JET colormap)
    cv::applyColorMap(normalized, colorized, cv::COLORMAP_JET);
    
    return colorized;
}
#endif

// GenICam协议设备初始化回调
void genicam_protocol_device_init_callback(TY_DEV_HANDLE hDevice, void* userdata)
{
    TY_STATUS status;
    std::cout << "GenICam protocol device parameters init!" << std::endl;
    //TODO...
    //TYIntegerSetValue();
    //TYEnumSetValue();
    //TYBooleanSetValue();
}

//自定义协议设备初始化回调
void custom_protocol_device_init_callback(TY_DEV_HANDLE hDevice, void* userdata)
{
    TY_STATUS status;
    std::cout << "Custom protocol device parameters init!" << std::endl;
    //TODO...
    //TYSetBool();
    //TYSetInt();
    //status = TYSetEnum(hDevice, TY_COMPONENT_DEPTH_CAM, TY_ENUM_IMAGE_MODE, TY_IMAGE_MODE_DEPTH16_240x96);
    //if(status) std::cout << "Failed to set depth stream image mode." << std::endl;

    //status = TYSetEnum(hDevice, TY_COMPONENT_RGB_CAM, TY_ENUM_IMAGE_MODE, TY_IMAGE_MODE_YUYV_640x360);
    //if(status) std::cout << "Failed to set color stream image mode." << std::endl;
}

void frame_callback(TY_DEV_HANDLE hDevice, TY_FRAME_INFO* frame, void* userdata) {
    for (int i = 0; i < frame->validCount; i++){
        if (frame->image[i].status != TY_STATUS_OK) continue;

        const char* component_name = "unknown";
        switch(frame->image[i].componentID) {
            case TY_COMPONENT_DEPTH_CAM:
                component_name = "depth";
                break;
            case TY_COMPONENT_RGB_CAM:
                component_name = "color";
                break;
            case TY_COMPONENT_IR_CAM_LEFT:
                component_name = "left-ir";
                break;
            case TY_COMPONENT_IR_CAM_RIGHT:
                component_name = "right-ir";
                break;
            default:
                component_name = "unknown";
                break;
        }

        std::cout << "got " << component_name << " image data:" << std::endl;
        std::cout << "\t size:       " << std::dec << frame->image[i].width << "x" << frame->image[i].height << std::endl;
        std::cout << "\t fmt:        0x" << std::hex << frame->image[i].pixelFormat << std::dec << std::endl;
        std::cout << "\t timestamp:  " << std::dec << frame->image[i].timestamp << std::endl;
        
        const float* intrinsic_data = frame->image[i].intrinsic.data;
        if(frame->image[i].componentID == TY_COMPONENT_RGB_CAM || frame->image[i].componentID == TY_COMPONENT_DEPTH_CAM) {
            std::cout << "\t intrinsic matrix (3x3):" << std::endl;
            std::cout << "\t   [" << std::fixed << std::setprecision(4) 
                    << intrinsic_data[0] << ", " << intrinsic_data[1] << ", " << intrinsic_data[2] << "]" << std::endl;
            std::cout << "\t   [" << intrinsic_data[3] << ", " << intrinsic_data[4] << ", " << intrinsic_data[5] << "]" << std::endl;
            std::cout << "\t   [" << intrinsic_data[6] << ", " << intrinsic_data[7] << ", " << intrinsic_data[8] << "]" << std::endl;
        }
        
        switch(frame->image[i].componentID) {
          case TY_COMPONENT_DEPTH_CAM: {
#ifdef OPENCV_VIEW
    // 创建OpenCV Mat对象
    cv::Mat depth = cv::Mat(
        cv::Size(frame->image[i].width, frame->image[i].height), 
        CV_16U, 
        frame->image[i].buffer
    ).clone();
    
    // 彩色化深度图
    cv::Mat depth_render = colorizeDepth(depth);
    
    // 显示深度图
    cv::imshow("depth", depth_render);
    
    // 在图像上添加内参信息
    std::ostringstream oss;
    oss << "fx=" << std::fixed << std::setprecision(1) << intrinsic_data[0]
        << " fy=" << intrinsic_data[4]
        << " cx=" << intrinsic_data[2]
        << " cy=" << intrinsic_data[5];
    cv::putText(depth_render, oss.str(), cv::Point(10, 30), 
               cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(255,255,255), 2);
    cv::imshow("depth", depth_render);
#endif
    break;
}
           case TY_COMPONENT_RGB_CAM: {
#ifdef OPENCV_VIEW
    // 创建OpenCV Mat对象
    cv::Mat color = cv::Mat(
        cv::Size(frame->image[i].width, frame->image[i].height), 
        CV_8UC3, 
        frame->image[i].buffer
    ).clone();
    
    // 显示彩色图
    cv::imshow("color", color);
    
    // 在图像上添加内参信息
    std::ostringstream oss;
    oss << "fx=" << std::fixed << std::setprecision(1) << intrinsic_data[0]
        << " fy=" << intrinsic_data[4]
        << " cx=" << intrinsic_data[2]
        << " cy=" << intrinsic_data[5];
    cv::putText(color, oss.str(), cv::Point(10, 30), 
               cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2);
    cv::imshow("color", color);
#endif
    break;
}
        }
        
        std::cout << std::endl;
    }
    
#ifdef OPENCV_VIEW
    cv::waitKey(1);
#endif
}

void device_status_callback(const char* device_id, CAM_DEVICE_STATUS status, void* userdata) {
    if (status == CAM_DEVICE_STATUS_ONLINE) {
        printf("Device %s is now online\n", device_id);
        
    } else if (status == CAM_DEVICE_STATUS_OFFLINE) {
        printf("Device %s is now offline\n", device_id);
    }
}

int main(int argc, char* argv[])
{
    int ret = 0;
    ret = TY_CAM_Init();
    std::cout << "TY_CAM_Init: " << ret << std::endl;
    
    ret = TY_CAM_RegisterDeviceStatusCallback(device_status_callback, NULL);
    std::cout << "TY_CAM_RegisterDeviceStatusCallback: " << ret << std::endl;

    // list devices
    CAM_DEVICE_INFO* devices;
    int count;

    while(true) {
        TY_CAM_GetDeviceList(&devices, &count);
        if(count > 0) break;
    }
    
    if (count > 0) {
        TY_DEV_HANDLE hDevice;
        //ret = TY_CAM_OpenDeviceByID(devices[0].id, &hDevice);
        //std::cout << "TY_CAM_OpenDeviceByID: " << ret << std::endl;
        std::cout << "IP: " << devices[0].ip << std::endl;//192.168.120.128
        ret = TY_CAM_OpenDeviceByIP(devices[0].ip, &hDevice);
        std::cout << "TY_CAM_OpenDeviceByIP: " << ret << std::endl;

        TY_CAM_PROTOCOL protocol = TY_PROTOCOL_UNKNOWN;
        ret = TY_CAM_GetDeviceProtocol(hDevice, &protocol);
        std::cout << "TY_CAM_GetDeviceProtocol: " << ret << std::endl;

        //register device init callback
        switch(protocol) {
            case TY_PROTOCOL_GIGE_VISION:
            case TY_PROTOCOL_USB3_VISION:
                ret = TY_CAM_RegisterDeviceInitCallback(hDevice, genicam_protocol_device_init_callback, NULL);
                std::cout << "TY_CAM_RegisterDeviceInitCallback: " << ret << std::endl;
                break;
            default:
                ret = TY_CAM_RegisterDeviceInitCallback(hDevice, custom_protocol_device_init_callback, NULL);
                std::cout << "TY_CAM_RegisterDeviceInitCallback: " << ret << std::endl;
                break;
        }

        ret = TY_CAM_SetDeviceInitConfigFile(hDevice, "/home/jet/workspace/percipio/tycamera/parameters.xml", false);
        std::cout << "TY_CAM_SetDeviceInitConfigFile: " << ret << std::endl;

        // enable depth and color
        ret = TY_CAM_EnableComponents(hDevice, 1, 0, 0, 1);
        std::cout << "TY_CAM_EnableComponents: " << ret << std::endl;
        
        // register frame callback
        ret = TY_CAM_RegisterFrameCallback(hDevice, frame_callback, NULL);
        std::cout << "TY_CAM_RegisterFrameCallback: " << ret << std::endl;
        
        // start capture
        ret = TY_CAM_StartCapture(hDevice);
        std::cout << "TY_CAM_StartCapture: " << ret << std::endl;

        printf("Press Enter to stop...\n");
        getchar();

        // stop and close device
        printf("TY_CAM_StopCapture.\n");
        TY_CAM_StopCapture(hDevice);

        printf("TY_CAM_CloseDevice.\n");
        TY_CAM_CloseDevice(hDevice);
    }
    
    printf("TY_CAM_FreeDeviceList.\n");
    TY_CAM_FreeDeviceList(devices);
    printf("TY_CAM_Deinit.\n");
    TY_CAM_Deinit();

    std::cout << "Main done!" << std::endl;
    return 0;
}

示例程序:可以概括为以下几个步骤:

1.初始化:调用TY_CAM_Init启动SDK,。

2.发现设备:调用TY_CAM_GetDeviceList查找可用的相机。

3.连接设备:调用TY_CAM_OpenDeviceByIP通过IP连接指定相机。

4.配置设备:

调用 TY_CAM_RegisterDeviceInitCallback设置参数。

在device_init_callback函数接口里设置相机属性

调用 TY_CAM_EnableComponents选择要开启的数据流。

调用 TY_CAM_RegisterFrameCallback设置数据到达时的处理函数。

5.开始采集:调用TY_CAM_StartCapture,此后程序进入等待数据的状态。

6.处理数据:数据到达后,自动触发 frame_callback函数,在这里进行图像显示或算法处理。

7.停止与清理:用户按下回车键后,程序依次调用  TY_CAM_StopCapture, TY_CAM_CloseDevice, TY_CAM_FreeDeviceList, TY_CAM_Deinit,完成资源释放。

3.5 src文件夹

私有实现的cpp文件

3.5.1 common.cpp

这个文件,实现了一个并行化的图漾相机设备发现与选择机制

cpp 复制代码
#include <cmath>
#include <cstring>

#include "common.h"
#include "TYThread.hpp"

static void *updateThreadFunc(void *userdata)
{
    TY_INTERFACE_HANDLE iface = (TY_INTERFACE_HANDLE)userdata;
    TYUpdateDeviceList(iface);
    return NULL;
}

static TY_STATUS updateDevicesParallel(std::vector<TY_INTERFACE_HANDLE> &ifaces,
    uint64_t timeout=2000)
{
    if(ifaces.size() != 0) {
        TYThread *updateThreads = new TYThread[ifaces.size()];
        for(int i = 0; i < ifaces.size(); i++) {
            updateThreads[i].create(updateThreadFunc, ifaces[i]);
        }
        for(int i = 0; i < ifaces.size(); i++) {
           updateThreads[i].destroy();
        }
        delete [] updateThreads;
        updateThreads = NULL;
    }
    return TY_STATUS_OK;
}

TY_STATUS selectDevice(TY_INTERFACE_TYPE iface
    , const std::string& ID, const std::string& IP
    , uint32_t deviceNum, std::vector<TY_DEVICE_BASE_INFO>& out)
{
    TY_STATUS status;
    status = TYUpdateInterfaceList();
    if(status) return status;

    uint32_t n = 0;
    status = TYGetInterfaceNumber(&n);
    if(status) return status;
    
    if(n == 0){
      std::cout << "interface number incorrect" << std::endl;
      return TY_STATUS_ERROR;
    }

    std::vector<TY_INTERFACE_INFO> ifaces(n);
    status = TYGetInterfaceList(&ifaces[0], n, &n);
    if(status) return status;

    out.clear();
    std::vector<TY_INTERFACE_TYPE> ifaceTypeList;
    std::vector<TY_INTERFACE_HANDLE> hIfaces;
    ifaceTypeList.push_back(TY_INTERFACE_USB);
    ifaceTypeList.push_back(TY_INTERFACE_ETHERNET);
    ifaceTypeList.push_back(TY_INTERFACE_IEEE80211);
    for(size_t t = 0; t < ifaceTypeList.size(); t++){
      for(uint32_t i = 0; i < ifaces.size(); i++){
        if(ifaces[i].type == ifaceTypeList[t] && (ifaces[i].type & iface) && deviceNum > out.size()){
          TY_INTERFACE_HANDLE hIface;
          status = TYOpenInterface(ifaces[i].id, &hIface);
          if(status) continue;
          hIfaces.push_back(hIface);
        }
      }
    }

    updateDevicesParallel(hIfaces);
    for (uint32_t i = 0; i < hIfaces.size(); i++) {
        TY_INTERFACE_HANDLE hIface = hIfaces[i];
        uint32_t n = 0;
        TYGetDeviceNumber(hIface, &n);
        if(n > 0){
          std::vector<TY_DEVICE_BASE_INFO> devs(n);
          TYGetDeviceList(hIface, &devs[0], n, &n);
          for(uint32_t j = 0; j < n; j++){
            if(deviceNum > out.size() && ((ID.empty() && IP.empty())
                || (!ID.empty() && devs[j].id == ID)
                || (!IP.empty() && IP == devs[j].netInfo.ip)))
            {
              if(TYIsNetworkInterface(devs[j].iface.type)){
                bool isInvalid = (std::string(devs[j].modelName) != "InvalidNetCam");
                if(isInvalid && devs[j].netInfo.tlversion != "Unknown") {
                    out.push_back(devs[j]);
                }
              } else {
                    out.push_back(devs[j]);
              }
            }
          }
        }
        TYCloseInterface(hIface);
    }

    if(out.size() == 0){
      return TY_STATUS_ERROR;
    }

    return TY_STATUS_OK;
}

///////////////////////
TYImageInfo ty_image_info(const TY_IMAGE_DATA& image_data) 
{
    TYImageInfo info;
    info.width = image_data.width;
    info.height = image_data.height; 
    info.format = image_data.pixelFormat;
    info.dataSize = image_data.size;
    info.data = image_data.buffer; 
    return info;
}

///////////////////////
TY_STATUS source_init(const TY_DEV_HANDLE hDevice, const int64_t source)
{
    int64_t m_current_source;
    TY_STATUS status = TYEnumGetValue(hDevice, "SourceSelector", &m_current_source);
    if(status) {
        std::cerr <<"SourceSelector read failed: " <<  status << std::endl;
        return status;
    }

    if(source != m_current_source) {
        status = TYEnumSetValue(hDevice, "SourceSelector", source);
        if(status) {
            std::cerr <<"SourceSelector init failed: " <<  status << std::endl;
            return status;
        }
    }

    return TY_STATUS_OK;
}

TY_STATUS fetchSelectedSourceCalibration(const TY_DEV_HANDLE hDevice, TY_CAMERA_CALIB_INFO& calib_data)
{
    static const char* requiredCalibParams[] = {
        "IntrinsicWidth",
        "IntrinsicHeight",
        "Intrinsic"
    };
    
    static const char* optionalCalibParams[] = {
        "Distortion",
        "Extrinsic"
    };
    
    //Initialize calibration data structure
    memset(&calib_data, 0, sizeof(TY_CAMERA_CALIB_INFO));
    
    //Check if required calibration parameters exist and are readable
    for (size_t i = 0; i < sizeof(requiredCalibParams)/sizeof(requiredCalibParams[0]); i++) {
        bool exist = false;
        TY_STATUS ret = TYParamExist(hDevice, requiredCalibParams[i], &exist);
        if (ret != TY_STATUS_OK || !exist) {
            std::cerr << requiredCalibParams[i] << " does not exist, calibration data is not available." << std::endl;
            return TY_STATUS_DEVICE_ERROR;
        }
        
        //Check parameter type (optional, for robustness)
        if (strcmp(requiredCalibParams[i], "Intrinsic") == 0) {
            ParamType type;
            ret = TYParamGetType(hDevice, requiredCalibParams[i], &type);
            if (ret == TY_STATUS_OK && type != ByteArray) {
                std::cerr << "Intrinsic parameter type must be ByteArray." << std::endl; 
                return TY_STATUS_WRONG_TYPE;
            }
        }
        
        //Check access permissions
        TY_ACCESS_MODE access = 0;
        ret = TYParamGetAccess(hDevice, requiredCalibParams[i], &access);
        if (ret == TY_STATUS_OK && !(access & TY_ACCESS_READABLE)) {
            std::cerr << requiredCalibParams[i] << " is not readable" << std::endl;
            return TY_STATUS_NOT_IMPLEMENTED;
        }
    }
    
    //Read IntrinsicWidth
    int64_t intrinsicWidth = 0;
    TY_STATUS ret = TYIntegerGetValue(hDevice, "IntrinsicWidth", &intrinsicWidth);
    if (ret != TY_STATUS_OK) {
        std::cerr << "Failed to read IntrinsicWidth, error: " << ret << std::endl;
        return ret;
    }
    
    //Validate IntrinsicWidth value validity
    if (intrinsicWidth <= 0 || intrinsicWidth > 100000) {  //Reasonable range check
        std::cerr << "Invalid IntrinsicWidth value: " << intrinsicWidth << std::endl;
        return TY_STATUS_INVALID_PARAMETER;
    }
    calib_data.intrinsicWidth = static_cast<int32_t>(intrinsicWidth);
    
    //Read IntrinsicHeight
    int64_t intrinsicHeight = 0;
    ret = TYIntegerGetValue(hDevice, "IntrinsicHeight", &intrinsicHeight);
    if (ret != TY_STATUS_OK) {
        std::cerr << "Failed to read IntrinsicHeight, error: " << ret << std::endl;
        return ret;
    }
    
    //Validate IntrinsicHeight value validity
    if (intrinsicHeight <= 0 || intrinsicHeight > 100000) {
        std::cerr << "Invalid IntrinsicHeight value: " << intrinsicHeight << std::endl;
        return TY_STATUS_INVALID_PARAMETER;
    }
    calib_data.intrinsicHeight = static_cast<int32_t>(intrinsicHeight);
    
    //Read Intrinsic matrix
    double intrinsic[9];
    memset(intrinsic, 0, sizeof(intrinsic));
    
    //Read Intrinsic byte array
    ret = TYByteArrayGetValue(hDevice, "Intrinsic", reinterpret_cast<uint8_t*>(intrinsic), sizeof(intrinsic));
    if (ret != TY_STATUS_OK) {
        std::cerr << "Failed to read Intrinsic, error: " << ret << std::endl;
        return ret;
    }
    
    //Validate Intrinsic matrix validity
    bool intrinsicValid = false;
    for (int32_t i = 0; i < 9; i++) {
        if (!std::isfinite(intrinsic[i])) {
            std::cerr << "Invalid Intrinsic value at index " << i  << ": " << intrinsic[i] << std::endl;
            intrinsicValid = false;
            break;
        }
        calib_data.intrinsic.data[i] = static_cast<float>(intrinsic[i]);
        intrinsicValid = true;
    }
    
    if (!intrinsicValid) {
        return TY_STATUS_INVALID_PARAMETER;
    }
    
    //Read optional calibration parameters
    //Read Distortion coefficients
    double distortion[12];
    memset(distortion, 0, sizeof(distortion));
    
    bool distortionExist = false;
    TYParamExist(hDevice, "Distortion", &distortionExist);
    
    if (distortionExist) {
        //Check Distortion parameter type
        ParamType distortionType;
        TYParamGetType(hDevice, "Distortion", &distortionType);
        
        if (distortionType == ByteArray) {
            ret = TYByteArrayGetValue(hDevice, "Distortion", reinterpret_cast<uint8_t*>(distortion), sizeof(distortion));
            if (ret == TY_STATUS_OK) {
                //Validate Distortion coefficient validity
                bool distortionValid = true;
                for (int32_t i = 0; i < 12; i++) {
                    if (!std::isfinite(distortion[i])) {
                        std::cerr << "Invalid Distortion value at index " << i << ": " << distortion[i] << std::endl;
                        distortionValid = false;
                        break;
                    }
                    calib_data.distortion.data[i] = static_cast<float>(distortion[i]);
                }
                
                if (!distortionValid) {
                    //If distortion coefficients are invalid, use zero values
                    memset(calib_data.distortion.data, 0, sizeof(calib_data.distortion.data));
                }
            } else {
                std::cerr << "Failed to read Distortion, error: " << ret << std::endl;
                //Use zero values when reading fails
                memset(calib_data.distortion.data, 0, sizeof(calib_data.distortion.data));
            }
        } else {
            std::cerr << "Distortion parameter exists but has wrong type: " << distortionType << std::endl;
            memset(calib_data.distortion.data, 0, sizeof(calib_data.distortion.data));
        }
    } else {
        //Distortion parameter does not exist, use zero values
        memset(calib_data.distortion.data, 0, sizeof(calib_data.distortion.data));
    }
    
    //Read Extrinsic matrix
    double extrinsic[16];
    memset(extrinsic, 0, sizeof(extrinsic));
    
    bool extrinsicExist = false;
    TYParamExist(hDevice, "Extrinsic", &extrinsicExist);
    
    if (extrinsicExist) {
        //Check Extrinsic parameter type
        ParamType extrinsicType;
        TYParamGetType(hDevice, "Extrinsic", &extrinsicType);
        
        if (extrinsicType == ByteArray) {
            ret = TYByteArrayGetValue(hDevice, "Extrinsic", reinterpret_cast<uint8_t*>(extrinsic), sizeof(extrinsic));
            if (ret == TY_STATUS_OK) {
                //Validate Extrinsic matrix validity
                bool extrinsicValid = true;
                for (int32_t i = 0; i < 16; i++) {
                    if (!std::isfinite(extrinsic[i])) {
                        std::cerr << "Invalid Extrinsic value at index " << i << ":"  << extrinsic[i] << std::endl;
                        extrinsicValid = false;
                        break;
                    }
                    calib_data.extrinsic.data[i] = static_cast<float>(extrinsic[i]);
                }
                
                if (!extrinsicValid) {
                    //If extrinsic matrix is invalid, use identity matrix or zero values
                    memset(calib_data.extrinsic.data, 0, sizeof(calib_data.extrinsic.data));
                }
            } else {
                std::cerr << "Failed to read Extrinsic, error: " << ret << std::endl;
                //Use zero values when reading fails
                memset(calib_data.extrinsic.data, 0, sizeof(calib_data.extrinsic.data));
            }
        } else {
            std::cerr << "Extrinsic parameter exists but has wrong type: " << extrinsicType << std::endl;
            memset(calib_data.extrinsic.data, 0, sizeof(calib_data.extrinsic.data));
        }
    } else {
        //Extrinsic parameter does not exist, use zero values
        memset(calib_data.extrinsic.data, 0, sizeof(calib_data.extrinsic.data));
    }
    
    return TY_STATUS_OK;
}
3.5.1.1 主要函数接口表
3.5.1.2 selectDevice() - 设备选择函数

实现流程

cpp 复制代码
1. 更新接口列表 (TYUpdateInterfaceList)
2. 获取接口数量 (TYGetInterfaceNumber)
3. 获取接口列表 (TYGetInterfaceList)
4. 遍历接口类型(USB、以太网)
5. 打开匹配的接口 (TYOpenInterface)
6. 并行更新设备列表 (updateDevicesParallel)
7. 获取设备列表 (TYGetDeviceList)
8. 根据条件筛选设备(ID、IP、数量)
9. 验证网络设备有效性
10. 返回匹配的设备列表
cpp 复制代码
TY_STATUS selectDevice(TY_INTERFACE_TYPE iface, const std::string& ID, 
                       const std::string& IP, uint32_t deviceNum, 
                       std::vector<TY_DEVICE_BASE_INFO>& out) {
    // 1. 更新接口列表
    status = TYUpdateInterfaceList();
    
    // 2. 获取接口数量
    uint32_t n = 0;
    status = TYGetInterfaceNumber(&n);
    
    // 3. 获取接口列表
    std::vector<TY_INTERFACE_INFO> ifaces(n);
    status = TYGetInterfaceList(&ifaces[0], n, &n);
    
    // 4-6. 打开接口并并行更新设备
    for(size_t t = 0; t < ifaceTypeList.size(); t++) {
        for(uint32_t i = 0; i < ifaces.size(); i++) {
            if(ifaces[i].type == ifaceTypeList[t]) {
                TYOpenInterface(ifaces[i].id, &hIface);
                hIfaces.push_back(hIface);
            }
        }
    }
    updateDevicesParallel(hIfaces);
    
    // 7-9. 筛选设备
    for (uint32_t i = 0; i < hIfaces.size(); i++) {
        TYGetDeviceList(hIface, &devs[0], n, &n);
        for(uint32_t j = 0; j < n; j++) {
            if((ID.empty() && IP.empty()) || 
               (!ID.empty() && devs[j].id == ID) ||
               (!IP.empty() && IP == devs[j].netInfo.ip)) {
                out.push_back(devs[j]);
            }
        }
    }
    
    return TY_STATUS_OK;
}
3.5.1.3 ty_image_info() - 图像格式转换函数

功能 :将底层 TY_IMAGE_DATA 结构转换为上层 TYImageInfo 结构

cpp 复制代码
TYImageInfo ty_image_info(const TY_IMAGE_DATA& image_data) {
    TYImageInfo info;
    info.width = image_data.width;
    info.height = image_data.height; 
    info.format = image_data.pixelFormat;
    info.dataSize = image_data.size;
    info.data = image_data.buffer; 
    return info;
}
3.5.1.4 source_init() - 相机源初始化函数

功能 :切换GenICam设备的相机源(Depth、Texture、Left、Right)
实现流程

cpp 复制代码
1. 读取当前源 (TYEnumGetValue "SourceSelector")
2. 比较目标源和当前源
3. 如果不同,切换到目标源 (TYEnumSetValue "SourceSelector")
4. 返回操作结果
cpp 复制代码
TY_STATUS source_init(const TY_DEV_HANDLE hDevice, const int64_t source) {
    int64_t m_current_source;
    status = TYEnumGetValue(hDevice, "SourceSelector", &m_current_source);
    
    if(source != m_current_source) {
        status = TYEnumSetValue(hDevice, "SourceSelector", source);
    }
    
    return TY_STATUS_OK;
}
3.5.1.5 fetchSelectedSourceCalibration() - 标定数据获取函数

功能 :获取当前选中源的标定数据(内参、畸变、外参)
实现流程

cpp 复制代码
1. 检查必需参数是否存在(IntrinsicWidth、IntrinsicHeight、Intrinsic)
2. 验证参数类型和访问权限
3. 读取IntrinsicWidth和IntrinsicHeight
4. 读取Intrinsic矩阵(3x3)
5. 验证内参矩阵有效性
6. 读取可选参数(Distortion、Extrinsic)
7. 验证可选参数有效性
8. 返回标定数据
cpp 复制代码
TY_STATUS fetchSelectedSourceCalibration(const TY_DEV_HANDLE hDevice, 
                                       TY_CAMERA_CALIB_INFO& calib_data) {
    // 1. 检查必需参数
    static const char* requiredCalibParams[] = {
        "IntrinsicWidth", "IntrinsicHeight", "Intrinsic"
    };
    for (size_t i = 0; i < sizeof(requiredCalibParams)/sizeof(requiredCalibParams[0]); i++) {
        bool exist = false;
        TYParamExist(hDevice, requiredCalibParams[i], &exist);
        if (!exist) return TY_STATUS_DEVICE_ERROR;
    }
    
    // 2-3. 读取内参尺寸
    int64_t intrinsicWidth = 0;
    TYIntegerGetValue(hDevice, "IntrinsicWidth", &intrinsicWidth);
    calib_data.intrinsicWidth = static_cast<int32_t>(intrinsicWidth);
    
    // 4. 读取内参矩阵
    double intrinsic[9];
    TYByteArrayGetValue(hDevice, "Intrinsic", 
                      reinterpret_cast<uint8_t*>(intrinsic), sizeof(intrinsic));
    
    // 5. 验证内参矩阵
    for (int32_t i = 0; i < 9; i++) {
        if (!std::isfinite(intrinsic[i])) {
            return TY_STATUS_INVALID_PARAMETER;
        }
        calib_data.intrinsic.data[i] = static_cast<float>(intrinsic[i]);
    }
    
    // 6-7. 读取可选参数(畸变、外参)
    // ... 类似处理
    
    return TY_STATUS_OK;
}
3.5.1.6 updateDevicesParallel() - 并行设备更新函数

功能 :使用多线程并行更新多个接口的设备列表

cpp 复制代码
static void *updateThreadFunc(void *userdata) {
    TY_INTERFACE_HANDLE iface = (TY_INTERFACE_HANDLE)userdata;
    TYUpdateDeviceList(iface);
    return NULL;
}

static TY_STATUS updateDevicesParallel(std::vector<TY_INTERFACE_HANDLE> &ifaces,
                                      uint64_t timeout) {
    if(ifaces.size() != 0) {
        TYThread *updateThreads = new TYThread[ifaces.size()];
        for(int i = 0; i < ifaces.size(); i++) {
            updateThreads[i].create(updateThreadFunc, ifaces[i]);
        }
        for(int i = 0; i < ifaces.size(); i++) {
           updateThreads[i].destroy();
        }
        delete [] updateThreads;
    }
    return TY_STATUS_OK;
}

3.5.2 tycamera.cpp ---SDK主实现模块

作用:实现SDK的核心功能,包括设备管理、数据采集、回调处理、自动重连、图像处理等。

3.5.2.1 ty_image类 - 图像封装类

功能 :封装图像数据,提供图像处理功能


3.5.2.2 DeviceSession结构 - 设备会话结构

功能 :管理单个设备的会话状态

cpp 复制代码
struct DeviceSession {
    TY_INTERFACE_HANDLE hIface;              // 接口句柄
    TY_DEV_HANDLE hDevice;                   // 设备句柄
    TY_CAM_PROTOCOL protocol;                // 设备协议
    FrameCallback frameCB;                    // 帧回调
    EventCallback eventCB;                    // 事件回调
    void* userdata;                          // 用户数据
    
    std::shared_ptr<TYCamXmlParametersBase> m_xml_parameter;  // XML配置
    DeviceInitCallback initCB;                // 初始化回调
    void* initUserdata;                      // 初始化用户数据
    
    std::atomic<bool> user_closed;           // 用户是否关闭
    std::atomic<bool> running;                // 是否运行中
    std::vector<std::vector<unsigned char>> buffers;  // 缓冲区
    std::thread worker;                      // 工作线程
    std::mutex cb_mutex;                     // 回调互斥锁
    std::string device_id;                    // 设备ID
    std::string device_model;                 // 设备型号
    std::atomic<bool> offline_reported;      // 是否已报告离线
    
    int enable_depth;                         // 是否启用深度
    int enable_leftir;                        // 是否启用左红外
    int enable_rightir;                       // 是否启用右红外
    int enable_color;                        // 是否启用彩色
    
    std::atomic<bool> reconnect_pending;      // 是否待重连
    
    bool is_depth_need_undist;               // 深度是否需要去畸变
    TY_CAMERA_CALIB_INFO depth_calib_data;   // 深度标定数据
    TY_CAMERA_CALIB_INFO color_calib_data;   // 彩色标定数据
    
    ty_image depth_image;                    // 深度图像
    ty_image color_image;                    // 彩色图像
};
3.5.2.3 全局变量


3.5.2.4 主要函数接口表



3.5.2.5 辅助函数接口表
3.5.2.6 TY_CAM_Init() - SDK初始化

功能 :初始化SDK环境,启动枚举线程和重连线程

实现流程 :

cpp 复制代码
1. 检查SDK是否已初始化
2. 初始化TY SDK (TYInitLib)
3. 启动枚举线程
4. 启动重连线程(如果启用自动重连)
5. 设置初始化标志
6. 返回成功
3.5.2.7 TY_CAM_GetDeviceList() - 获取设备列表

功能 :获取当前可用的设备列表

实现流程 :

cpp 复制代码
1. 检查SDK是否已初始化
2. 等待枚举线程完成设备列表更新
3. 复制设备列表到输出参数
4. 返回设备数量
3.5.2.8 TY_CAM_OpenDeviceByIP() - 通过IP打开设备

功能 :通过IP地址打开设备

实现流程 :

cpp 复制代码
1. 查找匹配IP的设备信息
2. 打开接口 (TYOpenInterface)
3. 打开设备 (TYOpenDevice)
4. 确定设备协议
5. 创建设备会话 (DeviceSession)
6. 初始化标定数据
7. 注册内部事件回调
8. 添加到活跃会话映射
9. 返回设备句柄
3.5.2.9 TY_CAM_SetDeviceInitConfigFile() - 设置XML配置文件

功能 :设置设备的XML配置文件

实现流程 :

cpp 复制代码
1. 检查XML文件是否存在
2. 解析XML文件 (parseConfigToMap)
3. 验证设备型号(如果不强制)
4. 保存配置到设备配置列表
5. 返回成功
3.5.2.10 TY_CAM_EnableComponents() - 启用设备组件

功能 :启用设备的指定组件

实现流程 :

cpp 复制代码
1. 查找设备会话
2. 保存启用标志
3. 根据协议启用组件
   - GenICam: TYEnableComponents
   - Custom: TYEnableComponents
4. 返回成功
3.5.2.11 TY_CAM_StartCapture() - 开始采集

功能 :开始数据采集

实现流程 :

cpp 复制代码
1. 查找设备会话
2. 调用初始化回调 (CallInitCallback)
3. 注册帧回调
4. 启动采集 (TYStartCapture)
5. 启动工作线程
6. 设置运行标志
7. 返回成功
3.5.2.12 ReconnectDevice() - 重连设备

功能 :自动重连离线设备

实现流程

cpp 复制代码
1. 查找目标会话
2. 检查设备是否在线
3. 停止工作线程和采集
4. 保存旧句柄
5. 打开新接口和设备
6. 更新会话句柄
7. 重新初始化标定数据
8. 重新启用组件
9. 重新开始采集
10. 清理旧句柄
11. 返回重连结果

3.5.3 TYThread.cpp

实现了一个跨平台的C++线程封装类

cpp 复制代码
#include "TYThread.hpp"

#ifdef _WIN32

#include <windows.h>
class TYThreadImpl
{
public:
  TYThreadImpl() : _thread(NULL) {}
  int  create(TYThread::Callback_t cb, void* arg) {
    DWORD  dwThreadId = 0;
    _thread = CreateThread(
        NULL,                   // default security attributes
        0,                      // use default stack size
        (LPTHREAD_START_ROUTINE)cb, // thread function name
        arg,                    // argument to thread function
        0,                      // use default creation flags
        &dwThreadId);           // returns the thread identifier
    return 0;
  }
  int destroy() {
    // TerminateThread(_thread, 0);
    switch (WaitForSingleObject(_thread, INFINITE))
    {
    case WAIT_OBJECT_0:
      if (CloseHandle(_thread)) {
        _thread = 0;
        return 0;
      }
      else {
        return -1;
      }
    default:
      return -2;
    }
  }
private:
  HANDLE _thread;
};

#else // _WIN32

#include <pthread.h>
class TYThreadImpl {
    int create(Callback_t cb, void* arg) {
        int ret = pthread_create(&_thread, NULL, cb, arg);
        return ret;
    }
    
    int destroy() {
        pthread_join(_thread, NULL);  // 等待线程结束
        return 0;
    }
private:
    pthread_t _thread;
};

#endif // _WIN32

////////////////////////////////////////////////////////////////////////////

TYThread::TYThread()
{
  impl = new TYThreadImpl();
}

TYThread::~TYThread()
{
  delete impl;
  impl = NULL;
}

int TYThread::create(Callback_t cb, void* arg)
{
  return impl->create(cb, arg);
}

int TYThread::destroy()
{
  return impl->destroy();
}
3.5.3.1 主要函数接口表
3.5.3.2 使用举例
cpp 复制代码
void* thread_func(void* arg) {
    // 线程执行代码
    return nullptr;
}

TYThread thread;
thread.create(thread_func, nullptr);
// ... 主线程继续执行
thread.destroy();  // 等待线程结束

3.5.4 XmlConfig.cpp

提供XML配置文件的解析和设备参数配置功能,支持GenICam和自定义协议两种设备类型。

3.5.4.1 主要函数接口表


3.5.4.2 特性名称到特征ID映射(GigE 2.0协议)
cpp 复制代码
static std::map<std::string, TY_FEATURE_ID> m_gige_2_0_feature_map = {
    {"TriggerDelay", TY_INT_TRIGGER_DELAY_US},
    {"ExposureAuto", TY_BOOL_AUTO_EXPOSURE},
    {"ExposureTime", TY_INT_EXPOSURE_TIME},
    {"PixelFormat", TY_ENUM_IMAGE_MODE},
    {"AcquisitionFrameRate", TY_STRUCT_TRIGGER_PARAM_EX},
    {"AcquisitionMode", TY_STRUCT_TRIGGER_PARAM_EX},
    {"DepthRangeMin", TY_INT_DEPTH_MIN_MM},
    {"DepthRangeMax", TY_INT_DEPTH_MAX_MM},
    // ... 更多映射
};
3.5.4.3 像素格式映射
cpp 复制代码
static std::map<int64_t, TY_PIXEL_FORMAT> m_gige_2_0_pix_format_map = {
    {TYPixelFormatMono8, TY_PIXEL_FORMAT_MONO},
    {TYPixelFormatBayerGRBG8, TY_PIXEL_FORMAT_BAYER8GB},
    {TYPixelFormatCoord3D_C16, TY_PIXEL_FORMAT_DEPTH16},
    {TYPixelFormatYUV422_8, TY_PIXEL_FORMAT_YUYV},
    {TYPixelFormatRGB8, TY_PIXEL_FORMAT_RGB},
    // ... 更多映射
};
3.5.4.4 parseConfigToMap() - XML解析函数

功能 :解析XML配置文件,转换为内存中的映射表结构
实现流程

cpp 复制代码
1. 检查XML文件是否存在
2. 加载XML文档 (tinyxml2::XMLDocument::LoadFile)
3. 获取根元素
4. 读取设备型号 (<device>)
5. 读取配置版本 (<config version>)
6. 遍历所有源 (<source>)
7. 遍历每个源的所有特性 (<feature>)
8. 构建配置映射表
9. 返回解析结果
cpp 复制代码
bool parseConfigToMap(const char* xmlFilePath, 
                      std::string& deviceModel,
                      std::map<std::string, std::vector<FeatureConfig>>& configMap) {
    // 1-2. 加载XML文档
    tinyxml2::XMLDocument doc;
    tinyxml2::XMLError error = doc.LoadFile(xmlFilePath);
    
    // 3. 获取根元素
    tinyxml2::XMLElement* root = doc.RootElement();
    
    // 4. 读取设备型号
    tinyxml2::XMLElement* deviceElem = root->FirstChildElement("device");
    deviceModel = deviceElem->GetText();
    
    // 5-8. 解析配置
    tinyxml2::XMLElement* configElem = root->FirstChildElement("config");
    for (tinyxml2::XMLElement* sourceElem = configElem->FirstChildElement("source");
         sourceElem != nullptr;
         sourceElem = sourceElem->NextSiblingElement("source")) {
        
        const char* sourceName = sourceElem->Attribute("name");
        std::vector<FeatureConfig> features;
        
        for (tinyxml2::XMLElement* featureElem = sourceElem->FirstChildElement("feature");
            featureElem != nullptr;
            featureElem = featureElem->NextSiblingElement("feature")) {
            
            FeatureConfig config;
            config.feature_name = featureElem->Attribute("name");
            config.feature_text = featureElem->GetText();
            features.push_back(config);
        }
        
        configMap[sourceNameStr] = features;
    }
    
    return true;
}
3.5.4.5TYCamXmlParametersGenICam::config() - GenICam设备配置

功能 :配置GenICam协议设备(GigE Vision、USB3 Vision)
实现流程

cpp 复制代码
1. 遍历所有源配置
2. 检查是否为有效源(Depth、Texture、Left、Right)
3. 读取当前源 (TYEnumGetString "SourceSelector")
4. 如果需要,切换到目标源 (TYEnumSetString "SourceSelector")
5. 遍历源的所有特性
6. 获取参数类型 (TYParamGetType)
7. 根据参数类型设置值
   - Integer: TYIntegerSetValue
   - Float: TYFloatSetValue
   - Boolean: TYBooleanSetValue
   - Enumeration: TYEnumSetValue
   - String: TYStringSetValue
8. 输出配置日志
9. 返回配置结果
cpp 复制代码
int TYCamXmlParametersGenICam::config() {
    for(auto& iter : xml_cfg) {
        static std::set<std::string> source_list = {
            "Depth", "Texture", "Left", "Right"
        };
        
        const std::string& source = iter.first;
        bool is_valid_source = (source_list.find(source) != source_list.end());
        
        // 2-4. 切换源
        if(is_valid_source) {
            char szSourceString[200];
            TYEnumGetString(hDevice, "SourceSelector", szSourceString, sizeof(szSourceString));
            
            if(m_current_source != source) {
                TYEnumSetString(hDevice, "SourceSelector", source.c_str());
            }
        }
        
        // 5-7. 配置特性
        for(auto& feat : iter.second) {
            ParamType type;
            TYParamGetType(hDevice, feat.feature_name.c_str(), &type);
            
            switch(type) {
                case Integer: {
                    int64_t val = 0;
                    tryParseInt64(feat.feature_text, val);
                    TYIntegerSetValue(hDevice, feat.feature_name.c_str(), val);
                    break;
                }
                case Float: {
                    double val = atof(feat.feature_text.c_str());
                    TYFloatSetValue(hDevice, feat.feature_name.c_str(), val);
                    break;
                }
                // ... 其他类型
            }
        }
    }
    
    return TY_STATUS_OK;
}
3.5.4.6 TYCamXmlParametersCustom::config() - 自定义协议设备配置

功能:配置自定义协议设备
实现流程

cpp 复制代码
1. 重置设备状态 (device_status_init)
2. 遍历所有源配置
3. 映射源名称到组件ID
   - Depth -> TY_COMPONENT_DEPTH_CAM
   - Texture -> TY_COMPONENT_RGB_CAM
   - Left -> TY_COMPONENT_IR_CAM_LEFT
   - Right -> TY_COMPONENT_IR_CAM_RIGHT
   - Device -> TY_COMPONENT_DEVICE
   - Laser -> TY_COMPONENT_LASER
4. 根据组件ID配置参数
5. 处理特殊参数(AEC ROI、触发模式、帧率控制等)
6. 应用配置到设备
7. 返回配置结果
cpp 复制代码
int TYCamXmlParametersCustom::config() {
    device_status_init();
    
    static std::map<std::string, TY_COMPONENT_ID> source_map = {
        {"Depth", TY_COMPONENT_DEPTH_CAM},
        {"Texture", TY_COMPONENT_RGB_CAM},
        {"Left", TY_COMPONENT_IR_CAM_LEFT},
        {"Right", TY_COMPONENT_IR_CAM_RIGHT},
        {"Device", TY_COMPONENT_DEVICE},
        {"Laser", TY_COMPONENT_LASER}
    };
    
    for(auto& iter : xml_cfg) {
        auto comp = source_map.find(iter.first);
        if(comp != source_map.end()) {
            TY_COMPONENT_ID compID = comp->second;
            
            // 处理彩色相机的AEC ROI
            if(compID == TY_COMPONENT_RGB_CAM) {
                auto offsetX = findFeatureText(iter.second, "AutoFunctionAOIOffsetX");
                auto offsetY = findFeatureText(iter.second, "AutoFunctionAOIOffsetY");
                // ... 设置AEC ROI
            }
            
            // 配置其他参数
            for(auto& feat : iter.second) {
                try_xml_parameter(compID, feat.feature_name, feat.feature_text);
            }
        }
    }
    
    return TY_STATUS_OK;
}

3.6 tinyxml2文件夹

3.6.1 类层次结构图

cpp 复制代码
XMLNode (基类)
    ├── XMLDocument (文档类)
    ├── XMLElement (元素类)
    ├── XMLText (文本类)
    ├── XMLComment (注释类)
    ├── XMLDeclaration (声明类)
    └── XMLUnknown (未知节点类)

XMLAttribute (属性类,独立于XMLNode)
XMLPrinter (打印类,用于生成XML)

3.6.2 类功能对比表

3.6.3 XMLNode - XML节点基类

类作用:所有XML节点的基类,提供通用的节点操作接口。

3.6.3.1 主要方法表


3.6.3.2 使用举例
cpp 复制代码
XMLNode* node = ...;
XMLElement* element = node->ToElement();
if (element) {
    const char* value = element->Value();
    XMLNode* child = element->FirstChild();
}

3.6.4 XMLDocument - XML文档类

类作用:代表整个XML文档,是XML树的根节点,负责文档的加载、保存和内存管理。

3.6.4.1 主要方法表


3.6.4.2 错误码枚举
cpp 复制代码
enum XMLError {
    XML_SUCCESS = 0,              // 成功
    XML_NO_ATTRIBUTE,             // 属性不存在
    XML_WRONG_ATTRIBUTE_TYPE,      // 属性类型错误
    XML_ERROR_FILE_NOT_FOUND,      // 文件未找到
    XML_ERROR_FILE_COULD_NOT_BE_OPENED,  // 文件无法打开
    XML_ERROR_FILE_READ_ERROR,     // 文件读取错误
    XML_ERROR_ELEMENT_MISMATCH,    // 元素不匹配
    XML_ERROR_PARSING_ELEMENT,     // 元素解析错误
    XML_ERROR_PARSING_ATTRIBUTE,   // 属性解析错误
    XML_ERROR_PARSING_TEXT,        // 文本解析错误
    XML_ERROR_PARSING_CDATA,       // CDATA解析错误
    XML_ERROR_PARSING_COMMENT,     // 注释解析错误
    XML_ERROR_PARSING_DECLARATION, // 声明解析错误
    XML_ERROR_PARSING_UNKNOWN,     // 未知内容解析错误
    XML_ERROR_EMPTY_DOCUMENT,      // 空文档
    XML_ERROR_MISMATCHED_ELEMENT,   // 元素不匹配
    XML_ERROR_PARSING,            // 通用解析错误
    XML_CAN_NOT_CONVERT_TEXT,      // 文本转换错误
    XML_NO_TEXT_NODE              // 无文本节点
};
3.6.4.3 使用举例
cpp 复制代码
// 创建文档
tinyxml2::XMLDocument doc;

// 从文件加载
tinyxml2::XMLError error = doc.LoadFile("config.xml");
if (error != tinyxml2::XML_SUCCESS) {
    std::cerr << "Error: " << doc.ErrorStr() << std::endl;
    return false;
}

// 获取根元素
tinyxml2::XMLElement* root = doc.RootElement();

// 保存到文件
doc.SaveFile("output.xml");

3.6.5 XMLElement - XML元素类

类作用:代表XML元素节点,支持属性操作和子元素遍历。

3.6.5.1 主要方法表


3.6.5.2 使用举例
cpp 复制代码
XMLElement* element = root->FirstChildElement("device");

// 获取属性
const char* name = element->Attribute("name");
int id = 0;
element->QueryIntAttribute("id", &id);

// 设置属性
element->SetAttribute("version", "1.0");
element->SetAttribute("count", 10);

// 获取文本内容
const char* text = element->GetText();

// 遍历子元素
for (XMLElement* child = element->FirstChildElement("feature");
     child != nullptr;
     child = child->NextSiblingElement("feature")) {
    // 处理每个feature元素
}

3.6.6 XMLAttribute - XML属性类

类作用:代表XML元素的属性,提供属性值的访问和修改。

3.6.6.1 主要方法表
3.6.6.2 使用举例
cpp 复制代码
XMLElement* element = ...;

// 遍历所有属性
for (const XMLAttribute* attr = element->FirstAttribute();
     attr != nullptr;
     attr = attr->Next()) {
    const char* name = attr->Name();
    const char* value = attr->Value();
    std::cout << name << " = " << value << std::endl;
}

3.6.7 XMLText - XML文本类

类作用:代表XML元素的文本内容,支持普通文本和CDATA。

3.6.7.1 主要方法表
3.6.7.2 使用举例
cpp 复制代码
XMLText* text = doc.NewText("This is text content");
text->SetCData(false);  // 普通文本

XMLText* cdata = doc.NewText("<special>content</special>");
cdata->SetCData(true);  // CDATA格式

3.6.8 XMLComment - XML注释类

类作用:代表XML注释节点。

3.6.8.1 使用举例
cpp 复制代码
XMLComment* comment = doc.NewComment("This is a comment");
element->InsertEndChild(comment);

3.6.9 XMLDeclaration - XML声明类

类作用:代表XML文档声明(如 <?xml version="1.0"?>)

3.6.9.1 使用举例
cpp 复制代码
XMLDeclaration* decl = doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"");
doc.InsertFirstChild(decl);

3.6.10 XMLPrinter - XML打印类

类作用:用于生成XML字符串或文件,支持格式化输出。

3.6.10.1 主要方法表
3.6.10.2 使用举例
cpp 复制代码
XMLPrinter printer;
printer.OpenElement("root");
printer.PushAttribute("version", "1.0");
printer.OpenElement("device");
printer.PushText("DeviceName");
printer.CloseElement();
printer.CloseElement();

const char* xml = printer.CStr();
std::cout << xml << std::endl;

3.6.11 在本项目中的应用

3.6.11.1使用位置
  • 文件 : src/XmlConfig.cpp
  • 功能 :解析相机配置的XML文件
3.6.11.2 典型使用流程
cpp 复制代码
// 1. 创建文档对象
tinyxml2::XMLDocument doc;

// 2. 加载XML文件
tinyxml2::XMLError error = doc.LoadFile(xmlFilePath);
if (error != tinyxml2::XML_SUCCESS) {
    std::cerr << "Error loading XML file: " << doc.ErrorStr() << std::endl;
    return false;
}

// 3. 获取根元素
tinyxml2::XMLElement* root = doc.RootElement();

// 4. 读取设备型号
tinyxml2::XMLElement* deviceElem = root->FirstChildElement("device");
const char* modelText = deviceElem->GetText();

// 5. 读取配置版本
tinyxml2::XMLElement* configElem = root->FirstChildElement("config");
const char* configVersion = configElem->Attribute("version");

// 6. 遍历所有源
for (tinyxml2::XMLElement* sourceElem = configElem->FirstChildElement("source");
     sourceElem != nullptr;
     sourceElem = sourceElem->NextSiblingElement("source")) {
    
    // 获取源名称
    const char* sourceName = sourceElem->Attribute("name");
    
    // 遍历所有特性
    for (tinyxml2::XMLElement* featureElem = sourceElem->FirstChildElement("feature");
        featureElem != nullptr;
        featureElem = featureElem->NextSiblingElement("feature")) {
        
        // 获取特性名称和值
        const char* featureName = featureElem->Attribute("name");
        const char* text = featureElem->GetText();
        
        // 保存到配置映射
        FeatureConfig config;
        config.feature_name = featureName;
        config.feature_text = text;
        features.push_back(config);
    }
}

4.补充资料

1.tinyxml2的入门教程

2.TinyXML2交叉编译与使用指南

相关推荐
爱凤的小光1 个月前
图漾PS800-E1相机专栏(待完善)
图漾相机
爱凤的小光1 个月前
图漾TM461-E2相机专栏
图漾相机
爱凤的小光2 个月前
解析图漾相机录制的bag视频文件
图漾相机
爱凤的小光9 个月前
图漾相机错误码解析
数码相机·图漾相机
爱凤的小光9 个月前
图漾相机——Sample_V2示例程序(待补充)
3d·图漾相机
爱凤的小光1 年前
图漾PercipioIPTool软件使用
图漾相机
爱凤的小光1 年前
图漾相机基础操作
图漾相机