图像获取流程
深度相机的配置和图像获取流程如下图所示。下文以 C++ SDK 例程 Simpleview_FetchFrame 为例详细说明图像获取流程。

图像获取流程图
初始化API
TYInitLib 初始化设备对象等数据结构。
// 加载库
LOGD("Init lib");
ASSERT_OK( TYInitLib() );
// 获取 SDK 版本信息
TY_VERSION_INFO ver;
ASSERT_OK( TYLibVersion(&ver) );
LOGD(" - lib version: %d.%d.%d", ver.major, ver.minor, ver.patch);
打开设备
获取设备列表
初次获取设备信息时可以通过 selectDevice() 查询已连接的设备数量,并获得所有已连接的设备列表。
std::vector<TY_DEVICE_BASE_INFO> selected; ASSERT_OK( selectDevice(TY_INTERFACE_ALL, ID, IP, 1, selected) ); ASSERT(selected.size() > 0); TY_DEVICE_BASE_INFO& selectedDev = selected[0];
打开接口
ASSERT_OK( TYOpenInterface(selectedDev.iface.id, &hIface) );
打开设备
ASSERT_OK( TYOpenDevice(hIface, selectedDev.id, &hDevice) );
配置组件
查询设备的组件状态
// 获取设备支持的组件信息 TY_COMPONENT_ID allComps; ASSERT_OK( TYGetComponentIDs(hDevice, &allComps) );
配置组件并配置属性
设备打开后,默认只有虚拟组件 TY_COMPONENT_DEVICE 是使能状态。
// 查询并使能 RGB 组件+配置 RGB 组件的属性 if(allComps & TY_COMPONENT_RGB_CAM && color) { LOGD("Has RGB camera, open RGB cam"); ASSERT_OK( TYEnableComponents(hDevice, TY_COMPONENT_RGB_CAM) ); //create a isp handle to convert raw image(color bayer format) to rgb image ASSERT_OK(TYISPCreate(&hColorIspHandle)); //Init code can be modified in common.hpp //NOTE: Should set RGB image format & size before init ISP ASSERT_OK(ColorIspInitSetting(hColorIspHandle, hDevice)); //You can call follow function to show color isp supported features // 查询并使能左 IR 组件 if (allComps & TY_COMPONENT_IR_CAM_LEFT && ir) { LOGD("Has IR left camera, open IR left cam"); ASSERT_OK(TYEnableComponents(hDevice, TY_COMPONENT_IR_CAM_LEFT)); } // 查询并使能右 IR 组件 if (allComps & TY_COMPONENT_IR_CAM_RIGHT && ir) { LOGD("Has IR right camera, open IR right cam"); ASSERT_OK(TYEnableComponents(hDevice, TY_COMPONENT_IR_CAM_RIGHT)); } // 查询并使能深度组件+配置深度组件的属性 LOGD("Configure components, open depth cam"); DepthViewer depthViewer("Depth"); if (allComps & TY_COMPONENT_DEPTH_CAM && depth) { /// 配置深度组件的属性(深度图分辨率) TY_IMAGE_MODE image_mode; ASSERT_OK(get_default_image_mode(hDevice, TY_COMPONENT_DEPTH_CAM, image_mode)); LOGD("Select depth map Mode: %dx%d", TYImageWidth(image_mode), TYImageHeight(image_mode)); ASSERT_OK(TYSetEnum(hDevice, TY_COMPONENT_DEPTH_CAM, TY_ENUM_IMAGE_MODE, image_mode)); /// 使能深度组件 ASSERT_OK(TYEnableComponents(hDevice, TY_COMPONENT_DEPTH_CAM)); /// 配置深度组件的属性(scale unit) //depth map pixel format is uint16_t ,which default unit is 1 mm //the acutal depth (mm)= PixelValue * ScaleUnit float scale_unit = 1.; TYGetFloat(hDevice, TY_COMPONENT_DEPTH_CAM, TY_FLOAT_SCALE_UNIT, &scale_unit); depthViewer.depth_scale_unit = scale_unit; }
帧缓冲管理
注解
在进行帧缓冲管理之前,确保已通过 TYEnableComponents() 接口使能了所需的组件,并且通过 TYSetEnum() 接口设置了正确的图像格式和分辨率。这是因为帧缓冲的大小取决于这些设置,否则可能会遇到帧缓冲空间不足的问题。
// 查询当前配置下每个帧缓冲的大小
LOGD("Prepare image buffer");
uint32_t frameSize;
ASSERT_OK( TYGetFrameBufferSize(hDevice, &frameSize) );
LOGD(" - Get size of framebuffer, %d", frameSize);
// 分配帧缓冲
LOGD(" - Allocate & enqueue buffers");
char* frameBuffer[2];
frameBuffer[0] = new char[frameSize];
frameBuffer[1] = new char[frameSize];
// 把分配的帧缓冲推入缓冲队列
LOGD(" - Enqueue buffer (%p, %d)", frameBuffer[0], frameSize);
ASSERT_OK( TYEnqueueBuffer(hDevice, frameBuffer[0], frameSize) );
LOGD(" - Enqueue buffer (%p, %d)", frameBuffer[1], frameSize);
ASSERT_OK( TYEnqueueBuffer(hDevice, frameBuffer[1], frameSize) );
回调函数注册
TYRegisterEventCallback
注册事件回调函数。异常事件发生的时候,会调用 TYRegisterEventCallback 注册的回调函数。以下示例的回调函数中包含重连的异常处理操作。
static bool offline = false;
void eventCallback(TY_EVENT_INFO *event_info, void *userdata)
{
if (event_info->eventId == TY_EVENT_DEVICE_OFFLINE) {
LOGD("=== Event Callback: Device Offline!");
// Note:
// Please set TY_BOOL_KEEP_ALIVE_ONOFF feature to false if you need to debug with breakpoint!
offline = true;
}
}
int main(int argc, char* argv[])
{
LOGD("Register event callback");
ASSERT_OK(TYRegisterEventCallback(hDevice, eventCallback, NULL))
while(!exit && !offline) {
//Fetch and process frame data
}
if (offline) {
//Release resources
TYStopCapture(hDevice);
TYCloseDevice(hDevice);
// Can try re-open and start device to capture image
// or just close interface exit
}
return 0;
}
配置工作模式
根据实际需要配置深度相机工作模式。关于其他工作模式的配置步骤,请参考 工作模式配置。
// 查询工作模式属性有无
bool hasTrigger;
ASSERT_OK(TYHasFeature(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_TRIGGER_PARAM_EX, &hasTrigger));
if (hasTrigger) {
// 配置深度相机工作在模式 0
LOGD("Disable trigger mode");
TY_TRIGGER_PARAM_EX trigger;
trigger.mode = TY_TRIGGER_MODE_OFF;
ASSERT_OK(TYSetStruct(hDevice, TY_COMPONENT_DEVICE, TY_STRUCT_TRIGGER_PARAM_EX, &trigger, sizeof(trigger)));
}
开始图像采集
LOGD("Start capture");
ASSERT_OK( TYStartCapture(hDevice) );
获取帧数据
LOGD("While loop to fetch frame");
bool exit_main = false;
TY_FRAME_DATA frame;
int index = 0;
while(!exit_main) {
int err = TYFetchFrame(hDevice, &frame, -1);
if( err == TY_STATUS_OK ) {
LOGD("Get frame %d", ++index);
int fps = get_fps();
if (fps > 0){
LOGI("fps: %d", fps);
}
cv::Mat depth, irl, irr, color;
parseFrame(frame, &depth, &irl, &irr, &color, hColorIspHandle);
if(!depth.empty()){
depthViewer.show(depth);
}
if(!irl.empty()){ cv::imshow("LeftIR", irl); }
if(!irr.empty()){ cv::imshow("RightIR", irr); }
if(!color.empty()){ cv::imshow("Color", color); }
int key = cv::waitKey(1);
switch(key & 0xff) {
case 0xff:
break;
case 'q':
exit_main = true;
break;
default:
LOGD("Unmapped key %d", key);
}
TYISPUpdateDevice(hColorIspHandle);
LOGD("Re-enqueue buffer(%p, %d)"
, frame.userBuffer, frame.bufferSize);
ASSERT_OK( TYEnqueueBuffer(hDevice, frame.userBuffer, frame.bufferSize) );
}
}
停止采集
ASSERT_OK( TYStopCapture(hDevice) );
关闭设备
// 关闭设备
ASSERT_OK( TYCloseDevice(hDevice));
// 释放接口句柄
ASSERT_OK( TYCloseInterface(hIface) );
ASSERT_OK(TYISPRelease(&hColorIspHandle));
释放API
// 卸载库
ASSERT_OK( TYDeinitLib() );
// 释放分配的内存资源
delete frameBuffer[0];
delete frameBuffer[1];