STL模型多视角可视点云数据获取
摘要
本文使用VTK库通过多面体细分提取给定STL模型的多视点可视点云数据。
实现
函数主体
void get_template(vtkSmartPointer<vtkPolyData> polydata, std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> &tem)
{
double CoM[3];
vtkIdType npts_com = 0;
vtkIdType *ptIds_com = nullptr;
vtkSmartPointer<vtkCellArray> cells_com = vtkSmartPointer<vtkCellArray>::New();
cells_com = polydata->GetPolys();
double center[3], p1_com[3], p2_com[3], p3_com[3], totalArea_com = 0;
double comx = 0, comy = 0, comz = 0;
for (cells_com->InitTraversal(); cells_com->GetNextCell(npts_com, ptIds_com);)
{
polydata->GetPoint(ptIds_com[0], p1_com);
polydata->GetPoint(ptIds_com[1], p2_com);
polydata->GetPoint(ptIds_com[2], p3_com);
vtkTriangle::TriangleCenter(p1_com, p2_com, p3_com, center);
double area_com = vtkTriangle::TriangleArea(p1_com, p2_com, p3_com);
comx += center[0] * area_com;
comy += center[1] * area_com;
comz += center[2] * area_com;
totalArea_com += area_com;
}
CoM[0] = comx / totalArea_com;
CoM[1] = comy / totalArea_com;
CoM[2] = comz / totalArea_com;
vtkSmartPointer<vtkTransform> trans_center = vtkSmartPointer<vtkTransform>::New();
trans_center->Translate(-CoM[0], -CoM[1], -CoM[2]);
vtkSmartPointer<vtkMatrix4x4> matrixCenter = trans_center->GetMatrix();
vtkSmartPointer<vtkTransformFilter> trans_filter_center = vtkSmartPointer<vtkTransformFilter>::New();
trans_filter_center->SetTransform(trans_center);
trans_filter_center->SetInputData(polydata);
trans_filter_center->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(trans_filter_center->GetOutputPort());
mapper->Update();
double bb[6];
mapper->GetBounds(bb);
double ms = (std::max)((std::fabs)(bb[0] - bb[1]), (std::max) ((std::fabs) (bb[2] - bb[3]), (std::fabs) (bb[4] - bb[5])));
double max_side = radius_sphere / 2.0;
double scale_factor = ms / max_side;
vtkSmartPointer<vtkPlatonicSolidSource> ico = vtkSmartPointer<vtkPlatonicSolidSource>::New();
ico->SetSolidTypeToIcosahedron();
ico->Update();
vtkSmartPointer<vtkLoopSubdivisionFilter> subdivide = vtkSmartPointer<vtkLoopSubdivisionFilter>::New();
subdivide->SetNumberOfSubdivisions(tesselation_level);
subdivide->SetInputConnection(ico->GetOutputPort());
subdivide->Update();
vtkSmartPointer<vtkPolyData> sphere_pre = vtkSmartPointer<vtkPolyData>::New();
sphere_pre = subdivide->GetOutput();
vtkSmartPointer<vtkTransform> trans_scale = vtkSmartPointer<vtkTransform> ::New();
trans_scale->Scale(scale_factor, scale_factor, scale_factor);
vtkSmartPointer<vtkMatrix4x4> matrixScale = trans_scale->GetMatrix();
vtkSmartPointer<vtkTransformFilter> trans_filter_scale = vtkSmartPointer<vtkTransformFilter>::New();
trans_filter_scale->SetTransform(trans_scale);
trans_filter_scale->SetInputData(sphere_pre);//相机放缩 这个自适应方法可以
trans_filter_scale->Update();
vtkSmartPointer<vtkPolyData> sphere = trans_filter_scale->GetPolyDataOutput();
vtkSmartPointer<vtkWorldPointPicker> worldPicker = vtkSmartPointer<vtkWorldPointPicker>::New();
std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f>> cam_positions;
cam_positions.resize(sphere->GetNumberOfPoints());
for (vtkIdType i = 0; i < sphere->GetNumberOfPoints(); i++)
{
double cam_pos[3];
sphere->GetPoint(i, cam_pos);
cam_positions[i] = Eigen::Vector3f(float(cam_pos[0]), float(cam_pos[1]), float(cam_pos[2]));
cam_positions[i].normalized();
}
for (const auto &cam_position : cam_positions)
{
PointCloudT::Ptr t(new PointCloudT);
double cam_pos[3];
cam_pos[0] = cam_position[0];
cam_pos[1] = cam_position[1];
cam_pos[2] = cam_position[2];
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
Eigen::Vector3f cam_pos_3f = cam_position;
Eigen::Vector3f perp = cam_pos_3f.cross(cam_pos_3f.cross(Eigen::Vector3f::UnitY()));
vtkSmartPointer<vtkCamera> cam = vtkSmartPointer<vtkCamera>::New();
cam->SetFocalPoint(0, 0, 0);
cam->SetViewUp(-perp[0], -perp[1], -perp[2]);
cam->SetPosition(cam_pos);
cam->SetViewAngle(view_angle);
cam->Modified();
vtkSmartPointer<vtkRenderer> render = vtkSmartPointer<vtkRenderer>::New();
render->AddActor(actor);
render->SetBackground(0, 0, 0);
render->SetActiveCamera(cam);
vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(render);
rw->SetSize(xres, yres);
rw->SetWindowName("multiview");
rw->SetOffScreenRendering(1);
rw->Render();
vtkSmartPointer<vtkWorldPointPicker> worldpicker = vtkSmartPointer<vtkWorldPointPicker>::New();
double coords[3];
for (int y = 0; y < yres; y++)
{
for (int x = 0; x < xres; x++)
{
double z = rw->GetZbufferDataAtPoint(x, y);
if (z == 1)
{
continue;
}
else
{
worldpicker->Pick(x, y, z, render);
worldpicker->GetPickPosition(coords);
PointT tmp;
tmp.x = coords[0];
tmp.y = coords[1];
tmp.z = coords[2];
t->push_back(tmp);
}
}
}
if (t->size() != 0) {
tem.push_back(t);
}
}
}
验证
HPR.h
#ifndef HIDDEN_POINT_REMOVAL
#define HIDDEN_POINT_REMOVAL
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <string>
#include <vector>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/common/transforms.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/project_inliers.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/surface/convex_hull.h>
#include <pcl/filters/extract_indices.h>
#include <Eigen/Dense>
#include <pcl/PolygonMesh.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkTriangle.h>
#include <vtkTransform.h>
#include <vtkMatrix4x4.h>
#include <vtkTransformFilter.h>
#include <vtkLoopSubdivisionFilter.h>
#include <vtkPlatonicSolidSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkWorldPointPicker.h>
#include <vtkcamera.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<pcl::PointXYZ> PointCloudT;
void HPR(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr& cloud_in, std::vector<float> camera_pos, int param, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out); // Hidden Point Removal
void get_template(std::string model_path, std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> &tem);
void get_template(vtkSmartPointer<vtkPolyData> polydata, std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> &tem);
#endif
HPR.cpp
#include "HPR.h"
using namespace Eigen;
using namespace pcl;
#define radius_sphere 1
#define tesselation_level 1
#define use_vertices FALSE
#define xres 120
#define yres 120
#define view_angle 90
void get_template(vtkSmartPointer<vtkPolyData> polydata, std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> &tem)
{
double CoM[3];
vtkIdType npts_com = 0;
vtkIdType *ptIds_com = nullptr;
vtkSmartPointer<vtkCellArray> cells_com = vtkSmartPointer<vtkCellArray>::New();
cells_com = polydata->GetPolys();
double center[3], p1_com[3], p2_com[3], p3_com[3], totalArea_com = 0;
double comx = 0, comy = 0, comz = 0;
for (cells_com->InitTraversal(); cells_com->GetNextCell(npts_com, ptIds_com);)
{
polydata->GetPoint(ptIds_com[0], p1_com);
polydata->GetPoint(ptIds_com[1], p2_com);
polydata->GetPoint(ptIds_com[2], p3_com);
vtkTriangle::TriangleCenter(p1_com, p2_com, p3_com, center);
double area_com = vtkTriangle::TriangleArea(p1_com, p2_com, p3_com);
comx += center[0] * area_com;
comy += center[1] * area_com;
comz += center[2] * area_com;
totalArea_com += area_com;
}
CoM[0] = comx / totalArea_com;
CoM[1] = comy / totalArea_com;
CoM[2] = comz / totalArea_com;
vtkSmartPointer<vtkTransform> trans_center = vtkSmartPointer<vtkTransform>::New();
trans_center->Translate(-CoM[0], -CoM[1], -CoM[2]);
vtkSmartPointer<vtkMatrix4x4> matrixCenter = trans_center->GetMatrix();
vtkSmartPointer<vtkTransformFilter> trans_filter_center = vtkSmartPointer<vtkTransformFilter>::New();
trans_filter_center->SetTransform(trans_center);
trans_filter_center->SetInputData(polydata);
trans_filter_center->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(trans_filter_center->GetOutputPort());
mapper->Update();
double bb[6];
mapper->GetBounds(bb);
double ms = (std::max)((std::fabs)(bb[0] - bb[1]), (std::max) ((std::fabs) (bb[2] - bb[3]), (std::fabs) (bb[4] - bb[5])));
double max_side = radius_sphere / 2.0;
double scale_factor = ms / max_side;
vtkSmartPointer<vtkPlatonicSolidSource> ico = vtkSmartPointer<vtkPlatonicSolidSource>::New();
ico->SetSolidTypeToIcosahedron();
ico->Update();
vtkSmartPointer<vtkLoopSubdivisionFilter> subdivide = vtkSmartPointer<vtkLoopSubdivisionFilter>::New();
subdivide->SetNumberOfSubdivisions(tesselation_level);
subdivide->SetInputConnection(ico->GetOutputPort());
subdivide->Update();
vtkSmartPointer<vtkPolyData> sphere_pre = vtkSmartPointer<vtkPolyData>::New();
sphere_pre = subdivide->GetOutput();
vtkSmartPointer<vtkTransform> trans_scale = vtkSmartPointer<vtkTransform> ::New();
trans_scale->Scale(scale_factor, scale_factor, scale_factor);
vtkSmartPointer<vtkMatrix4x4> matrixScale = trans_scale->GetMatrix();
vtkSmartPointer<vtkTransformFilter> trans_filter_scale = vtkSmartPointer<vtkTransformFilter>::New();
trans_filter_scale->SetTransform(trans_scale);
trans_filter_scale->SetInputData(sphere_pre);//相机放缩 这个自适应方法可以
trans_filter_scale->Update();
vtkSmartPointer<vtkPolyData> sphere = trans_filter_scale->GetPolyDataOutput();
vtkSmartPointer<vtkWorldPointPicker> worldPicker = vtkSmartPointer<vtkWorldPointPicker>::New();
std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f>> cam_positions;
cam_positions.resize(sphere->GetNumberOfPoints());
for (vtkIdType i = 0; i < sphere->GetNumberOfPoints(); i++)
{
double cam_pos[3];
sphere->GetPoint(i, cam_pos);
cam_positions[i] = Eigen::Vector3f(float(cam_pos[0]), float(cam_pos[1]), float(cam_pos[2]));
cam_positions[i].normalized();
}
for (const auto &cam_position : cam_positions)
{
PointCloudT::Ptr t(new PointCloudT);
double cam_pos[3];
cam_pos[0] = cam_position[0];
cam_pos[1] = cam_position[1];
cam_pos[2] = cam_position[2];
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
Eigen::Vector3f cam_pos_3f = cam_position;
Eigen::Vector3f perp = cam_pos_3f.cross(cam_pos_3f.cross(Eigen::Vector3f::UnitY()));
vtkSmartPointer<vtkCamera> cam = vtkSmartPointer<vtkCamera>::New();
cam->SetFocalPoint(0, 0, 0);
cam->SetViewUp(-perp[0], -perp[1], -perp[2]);
cam->SetPosition(cam_pos);
cam->SetViewAngle(view_angle);
cam->Modified();
vtkSmartPointer<vtkRenderer> render = vtkSmartPointer<vtkRenderer>::New();
render->AddActor(actor);
render->SetBackground(0, 0, 0);
render->SetActiveCamera(cam);
vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(render);
rw->SetSize(xres, yres);
rw->SetWindowName("multiview");
rw->SetOffScreenRendering(1);
rw->Render();
vtkSmartPointer<vtkWorldPointPicker> worldpicker = vtkSmartPointer<vtkWorldPointPicker>::New();
double coords[3];
for (int y = 0; y < yres; y++)
{
for (int x = 0; x < xres; x++)
{
double z = rw->GetZbufferDataAtPoint(x, y);
if (z == 1)
{
continue;
}
else
{
worldpicker->Pick(x, y, z, render);
worldpicker->GetPickPosition(coords);
PointT tmp;
tmp.x = coords[0];
tmp.y = coords[1];
tmp.z = coords[2];
t->push_back(tmp);
}
}
}
if (t->size() != 0) {
tem.push_back(t);
}
}
}
main.cpp
#include"HPR.h"
using namespace pcl;
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<pcl::PointXYZ> PointCloudT;
int main()
{
vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
reader->SetFileName("C:/Users/chensi/Desktop/cup.stl");
reader->Update();
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata = reader->GetOutput();
std::vector<PointCloudT::Ptr> v_pc;
get_template(polydata, v_pc);
pcl::visualization::PCLVisualizer::Ptr view(new pcl::visualization::PCLVisualizer);
view->setBackgroundColor(0, 0, 0);
view->addCoordinateSystem(0.1f);
for (int i = 1; i < v_pc.size();i++)
{
PointCloudT::Ptr tmp = v_pc[i];
pcl::visualization::PointCloudColorHandlerCustom<PointT>tmp_color(tmp, 100, 255, 200);
view->removeAllPointClouds();
view->addPointCloud(tmp, tmp_color, "tmp");
view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "tmp");
view->spinOnce(1000);
}
cout << v_pc.size() << endl;
return 0;
}
结果展示
结论
本文给出了多视角提取给定模型可视点云的算法。