PCL(Point Cloud Library )是功能很强大的开源C++库,最近博主需要结合PCL和QT可视化ply格网文件。
查阅了相关资料,得知PCL的可视化是通过VTK实现的,所以需要搞清楚VTK和QT的绑定方法就行了,最简单的就是使用QVTKWidget,这个在Qt Designer里面是以插件形式使用的。因此要在UI设计时,添加QVTKWidget控件.
1. 编译VTK
记住一定要用VTK源码编译!!!!如果你用官网的二进制文件直接安装VTK的话是缺少QVTKWidget插件的。
在编译VTK的时候,VTK_USE_QT以及BUILD_SHARED_LIBS这两个选项需要勾选,编译完成后会生成QVTKWidgetPlugin.dll和QVTKWidgetPlugin.lib。把生成release(debug版本的话QT Designer会打不开,博主亲测打不开)版本的QVTKWidgetPlugin.dll和QVTKWidgetPlugin.lib拷贝到qt的安装目录里的plugins/designer目录下。打开Qt Designer时即可看到相关的插件。如下图所示:
2.UI设计
在主窗口中把QVTKWidget控件拖到合适的位置。然后添加打开格网文件的“open动作”,并转到该动作的槽函数,对槽函数添加你需要实现打开ply文件的代码。
3. 代码
头文件:
#ifndef RECONSTRUCTIONMAINWINDOW_H
#define RECONSTRUCTIONMAINWINDOW_H
#include <QMainWindow>
#include <QList>
#include <QString>
#ifndef Q_MOC_RUN
#include <boost/shared_ptr.hpp>
#include <pcl/PolygonMesh.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/io/vtk_io.h>
#endif
namespace Ui {
class ReconstructionMainWindow;
}
class ReconstructionMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit ReconstructionMainWindow(QWidget *parent = 0);
~ReconstructionMainWindow();
private:
Ui::ReconstructionMainWindow *ui;
//格网数据的存储
pcl::PolygonMesh::Ptr plyfile;
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
public slots:
void on_actionOpen_triggered();
};
#endif // RECONSTRUCTIONMAINWINDOW_H
大家注意上面代码中的
#ifndef Q_MOC_RUN
.....
.....
.....
#endif
之所以这样把包含boost相关的头文件放在这个里面是因为:Qt需要用Moc工具moc你的代码,而博主的QT版本是4.8.0,boost版本是1.5.0,由于moc编译器和boost不兼容,所以会出现Parse error at “BOOST_JOIN”这样的错误,解决方法有好几种:
- 我用的是:将Qt外的头文件放在#ifndef Q_MOC_RUN …#endif里面。
- 如果你用的是QT5.0以上的版本就没有这个错误了,因为5.0版本已经解决这个bug了。
槽函数实现代码:
static int num_ply = 0;
QString _plf_fileName = QFileDialog::getOpenFileName(this, tr("Open PlyFile"), ".", "ply(*.ply)");
if(_plf_fileName.length() == 0)
{
QMessageBox::information(NULL, tr("Path"), tr("You didn't select any files."));
}
std::string file_name = _plf_fileName.toStdString();
char ply_id[ 1024 ];
sprintf( ply_id, "%05d", num_ply );
if ( num_ply == 0 )
{
plyfile.reset (new pcl::PolygonMesh);
viewer.reset (new pcl::visualization::PCLVisualizer ("viewer",false));
//initialVtkWidget();
pcl::io::loadPolygonFilePLY(file_name,*plyfile);
viewer->addPolygonMesh(*plyfile,ply_id);
ui->qvtkWidget->SetRenderWindow(viewer->getRenderWindow ());
viewer->setupInteractor (ui->qvtkWidget->GetInteractor (), ui->qvtkWidget->GetRenderWindow ());
}
else
{
plyfile.reset (new pcl::PolygonMesh);
pcl::io::loadPolygonFilePLY(file_name,*plyfile);
viewer->addPolygonMesh(*plyfile,ply_id);
}
num_ply++;
viewer->resetCamera ();
ui->qvtkWidget->update ();
为了打开多个ply文件,我通过最笨的方法来实现:在函数中加入静态变量num_ply来计数打开ply的数目。 注意viewer->addPolygonMesh(*plyfile,ply_id);
这句代码,viewer识别不同的ply文件是通过string类型的ply_id来识别的,所以添加多个ply文件,并让多个ply文件同时显示只要给不同的ply文件赋予不同的id即可。