乐视三合一体感摄像头Astra pro开发记录2(Qt界面)

7 篇文章 3 订阅

本文是在上一篇文章乐视三合一体感摄像头Astra pro开发记录1(深度图、彩色图及点云简单显示)的基础上写的。在开学之前终于把界面的基础功能做完了,估计还有一些bug,也没时间继续调了。开学之后得憋论文了。
界面的主要功能还是Astra pro相机的彩色图、深度图以及点云显示。在之前的基础上,完善了一些比如图像和点云的保存、读取,相机的打开、关闭以及参数设置等功能。由于只是追求基本功能的实现,整个项目文件代码量算上注释也就一千行左右。依赖的第三方库有OpenCV(图像处理)、OpenNI(深度图)、PCL(点云处理)和VTK(点云显示),下面放代码:

/**
  *@file camera_settings.h
  *@brief 相机设置头文件
  */


#ifndef CAMERA_SETTINGS_H
#define CAMERA_SETTINGS_H

#include <QDialog>
#include <QString>


namespace Ui {
class Camera_Settings;
}


/**
 * @brief The Camera_Settings class
 */
class Camera_Settings : public QDialog
{
    Q_OBJECT

public:
    Camera_Settings(QWidget *parent = 0);

    ~Camera_Settings();

    /**
     * @brief color_index 彩色摄像头编号
     */
    static int color_index;

    /**
     * @brief color_resolution 彩色摄像头分辨率
     */
    static QString color_resolution;

    /**
     * @brief color_fps 彩色摄像头帧率
     */
    static QString color_fps;

    /**
     * @brief depth_resolution 深度摄像头分辨率
     */
    static QString depth_resolution;

    /**
     * @brief depth_fps 深度摄像头帧率
     */
    static QString depth_fps;

    /**
     * @brief flag_applied 相机设置应用标志
     */
    static bool flag_applied;

private slots:
    /**
     * @brief on_pushButton_apply_clicked 应用相机设置
     */
    void on_pushButton_apply_clicked();

private:
    Ui::Camera_Settings *ui;
};

#endif // CAMERA_SETTINGS_H

/**
  *@file cloud_generate.h
  *@brief 点云生成头文件
  */


#ifndef CLOUD_GENERATE_H
#define CLOUD_GENERATE_H


#include "mainwindow.h"


/**
 * @brief The Cloud_Generate class
 */
class Cloud_Generate : public QThread
{
private:
    /**
     * @brief run 重写QThread的run方法
     */
    void run();
};


#endif // CLOUD_GENERATE_H

/**
  *@file mainwindow.h
  *@brief 主窗口头文件
  */


#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QMainWindow>
#include <QVTKWidget.h>
#include <QMessageBox>
#include <QAbstractButton>
#include <QTimer>
#include <QThread>
#include <QString>
#include <QFileDialog>

#include <iostream>
#include <opencv2/opencv.hpp>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <OpenNI.h>
#include <vtkAutoInit.h>
#include <vtkRenderWindow.h>

#include "blockingconcurrentqueue.h"
#include "camera_settings.h"
#include "cloud_generate.h"


VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)


typedef pcl::PointCloud<pcl::PointXYZ> PointCloud;
typedef pcl::PointCloud<pcl::PointXYZRGB> PointCloudRGB;


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
using namespace moodycamel;
QT_END_NAMESPACE


/**
 * @brief The Astra class
 */
class Astra : public QMainWindow
{
    Q_OBJECT

public:
    explicit Astra(QWidget *parent = 0);

    ~Astra();

    Ui::MainWindow *ui;

private slots:
    /**
     * @brief save_color_image 保存彩色图
     */
    void save_color_image();

    /**
     * @brief save_depth_image 保存深度图
     */
    void save_depth_image();

    /**
     * @brief save_point_cloud 保存点云
     */
    void save_point_cloud();

    /**
     * @brief open_color_image 打开彩色图
     */
    void open_color_image();

    /**
     * @brief open_depth_image 打开深度图
     */
    void open_depth_image();

    /**
     * @brief open_point_cloud 打开点云
     */
    void open_point_cloud();


    /**
     * @brief close_all 关闭所有文件
     */
    void close_all();

    /**
     * @brief open_camera 打开相机
     */
    void open_camera();

    /**
     * @brief close_camera 关闭相机
     */
    void close_camera();

    //void set_camera();

