Orbbec SDK 文档
欢迎阅读Orbbec SDK(以下简称“SDK”)的使用教程!SDK 不仅提供了简洁的高阶API,又提供全面、灵活的低阶API,能够让您更快速的了解和使用奥比中光3D传感摄像头。
代码示例——C&C++示例说明
获取所有示例都可以在工程的Examples目录中找到
名称 | 语言 | 描述 |
---|---|---|
HelloOrbbec | C | 演示连接到设备获取SDK版本和设备信息 |
固件升级示例 | C | 演示选择固件bin或者img文件给设备升级固件版本 |
传感器控制示例 | C | 演示对设备、传感器控制命令的操作 |
深度示例 | C | 演示使用SDK获取深度数据并绘制显示、获取分辨率并进行设置、显示深度图像 |
彩色示例 | C | 演示使用SDK获取彩色数据并绘制显示、获取分辨率并进行设置、显示彩色图像 |
红外示例 | C | 演示使用SDK获取红外数据并绘制显示、获取分辨率并进行设置、显示红外图像 |
深度模式 | C | 演示如何获取相机深度工作模式,查询支持的深度模式列表,切换模式 |
热拔插示例 | C | 演示设备热拔插监控,检测到设备上线自动连接设备打开深度流,检测到设备掉线自动断开设备连接 |
点云示例 | C | 演示生成深度点云或RGBD点云并保存成ply格式文件 |
HelloOrbbec | C++ | 演示连接到设备获取SDK版本和设备信息 |
深度示例 | C++ | 演示使用SDK获取深度数据并绘制显示、获取分辨率并进行设置、显示深度图像 |
彩色示例 | C++ | 演示使用SDK获取彩色数据并绘制显示、获取分辨率并进行设置、显示彩色图像 |
红外示例 | C++ | 演示使用SDK获取红外数据并绘制显示、获取分辨率并进行设置、显示红外图像 |
流对齐示例 | C++ | 演示对传感器数据流对齐的操作 |
固件升级示例 | C++ | 演示选择固件bin或者img文件给设备升级固件版本 |
传感器控制示例 | C++ | 演示对设备和传感器控制命令的操作 |
多路流同时开流示例 | C++ | 演示一个设备同时打开多路流的操作 |
多设备示例 | C++ | 演示对多设备进行操作 |
深度模式 | C++ | 演示如何获取相机深度工作模式,查询支持的深度模式列表,切换模式 |
热拔插示例 | C++ | 演示设备拔插回调的设置,并获取到插拔后处理的流 |
IMU示例 | C++ | 获取IMU数据并输出显示 |
多机同步示例 | C++ | 演示多机同步功能 |
点云示例 | C++ | 演示生成深度点云或RGBD点云并保存成ply格式文件 |
存储示例 | C++ | 获取彩色和深度图并存储为png格式 |
录制示例 | C++ | 录制当前视频流到文件 |
回放示例 | C++ | 载入视频文件进行回放 |
C
HelloOrbbec
功能描述:用于演示SDK初始化、获取SDK版本、获取设备型号、获取设备序列号、获取固件版本号、SDK释放资源。本示例基于C Low Level API进行演示首先获取并打印当前SDK版本
printf("SDK version: %d.%d.%d\n", ob_get_major_version(), ob_get_minor_version(), ob_get_patch_version());
ob_error* error = NULL;
ob_context* ctx = ob_create_context( &error );
ob_device_list* dev_list = ob_query_device_list( ctx, &error );
int dev_count = ob_device_list_device_count(dev_list, &error);
if(dev_count == 0) {
printf("Device not found!\n");
return -1;
}
ob_device* dev = ob_device_list_get_device(dev_list, 0, &error);
//获取设备信息
ob_device_info* dev_info = ob_device_get_device_info(dev, &error);
//获取设备名称
const char* name = ob_device_info_name(dev_info, &error);
//获取设备的pid, vid, uid
int pid = ob_device_info_pid(dev_info, &error);
int vid = ob_device_info_vid(dev_info, &error);
int uid = ob_device_info_uid(dev_info, &error);
//通过获取设备的固件版本号
const char* fw_ver = ob_device_info_firmware_version(dev_info, &error);
//通过获取设备的序列号
const char* sn = ob_device_info_serial_number(dev_info, &error);
//获取支持的传感器列表
ob_sensor_list* sensor_list = ob_device_get_sensor_list(dev, &error);
//获取传感器数量
int count = ob_sensor_list_get_sensor_count(sensor_list, &error);
for(int i = 0; i < count; i++)
{
ob_sensor_type sensor_type = ob_sensor_list_get_sensor_type(sensor_list, i, &error);
switch (sensor_type)
{
case OB_SENSOR_COLOR:
break;
case OB_SENSOR_DEPTH:
break;
case OB_SENSOR_IR:
break;
}
}
//销毁sensor list
ob_delete_sensor_list(sensor_list, &error);
//销毁device info
ob_delete_device_info(dev_info, &error);
//销毁device
ob_delete_device(dev, &error);
//销毁device list
ob_delete_device_list(dev_list, &error);
//销毁context
ob_delete_context(ctx, &error);
固件升级示例-FirmwareUpgrade
功能描述:本示例演示如何用固件文件给设备升级。本示例基于C Low Level API进行演示,示例编译语言为C++,Orbbec SDK使用C语言API在main函数接口通过命令参数获取固件文件
// check_firmware_file_path()函数用于检查文件是否存在,实际代码中最好检查后缀是否为bin或者img, 以及固件文件是否与目标设备相匹配
const char *check_firmware_file_path(int argc, char **argv) {
if(argc < 2) {
printf("Please input firmware path.\n");
return "";
}
const char *filePath = *(argv + 1);
FILE *file = fopen(filePath, "r");
if(!file) {
printf("Open Firmware file failed. filePath: %s\n", filePath);
return "";
}
fclose(file);
return filePath;
}
int main(int argc, char **argv) {
const char *firmware_file_path = check_firmware_file_path(argc, argv);
if(!firmware_file_path || 0 == strlen(firmware_file_path)) {
printf("command: \n$ ./frameware_upgrade[.exe] firmwareFile.bin\n");
return 0;
}
// 接下来的业务代码
return 0;
}
// 构建ob_context对象
ob_error *error = NULL;
ob_context *ctx = ob_create_context(&error);
check_error(error);
// 设置设备变化监听器,device_changed_callback是管理device声明周期的关键函数,开发者必须关注该回调
ob_set_device_changed_callback(ctx, device_changed_callback, &callback_user_data_, &error);
check_error(error);
// 查询当前已经接入的设备
ob_device_list *dev_list = ob_query_device_list(ctx, &error);
check_error(error);
// 从ob_device_list中获取当前接入设备的数量
int dev_count = ob_device_list_device_count(dev_list, &error);
check_error(error);
if(dev_count == 0) {
// 固件升级示例假设设备已经接入到上位机(Windows、Ubuntu、Android平台)
printf("Device not found!\n");
return -1;
}
// 获取第一个设备,index=0
ob_device *dev = ob_device_list_get_device(dev_list, 0, &error);
check_error(error);
// 打印设备信息
dump_device_info(dev);
// 打印设备名称,SN,VID,PID以及固件版本
void dump_device_info(ob_device *device) {
ob_error *error = NULL;
// 获取ob_device_info对象,通过ob_device_info可以获取目标设备的基本信息
ob_device_info *dev_info = ob_device_get_device_info(device, &error);
check_error(error);
// 设备名称
const char *name = ob_device_info_name(dev_info, &error);
check_error(error);
printf("Device name: %s\n", name);
// 设备VID,PID,UID
int pid = ob_device_info_pid(dev_info, &error);
check_error(error);
int vid = ob_device_info_vid(dev_info, &error);
check_error(error);
const char *uid = ob_device_info_uid(dev_info, &error);
check_error(error);
printf("Device pid: %d vid: %d uid: %s\n", pid, vid, uid);
// 设备当前的固件版本号
const char *fw_ver = ob_device_info_firmware_version(dev_info, &error);
check_error(error);
printf("Firmware version: %s\n", fw_ver);
// 设备SN
const char *sn = ob_device_info_serial_number(dev_info, &error);
check_error(error);
printf("Serial number: %s\n", sn);
// 释放资源,否则会造成内存泄漏
ob_delete_device_info(dev_info, &error);
check_error(error);
}
// 实现C API的固件升级回调接口;
void device_upgrade_callback(ob_upgrade_state state, const char *message, uint8_t percent, void *user_data) {
if(state == STAT_START) {
printf("Upgrade Firmware start\n");
}
else if(state == STAT_FILE_TRANSFER) {
printf("Upgrade Firmware file transfer, percent: %u\n", (uint32_t)percent);
}
else if(state == STAT_IN_PROGRESS) {
printf("Upgrade Firmware in progress, percent: %u\n", (uint32_t)percent);
}
else if(state == STAT_DONE) {
// 固件升级成功
printf("Upgrade Firmware done, percent: %u\n", (uint32_t)percent);
is_upgrade_success_ = true;
}
else if(state == STAT_VERIFY_IMAGE) {
printf("Upgrade Firmware verify image\n");
}
else {
// 固件升级失败
printf("Upgrade Firmware failed. state: %d, errMsg: %s, percent: %u \n", (int)state, message ? message : "", (uint32_t)percent);
}
}
// 对目标设备进行固件升级
bool upgrade_firmware(ob_device *device, const char *firmwarePath) {
const char *index = strstr(firmwarePath, ".img");
bool isImgFile = (bool)index;
index = strstr(firmwarePath, ".bin");
bool isBinFile = (bool)index;
if(!(isImgFile || isBinFile)) {
// 固件升级文件一般为bin或者img,实际业务中最好通过文件名称、文件MD5等信息做防呆
printf("Upgrade Fimware failed. invalid firmware file: %s\n", firmwarePath);
return false;
}
// 调用固件升级接口进行升级;
is_upgrade_success_ = false;
ob_error *error = NULL;
ob_device_upgrade(device, firmwarePath, device_upgrade_callback, false, &callback_user_data_, &error);
check_error(error);
return is_upgrade_success_;
}
// 重启设备
printf("Reboot device\n");
is_device_removed_ = false;
is_wait_reboot_complete_ = true;
ob_device_reboot(dev, &error);
check_error(error);
// 释放资源,防止内存泄漏
ob_delete_device(dev, &error);
check_error(error);
// 监听设备变化
void device_changed_callback(ob_device_list *removed, ob_device_list *added, void *user_data) {
ob_error *error = NULL;
// 通过added处理上线的设备
// 通过removed处理下线的设备
// 释放资源,避免内存泄漏
ob_delete_device_list(removed, &error);
check_error(error);
// 释放资源,避免内存泄漏
ob_delete_device_list(added, &error);
check_error(error);
}
传感器控制示例-SensorControl
功能描述:本示例主要演示了对device控制命令的操作、对Sensor控制命令的操作、对Sensor进行流操作。本示例基于C Low Level API进行演示创建一个Context,并查询已经接入设备的列表
ob_error* error = NULL;
ob_context* ctx = ob_create_context( &error );
ob_device_list* dev_list = ob_query_device_list( ctx, &error );
const char *name = ob_device_list_get_device_name(device_list, i, &g_error);
int pid = ob_device_list_get_device_pid(device_list, i, &g_error);
int vid = ob_device_list_get_device_vid(device_list, i, &g_error);
const char *uid = ob_device_list_get_device_uid(device_list, i, &g_error);
const char *sn = ob_device_list_get_device_serial_number(device_list, i, &g_error);
printf("%d. name: %s, pid: %d, vid: %d, uid: %s, sn: %s\n", i, name, pid, vid, uid, sn);
if(devCount <= 1) {
// 如果插入单个设备,默认选择第一个
device = ob_device_list_get_device(dev_list, 0, &g_error);
}
else {
// 如果有多个设备,用户输入选择
device = select_device(dev_list); // select_device 代码请参考实例源码
}
ob_device_info *deviceInfo = ob_device_get_device_info(device, &g_error);
const char *name = ob_device_info_name(deviceInfo, &g_error);
int pid = ob_device_info_pid(deviceInfo, &g_error);
int vid = ob_device_info_vid(deviceInfo, &g_error);
const char *uid = ob_device_info_uid(deviceInfo, &g_error);
printf("Current Device: name: %s, pid: %d, vid: %d, uid: %s\n", name, pid, vid, uid);
// 获取支持控制命令属性个数
uint32_t propertySize = ob_device_get_supported_property_count(device, &g_error);
// 通过索引号i获取控制命令属性项
ob_property_item property_item = ob_device_get_supported_property(device, i, &g_error);
// 读取
bool_ret = ob_device_get_bool_property(device, property_item.id, &g_error);// bool型参数
int_ret = ob_device_get_int_property(device, property_item.id, &g_error);/ int 型参数
float_ret = ob_device_get_float_property(device, property_item.id, &g_error);// float型参数
// 读取命令的值范围、默认值、步进值等信息
ob_int_property_range int_range;
ob_float_property_range float_range;
ob_bool_property_range bool_range;
sprintf(str, "Bool value(min:0, max:1, step:1)"); // bool 型
int_range = ob_device_get_int_property_range(device, property_item.id, &g_error); // int 型
float_range = ob_device_get_float_property_range(device, property_item.id, &g_error); // float型
// 写入
ob_device_set_bool_property(device, property_item.id, bool_value, &g_error); // bool型参数
ob_device_set_int_property(device, property_item.id, int_value, &g_error); // int 型参数
ob_device_set_float_property(device, property_item.id, float_value, &g_error); // float型参数
//销毁context
ob_delete_context(ctx, &g_error);
//销毁device list
ob_delete_device_list(dev_list, &g_error);
//销毁device
ob_delete_device(device, &g_error);
深度示例-DepthViewer
功能描述:演示使用SDK获取深度数据并绘制显示、获取分辨率并进行设置、显示深度图像本示例基于C High Level API进行演示首先需要创建Pipeline,用于连接设备后打开彩色和深度流
pipe = ob_create_pipeline( &error );
ob_config* config = ob_create_config( &error );
//配置Depth流
ob_stream_profile * depth_profile = NULL;
ob_stream_profile_list *profiles = ob_pipeline_get_stream_profile_list(pipe, OB_SENSOR_DEPTH, &error);
//根据指定的格式查找对应的Profile,优先查找Y16格式
depth_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_Y16, 30, &error);
//没找到Y16格式后不匹配格式查找对应的Profile进行开流
if(error){
depth_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_UNKNOWN, 30, &error);
error = nullptr;
}
ob_config_enable_stream(config, depth_profile, &error); // 使能配置
ob_pipeline_start_with_config(pipe, config, &error);
//销毁frameSet,回收内存
ob_delete_frame(frameset, &error);
//销毁profile
ob_delete_stream_profile(depth_profile, &error);
//销毁profile list
ob_delete_stream_profile_list(profiles, &error);
//销毁device
ob_delete_device(device, &error);
//销毁pipeline
ob_delete_pipeline(pipe, &error);
彩色示例-ColorViewer
功能描述:演示使用SDK获取彩色数据并绘制显示、获取分辨率并进行设置、显示彩色图像本示例基于C High Level API进行演示首先需要创建Pipeline,用于连接设备后打开彩色和深度流
pipe = ob_create_pipeline( &error );
ob_config* config = ob_create_config( &error );
//配置Color流
ob_stream_profile * color_profile = NULL;
ob_stream_profile_list *profiles = ob_pipeline_get_stream_profile_list(pipe, OB_SENSOR_Color, &error);
//根据指定的格式查找对应的Profile,优先选择RGB888格式
color_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_RGB, 30, &error);
//没找到RGB888格式后不匹配格式查找对应的Profile进行开流
if(error){
color_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_UNKNOWN, 30, &error);
error = nullptr;
}
ob_config_enable_stream(config, depth_profile, &error); // 使能配置
ob_pipeline_start_with_config(pipe, config, &error);
//销毁frameSet,回收内存
ob_delete_frame(frameset, &error);
//销毁profile
ob_delete_stream_profile(color_profile, &error);
//销毁profile list
ob_delete_stream_profile_list(profiles, &error);
//销毁device
ob_delete_device(device, &error);
//销毁pipeline
ob_delete_pipeline(pipe, &error);
红外示例-InfraredViewer
功能描述:演示使用SDK获取红外数据并绘制显示、获取分辨率并进行设置、显示红外图像本示例基于C High Level API进行演示首先需要创建Pipeline,用于连接设备后打开彩色和深度流
pipe = ob_create_pipeline( &error );
ob_config* config = ob_create_config( &error );
//配置IR流
ob_stream_profile * ir_profile = NULL;
ob_stream_profile_list *profiles = ob_pipeline_get_stream_profile_list(pipe, OB_SENSOR_IR, &error);
//根据指定的格式查找对应的Profile,优先查找Y16格式
ir_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_Y16, 30, &error);
//没找到Y16格式后不匹配格式查找对应的Profile进行开流
if(error) {
ir_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_UNKNOWN, 30, &error);
error = nullptr;
}
ob_config_enable_stream(config, depth_profile, &error); // 使能配置
//判断是否支持切换左右IR通道
if(ob_device_is_property_supported(device, OB_PROP_IR_CHANNEL_DATA_SOURCE_INT, OB_PERMISSION_READ_WRITE, &error)) {
// Gemini 2 和 Gemini 2 L 产品支持SENSOR_IR选择sensor输出,0是左IR,1是右IR。
int32_t dataSource = 0;
ob_device_set_int_property(device, OB_PROP_IR_CHANNEL_DATA_SOURCE_INT, dataSource, &error);
}
ob_pipeline_start_with_config(pipe, config, &error);
//销毁frameSet,回收内存
ob_delete_frame(frameset, &error);
//销毁profile
ob_delete_stream_profile(ir_profile, &error);
//销毁profile list
ob_delete_stream_profile_list(profiles, &error);
//销毁device
ob_delete_device(device, &error);
//销毁pipeline
ob_delete_pipeline(pipe, &error);
切换相机深度工作模式-DepthWorkMode
功能描述:Gemini 2 、Gemini 2 L 、Astra 2、 Gemini 2 XL 设备支持深度工作模式切换。主要演示切换相机深度模式,先查询深度模式列表,然后选择对应的相机深度模式,调用接口切换 首先获取设备//创建一个Context,与Pipeline不同,Context是底层API的入口,在开关流等常用操作上
//使用低级会稍微复杂一些,但是底层API可以提供更多灵活的操作,如获取多个设备,读写
//设备及相机的属性等
ob_error * error = NULL;
ob_context *ctx = ob_create_context(&error);
check_error(error);
//查询已经接入设备的列表
ob_device_list *dev_list = ob_query_device_list(ctx, &error);
check_error(error);
//获取接入设备的数量
int dev_count = ob_device_list_device_count(dev_list, &error);
check_error(error);
if(dev_count == 0) {
printf("Device not found!\n");
return -1;
}
//创建设备,0表示第一个设备的索引
ob_device *dev = ob_device_list_get_device(dev_list, 0, &error);
check_error(error);
// 检查是否支持相机深度工作模式
if(!ob_device_is_property_supported(dev, OB_STRUCT_CURRENT_DEPTH_ALG_MODE, OB_PERMISSION_READ_WRITE, &error)) {
printf("FAILED!!, Device not support depth work mode");
check_error(error);
return -1;
}
check_error(error);
// 查询当前的深度工作模式
ob_depth_work_mode cur_work_mode = ob_device_get_current_depth_work_mode(dev, &error);
check_error(error);
printf("Current depth work mode: %s\n", cur_work_mode.name);
// 获取列表长度
uint32_t mode_count = ob_depth_work_mode_list_count(mode_list, &error);
printf("Support depth work mode list count: %u\n", mode_count);
int cur_mode_index = -1;
for(uint32_t i = 0; i < mode_count; i++) {
ob_depth_work_mode mode = ob_depth_work_mode_list_get_item(mode_list, i, &error);
check_error(error);
printf("depth work mode[%u], name: %s", i, mode.name);
}
// 切换到新的相机深度模式
ob_device_switch_depth_work_mode_by_name(dev, mode.name, &error);
check_error(error);
- 如果需要切换相机深度模式,那么打开数据流必须在切换深度工作模式之后;每个相机深度模式下支持的有效分辨率不同
- 如果已经用pipeline打开数据流,那么切换相机深度工作模式前必须把原来申请的pipeline释放; 切换相机深度工作模式后重新创建pipeline,否则会造成野指针或者内存泄露;
// 销毁mode_list
ob_delete_depth_work_mode_list(mode_list, &error);
check_error(error);
//销毁device
ob_delete_device(dev, &error);
check_error(error);
//销毁device list
ob_delete_device_list(dev_list, &error);
check_error(error);
//销毁context
ob_delete_context(ctx, &error);
check_error(error);
热拔插示例-HotPlugin
功能描述: 设备热拔插监控,检测到设备上线自动连接设备打开深度流,检测到设备掉线自动断开设备连接。本示例基于C Low Level API进行注册设备上下线回调,基于High Level API进行开流取帧演示创建设备连接处理函数,函数内创建pipeline并调用create_and_start_with_config开启彩色流和深度流。
//设备连接处理
void device_connect_callback( ob_device_list* connectList ) {
uint32_t count = ob_device_list_device_count(connectList, &error);
check_error(error);
printf("Device connect: %d\n", count);
if(count > 0) {
if(pipeline == NULL) {
pipeline = ob_create_pipeline(&error);
check_error(error);
create_and_start_with_config();
}
}
}
//设备断开处理
void device_disconnect_callback( ob_device_list* disconnectList ) {
uint32_t count = ob_device_list_device_count(disconnectList, &error);
check_error(error);
printf("Device disconnect: %d\n", count);
if(count > 0) {
isExit = true;
}
}
//设备状态改变回调
void on_device_changed_callback( ob_device_list* removed, ob_device_list* added, void* pCallback ) {
device_disconnect_callback( removed );
device_connect_callback( added );
}
//创建上下文
ob_context* ctx = ob_create_context( &error );
//注册设备回调
ob_set_device_changed_callback( ctx, on_device_changed_callback, NULL, &error );
//等待一帧数据,超时时间为100ms
ob_frame* frameset = ob_pipeline_wait_for_frameset( pipeline, 100, &error );
if ( frameset ) {
//获取深度数据帧
ob_frame* depth_frame = ob_frameset_depth_frame( frameset, &error );
if ( depth_frame ) {
printf( "=====Depth Frame Info======Index: %lld TimeStamp: %lld\n", ob_frame_index( depth_frame, &error ), ob_frame_time_stamp( depth_frame, &error ) );
//释放深度数据帧
ob_delete_frame( depth_frame, &error );
}
//获取Color数据帧
ob_frame* color_frame = ob_frameset_color_frame( frameset, &error );
if ( color_frame ) {
printf( "=====Color Frame Info======Index: %lld TimeStamp: %lld\n", ob_frame_index( color_frame, &error ), ob_frame_time_stamp( color_frame, &error ) );
//释放Color数据帧
ob_delete_frame( color_frame, &error );
}
//释放frameSet
ob_delete_frame( frameset, &error );
}
if ( pipeline ) {
//停止pipeline
ob_pipeline_stop( pipeline, &error );
// 销毁pipeline
ob_delete_pipeline( pipeline, &error );
}
// 销毁dev_list
if ( dev_list ) {
ob_delete_device_list( dev_list, &error );
}
// 销毁ctx
if ( ctx ) {
ob_delete_context( ctx, &error );
}
点云示例-PointCloud
功能描述:连接设备开流,生成深度点云或RGBD点云并保存成ply格式文件。本示例基于C++ High Level API进行演示创建点云保存成ply格式文件函数,ply文件格式详细描述可在网络上查看
//保存点云数据到ply
void save_points_to_ply( ob_frame* frame, const char* fileName ) {
int pointsSize = ob_frame_data_size( frame, &error ) / sizeof( ob_point );
check_error( error );
FILE* fp = fopen( fileName, "wb+" );
fprintf( fp, "ply\n" );
fprintf( fp, "format ascii 1.0\n" );
fprintf( fp, "element vertex %d\n", pointsSize );
fprintf( fp, "property float x\n" );
fprintf( fp, "property float y\n" );
fprintf( fp, "property float z\n" );
fprintf( fp, "end_header\n" );
ob_point* point = ( ob_point* )ob_frame_data( frame, &error );
check_error( error );
for ( int i = 0; i < pointsSize; i++ ) {
fprintf( fp, "%.3f %.3f %.3f\n", point->x, point->y, point->z );
point++;
}
fflush( fp );
fclose( fp );
}
//保存彩色点云数据到ply
void save_rgb_points_to_ply( ob_frame* frame, const char* fileName ) {
int pointsSize = ob_frame_data_size( frame, &error ) / sizeof( ob_color_point );
check_error( error );
FILE* fp = fopen( fileName, "wb+" );
fprintf( fp, "ply\n" );
fprintf( fp, "format ascii 1.0\n" );
fprintf( fp, "element vertex %d\n", pointsSize );
fprintf( fp, "property float x\n" );
fprintf( fp, "property float y\n" );
fprintf( fp, "property float z\n" );
fprintf( fp, "property uchar red\n" );
fprintf( fp, "property uchar green\n" );
fprintf( fp, "property uchar blue\n" );
fprintf( fp, "end_header\n" );
ob_color_point* point = ( ob_color_point* )ob_frame_data( frame, &error );
check_error( error );
for ( int i = 0; i < pointsSize; i++ ) {
fprintf( fp, "%.3f %.3f %.3f %d %d %d\n", point->x, point->y, point->z, ( int )point->r, ( int )point->g, ( int )point->b );
point++;
}
fflush( fp );
fclose( fp );
}
//创建pipeline 用于连接设备后打开Color和Depth流
pipeline = ob_create_pipeline( &error );
//创建config,用于配置 Color 和 Depth 流的 分辨率、帧率、格式
ob_config* config = ob_create_config( &error );
//配置Depth流
ob_stream_profile * depth_profile = NULL;
ob_stream_profile_list *profiles = ob_pipeline_get_stream_profile_list(pipeline, OB_SENSOR_DEPTH, &error);
//根据指定的格式查找对应的Profile,优先查找Y16格式
depth_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_Y16, 30, &error);
//没找到Y16格式后不匹配格式查找对应的Profile进行开流
if(error){
depth_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_UNKNOWN, 30, &error);
error = NULL;
}
//配置Color流
ob_stream_profile *color_profile = NULL;
profiles = ob_pipeline_get_stream_profile_list(pipeline, OB_SENSOR_COLOR, &error);
if(error){
printf("Current device is not support color sensor!\n");
//如果不存在Color Sensor 点云转换分辨率配置为深度分辨率
ob_config_set_d2c_target_resolution(config,ob_video_stream_profile_width(depth_profile, &error),ob_video_stream_profile_height(depth_profile, &error),&error);
ob_config_set_depth_scale_require(config,false,&error);
error = NULL;
}
//根据指定的格式查找对应的Profile,优先选择RGB888格式
if(profiles){
color_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_RGB, 30, &error);
}
//没找到RGB888格式后不匹配格式查找对应的Profile进行开流
if(profiles && error){
color_profile = ob_stream_profile_list_get_video_stream_profile(profiles, 640, 0, OB_FORMAT_UNKNOWN, 30, &error);
error = NULL;
}
ob_config_enable_stream( config, color_profile, &error ); // 使能配置
//获取device句柄
ob_device *device = ob_pipeline_get_device(pipeline, &error);
// 开启D2C对齐, 生成RGBD点云时需要开启
ob_config_set_align_mode(config,ALIGN_D2C_HW_MODE,&error);
//创建点云Filter对象(点云Filter创建时会在Pipeline内部获取设备参数, 所以尽量在Filter创建前配置好设备)
ob_filter *point_cloud = ob_create_pointcloud_filter(&error);
//从pipeline获取当前开流的相机参数,并传入到点云filter
ob_camera_param camera_param = ob_pipeline_get_camera_param(pipeline, &error);
ob_pointcloud_filter_set_camera_param(point_cloud, camera_param, &error);
//等待一帧数据,超时时间为100ms
ob_frame* frameset = ob_pipeline_wait_for_frames( pipeline, 100, &error );
if ( frameset != NULL )
{
//按R键保存ply数据
if ( ( key == 'R' || key == 'r' ) && frameset != NULL ) {
ob_pointcloud_filter_set_point_format( point_cloud, OB_FORMAT_RGB_POINT, &error );
ob_frame *pointsFrame = ob_filter_process(point_cloud, frameset, &error);
save_rgb_points_to_ply( pointsFrame, "rgb_points.ply" );
ob_delete_frame( pointsFrame, &error );
}
else if ( ( key == 'D' || key == 'd' ) && frameset != NULL ) {
//生成点云并保存
ob_pointcloud_filter_set_point_format( point_cloud, OB_FORMAT_POINT, &error );
ob_frame *pointsFrame = ob_filter_process(point_cloud, frameset, &error);
save_points_to_ply( pointsFrame, "points.ply" );
ob_delete_frame( pointsFrame, &error );
}
ob_delete_frame( frameset, &error ); // 销毁frameSet 回收内存
}
// 停止pipeline
ob_pipeline_stop( pipeline, &error );
// 销毁pipeline
ob_delete_pipeline( pipeline, &error );
ob_delete_context( ctx, &error );