1.項目背景
Realsense是Inter公司的一個立體相機系列,提供了易用的深度相機硬件並配備了開發SDK。但是在實踐中,我們往往需要按照自己的功能需求對圖像進行處理。一般的做法是僅使用Realsense的通訊庫,獲得左右相機圖像、彩色相機圖像、深度圖像后使用OpenCV對獲得的圖像進行處理。如果僅僅是對圖像進行處理分析的話,OpenCV自帶的也有簡單的GUI。但是,如果考慮將其開發為一個完整的桌面程序,配合Qt或許是個好選擇。
2.項目簡介
本項目作為一個例程,所要完成的目標是從錄制好的.bag文件讀取視頻,並將其在Qt繪制的界面中播放出來。項目本身有幾個關鍵點:
(1)Qt+OpenCV+Realsense開發環境的配置
(2)圖像幀的讀取與格式轉換
(3)程序中各函數的功能設計
由於開發環境配置具有一定的通用性,我准備之后再專門寫一個說明,在本例中假設在Windows下的開發環境已經搭建良好,可以直接開始工作。
3.程序介紹
本程序遵照Qt程序的一般設計規則,程序主要包括.pro文件;main.cpp;mainwindow.h;mainwindow.cpp;mainwindow.ui。另外為了環境配置的簡單,單獨的寫了一個opencv+realsense的.pri配置文件。實際情況如下圖
下面將對每個文件進行介紹。
3.1項目文件.pro與配置文件.pri
Qt的pro文件是Qt的項目管理文件,當你新建項目時會自動創建,在本例中,pro文件僅有兩句與自動生成的不同,具體為:
DISTFILES += \
../opencv_realsense.pri//在項目中添加已經配置好的pri文件
win32{
include("../opencv_realsense.pri")
}//在window下包含pri文件內聲明的庫
而在pri文件中主要完成的是對項目使用的opencv以及realsense庫進行包含,具體代碼為:
INCLUDEPATH += D:/opencv348/opencv/build/include\
D:/opencv348/opencv/build/include/opencv\
D:/opencv348/opencv/build/include/opencv2\
"C:/Program Files (x86)/Intel RealSense SDK 2.0/include/"
Debug: {
LIBS += D:/opencv348/opencv/build/x64/vc14/lib/opencv_world348d.lib\
"C:/Program Files (x86)/Intel RealSense SDK 2.0/lib/x64/realsense2.lib"
}
Release: {
LIBS += D:/opencv348/opencv/build/x64/vc14/lib/opencv_world348.lib\
"C:/Program Files (x86)/Intel RealSense SDK 2.0/lib/x64/realsense2.lib"
}//庫的位置與opencv以及realsense的安裝位置有關
3.2 UI介紹
本例僅考慮對已錄制的bag文件的播放,界面設計比較簡單,功能也是一看便知,直接上圖不再贅言
各個控件的命名如下
需要提醒的是,本例為了簡單直接使用了QLabel作為顯示空間,如果你需要在顯示上實現更復雜的功能,可能QGraphicsItem更適合。
3.3 main.cpp
本例中沒有對main.cpp修改,直接實例化mainwindow調用show方法,進入循環,代碼如下:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
3.4 mainwindow.h
在mainwindow.h中,主要完成的任務是對使用的頭文件進行包含;mainwindow中需要的函數聲明;以及一些類和變量的聲明。
按照上面的任務分類分三部分展示代碼:
#include <QMainWindow>
#include <QTimer>
#include <QString>
#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>
#include <QFile>
#include <QPixmap>
#include <QDir>
#include <QTransform>
#include "opencv2/opencv.hpp"
#include "librealsense2/rs.hpp"
private slots:
void on_btn_play_clicked();
void on_btn_stop_clicked();
void updateWindow();
void on_btn_openFile_pressed();
void on_lineEdit_openFile_textChanged(const QString &arg1);
private:
Ui::MainWindow *ui;
QTimer * timer;//刷新定時器
QImage depth_QImage,color_QImage;//QImage格式幀
QString fileName;//文件名變量
3.5 mainwindow.cpp
mainwindow.cpp是我們這個小程序的核心功能實現部分,我會將其分為幾個部分分別介紹。
(1) 變量聲明以及定時器實例化
有一些后面需要使用的變量提前聲明,以及使用的命名空間
using namespace cv;
using namespace rs2;
Mat depth_Mat,color_Mat;//Mat格式幀
colorizer color_map;//深度圖着色過濾器
pipeline pipe;//創建管道
另外需要在構造函數中實例化一個定時器,只需要添加一行代碼
timer = new QTimer(this);
(2) 獲取bag文件的實際位置
本來這個小例程是可以直接把bag文件拖到可執行文件的目錄下,然后硬編碼fileName的具體值的,但是bag文件是很大的,可能一分鍾的視頻就幾個G了,來回拖有些占地方也不方便。因此,在這里使用了一個lineEdit和pushButton配合獲得文件的地址,這兩個函數都不難,直接寫下
void MainWindow::on_btn_openFile_pressed()//選擇文件
{
QString fileName = QFileDialog::getOpenFileName(this,tr("Open Image"), QDir::currentPath(), tr("Files (*.bag)"),0, QFileDialog::DontUseNativeDialog);
if(QFile::exists(fileName))
{
qDebug()<<"exist";
ui->lineEdit_openFile->setText(fileName);
}
}
void MainWindow::on_lineEdit_openFile_textChanged(const QString &arg1)//更新行編輯器的文本內容
{
this->fileName = arg1;
}
唯一有一點比較困擾我的是,在我使用QFileDialog::getOpenFileName
函數時,直接使用四參數的常用類型就導致程序卡死,配置第六個參數后才能正常運行,但是和默認的四參數的效果有一點點差異,如果有知道怎么回事的大佬還請教我。使用六參數版的解決方案出自鏈接。
(3)打開與關閉視頻
打開與關閉按鈕對應的槽函數分別為
void MainWindow::on_btn_play_clicked()//播放視頻
{
QString fileName = ui->lineEdit_openFile->text();//從行編輯器獲取實際的文件名
if(QFile::exists(fileName))//文件存在判別
{
qDebug()<<"exist";
}
config cfg;//從文件讀取視頻流時需要的配置
cfg.enable_device_from_file(fileName.toStdString());
connect(timer,SIGNAL(timeout()),this,SLOT(updateWindow()));//使用定時器定時刷新窗口
timer->start(20);
pipe.start(cfg);//打開視頻流
ui->lb_message->setText("playing");//更改狀態指示
}
void MainWindow::on_btn_stop_clicked()//關閉視頻
{
pipe.stop();
timer->stop();
ui->lb_color->clear();
ui->lb_depth->clear();
ui->lb_message->setText("closed");
}
而在on_btn_play_clicked
函數中,通過connect將定時器與刷新函數鏈接起來,實現每隔20ms刷新顯示,而刷新函數的代碼如下:
void MainWindow::updateWindow()//刷新窗口
{
frameset data = pipe.wait_for_frames();//獲取圖像幀
frame depth = data.get_depth_frame().apply_filter(color_map);//獲得着色后的深度圖像
const int w = depth.as<video_frame>().get_width();//獲得幀的大小
const int h = depth.as<video_frame>().get_height();
depth_Mat = Mat(Size(w,h),CV_8UC3,(void*)depth.get_data(),Mat::AUTO_STEP);//構造mat類型數據
cvtColor(depth_Mat,depth_Mat,CV_BGR2RGB);//對顏色通道進行調整
depth_QImage = QImage((const unsigned char*)(depth_Mat.data),depth_Mat.cols,depth_Mat.rows,QImage::Format_RGB888);//實現Mat到QImage的轉換
ui->lb_depth->setPixmap(QPixmap::fromImage(depth_QImage));//顯示設置
ui->lb_depth->setFixedSize(480,260);
ui->lb_depth->setScaledContents(true);
//彩色窗口與深度窗口大致相同
//frame color = data.get_color_frame();
}
4 實現效果圖
程序啟動
選擇文件
文件選擇后
播放界面
關閉播放
5 最后
還要提醒的是,如果你的程序編譯通過但是打不開,有可能是因為realsense2.dll沒被復制到程序運行目錄。
6最后的最后
完整的代碼我厚顏放公號了
發送Qt001即可獲得。
按理來說,這個程序介紹的已經很詳細了,但是如果你在實際操作中遇到了問題可以與完整的對比一下,這個方向目前我還會繼續做下去,感興趣的話可以互相交流一下。
完結,撒花。