    /**
     * @brief show_color_image 显示彩色图
     */
    void show_color_image();

    /**
     * @brief show_depth_image 显示深度图
     */
    void show_depth_image();

    /**
     * @brief show_point_cloud 显示点云
     */
    void show_point_cloud();

    /**
     * @brief help_guide 使用说明
     */
    void help_guide();

    /**
     * @brief help_about 关于AstraGUI
     */
    void help_about();

private:
    /**
     * @brief camera_settings 相机设置界面类指针
     */
    Camera_Settings *camera_settings;

    /**
     * @brief capture 彩色摄像头
     */
    cv::VideoCapture capture;

    /**
     * @brief device 深度摄像头
     */
    openni::Device device;

    /**
     * @brief depthStream 深度流
     */
    openni::VideoStream depthStream;

    /**
     * @brief depthMode 深度模式
     */
    openni::VideoMode depthMode;

    /**
     * @brief viewer pclviewer窗口
     */
    boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;

    /**
     * @brief timerColor 彩色图像显示定时器
     */
    QTimer *timerColor;

    /**
     * @brief timerDepth 深度图像显示定时器
     */
    QTimer *timerDepth;

    /**
     * @brief timerCloud 点云显示定时器
     */
    QTimer *timerCloud;

    /**
     * @brief colorMat 彩色图像
     */
    cv::Mat colorMat;

    /**
     * @brief depthMat 深度图像
     */
    cv::Mat depthMat;

    /**
     * @brief flag_depth 深度图采集标志
     */
    bool flag_depth = false;

    /**
     * @brief flag_cloud 点云生成标志
     */
    bool flag_cloud =false;
};


#endif // MAINWINDOW_H

/**
  *@file camera_settings.cpp
  *@brief 相机设置源文件
  */


#include "camera_settings.h"
#include "mainwindow.h"
#include "ui_camera_settings.h"
#include "ui_mainwindow.h"
#include <QDebug>


int Camera_Settings::color_index = 0;
QString Camera_Settings::color_resolution = "640*480";
QString Camera_Settings::color_fps= "30fps";
QString Camera_Settings::depth_resolution = "640*480";
QString Camera_Settings::depth_fps = "30fps";
bool Camera_Settings::flag_applied = false;


Camera_Settings::Camera_Settings(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Camera_Settings)
{
    ui->setupUi(this);
}


Camera_Settings::~Camera_Settings()
{
    delete ui;
}


