QT集成intel RealSense 双目摄像头
最近一个小项目,用到了双目相机,选用了Intel的RealSense双目相机。功能很简单,就是识别某一个物体,然后对对这个物体进行操作。具体功能随后再说,这里只介绍QT如何集成IntelRealSense相机,就是下面这个。
首先还是下载SDK,https://www.intelrealsense.com/developers/。这个页面有下载地址。不过下载地址是在github上,然后就比较尴尬,很难下载。下载安装完成以后,会得到一个官方提供的查看软件Intel RealSense Viewer。打开可以看图像,见下图。
相机获取了两个图像,上面颜色表示的是深度图。下面是常规照片。还可以用两个图像,合成一个3D的模型。见下图。
除查看软件外,还有用于开发的SDK和样例代码,文件夹结构如下图:
大致看了一下官方提供的样例代码,都可以跑起来,但是都用了第三方的显示库,和opencv。并且都是用的VS。由于这个项目前期用的QT做的设备控制功能,再换VS可能性不大,所以需要在QT里面集成一下。网上搜了一下,资料很少,也不完全能用,还是自己弄把,正文开始:
第一步,给SDK相关文件拷贝到项目路径,lib,include,以及bin,就是dll。include是头文件,写代码的时候用的,只有头文件,没有具体实现,所以还需要lib文件,有了lib才能编译。编译完以后,再运行,就需要用dll文件。
第二步:在pro文件包含include文件夹,和lib文件。lib文件用的是x64。-L是lib文件所在路径,$$PWD是当前路径。-l是lib文件名称,后面是lib文件不带后缀。-L和-l两个后面都是没有空格,直接写。
第三步:创建一个Camera类,继承自QThread,在子线程获取图像,不卡主界面。
#include <QObject>
#include <QThread>
#include <librealsense2/rsutil.h>//包含sdk文件
#include <librealsense2/rs.hpp>//包含sdk文件
#include <QImage>
class Camera :public QThread
{Q_OBJECT
public:Camera();static Camera* getInstance();//单例模式void startCapture(); //开始采集void stopCapture(); //结束采集void run() override; //线程函数
private slots:void doCam(int code,QString msg); //用于接收线程信息,并弹出消息框
signals:void onCameraEvent(int code,QString msg); //线程内部发送消息void onImage(QImage img); //线程内部发送图像采集成功信号private:bool isCapture; //是否采集中rs2::pipeline pipe; //采集采集对象};#endif // CAMERA_H
第三步:开始采集,按照官方SDK说法,只需要一个rs2::pipelie对象,start()开始采集,然后pipe.wait_for_frames()就ok了。
/*** @brief Camera::run 线程函数,用于打开相机和采集图像*/
void Camera::run(){try {pipe.start(); //尝试打开相机}catch (const std::exception& e){emit onCameraEvent(1, e.what() ); //如果没有成功,发送给主线程一个消息return;//返回,不继续了}emit onCameraEvent(0,"相机打开成功"); //如果打开成功,也发送一个rs2::colorizer color_map;//用于将深度数据,转换为图像数据色彩数据的map,isCapture=true;//循环控制变量while(isCapture){try {rs2::frameset data= pipe.wait_for_frames(); //获取一帧数据 rs2::frame color=data.get_color_frame(); //获取彩色图像 const int w = color.as<rs2::video_frame>().get_width(); //获取图像宽度const int h = color.as<rs2::video_frame>().get_height(); //获取图像高度qDebug()<<"get frame"<<"width "<<w<<"height"<<h;}catch (const std::exception& e) {emit onCameraEvent(2,e.what());}}
}
代码运行,输出下面的结果,表示图像采集到了。这是获取的彩色图像的数据。
第四步:显示图像,官方提供的SDK是用openCV显示的,奈何只提供了VC编译的库,没有minGW版本的opencv库。无法使用。所以放弃opencv。 官方使用opencv代码如下:
// Create OpenCV matrix of size (w,h) from the colorized depth dataMat image(Size(w, h), CV_8UC3, (void*)depth.get_data(), Mat::AUTO_STEP);// Update the window with new dataimshow(window_name, image);
不难发现,这个图像的数据,实际上就是24位的RGB数据,也就是说,是标准的图像数据。有了这个结果,就简单了。不能用opencv,那就用QImage。反正是一样的用法,代码如下:
rs2::frameset data= pipe.wait_for_frames(); //获取一帧数据 rs2::frame color=data.get_color_frame(); //获取彩色图像 const int w = color.as<rs2::video_frame>().get_width(); //获取图像宽度const int h = color.as<rs2::video_frame>().get_height(); //获取图像高度qDebug()<<"get frame"<<"width "<<w<<"height"<<h;QImage img((uchar*)color.get_data(),w,h,QImage::Format_RGB888); //创建一个图片emit onImage(img); //图片发送给主线程,mainwindow接收,并显示一下。
成功打开彩色图片
第五步:获取深度图像。咱们的目标是获取深度图。按官方说法,使用data.get_depth_frame();就可以。见下面代码:
rs2::frame depth=data.get_depth_frame(); //获取深度数据const int w = depth.as<rs2::video_frame>().get_width(); //获取图像宽度const int h = depth.as<rs2::video_frame>().get_height(); //获取图像高度qDebug()<<"get frame"<<"width "<<w<<"height"<<h;QImage img((uchar*)depth.get_data(),w,h,QImage::Format_RGB888); //创建一个图片emit onImage(img); //图片发送给主线程,mainwindow接收,并显示一下。
运行,可以获取宽高,但是程序崩溃了。一般情况下,深度图像是单通道的,也就是说是一个8位灰度图或者是16位的灰度图。通过查看源码,确实是16位灰度图。
创建QImage的时候,换成Grayscale16,见下图:
QImage img((uchar*)depth.get_data(),w,h,QImage::Format_Grayscale16); //创建一个图片
依稀能看出来是有数据的,但是直接显示不太好看,官方提供了一个深度转色彩的功能.apply_filter(color_map);可以转换为便于观看的色彩图片。
完整Camera类代码:
#include "camera.h"
#include <QDebug>
#include <QException>
#include <common.h>Camera::Camera()
{connect(this,&Camera::onCameraEvent,this,&Camera::doCam);//链接线程内部的信号
}
/*** @brief Camera::getInstance 单例模式* @return*/
Camera* Camera::getInstance(){static Camera* ins=NULL;//static代码,唯一对象if(ins==NULL)ins=new Camera();//创建一个实力return ins;
}void Camera::startCapture(){loading("打开摄像头",0);//显示打开摄像头弹窗,一直显示,直到成功或是失败this->start();//开始子线程
}
/*** @brief Camera::stopCapture 停止采集*/
void Camera::stopCapture(){isCapture=false;//退出子线程pipe.stop();//停止相机
}
/*** @brief Camera::doCam 接收线程的消息,并弹窗显示* @param code 消息编码,0表示成功* @param msg 消息内容*/
void Camera::doCam(int code,QString msg){if(code==0)success(msg);else error(msg);
}
/*** @brief Camera::run 线程函数,用于打开相机和采集图像*/
void Camera::run(){try {pipe.start(); //尝试打开相机}catch (const std::exception& e){emit onCameraEvent(1, e.what() ); //如果没有成功,发送给主线程一个消息return;//返回,不继续了}emit onCameraEvent(0,"相机打开成功"); //如果打开成功,也发送一个rs2::colorizer color_map;//用于将深度数据,转换为图像数据色彩数据的map,isCapture=true;//循环控制变量while(isCapture){try {rs2::frameset data= pipe.wait_for_frames(); //获取一帧数据 rs2::frame color=data.get_color_frame(); //获取彩色图像rs2::frame depth=data.get_depth_frame().apply_filter(color_map); //获取深度数据,并转换为可见图const int w = depth.as<rs2::video_frame>().get_width(); //获取图像宽度const int h = depth.as<rs2::video_frame>().get_height(); //获取图像高度qDebug()<<"get frame"<<"width "<<w<<"height"<<h;QImage img((uchar*)depth.get_data(),w,h,QImage::Format_RGB888); //创建一个图片emit onImage(img); //图片发送给主线程,mainwindow接收,并显示一下。}catch (const std::exception& e) {emit onCameraEvent(2,e.what());}}
}
后续准备同时显示深度和彩色图片,并在QT显示3D模型。