pcl-vtk

张开发
2026/4/18 2:56:26 15 分钟阅读

分享文章

pcl-vtk
#pragma once#include QMainWindow#include ui_TSPointCloudMainWindow.h#include QVTKOpenGLNativeWidget.h// PCL/VTK 核心头文件保留#include pcl/point_cloud.h#include pcl/point_types.h#include pcl/io/pcd_io.h#include pcl/io/ply_io.h#include pcl/common/common.h#include memory#include mutex#include vtkSmartPointer.h#include vtkRenderer.h#include vtkActor.h#include vtkPolyData.h#include vtkPoints.h#include vtkCellArray.h#include vtkPolyDataMapper.h#include vtkAxesActor.h#include vtkCamera.h#include vtkGenericOpenGLRenderWindow.h#include vtkProperty.h#include vtkFloatArray.h#include vtkPointData.h#include vtkColorTransferFunction.h#include vtkInteractorStyleTrackballCamera.h // 交互样式#include vtkAxesActor.h // 坐标轴Actor头文件#include vtkRenderer.h#include vtkActorCollection.h#include vtkCaptionActor2D.h#include vtkTextActor.h#include vtkScalarBarActor.h#include vtkColorTransferFunction.h // 用于颜色渐变#include vtkScalarBarActor.h // 用于颜色条 Actor#include vtkTextProperty.h // 【报错缺失的这个】用于设置字体、颜色、大小#include vtkLookupTable.h // (可选) 如果使用 LUT#pragma execution_character_set(utf-8)class TSPointCloudMainWindow : public QMainWindow{Q_OBJECTpublic:TSPointCloudMainWindow(QWidget *parent nullptr);~TSPointCloudMainWindow();void setData(std::vectordouble x, std::vectordouble y, std::vectordouble z);protected:void showEvent(QShowEvent* event) override;void setupVTKRender();vtkSmartPointervtkPolyData convertPCLToVTK(const pcl::PointCloudpcl::PointXYZ::Ptr cloud);void updatePointCloudHeightRamp(int preset, QColor minColor, QColor maxColor, QColor midColor, float minZ, float maxZ);void resetRender();private:Ui::TSPointCloudMainWindowClass ui;pcl::PointCloudpcl::PointXYZ::Ptr cloud;bool isViewerInitialized;QColor currentColor Qt::white;// VTK 核心对象vtkSmartPointervtkRenderer renderer;vtkSmartPointervtkActor pointActor;vtkSmartPointervtkAxesActor axesActor; // 三维轴Actor};#include TSPointCloudMainWindow.h#include vtkOrientationMarkerWidget.h#include vtkInteractorStyleTrackballCamera.hTSPointCloudMainWindow::TSPointCloudMainWindow(QWidget* parent) :QMainWindow(parent), cloud(new pcl::PointCloudpcl::PointXYZ), isViewerInitialized(false), renderer(vtkSmartPointervtkRenderer::New()), pointActor(vtkSmartPointervtkActor::New()){ui.setupUi(this);vtkObject::GlobalWarningDisplayOff();}TSPointCloudMainWindow::~TSPointCloudMainWindow(){}void TSPointCloudMainWindow::setData(std::vectordouble x, std::vectordouble y, std::vectordouble z){cloud-clear();int len x.size();for (int i 0; i len; i){pcl::PointXYZ point;point.x x[i];point.y y[i];point.z z[i];cloud-push_back(point);}// 转换PCL到VTK修正调用方式vtkSmartPointervtkPolyData vtkCloud convertPCLToVTK(cloud);// 更新MappervtkSmartPointervtkPolyDataMapper mapper vtkSmartPointervtkPolyDataMapper::New();mapper-SetInputData(vtkCloud);pointActor-SetMapper(mapper);resetRender();}void TSPointCloudMainWindow::resetRender(){if (!renderer || !cloud || cloud-empty()) {return;}Eigen::Vector4f min_p, max_p;pcl::getMinMax3D(*cloud, min_p, max_p);double bounds[6] {static_castdouble(min_p[0]), static_castdouble(max_p[0]),static_castdouble(min_p[1]), static_castdouble(max_p[1]),static_castdouble(min_p[2]), static_castdouble(max_p[2])};double z_min bounds[4];double z_max bounds[5];if (z_max - z_min 1e-6) {z_min - 1.0;z_max 1.0;}vtkPolyDataMapper* mapper vtkPolyDataMapper::SafeDownCast(pointActor-GetMapper());if (!mapper) {return;}vtkPolyData* polyData vtkPolyData::SafeDownCast(mapper-GetInput());if (!polyData) {return;}vtkSmartPointervtkFloatArray zScalars vtkSmartPointervtkFloatArray::New();zScalars-SetName(Elevation);zScalars-SetNumberOfComponents(1);zScalars-SetNumberOfTuples(static_castvtkIdType(cloud-size()));for (size_t i 0; i cloud-size(); i) {zScalars-SetTuple1(static_castvtkIdType(i), cloud-points[i].z);}polyData-GetPointData()-SetScalars(zScalars);polyData-Modified();mapper-SetColorModeToMapScalars();mapper-SetScalarModeToUsePointData();mapper-SetScalarRange(z_min, z_max);mapper-ScalarVisibilityOn();vtkLookupTable* lut vtkLookupTable::SafeDownCast(mapper-GetLookupTable());if (!lut) {vtkSmartPointervtkLookupTable newLut vtkSmartPointervtkLookupTable::New();newLut-SetHueRange(0.667, 0.0);newLut-SetSaturationRange(1.0, 1.0);newLut-SetValueRange(1.0, 1.0);newLut-SetNumberOfTableValues(256);newLut-SetTableRange(z_min, z_max);newLut-Build();mapper-SetLookupTable(newLut);}else {lut-SetTableRange(z_min, z_max);lut-Build();lut-Modified();}mapper-Modified();mapper-Update();double center[3] {(bounds[0] bounds[1]) / 2.0,(bounds[2] bounds[3]) / 2.0,(bounds[4] bounds[5]) / 2.0};double x_span bounds[1] - bounds[0];double y_span bounds[3] - bounds[2];double z_span bounds[5] - bounds[4];if (x_span 1e-6) x_span 1.0;if (y_span 1e-6) y_span 1.0;if (z_span 1e-6) z_span 1.0;// 以 XY 的较大跨度为参考避免 target_span 被极端 z 放大反向污染double target_span std::max(x_span, y_span);double scale_x target_span / x_span;double scale_y target_span / y_span;double scale_z target_span / z_span;// 防止 z_span 极小时 scale_z 爆炸const double MAX_SCALE 100.0;scale_x std::min(scale_x, MAX_SCALE);scale_y std::min(scale_y, MAX_SCALE);scale_z std::min(scale_z, MAX_SCALE);std::cout x_span: x_span std::endl;std::cout y_span: y_span std::endl;std::cout z_span: z_span std::endl;std::cout scale_x: scale_x std::endl;std::cout scale_y: scale_y std::endl;std::cout scale_z: scale_z std::endl;pointActor-SetScale(scale_x, scale_y, scale_z);vtkCamera* camera renderer-GetActiveCamera();if (camera) {camera-ParallelProjectionOff();camera-SetFocalPoint(center);camera-SetViewUp(0, 0, 1);}renderer-ResetCamera();if (camera) {double scaled_x x_span * scale_x;double scaled_y y_span * scale_y;double scaled_z z_span * scale_z;double diag std::sqrt(scaled_x * scaled_x scaled_y * scaled_y scaled_z * scaled_z);if (diag 1e-6) {diag 1.0;}double camDist camera-GetDistance();double nearClip std::max(0.01, camDist - diag * 2.0);double farClip camDist diag * 2.0;camera-SetClippingRange(nearClip, farClip);camera-SetViewUp(0, 0, 1);}ui.m_qvtkWidget-renderWindow()-Render();ui.m_qvtkWidget-update();updatePointCloudHeightRamp(1, QColor(), QColor(), QColor(),static_castfloat(z_min), static_castfloat(z_max));ui.m_qvtkWidget-renderWindow()-Render();ui.m_qvtkWidget-update();}vtkSmartPointervtkPolyData TSPointCloudMainWindow::convertPCLToVTK(const pcl::PointCloudpcl::PointXYZ::Ptr cloud){vtkSmartPointervtkPoints points vtkSmartPointervtkPoints::New();vtkSmartPointervtkCellArray vertices vtkSmartPointervtkCellArray::New();// 遍历PCL点云for (const auto p : *cloud) {if (std::isnan(p.x) || std::isnan(p.y) || std::isnan(p.z)) continue;vtkIdType id points-InsertNextPoint(p.x, p.y, p.z);vertices-InsertNextCell(1, id);}// 构建VTK PolyDatavtkSmartPointervtkPolyData polyData vtkSmartPointervtkPolyData::New();polyData-SetPoints(points);polyData-SetVerts(vertices);return polyData;}// 窗口显示事件void TSPointCloudMainWindow::showEvent(QShowEvent* event){QMainWindow::showEvent(event);if (!isViewerInitialized) {setupVTKRender();isViewerInitialized true;}}void TSPointCloudMainWindow::setupVTKRender(){vtkSmartPointervtkGenericOpenGLRenderWindow renderWindow vtkSmartPointervtkGenericOpenGLRenderWindow::New();ui.m_qvtkWidget-setRenderWindow(renderWindow);renderWindow-AddRenderer(renderer);vtkRenderWindowInteractor* interactor ui.m_qvtkWidget-interactor();if (interactor){interactor-SetRenderWindow(renderWindow);// 关键启用相机交互风格vtkSmartPointervtkInteractorStyleTrackballCamera style vtkSmartPointervtkInteractorStyleTrackballCamera::New();interactor-SetInteractorStyle(style);interactor-Initialize();}renderer-SetBackground(0.0, 0.0, 0.0);renderer-ResetCamera();// 点云 ActorpointActor-GetProperty()-SetPointSize(2);pointActor-GetProperty()-SetColor(this-currentColor.redF(),this-currentColor.greenF(),this-currentColor.blueF());renderer-AddActor(pointActor);// 方向坐标轴不再加到主 rendereraxesActor vtkSmartPointervtkAxesActor::New();axesActor-SetTotalLength(0.8, 0.8, 0.8);axesActor-SetAxisLabels(1);vtkSmartPointervtkOrientationMarkerWidget axesWidget vtkSmartPointervtkOrientationMarkerWidget::New();axesWidget-SetOrientationMarker(axesActor);axesWidget-SetInteractor(interactor);axesWidget-SetViewport(0.0, 0.0, 0.2, 0.2); // 左下角axesWidget-SetEnabled(1);axesWidget-InteractiveOff(); // 不允许鼠标单独拖它}//void TSPointCloudMainWindow::setupVTKRender()//{// vtkSmartPointervtkGenericOpenGLRenderWindow renderWindow // vtkSmartPointervtkGenericOpenGLRenderWindow::New();// ui.m_qvtkWidget-setRenderWindow(renderWindow);// renderWindow-AddRenderer(renderer);//// // 初始化交互器// vtkRenderWindowInteractor* interactor ui.m_qvtkWidget-interactor();// if (interactor)// {// interactor-SetRenderWindow(renderWindow);// interactor-Initialize();// }//// // 配置渲染器// renderer-SetBackground(0.0, 0.0, 0.0); // 黑色背景// renderer-ResetCamera();//// // 添加坐标系作为类成员默认隐藏// axesActor vtkSmartPointervtkAxesActor::New();// axesActor-SetTotalLength(0.2, 0.2, 0.2);// axesActor-SetAxisLabels(0);// axesActor-SetVisibility(true); // 关键设置为隐藏// renderer-AddActor(axesActor);//// // 初始化点云Actor// pointActor-GetProperty()-SetPointSize(2);// pointActor-GetProperty()-SetColor(this-currentColor.redF(),// this-currentColor.greenF(),// this-currentColor.blueF());// renderer-AddActor(pointActor);//}void TSPointCloudMainWindow::updatePointCloudHeightRamp(int preset, QColor minColor, QColor maxColor, QColor midColor, float minZ, float maxZ){// 1. 组件校验 if (!pointActor || !renderer) return;vtkPolyDataMapper* mapper vtkPolyDataMapper::SafeDownCast(pointActor-GetMapper());if (!mapper || !cloud || cloud-empty()) return;vtkPolyData* polyData mapper-GetInput();if (!polyData) return;// 2. 高度范围校验 if (qFuzzyCompare(minZ, maxZ) || minZ maxZ) {Eigen::Vector4f min_p, max_p;pcl::getMinMax3D(*cloud, min_p, max_p);minZ static_castfloat(min_p[2]);maxZ static_castfloat(max_p[2]);// 防止范围为 0if (qFuzzyCompare(minZ, maxZ)) {minZ - 0.1f;maxZ 0.1f;}}// 3. 确保 Z 轴标量存在 vtkPointData* pointData polyData-GetPointData();// 检查是否已有名为 ZCoordinates 的标量避免重复创建bool needCreateScalars true;if (pointData pointData-GetScalars()) {if (pointData-GetScalars()-GetName() strcmp(pointData-GetScalars()-GetName(), ZCoordinates) 0) {needCreateScalars false;}}if (needCreateScalars) {vtkSmartPointervtkFloatArray zScalars vtkSmartPointervtkFloatArray::New();zScalars-SetName(ZCoordinates);zScalars-SetNumberOfComponents(1);zScalars-SetNumberOfTuples(polyData-GetNumberOfPoints());double point[3];for (vtkIdType i 0; i polyData-GetNumberOfPoints(); i) {polyData-GetPoint(i, point);zScalars-SetValue(i, point[2]);}pointData-SetScalars(zScalars);polyData-Modified(); // 通知数据已修改}vtkSmartPointervtkColorTransferFunction colorTF vtkSmartPointervtkColorTransferFunction::New();colorTF-SetColorSpaceToRGB();auto mapPosToZ [minZ, maxZ](double pos) - double{return minZ pos * (maxZ - minZ);};colorTF-AddRGBPoint(mapPosToZ(0.00), 0.0, 0.0, 139.0 / 255.0); // #00008BcolorTF-AddRGBPoint(mapPosToZ(0.17), 0.0, 0.0, 1.0); // #0000FFcolorTF-AddRGBPoint(mapPosToZ(0.34), 0.0, 1.0, 1.0); // #00FFFFcolorTF-AddRGBPoint(mapPosToZ(0.50), 0.0, 1.0, 0.0); // #00FF00colorTF-AddRGBPoint(mapPosToZ(0.67), 1.0, 1.0, 0.0); // #FFFF00colorTF-AddRGBPoint(mapPosToZ(0.84), 1.0, 0.0, 0.0); // #FF0000colorTF-AddRGBPoint(mapPosToZ(1.00), 139.0 / 255.0, 0.0, 0.0); // #8B0000mapper-ScalarVisibilityOn();mapper-SetScalarModeToUsePointData();mapper-SetLookupTable(colorTF); // 直接应用颜色传输函数mapper-SetScalarRange(minZ, maxZ);mapper-SetUseLookupTableScalarRange(true);mapper-Update();// 重置 Actor 颜色防止覆盖渐变pointActor-GetProperty()-SetColor(1.0, 1.0, 1.0);pointActor-GetProperty()-SetOpacity(1.0);// 假设你没有成员变量我们采用“查找并移除旧条创建新条”的策略防止重复叠加vtkActorCollection* actors renderer-GetActors();actors-InitTraversal();vtkActor* oldBar nullptr;while (vtkActor* actor actors-GetNextActor()) {if (actor-IsA(vtkScalarBarActor)) {oldBar actor;break;}}if (oldBar) {renderer-RemoveActor(oldBar);}// 6.2 创建新的 ScalarBarActorvtkSmartPointervtkScalarBarActor scalarBar vtkSmartPointervtkScalarBarActor::New();// 关联 LookupTable (必须与 Mapper 使用的相同)scalarBar-SetLookupTable(mapper-GetLookupTable());//// 设置标题//scalarBar-SetTitle(Height (Z));//scalarBar-GetTitleTextProperty()-SetColor(1.0, 1.0, 1.0); // 标题颜色 (白色)//scalarBar-GetTitleTextProperty()-SetFontSize(14);// 设置标签格式 (例如保留 2 位小数)scalarBar-SetLabelFormat(%.4f);scalarBar-GetLabelTextProperty()-SetColor(1.0, 1.0, 1.0); // 标签颜色scalarBar-GetLabelTextProperty()-SetFontSize(12);// 设置位置和大小 (Viewport 坐标 0.0-1.0)scalarBar-SetWidth(0.1);scalarBar-SetHeight(0.8);scalarBar-SetPosition(0.85, 0.1); // x, y (左下角坐标)// 设置标签数量scalarBar-SetNumberOfLabels(6);// 6.3 添加到渲染器renderer-AddActor(scalarBar);// 强制重绘ui.m_qvtkWidget-renderWindow()-Render();ui.m_qvtkWidget-update();QCoreApplication::processEvents();}

更多文章