深度相机调试界面开发工具可供的选择有很多,主流的有QT,imgui,Pangolin等,但是以上的UI界面开发工具或者使用繁琐,入门比较困难,或者需要复杂的环境依赖,无法短时间快速掌握。本文介绍了一个小而美的UI界面开发工具,基于OpenCV的cvui,使用时只需添加一个头文件,控件简单,适合短时间内2D图像处理的快速开发。
一. CVUI介绍
cvui是一个非常简单的UI库,其渲染和UI控件均基于OpenCV实现,因此除OpenCV外无需其他的外部依赖,同时,简单友好的API和只有一个头文件的结构使其可以快速嵌入到项目中,极大地提高开发效率。
cvui演示图:

二. MV-EB435i集成
cvui主要针对2D图像处理,因此我们要从立体相机中获得彩色图,深度图,红外相机图进行渲染。
MV3D_RGBD_FetchFrame(handle, &stFrameData, 5000); //获取帧数据
RIFrameInfo depth = {0};
RIFrameInfo rgb = {0};
parseFrame(&stFrameData, &depth, &rgb);//解析帧数据
cv::Mat color_frame(rgb.nHeight, rgb.nWidth, CV_8UC3, rgb.pData);//将彩色图和深度图转化成OpenCV的Mat格式
cv::Mat depth_frame(depth.nHeight, depth.nWidth, CV_16UC1, depth.pData);
获得待处理的图像后,进行UI控件设置,包括数值窗口,按钮,标题等。
// 显示title
cvui::text(back_ground, 530, 10, "|color view|", 0.8, 0xFFFFFFFF);
cvui::text(back_ground, 1350, 10, "|depth view|", 0.8, 0xFFFFFFFF);
cvui::text(back_ground, 510, 500, "|custom1 view|", 0.8, 0xFFFFFFFF);
cvui::text(back_ground, 1320, 500, "|custom2 view|", 0.8, 0xFFFFFFFF);
//分辨率
int pose_x = 10, pose_y = 10, text_pos_y = 60;
int y_step = 90;
cvui::window(back_ground, pose_x, pose_y, 180, 80, "image width", 0.8);
cvui::text(back_ground, pose_x + 60, text_pos_y, std::to_string(image_width), 0.8, 0xFFFFFFFF);
pose_y += y_step;
text_pos_y += y_step;
cvui::window(back_ground, pose_x, pose_y, 180, 80, "image height", 0.8);
cvui::text(back_ground, pose_x + 60, text_pos_y, std::to_string(image_height), 0.8, 0xFFFFFFFF);
// 鼠标点获取
pose_y += y_step;
text_pos_y += y_step;
cvui::window(back_ground, pose_x, pose_y, 180, 80, "mouse point", 0.8);
cvui::text(back_ground, pose_x + 10, text_pos_y, "(" + std::to_string(mouse_x) + "," + std::to_string(mouse_y) + ")", 0.8, 0xFFFFFFFF);
// 深度值获取
pose_y += y_step;
text_pos_y += y_step;
cvui::window(back_ground, pose_x, pose_y, 180, 80, "depth value", 0.8);
cvui::text(back_ground, pose_x + 50, text_pos_y, std::to_string(depth_value), 0.8, 0xFFFFFFFF);
// 自定义窗口鼠标获取
pose_y += y_step;
text_pos_y += y_step;
cvui::window(back_ground, pose_x, pose_y, 180, 80, "custom mouse", 0.8);
cvui::text(back_ground, pose_x + 10, text_pos_y, "(" + std::to_string(custom_point_x) + "," + std::to_string(custom_point_y) + ")", 0.8, 0xFFFFFFFF);
整体显示控件:

三. 交互区域设置及多窗口
立体相机获取的深度值在调试过程中往往需要针对某一点进行输出,因此可以在UI界面上设置鼠标交互界面,鼠标停留在深度图的某一点上,UI便能实时反映出深度值。需注意的是,在UI界面上已经指定了深度图及彩色图大小,所以要进行坐标转换,才能反映出在真实大小图片的坐标。设置交互区域如下:
// 深度图鼠标交互区域
int status_depth = cvui::iarea(1020, 40, 800, 450);
if (status_depth == cvui::OVER)
{
mouse_x = (cvui::mouse().x - 1020) * image_width / 800;
mouse_y = (cvui::mouse().y - 40) * image_height / 450;
if (!depth_image.empty())
{
depth_value = static_cast(depth_image.at(cv::Point(mouse_x, mouse_y)));
}
}
设置UI多窗口显示使用的是cvui::image()函数,在背景上一共显示了四个界面,分别是彩色图,深度图,自定义图片窗口一,自定义图片窗口二,彩色图和深度图为相机获取的原数据,自定义窗口为用户根据自己需求显示的图片,这里作为演示将彩色图二值化后放在了自定义窗口,实际上可以放置其他满足OpenCV中copyTo()函数要求的Mat类型图片。
// 显示彩色图
if (!color_image.empty())
{
cvui::image(back_ground, 200, 40, color_image);
// 这里作为演示,将彩色图进行二值化,用户可以对custom_image做任何图像处理
cv::cvtColor(color_image, custom_image1, cv::COLOR_BGR2GRAY);
cv::threshold(custom_image1, custom_image1, 150, 255, cv::THRESH_OTSU);
//转换成伪彩色图显示灰度,因为源代码使用了copyTo
cv::cvtColor(custom_image1, custom_image1, cv::COLOR_GRAY2BGR);
}
// 如果彩色图为空,则在该位置显示警告
else
cvui::image(back_ground, 200, 40, empty_image);
// 显示深度图
if (!render_depth.empty())
{
cvui::image(back_ground, 1020, 40, render_depth);
}
else
cvui::image(back_ground, 1020, 40, empty_image);
最后,放置按钮控件,这里用作退出程序和进行录像。
////////////////////////// 按钮部分/////////////////////////////
if (cvui::button(back_ground, 60, 800, "&Record"))
{
enable_record = !enable_record;
}
if (cvui::button(back_ground, 60, 900, "&EXIT"))
{
break;
}
最终画面:

代码链接:https://github.com/Nick-the-remaker/Hikrobot_ros.git