VTK9.2.0+Qt5.14.0 绘制点云
背景
为了显示结构光重建后的点云,开发QT5.14.0+VTK9.2.0的上位机软件,用于对结构光3D相机进行控制,并接收传输回来的3D数据,显示在窗口中。
配置QT和VTK
VTK9.2.0下载源码,用Cmake编译,编译好的VTK9.2.0-vs2017在链接中:VTK9.2.0-vs2017编译工程
QT5.14.0下载链接
VTK绘制点云
VTK构造显示数据的基本流程是:
Point -> Cell -> Poly -> PolyMapper -> Actor -> Renderer -> QVTKOpenGLNativeWidget
其中,
⋅ \cdot ⋅ vtkPoints类对应创建点数据,包含点的坐标,以及属性
⋅ \cdot ⋅ vtkCellArray类是构造一种元素,比如三角网格,对应有三个point,那么一个cell中就会存储这三个point的索引值
⋅ \cdot ⋅ vtkPolyData类是构造多边形元素
⋅ \cdot ⋅ vtkActor类是构造“演员”
⋅ \cdot ⋅ vtkRenderer类是构造着色器,理解为渲染场景的控制,包含“演员”、光源、背景等
⋅ \cdot ⋅ vtkPolyDataMapper类将多边形元素和Actor建立联系
⋅ \cdot ⋅ QVTKOpenGLNativeWidget类是渲染窗口控件
在qt中创建VTK渲染窗口控件有两种方式:
① 双击工程左侧.ui文件,在qt designer中创建ui.openGLWidget对象
ui.openGLWidget是通过qt designer,拖入QVTKWidget控件,右键该控件选择“提升窗口部件”,基类选择QOpenGLWidget, 提升的类名称为QVTKOpenGLNativeWidget, 在右上角的对象查看器中,重命名为openGLWidget. (注意:VTK8的创建方式是不一样的,注意版本)
② 方法二是直接用代码生成的方式,在工程的构造函数中直接new一个QVTKOpenGLNativeWidget对象,并设置其位置信息
QVtkDemo2::QVtkDemo2(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); //new一个QVTKOpenGLNativeWidget的对象 ui.openGLWidget = new QVTKOpenGLNativeWidget(this); //设置渲染窗口的尺寸 ui.openGLWidget->resize(100, 100); //设置左上角的在主窗口中的坐标 ui.openGLWidget->move(50, 50); testVtk3D(); }
构造一个testVtk3D函数,用于绘制点云,并使用vtkCameraOrientationWidget类创建一个坐标轴对象,由于testVtk3D在构造函数中调用,需要在头文件中将其定义为全局变量。另外,VTK使用的是智能指针vtkSmartPointer,无需管理其释放问题,VTK还提供vtkNew类的智能指针,
vtkSmartPointer与vtkNew两者主要的使用区别在于:前者多用于全局变量,后者多用于局部变量
//在头文件中定义为全局变量 vtkSmartPointer cameraOrientationWidget;
void QVtkDemo2::testVtk3D() { //创建着色器对象 vtkSmartPointer g_vtkRenderer = vtkSmartPointer::New(); //设置背景颜色 g_vtkRenderer->SetBackground(.1, .2, .4); //创建point对象 vtkSmartPointer g_vtkPoints = vtkSmartPointer::New(); //创建cell对象 vtkSmartPointer g_vtkVertices = vtkSmartPointer::New(); vtkIdType id[1]; //随机生成200个点 for (int i = 0; i InsertNextPoint(x, y, z); g_vtkVertices->InsertNextCell(1, id); } //创建poly对象 vtkSmartPointer g_vtkpolyData = vtkSmartPointer::New(); g_vtkpolyData->SetPoints(g_vtkPoints); g_vtkpolyData->SetVerts(g_vtkVertices); //创建polyMapper vtkSmartPointer g_vtkpointsMapper = vtkSmartPointer::New(); g_vtkpointsMapper->SetInputData(g_vtkpolyData); //创建Actor vtkSmartPointer g_vtkpointsActor = vtkSmartPointer::New(); g_vtkpointsActor->SetMapper(g_vtkpointsMapper); g_vtkpointsActor->GetProperty()->SetPointSize(3);//设置点的大小 g_vtkRenderer->AddActor(g_vtkpointsActor); //根据点云的包围盒,寻找最佳的显示视点位置 g_vtkRenderer->ResetCamera(); //ui中的绘制窗口添加定义的着色器 ui.openGLWidget->renderWindow()->AddRenderer(g_vtkRenderer); //开始三维渲染 ui.openGLWidget->renderWindow()->Render(); //绘制坐标轴 cameraOrientationWidget = vtkSmartPointer::New(); cameraOrientationWidget->SetInteractor(ui.openGLWidget->interactor()); cameraOrientationWidget->SetParentRenderer(g_vtkRenderer); cameraOrientationWidget->SetEnabled(1); return; }
运行效果如下图
VTK根据Z值绘制点云颜色
void QVtkDemo2::testVtk3D() { //创建着色器对象 vtkSmartPointer g_vtkRenderer = vtkSmartPointer::New(); //设置背景颜色 g_vtkRenderer->SetBackground(.1, .2, .4); //创建point对象 vtkSmartPointer g_vtkPoints = vtkSmartPointer::New(); g_vtkPoints->SetNumberOfPoints(200); //创建cell对象 vtkSmartPointer g_vtkVertices = vtkSmartPointer::New(); vtkIdType id[1]; //随机生成200个点 float minz = VTK_FLOAT_MAX, maxz = VTK_FLOAT_MIN; for (int i = 0; i SetPoint(i, x, y, z); id[0] = i; g_vtkVertices->InsertNextCell(1, id); if (z > maxz) { maxz = z; } if (z SetPoints(g_vtkPoints); g_vtkpolyData->SetVerts(g_vtkVertices); vtkSmartPointer g_glyphFilter = vtkSmartPointer::New(); g_glyphFilter->SetInputData(g_vtkpolyData); g_glyphFilter->Update(); vtkSmartPointer g_elevationFilter = vtkSmartPointer::New(); g_elevationFilter->SetInputConnection(g_glyphFilter->GetOutputPort()); g_elevationFilter->SetLowPoint(0, 0, minz); g_elevationFilter->SetHighPoint(0, 0, maxz); //创建polyMapper vtkSmartPointer g_vtkpointsMapper = vtkSmartPointer::New(); g_vtkpointsMapper->SetInputConnection(g_elevationFilter->GetOutputPort()); //创建Actor vtkSmartPointer g_vtkpointsActor = vtkSmartPointer::New(); g_vtkpointsActor->SetMapper(g_vtkpointsMapper); g_vtkpointsActor->GetProperty()->SetPointSize(3);//设置点的大小 g_vtkRenderer->AddActor(g_vtkpointsActor); //建立查找表,将Z深度映射为一个查找表,表的值对应不同的颜色 vtkNew lut = vtkNew::vtkNew(); lut->SetNumberOfTableValues(7); lut->SetHueRange(0.0, 0.67); //这里是红到蓝,设置为蓝到红 lut->SetTableRange(minz, maxz); lut->Build(); //创建色谱栏 vtkNew colorBar = vtkNew::vtkNew(); colorBar->SetLookupTable(lut); colorBar->SetNumberOfLabels(7); colorBar->SetBarRatio(0.10); colorBar->SetUnconstrainedFontSize(0.05); colorBar->SetMaximumHeightInPixels(100); colorBar->SetDisplayPosition(500, 80); g_vtkRenderer->AddActor2D(colorBar); //根据点云的包围盒,寻找最佳的显示视点位置 g_vtkRenderer->ResetCamera(); //ui中的绘制窗口添加定义的着色器 ui.openGLWidget->renderWindow()->AddRenderer(g_vtkRenderer); //开始三维渲染 ui.openGLWidget->renderWindow()->Render(); //绘制坐标轴 cameraOrientationWidget = vtkSmartPointer::New(); cameraOrientationWidget->SetInteractor(ui.openGLWidget->interactor()); cameraOrientationWidget->SetParentRenderer(g_vtkRenderer); cameraOrientationWidget->SetEnabled(1); return; }
VTK赋予点云真实纹理信息(灰度\彩色)
这个功能的需要,是因为重建点云是一个“白模”或像上一节中的深度颜色映射图一样,有时候会需要点云贴上相机拍摄的灰度纹理或彩色纹理。下面的代码中,我定义了vtkUnsignedCharArray的指针,对256个点,分别赋予了一个颜色,R=G=B的情况就是灰度。由此,可实现点云真实纹理的显示。
void QVtkDemo2::testVtk3D() { //创建着色器对象 vtkSmartPointer g_vtkRenderer = vtkSmartPointer::New(); //设置背景颜色 g_vtkRenderer->SetBackground(.1, .2, .4); //创建point对象 vtkSmartPointer g_vtkPoints = vtkSmartPointer::New(); g_vtkPoints->SetNumberOfPoints(256); //创建cell对象 vtkSmartPointer g_vtkVertices = vtkSmartPointer::New(); vtkIdType id[1]; vtkSmartPointer ptColor = vtkSmartPointer::New(); ptColor->SetNumberOfTuples(256); ptColor->SetNumberOfComponents(3); //随机生成256个点, 每个点一个灰度值 float minz = VTK_FLOAT_MAX, maxz = VTK_FLOAT_MIN; for (int i = 0; i SetPoint(i, x, y, z); id[0] = i; g_vtkVertices->InsertNextCell(1, id); //赋予每一个点一个RGB值,R=G=B显示灰度,根据需要修改程序 unsigned char rgb[3]; rgb[0] = i; rgb[1] = i; rgb[2] = i; ptColor->InsertTypedTuple(i, rgb); } //创建poly对象 vtkSmartPointer g_vtkpolyData = vtkSmartPointer::New(); g_vtkpolyData->SetPoints(g_vtkPoints); g_vtkpolyData->SetVerts(g_vtkVertices); g_vtkpolyData->GetPointData()->SetScalars(ptColor); //创建polyMapper vtkSmartPointer g_vtkpointsMapper = vtkSmartPointer::New(); g_vtkpointsMapper->SetInputData(g_vtkpolyData); //创建Actor vtkSmartPointer g_vtkpointsActor = vtkSmartPointer::New(); g_vtkpointsActor->SetMapper(g_vtkpointsMapper); g_vtkpointsActor->GetProperty()->SetPointSize(3);//设置点的大小 g_vtkRenderer->AddActor(g_vtkpointsActor); //根据点云的包围盒,寻找最佳的显示视点位置 g_vtkRenderer->ResetCamera(); //ui中的绘制窗口添加定义的着色器 ui.openGLWidget->renderWindow()->AddRenderer(g_vtkRenderer); //开始三维渲染 ui.openGLWidget->renderWindow()->Render(); //绘制坐标轴 cameraOrientationWidget = vtkSmartPointer::New(); cameraOrientationWidget->SetInteractor(ui.openGLWidget->interactor()); cameraOrientationWidget->SetParentRenderer(g_vtkRenderer); cameraOrientationWidget->SetEnabled(1); return; }
petal_20240322_142336