一、问题
想在利用PCL在点云可视化界面达到下图效果,主要是如何画圆。
找了很多资料,pcl中有 pcl::visualization::PCLVisualizer::addCircle 画圆环,但是明显看到圆环不圆,线条不光滑,不好看,于是有了我的画圆的方法。
在PCL中画圆环,pcl可视化pcl::visualization::PCLVisualizer
但是这样利用线段画圆性能不好,画得越多越卡,那还有什么办法呢?
二、利用vtk的不规则图形vtkRegularPolygonSource画圆
pcl没有画圆的接口,那就只有用VTK了,vtk也没有直接的画圆方案,但是参考了很多资料,发现了vtkRegularPolygonSource,画一个多边形,边设置多一点就无限接近圆了,和用线段拼接一个道理,只是这样效果更好。
重点是vtk画的图形和pcl可视化pcl::visualization::PCLVisualizer的viewer同时显示,而不是独立的。话不多说,上代码。
三、源码
void mainwindow::on_action_showGrid_triggered(bool isChecked)
{
if (isChecked) //绘制圆环及网格
{
//画网格
for (int i = -100; i <= 100; i += 10) {
viewer->addLine(pcl::PointXYZ(i, -100, 0), pcl::PointXYZ(i, 100, 0), QString("GridlineY%1").arg(i).toStdString(), 0);
viewer->addLine(pcl::PointXYZ(-100, i, 0), pcl::PointXYZ(100, i, 0), QString("GridlineX%1").arg(i).toStdString(), 0);
if(i > 0)
viewer->addText3D(QString::number(i).append("m").toStdString(), pcl::PointXYZ(0, i, 0), 0.8, 0.5, 0.5, 0.5, QString("GridText%1").arg(i).toStdString(), 0);
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_LINE_WIDTH, 0.1, QString("GridlineY%1").arg(i).toStdString(), 0);
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_LINE_WIDTH, 0.1, QString("GridlineX%1").arg(i).toStdString(), 0);
}
//画圆环
QVector<pcl::PointXYZ> points;
for (int j = 1; j <= 10; j++) {
int r = 10 * j;
vtkSmartPointer<vtkRegularPolygonSource> source = vtkSmartPointer<vtkRegularPolygonSource>::New();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
source->SetNumberOfSides(70); //多边形边数
source->SetRadius(r); //半径
source->SetCenter(0, 0, 0); //圆心
mapper->SetInputConnection(source->GetOutputPort());
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(0.5, 0.5, 0.5); //颜色
actor->GetProperty()->SetOpacity(1); //透明度
actor->GetProperty()->SetRepresentationToWireframe();//图形不填充,只要边框
ui.qvtkWidget->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(actor);
}
}
else //删除圆环及网格
{
//删除网格图形
viewer->removeAllShapes();
//删除圆环
vtkActorCollection* actorCollection = ui.qvtkWidget->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActors();
int num = actorCollection->GetNumberOfItems();
actorCollection->InitTraversal();
for (int i = 0; i < num; ++i)
{
vtkActor* actor = actorCollection->GetNextActor();
ui.qvtkWidget->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->RemoveActor(actor);
}
}
ui.qvtkWidget->update();
}
画网格是利用viewer直接画的线,画圆是利用vtk画的多边形,他们本不关联,但要显示在一个图里,就需要画在同一个renderer里,关键代码:
ui.qvtkWidget->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(actor);
因为在初始化viewer时,我们都添加了这几行代码:
ui.qvtkWidget->SetRenderWindow(viewer->getRenderWindow());
viewer->setupInteractor(ui.qvtkWidget->GetInteractor(), ui.qvtkWidget->GetRenderWindow());
ui.qvtkWidget->update();
四、最终效果
1.只保留圆环边框效果
actor->GetProperty()->SetColor(0.5, 0.5, 0.5);
actor->GetProperty()->SetOpacity(1);
actor->GetProperty()->SetRepresentationToWireframe();
2.圆环填充效果
actor->GetProperty()->SetColor(0.5, 0.5, 0.7);
actor->GetProperty()->SetOpacity(0.1);
//actor->GetProperty()->SetRepresentationToWireframe();
五、总结
说实话,代码不多,也很简单,但是我找了很多资料也没找到,一直想要这个效果,已经很久了,去年就想画这个,但是没找到合适的资料。慢慢积累吧,我获取知识的途径还是太少了。今天分享给大家,希望对大家有所帮助,程序员何苦为难程序员。