void Camera_Settings::on_pushButton_apply_clicked()
{
    Astra *ptr = (Astra*)parentWidget(); //指向父窗口的指针

    color_index = ui->comboBox_color_index->currentIndex();

    color_resolution = ui->comboBox_color_resolution->currentText();
    depth_resolution = ui->comboBox_depth_resolution->currentText();

    if(color_resolution=="640*480" && depth_resolution=="640*480")
    {
        ptr->ui->stackedWidget->setCurrentIndex(0);
    }
    else if(color_resolution=="320*240" && depth_resolution=="320*240")
    {
        ptr->ui->stackedWidget->setCurrentIndex(1);
    }
    else if(color_resolution == "1280*720")
    {
        ptr->ui->stackedWidget->setCurrentIndex(2);
    }
    else
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("分辨率设置错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    color_fps = ui->comboBox_color_fps->currentText();
    depth_fps = ui->comboBox_depth_fps->currentText();

    if(color_resolution != "1280*720" && color_fps != depth_fps)
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("帧率设置错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    flag_applied = true;
    this->close(); //点击应用后相机设置窗口关闭
}
/**
  *@file cloud_generate.cpp
  *@brief 点云生成源文件
  */


#include "cloud_generate.h"


extern PointCloud::Ptr cloud;
extern PointCloudRGB::Ptr cloudRGB;

extern BlockingConcurrentQueue<cv::Mat> bcq_colorMat;
extern BlockingConcurrentQueue<cv::Mat> bcq_depthMat;
extern BlockingConcurrentQueue<PointCloud::Ptr> bcq_cloud;
extern BlockingConcurrentQueue<PointCloudRGB::Ptr> bcq_cloudRGB;


void Cloud_Generate::run()
{
    float camera_factor, camera_cx, camera_cy, camera_fx, camera_fy; //相机内参
    cv::Mat colorMat, depthMat;

    while(true)
    {
        if(bcq_depthMat.try_dequeue(depthMat))
        {
            if(Camera_Settings::depth_resolution == "640*480")
            {
                camera_factor = 1;
                camera_cx = 311.0;
                camera_cy = 244.0;
                camera_fx = 593.0;
                camera_fy = 588.0;
            }
            else if(Camera_Settings::depth_resolution == "320*240")
            {
                camera_factor = 1;
                camera_cx = 311.0*0.5;
                camera_cy = 244.0*0.5;
                camera_fx = 593.0*0.5;
                camera_fy = 588.0*0.5;
            }

            if(bcq_colorMat.try_dequeue(colorMat))
            {
                cloudRGB->clear(); //重置点云为空

                //遍历深度图
                for (int i = 0; i < depthMat.rows; ++i)
                {
                    uchar* depthData = depthMat.data + i*depthMat.step;
                    uchar* colorData = colorMat.data + i*colorMat.step;
                    for (int j = 0; j < depthMat.cols; ++j)
                    {
                        if (depthData == 0)
                            continue;

                        pcl::PointXYZRGB point;

                        //计算点的空间坐标
                        point.z = double(*(depthData++)) / camera_factor;
                        point.x = (j - camera_cx) * point.z / camera_fx;
                        point.y = -(i - camera_cy) * point.z / camera_fy;

                        //从彩色图像中获取该点的颜色
                        point.b = *(colorData++);
                        point.g = *(colorData++);
                        point.r = *(colorData++);

                        //把该点加入到点云中
                        cloudRGB->points.push_back(point);
                    }
                }
                bcq_cloudRGB.enqueue(cloudRGB);
            }
            else
            {
                cloud->clear(); //重置点云为空

                //遍历深度图
                for (int i = 0; i < depthMat.rows; ++i)
                {
                    uchar* depthData = depthMat.data + i*depthMat.step;
                    for (int j = 0; j < depthMat.cols; ++j)
                    {
                        if (depthData == 0)
                            continue;

                        pcl::PointXYZ point;

                        //计算点的空间坐标
                        point.z = double(*(depthData++)) / camera_factor;
                        point.x = (j - camera_cx) * point.z / camera_fx;
                        point.y = -(i - camera_cy) * point.z / camera_fy;

                        //把该点加入到点云中
                        cloud->points.push_back(point);
                    }
                }
                bcq_cloud.enqueue(cloud);
            }
        }
    }
}

/**
  *@file main.cpp
  *@brief 主函数源文件
  */


#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Astra *w = new Astra;
    w->show();

    return a.exec();
}

/**
  *@file mainwindow.cpp
  *@brief 主窗口源文件
  */


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

/**
 * @brief cloud 无色点云
 */
PointCloud::Ptr cloud(new PointCloud);

/**
 * @brief cloudRGB 彩色点云
 */
PointCloudRGB::Ptr cloudRGB(new PointCloudRGB);

/**
 * @brief bcq_colorMat colorMat阻塞队列
 */
BlockingConcurrentQueue<cv::Mat> bcq_colorMat;

/**
 * @brief bcq_depthMat depthMat阻塞队列
 */
BlockingConcurrentQueue<cv::Mat> bcq_depthMat;

/**
 * @brief bcq_cloud cloud阻塞队列
 */
BlockingConcurrentQueue<PointCloud::Ptr> bcq_cloud;

/**
 * @brief bcq_cloudRGB cloudRGB阻塞队列
 */
BlockingConcurrentQueue<PointCloudRGB::Ptr> bcq_cloudRGB;


Astra::Astra(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->action_save_colorMat, &QAction::triggered, [=]{this->save_color_image();});
    connect(ui->action_save_depthMat, &QAction::triggered, [=]{this->save_depth_image();});
    connect(ui->action_save_pointcloud, &QAction::triggered, [=]{this->save_point_cloud();});
    connect(ui->action_open_colorMat, &QAction::triggered, [=]{this->open_color_image();});
    connect(ui->action_open_depthMat, &QAction::triggered, [=]{this->open_depth_image();});
    connect(ui->action_open_pointcloud, &QAction::triggered, [=]{this->open_point_cloud();});
    connect(ui->action_close_all, &QAction::triggered, [=]{this->close_all();});
    connect(ui->action_exit, &QAction::triggered, [=]{this->close();});
    connect(ui->action_open_camera, &QAction::triggered, [=]{this->open_camera();});
    connect(ui->action_close_camera, &QAction::triggered, [=]{this->close_camera();});
    //connect(ui->action_set_camera, &QAction::triggered, [=]{this->set_camera();});
    connect(ui->action_help_guide, &QAction::triggered, [=]{this->help_guide();});
    connect(ui->action_help_about, &QAction::triggered, [=]{this->help_about();});

    openni::OpenNI::initialize();
}


Astra::~Astra()
{
    delete ui;

    openni::OpenNI::shutdown();
}

void Astra::save_color_image()
{
    //选择路径
    QString fileName = QFileDialog::getSaveFileName(this,QString::fromLocal8Bit("保存彩色图")," ",tr(" (*.bmp *.jpg *.png)"));

    //文件名为空
    if (fileName.isEmpty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("文件名为空!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //彩色图像为空
    if (colorMat.empty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("彩色图保存错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    std::string filename(fileName.toLocal8Bit().data()); //支持带中文路径的读取
    cv::imwrite(filename, colorMat); //将彩色图像写入磁盘
}


void Astra::save_depth_image()
{
    //选择路径
    QString fileName = QFileDialog::getSaveFileName(this,QString::fromLocal8Bit("保存深度图")," ",tr(" (*.bmp *.jpg *.png)"));

    //文件名为空
    if (fileName.isEmpty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("文件名为空!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //深度图为空
    if (depthMat.empty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("深度图保存错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    std::string filename(fileName.toLocal8Bit().data()); //支持带中文路径的读取
    cv::imwrite(filename, depthMat); //将深度图像写入磁盘
}


void Astra::save_point_cloud()
{
    //选择路径
    QString fileName = QFileDialog::getSaveFileName(this,QString::fromLocal8Bit("保存点云")," ",tr(" (*.pcd)"));

    //文件名为空
    if (fileName.isEmpty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("文件名为空!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //点云数据为空
    if (cloudRGB->size()==0 && cloud->size()==0)
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("点云保存错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    std::string filename(fileName.toLocal8Bit().data()); //支持带中文路径的读取
    if(flag_cloud)
        pcl::io::savePCDFileBinary(filename,*cloud); //将无色点云写入磁盘
    else
        pcl::io::savePCDFileBinary(filename,*cloudRGB); //将彩色点云写入磁盘
}


void Astra::open_color_image()
{
    ui->stackedWidget->setCurrentIndex(0);

    //选择路径
    QString fileName  = QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开彩色图"),"home",tr("(*.bmp *.jpg *.png )"));
    //文件名为空
    if (fileName.isEmpty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("文件名为空!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    std::string filename(fileName.toLocal8Bit().data()); //支持带中文路径的读取
    cv::Mat colorMat = cv::imread(filename,-1); //-1表示读取原始数据
    //彩色图像为空或通道数不为3
    if(colorMat.empty() || colorMat.channels()!=3)
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("彩色图打开错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //缩放图像使其适应窗口大小
    cv::resize(colorMat,colorMat,cv::Size(ui->label_color_1->width(),ui->label_color_1->height()));
    //cv::Mat转QImage
    QImage image_color = QImage((const uchar*)colorMat.data,colorMat.cols,colorMat.rows,QImage::Format_RGB888).rgbSwapped();

    //更新ui
    ui->label_color_1->clear();
    ui->label_color_1->setPixmap(QPixmap::fromImage(image_color));
}


void Astra::open_depth_image()
{
    ui->stackedWidget->setCurrentIndex(0);

    //选择路径
    QString fileName  = QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开深度图"),"home",tr("(*.bmp *.jpg *.png )"));
    //文件名为空
    if (fileName.isEmpty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("文件名为空!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    std::string filename(fileName.toLocal8Bit().data()); //支持带中文路径的读取
    cv::Mat depthMat = cv::imread(filename,-1); //-1表示读取原始数据
     //深度图像为空或通道数不为1
    if(depthMat.empty() || depthMat.channels()!=1)
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("深度图打开错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //缩放图像使其适应窗口大小
    cv::resize(depthMat,depthMat,cv::Size(ui->label_depth_1->width(),ui->label_depth_1->height()));
    //cv::Mat转QImage
    QImage image_depth = QImage((const uchar*)depthMat.data,depthMat.cols,depthMat.rows,QImage::Format_Grayscale8).rgbSwapped();

    //更新ui
    ui->label_depth_1->clear();
    ui->label_depth_1->setPixmap(QPixmap::fromImage(image_depth));

}


void Astra::open_point_cloud()
{
    ui->stackedWidget->setCurrentIndex(0);
    //选择路径
    QString fileName = QFileDialog::getOpenFileName(this,QString::fromLocal8Bit("打开点云"),"home",tr("(*.pcd)"));
    //文件名为空
    if (fileName.isEmpty())
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("文件名为空!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    std::string filename(fileName.toLocal8Bit().data()); //支持带中文路径的读取

//    PointCloud::Ptr cloud(new PointCloud);
//    PointCloudRGB::Ptr cloudRGB(new PointCloudRGB);

    //点云加载失败
    if(pcl::io::loadPCDFile(filename,*cloudRGB)==-1)
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("点云打开错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //判断点云是否带有rgb信息
    if(cloudRGB->points[0].r)
    {
        viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
        viewer->addPointCloud(cloudRGB);
        ui->qvtkWidget_1->SetRenderWindow(viewer->getRenderWindow());
        ui->qvtkWidget_1->update();
    }
    else
    {
        pcl::io::loadPCDFile(filename,*cloud);
        viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
        viewer->addPointCloud(cloud);
        ui->qvtkWidget_1->SetRenderWindow(viewer->getRenderWindow());
        ui->qvtkWidget_1->update();
    }
}


void Astra::close_all()
{
    //清除彩色图像显示
    ui->label_color_1->clear();
    ui->label_color_2->clear();
    ui->label_color_3->clear();
    //清除深度图像显示
    ui->label_depth_1->clear();
    ui->label_depth_2->clear();

    if(cloud->points.size()||cloudRGB->points.size())
    {
        //移除viewer中的点云
        viewer->removeAllPointClouds();
        //清除点云显示
        ui->qvtkWidget_1->update();
        ui->qvtkWidget_2->update();
    }
}


void Astra::open_camera()
{  
    //弹出相机设置界面
    Camera_Settings camera_settings(this);
    camera_settings.setWindowTitle(QString::fromLocal8Bit("相机设置"));
    camera_settings.exec();

    //如果没有点击相机设置界面中的应用按钮则什么都不做
    if(!Camera_Settings::flag_applied)
    {
        return;
    }

    //彩色摄像头或深度摄像头已被打开
    if(capture.isOpened() || flag_depth)
    {
        close_camera(); //先调用关闭相机的函数
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("摄像头打开出错!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //如果彩色图分辨率不为1280*720则开启深度摄像头
    if(Camera_Settings::color_resolution != "1280*720")
    {
        if (device.open(openni::ANY_DEVICE) != openni::STATUS_OK)
        {
            QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("深度摄像头打开出错!"),QMessageBox::Ok);
            if(NULL!=box->button(QMessageBox::Ok))
            {
               box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
            }
            QTimer::singleShot(3000,box,SLOT(accept()));
            box->exec();
            goto color;
        }

        //创建深度流
        depthStream.create(device, openni::SENSOR_DEPTH);

        //配置深度流的模式
        std::string depth_resolution = Camera_Settings::depth_resolution.toStdString();
        int DEPTH_COLS = std::stoi(depth_resolution.substr(0,depth_resolution.size()-4));
        int DEPTH_ROWS = std::stoi(depth_resolution.substr(depth_resolution.size()-3));

        std::string depth_fps = Camera_Settings::depth_fps.toStdString();
        int DEPTH_FPS = std::stoi(depth_fps.substr(0,depth_fps.size()-3));

        depthMode.setResolution(DEPTH_COLS, DEPTH_ROWS);
        depthMode.setPixelFormat(openni::PIXEL_FORMAT_DEPTH_1_MM);
        depthMode.setFps(DEPTH_FPS);
        depthStream.setVideoMode(depthMode);

        //打开深度流
        depthStream.start();

        //设置深度图像采集标志位
        flag_depth = true;

        //创建并开启深度图像显示定时器
        timerDepth = new QTimer(this);
        timerDepth-> setTimerType(Qt::PreciseTimer);
        connect(timerDepth, SIGNAL(timeout()), this, SLOT(show_depth_image()));
        timerDepth->start(100);
    }

    //打开彩色摄像头
color:
    //彩色摄像头打开失败
    if(capture.open(Camera_Settings::color_index) != true)
    {
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("彩色摄像打开出错!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //配置rgb流的模式
    std::string color_resolution = Camera_Settings::color_resolution.toStdString();
    int COLOR_COLS = std::stoi(color_resolution.substr(0,color_resolution.size()-4));
    int COLOR_ROWS = std::stoi(color_resolution.substr(color_resolution.size()-3));

    std::string color_fps = Camera_Settings::color_fps.toStdString();
    int COLOR_FPS = std::stoi(color_fps.substr(0,color_fps.size()-3));

    capture.set(cv::CAP_PROP_FRAME_WIDTH, COLOR_COLS);//宽度
    capture.set(cv::CAP_PROP_FRAME_HEIGHT, COLOR_ROWS);//高度
    capture.set(cv::CAP_PROP_FPS, COLOR_FPS);//帧率 帧/秒

    //创建并开启彩色图像显示定时器
    timerColor = new QTimer(this);
    timerColor-> setTimerType(Qt::PreciseTimer);
    connect(timerColor, SIGNAL(timeout()), this, SLOT(show_color_image()));
    timerColor->start(100);

    //创建并开启点云显示定时器
    if(flag_depth)
    {
        timerCloud = new QTimer(this);
        timerCloud-> setTimerType(Qt::PreciseTimer);
        connect(timerCloud, SIGNAL(timeout()), this, SLOT(show_point_cloud()));
        timerCloud->start(100);
    }

    //启动点云生成线程
    Cloud_Generate *task = new Cloud_Generate;
    task->start();
}


void Astra::close_camera()
{
    //如果相机未开启则直接返回
    if(!capture.isOpened())
    {
        return;
    }

    //关闭彩色图像显示定时器
    timerColor->stop();
    //关闭彩色摄像头
    capture.release();
    //清除彩色图像显示
    ui->label_color_1->clear();
    ui->label_color_2->clear();
    ui->label_color_3->clear();

    if(Camera_Settings::color_resolution != "1280*720" && flag_depth)
    {
        //关闭深度图像显示定时器
        timerDepth->stop();
        //关闭点云显示定时器
        timerCloud->stop();
        //关闭深度流
        depthStream.stop();
        depthStream.destroy();
        //关闭深度摄像头
        device.close();
        //清除深度图像显示
        ui->label_depth_1->clear();
        ui->label_depth_2->clear();
        //清除点云
        cloud->clear();
        cloudRGB->clear();
        //移除viewer中的点云
        viewer->removeAllPointClouds();
        //清除点云显示
        ui->qvtkWidget_1->update();
        ui->qvtkWidget_2->update();
        //设置深度图像采集标志
        flag_depth = false;
    }

    //设置相机设置应用标志位
    Camera_Settings::flag_applied = false;
}


//void Astra::set_camera()
//{
    camera_settings = new Camera_Settings(this);
    camera_settings->setWindowTitle(QString::fromLocal8Bit("相机设置"));
    camera_settings->show();
//    Camera_Settings camera_settings(this);
//    camera_settings.setWindowTitle(QString::fromLocal8Bit("相机设置"));
//    camera_settings.exec();
//}


void Astra::show_color_image()
{
    capture >> colorMat;

    //彩色图像采集为空
    if(colorMat.empty())
    {
        timerColor->stop();
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("彩色图采集错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //彩色图和深度图呈镜像关系,所以要翻转一下
    cv::flip(colorMat, colorMat, 1);
    //cv::Mat转QImage
    QImage image_color = QImage((const uchar*)colorMat.data, colorMat.cols, colorMat.rows, QImage::Format_RGB888).rgbSwapped();

    //依据不同分辨率显示不同大小的彩色图像
    if(Camera_Settings::color_resolution == "640*480")
    {
        ui->label_color_1->clear();
        ui->label_color_1->setPixmap(QPixmap::fromImage(image_color));
    }
    else if(Camera_Settings::color_resolution == "320*240")
    {
        ui->label_color_2->clear();
        ui->label_color_2->setPixmap(QPixmap::fromImage(image_color));
    }
    else if(Camera_Settings::color_resolution == "1280*720")
    {
        ui->label_color_3->clear();
        ui->label_color_3->setPixmap(QPixmap::fromImage(image_color));
    }

    bcq_colorMat.enqueue(colorMat);

    cv::waitKey(10); //防止程序卡住
}


void Astra::show_depth_image()
{
    openni::VideoFrameRef depth_frame;
    int iMaxDepth = depthStream.getMaxPixelValue();
    openni::VideoStream* pstream = &depthStream;

    int changedStreamDummy;

    openni::Status ops = openni::OpenNI::waitForAnyStream(&pstream, 1, &changedStreamDummy, 50); //等待一帧
    ops = depthStream.readFrame(&depth_frame);

    if (ops != openni::STATUS_OK)
    {
        timerDepth->stop();
        return;
    }

    //获取深度帧数据
    auto depth = depth_frame.getData();
    auto depthWidth = depth_frame.getWidth();
    auto depthHeight = depth_frame.getHeight();

    //处理并渲染深度帧数据
    cv::Mat rawMat(depthHeight, depthWidth, CV_16UC1, (void*)depth);
    rawMat.convertTo(depthMat, CV_8UC1, 255.0 / iMaxDepth);

    //深度图采集为空
    if(depthMat.empty())
    {
        timerDepth->stop();
        QMessageBox *box = new QMessageBox(QMessageBox::Warning,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("深度图采集错误!"),QMessageBox::Ok);
        if(NULL!=box->button(QMessageBox::Ok))
        {
           box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
        }
        QTimer::singleShot(3000,box,SLOT(accept()));
        box->exec();
        return;
    }

    //cv::Mat转QImage
    QImage image_depth = QImage((const uchar*)depthMat.data, depthMat.cols,depthMat.rows, QImage::Format_Grayscale8).rgbSwapped();

    //依据不同分辨率显示不同大小的深度图像
    if(Camera_Settings::depth_resolution == "640*480")
    {
        ui->label_depth_1->clear();
        ui->label_depth_1->setPixmap(QPixmap::fromImage(image_depth));
    }
    else if(Camera_Settings::depth_resolution == "320*240")
    {
        ui->label_depth_2->clear();
        ui->label_depth_2->setPixmap(QPixmap::fromImage(image_depth));
    }

    bcq_depthMat.enqueue(depthMat);

    cv::waitKey(10); //防止程序卡住
}


void Astra::show_point_cloud()
{
    if(bcq_cloudRGB.try_dequeue(cloudRGB))
    {
        viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
        viewer->addPointCloud(cloudRGB);
        flag_cloud = false;

    }
    else if(bcq_cloud.try_dequeue(cloud))
    {
        viewer.reset(new pcl::visualization::PCLVisualizer("viewer", false));
        viewer->addPointCloud(cloud);
        flag_cloud = true;
    }

    //依据不同分辨率显示点云
    if(Camera_Settings::depth_resolution == "640*480")
    {
        ui->qvtkWidget_1->SetRenderWindow(viewer->getRenderWindow());
        ui->qvtkWidget_1->update();
    }
    else if(Camera_Settings::depth_resolution == "320*240")
    {
        ui->qvtkWidget_2->SetRenderWindow(viewer->getRenderWindow());
        ui->qvtkWidget_2->update();
    }
}


void Astra::help_guide()
{
    QMessageBox *box = new QMessageBox(QMessageBox::Information, QString::fromLocal8Bit("使用说明"),
                                       QString::fromLocal8Bit(" 本软件提供了Astra相机的深度图,\n 彩色图以及点云显示和保存功能。\n\n"
                                                              " 由于开发周期短和本人能力有限,\n 其他功能还尚未完善,敬请谅解。"),
                                       QMessageBox::Ok);
    if(NULL!=box->button(QMessageBox::Ok))
    {
       box->button(QMessageBox::Ok)->setText(QString::fromLocal8Bit("确 定"));
    }
    box->setStyleSheet("QLabel{min-width: 240px;min-height: 180px;}");
    box->exec();
}


void Astra::help_about()
{
    QMessageBox::about(NULL, QString::fromLocal8Bit("关于AstraGUI"), "by taify");
}


代码写的比较糙,但功能基本上都实现了。本来想用cmake管理工程,但发现vtk库和pcl库写在CMakeLists里面不知道为啥似乎会有冲突,两个库单独用好像都可以,只好还是用Qt自带的.pro文件来配置了。完整工程文件已上传GitHub
另外,我把win10下Release-x64编译打包的应用程序放到百度网盘链接(链接:https://pan.baidu.com/s/160MyTBiNr0N6WbSjNLUZpw提取码:oqv3 )里面了,在另外一台win10电脑上测试过了也能凑合着用。图像如果有读不出来的情况把相机拔下来重插一下就好了。

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

给算法爸爸上香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值