当前位置: 首页 > news >正文

8.pcl 点云特征

文章目录

  • 法向量特征估计
  • 估计点云子集的表面法线(error)
  • 积分图进行法线估计
  • 点特征直方图
  • 快速特征直方图 FPFH
  • 深度图像(range image)中提取NARF特征

法向量特征估计

#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/search/kdtree.h>
#include <pcl/point_types.h>
#include <boost/thread/thread.hpp>
#include <thread>
#include <iostream>
#include <chrono>  // std::chronoint main()
{// 打开点云文件pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile("../table_scene_lms400.pcd", *cloud) == -1){PCL_ERROR("Couldn't read the pcd file.\n");return -1;}std::cout << "Loaded " << cloud->size() << " points." << std::endl;// 创建法线估计对象pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud(cloud);// 创建KdTree用于搜索pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());ne.setSearchMethod(tree);// 输出法线点云pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);ne.setRadiusSearch(0.03); // 半径搜索邻域ne.compute(*cloud_normals);// ✅ 正确保存法线点云(使用 savePCDFile)pcl::io::savePCDFile("../table_cloud_normals.pcd", *cloud_normals);std::cout << "Saved " << cloud_normals->size() << " normal points." << std::endl;// 可视化pcl::visualization::PCLVisualizer viewer("PCL Viewer");viewer.setBackgroundColor(0, 0, 0);viewer.addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, cloud_normals, 10, 0.05, "normals");// 主循环while (!viewer.wasStopped()){viewer.spinOnce(100);std::this_thread::sleep_for(std::chrono::milliseconds(100));}return 0;
}

在这里插入图片描述

估计点云子集的表面法线(error)

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d.h>
#include <pcl/search/kdtree.h>         // 需要 kdtree
#include <vector>                      // std::vector
#include <cmath>                       // 必须添加:std::floor 所在头文件int main (){//打开点云代码pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile ("../table_scene_lms400.pcd", *cloud);//创建一组要使用的索引。为简单起见,我们将使用云中前10%的点std::vector<int> indices (std::floor (cloud->size () / 10));for (std::size_t i = 0; i < indices.size (); ++i) indices[i] = i;// //创建NormalEstimation类,并将输入数据集传递给它pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud (cloud);// 传递索引// std::shared_ptr<std::vector<int> > indicesptr (new std::vector<int> (indices)); // 报错pcl::shared_ptr<std::vector<int> > indicesptr (new std::vector<int> (indices)); // 报错ne.setIndices (indicesptr);// 创建一个空的kdtree表示形式,并将其传递给normal estimation 对象// 它的内容将根据给定的输入数据集填充到对象内部(因为未提供其他搜索表面)。pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());ne.setSearchMethod (tree);// Output datasetspcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);// 在半径3cm的范围内近邻ne.setRadiusSearch (0.03);// 计算特征ne.compute (*cloud_normals);}

积分图进行法线估计

#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/integral_image_normal.h>
#include <pcl/visualization/cloud_viewer.h>
int main ()
{//打开点云pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile ("../table_scene_mug_stereo_textured.pcd", *cloud);//创建法线估计向量pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal> ne;/****************************************************************************************三种法线估计方法COVARIANCE_MATRIX 模式从具体某个点的局部邻域的协方差矩阵创建9个积分,来计算这个点的法线AVERAGE_3D_GRADIENT   模式创建6个积分图来计算水平方向和垂直方向的平滑后的三维梯度并使用两个梯度间的向量积计算法线AVERAGE_DEPTH——CHANGE  模式只创建了一个单一的积分图,从而平局深度变化计算法线********************************************************************************************/ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);  //设置法线估计的方式AVERAGE_3D_GRADIENTne.setMaxDepthChangeFactor(0.02f);   //设置深度变化系数ne.setNormalSmoothingSize(10.0f);   //设置法线优化时考虑的邻域的大小ne.setInputCloud(cloud);               //输入的点云ne.compute(*normals);                    //计算法线//可视化pcl::visualization::PCLVisualizer viewer("PCL Viewer");   //视口的名称viewer.setBackgroundColor (0.0, 0.0, 0.5);    //背景颜色的设置viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud, normals);  //将法线加入到点云中while (!viewer.wasStopped ()){viewer.spinOnce ();}return 0;
}

在这里插入图片描述

点特征直方图

在这里插入图片描述

#include<iostream>
#include<vector>
#include <pcl/point_types.h>
#include <pcl/features/pfh.h>
#include <pcl/io/pcd_io.h>//点云文件pcd 读写
#include <pcl/features/normal_3d.h>//法线特征
#include <pcl/visualization/pcl_plotter.h>// 直方图的可视化 方法2using namespace std;
int main(int argc, char** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr(new pcl::PointCloud<pcl::PointXYZ>);//======【1】 读取点云文件 填充点云对象======pcl::PCDReader reader;reader.read("../ism_test_cat.pcd", *cloud_ptr);// =====【2】计算法线========创建法线估计类====================================pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud(cloud_ptr);pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());ne.setSearchMethod(tree);//设置近邻搜索算法// 输出点云 带有法线描述pcl::PointCloud<pcl::Normal>::Ptr cloud_normals_ptr(new pcl::PointCloud<pcl::Normal>);pcl::PointCloud<pcl::Normal>& cloud_normals = *cloud_normals_ptr;// Use all neighbors in a sphere of radius 3cmne.setRadiusSearch(0.03);//半价内搜索临近点 3cm// 计算表面法线特征ne.compute(cloud_normals);//=======【3】创建PFH估计对象pfh,并将输入点云数据集cloud和法线normals传递给它=================pcl::PFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::PFHSignature125> pfh;// phf特征估计其器pfh.setInputCloud(cloud_ptr);pfh.setInputNormals(cloud_normals_ptr);//如果点云是类型为PointNormal,则执行pfh.setInputNormals (cloud);//创建一个空的kd树表示法,并把它传递给PFH估计对象。//基于已给的输入数据集,建立kdtreepcl::search::KdTree<pcl::PointXYZ>::Ptr tree2(new pcl::search::KdTree<pcl::PointXYZ>());//pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree2 (new pcl::KdTreeFLANN<pcl::PointXYZ> ()); //-- older call for PCL 1.5-pfh.setSearchMethod(tree2);//设置近邻搜索算法//输出数据集pcl::PointCloud<pcl::PFHSignature125>::Ptr pfh_fe_ptr(new pcl::PointCloud<pcl::PFHSignature125>());//phf特征//使用半径在5厘米范围内的所有邻元素。//注意:此处使用的半径必须要大于估计表面法线时使用的半径!!!pfh.setRadiusSearch(0.05);//计算pfh特征值pfh.compute(*pfh_fe_ptr);cout << "phf feature size : " << pfh_fe_ptr->points.size() << endl;// 应该与input cloud->points.size ()有相同的大小,即每个点都有一个pfh特征向量// ========直方图可视化=============================pcl::visualization::PCLPlotter plotter;plotter.addFeatureHistogram(*pfh_fe_ptr, 300); //设置的很坐标长度,该值越大,则显示的越细致plotter.plot();return 0;
}

快速特征直方图 FPFH

在这里插入图片描述

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>                  // 加载点云
#include <pcl/features/normal_3d.h>         // 法线估计
#include <pcl/features/fpfh.h>              // FPFH 特征
#include <pcl/search/kdtree.h>              // KdTree 搜索
#include <pcl/visualization/pcl_plotter.h>  // 可视化直方图using namespace std;int main()
{// ============ 【1】加载点云 ============pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile("../ism_test_cat.pcd", *cloud) == -1){PCL_ERROR("Couldn't read the pcd file.\n");return -1;}std::cout << "Loaded " << cloud->size() << " points." << std::endl;// ============ 【2】估计法线 ============pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud(cloud);pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);ne.setSearchMethod(tree);ne.setRadiusSearch(0.03);  // 3cm 用于法线估计pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);ne.compute(*normals);std::cout << "Computed " << normals->size() << " normals." << std::endl;// ============ 【3】计算 FPFH 特征 ============pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh;fpfh.setInputCloud(cloud);fpfh.setInputNormals(normals);fpfh.setSearchMethod(tree);// ⚠️ 注意:FPFH 半径应 > 法线估计半径fpfh.setRadiusSearch(0.05);  // 5cm// 输出 FPFH 特征pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfhs(new pcl::PointCloud<pcl::FPFHSignature33>);fpfh.compute(*fpfhs);std::cout << "FPFH feature size: " << fpfhs->size() << std::endl;if (fpfhs->empty()){PCL_ERROR("FPFH computation failed!\n");return -1;}// ============ 【4】可视化 FPFH 直方图 ============pcl::visualization::PCLPlotter plotter;plotter.addFeatureHistogram(*fpfhs, 300);  // 每个特征用 300 个 bin 显示plotter.plot();plotter.spin();  // 阻塞,直到用户关闭窗口return 0;
}

在这里插入图片描述

深度图像(range image)中提取NARF特征

在这里插入图片描述

#include <iostream>#include <boost/thread/thread.hpp>#include <pcl/range_image/range_image.h>
#include <pcl/io/pcd_io.h>#include <pcl/visualization/range_image_visualizer.h>#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/features/range_image_border_extractor.h>
#include <pcl/keypoints/narf_keypoint.h>
#include <pcl/features/narf_descriptor.h>#include <pcl/console/parse.h>// 定义点类型别名
typedef pcl::PointXYZ PointType;// ========================================
// 全局参数设置
// ========================================
float angular_resolution = 0.5f;        // 角度分辨率(单位:度)
float support_size = 0.2f;              // 支持区域大小(关键点周围球体直径)
pcl::RangeImage::CoordinateFrame coordinate_frame = pcl::RangeImage::CAMERA_FRAME; // 坐标系:相机坐标系
bool setUnseenToMaxRange = false;       // 是否将“看不见”的点设为最大距离
bool rotation_invariant = true;         // 是否使用旋转不变的 NARF 特征// ========================================
// 打印使用说明(命令行帮助)
// ========================================
void printUsage(const char* progName)
{/*std::cout << "\n\n用法: " << progName << " [选项] <scene.pcd>\n\n"<< "选项:\n"<< "-------------------------------------------\n"<< "-r <浮点数>   角度分辨率(单位:度,默认 " << angular_resolution << ")\n"<< "-c <整数>     坐标系(0: CAMERA_FRAME, 1: LASER_FRAME,默认 " << (int)coordinate_frame << ")\n"<< "-m            将未观测点的距离设为最大值\n"<< "-s <浮点数>   关键点支持区域大小(球体直径,默认 " << support_size << ")\n"<< "-o <0/1>      是否开启旋转不变特征(默认 " << (int)rotation_invariant << ")\n"<< "-h            显示此帮助信息\n"<< "\n\n";*/std::cout << "\n\nUsage: " << progName << " [options] <scene.pcd>\n\n"<< "Options:\n"<< "-------------------------------------------\n"<< "-r <float>   angular resolution in degrees (default " << angular_resolution << ")\n"<< "-c <int>     coordinate frame (default " << (int)coordinate_frame << ")\n"<< "-m           Treat all unseen points to max range\n"<< "-s <float>   support size for the interest points (diameter of the used sphere - ""default " << support_size << ")\n"<< "-o <0/1>     switch rotational invariant version of the feature on/off"<< " (default " << (int)rotation_invariant << ")\n"<< "-h           this help\n"<< "\n\n";
}// ========================================
// 设置可视化相机视角
// ========================================
void setViewerPose(pcl::visualization::PCLVisualizer& viewer, const Eigen::Affine3f& viewer_pose)
{// 计算相机位置Eigen::Vector3f pos_vector = viewer_pose * Eigen::Vector3f(0, 0, 0);// 计算观察方向(看向哪里)Eigen::Vector3f look_at_vector = viewer_pose.rotation() * Eigen::Vector3f(0, 0, 1) + pos_vector;// 计算“上”方向(用于正确朝向)Eigen::Vector3f up_vector = viewer_pose.rotation() * Eigen::Vector3f(0, -1, 0);// 设置相机参数viewer.setCameraPosition(pos_vector[0], pos_vector[1], pos_vector[2],look_at_vector[0], look_at_vector[1], look_at_vector[2],up_vector[0], up_vector[1], up_vector[2]);
}// ========================================
// 主函数
// ========================================
int main(int argc, char** argv)
{// ========= 1. 解析命令行参数 =========if (pcl::console::find_argument(argc, argv, "-h") >= 0){printUsage(argv[0]);return 0;}/*if (pcl::console::find_argument(argc, argv, "-m") >= 0){setUnseenToMaxRange = true;std::cout << "将未观测点的距离设为最大值。\n";}if (pcl::console::parse(argc, argv, "-o", rotation_invariant) >= 0)std::cout << "旋转不变特征已" << (rotation_invariant ? "开启" : "关闭") << "。\n";int tmp_coordinate_frame;if (pcl::console::parse(argc, argv, "-c", tmp_coordinate_frame) >= 0){coordinate_frame = pcl::RangeImage::CoordinateFrame(tmp_coordinate_frame);std::cout << "使用坐标系 " << (int)coordinate_frame << "。\n";}if (pcl::console::parse(argc, argv, "-s", support_size) >= 0)std::cout << "设置支持区域大小为 " << support_size << "。\n";if (pcl::console::parse(argc, argv, "-r", angular_resolution) >= 0)std::cout << "设置角度分辨率为 " << angular_resolution << " 度。\n";*/if (pcl::console::find_argument(argc, argv, "-m") >= 0){setUnseenToMaxRange = true;cout << "Setting unseen values in range image to maximum range readings.\n";}if (pcl::console::parse(argc, argv, "-o", rotation_invariant) >= 0)cout << "Switching rotation invariant feature version " << (rotation_invariant ? "on" : "off") << ".\n";int tmp_coordinate_frame;if (pcl::console::parse(argc, argv, "-c", tmp_coordinate_frame) >= 0){coordinate_frame = pcl::RangeImage::CoordinateFrame(tmp_coordinate_frame);cout << "Using coordinate frame " << (int)coordinate_frame << ".\n";}if (pcl::console::parse(argc, argv, "-s", support_size) >= 0)cout << "Setting support size to " << support_size << ".\n";if (pcl::console::parse(argc, argv, "-r", angular_resolution) >= 0)cout << "Setting angular resolution to " << angular_resolution << "deg.\n";// 将角度转为弧度(PCL 内部使用弧度)angular_resolution = pcl::deg2rad(angular_resolution);// ========= 2. 加载或生成点云 =========pcl::PointCloud<PointType>::Ptr point_cloud_ptr(new pcl::PointCloud<PointType>);pcl::PointCloud<PointType>& point_cloud = *point_cloud_ptr;// 存储远距离点(用于补全深度图)pcl::PointCloud<pcl::PointWithViewpoint> far_ranges;// 传感器位姿(从文件中读取或默认为原点)Eigen::Affine3f scene_sensor_pose(Eigen::Affine3f::Identity());// 查找命令行中是否有 .pcd 文件std::vector<int> pcd_filename_indices = pcl::console::parse_file_extension_argument(argc, argv, "pcd");if (!pcd_filename_indices.empty()){std::string filename = argv[pcd_filename_indices[0]];if (pcl::io::loadPCDFile(filename, point_cloud) == -1){std::cerr << "无法打开文件 \"" << filename << "\"。\n";printUsage(argv[0]);return -1;}// 从点云元数据中恢复传感器位置和朝向scene_sensor_pose = Eigen::Affine3f(Eigen::Translation3f(point_cloud.sensor_origin_[0],point_cloud.sensor_origin_[1],point_cloud.sensor_origin_[2])) * Eigen::Affine3f(point_cloud.sensor_orientation_);}else{// 如果没有提供文件,则生成一个示例点云(平面)setUnseenToMaxRange = true;std::cout << "\n未提供 .pcd 文件 => 生成示例点云。\n\n";for (float x = -0.5f; x <= 0.5f; x += 0.01f){for (float y = -0.5f; y <= 0.5f; y += 0.01f){PointType point;point.x = x;point.y = y;point.z = 2.0f - y;  // 斜面point_cloud.points.push_back(point);}}point_cloud.width = static_cast<int>(point_cloud.points.size());point_cloud.height = 1;}// ========= 3. 从点云生成深度图(Range Image) =========float noise_level = 0.0;      // 噪声水平float min_range = 0.0f;       // 最小有效距离int border_size = 1;          // 边框大小(保留边缘像素)// 创建深度图对象boost::shared_ptr<pcl::RangeImage> range_image_ptr(new pcl::RangeImage);pcl::RangeImage& range_image = *range_image_ptr;// 核心:将 3D 点云 投影为 2D 深度图range_image.createFromPointCloud(point_cloud,               // 输入点云angular_resolution,        // 角度分辨率pcl::deg2rad(360.0f),      // 水平视场角pcl::deg2rad(180.0f),      // 垂直视场角scene_sensor_pose,         // 传感器位姿coordinate_frame,          // 坐标系noise_level,               // 噪声min_range,                 // 最小距离border_size                // 边框);// 如果有远距离点数据,可以融合进来(增强深度图完整性)// range_image.integrateFarRanges(far_ranges);// 将未观测区域设为最大距离(便于后续处理)if (setUnseenToMaxRange)range_image.setUnseenToMaxRange();// ========= 4. 可视化:打开 3D 查看器 =========/*pcl::visualization::PCLVisualizer viewer("3D Viewer");viewer.setBackgroundColor(1, 1, 1);  // 白色背景// 给深度图上色(按距离)pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> range_image_color_handler(range_image_ptr, 0, 0, 0);viewer.addPointCloud(range_image_ptr, range_image_color_handler, "range image");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");viewer.initCameraParameters();  // 初始化相机setViewerPose(viewer, range_image.getTransformationToWorldSystem());  // 设置视角*/// ========= 4. 可视化:打开 3D 查看器 =========pcl::visualization::PCLVisualizer viewer("3D Viewer");viewer.setBackgroundColor(1, 1, 1);  // 白色背景// 将 RangeImage 转换为 PointCloud<pcl::PointWithRange>pcl::PointCloud<pcl::PointWithRange>::Ptr range_image_cloud_ptr(new pcl::PointCloud<pcl::PointWithRange>);pcl::copyPointCloud(range_image, *range_image_cloud_ptr);// 给深度图上色(按距离)pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange> range_image_color_handler(range_image_cloud_ptr, 0, 0, 0);viewer.addPointCloud<pcl::PointWithRange>(range_image_cloud_ptr, range_image_color_handler, "range image");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "range image");// ========= 5. 可视化:打开深度图窗口 =========pcl::visualization::RangeImageVisualizer range_image_widget("Range image");range_image_widget.showRangeImage(range_image);  // 显示深度图(灰度图)// ========= 6. 提取 NARF 关键点 =========pcl::RangeImageBorderExtractor range_image_border_extractor;  // 边缘提取器pcl::NarfKeypoint narf_keypoint_detector;                    // NARF 关键点检测器// 设置输入narf_keypoint_detector.setRangeImageBorderExtractor(&range_image_border_extractor);narf_keypoint_detector.setRangeImage(&range_image);narf_keypoint_detector.getParameters().support_size = support_size;  // 设置关键点支持区域// 存储关键点索引pcl::PointCloud<int> keypoint_indices;narf_keypoint_detector.compute(keypoint_indices);  // 执行关键点检测std::cout << "检测到 " << keypoint_indices.points.size() << " 个关键点。\n";// ========= 7. 在 3D 查看器中显示关键点 =========pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_ptr(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ>& keypoints = *keypoints_ptr;keypoints.points.resize(keypoint_indices.points.size());// 将关键点索引转为 3D 坐标for (size_t i = 0; i < keypoint_indices.points.size(); ++i)keypoints.points[i].getVector3fMap() = range_image.points[keypoint_indices.points[i]].getVector3fMap();// 添加到可视化器(绿色大点)pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> keypoints_color_handler(keypoints_ptr, 0, 255, 0);viewer.addPointCloud<pcl::PointXYZ>(keypoints_ptr, keypoints_color_handler, "keypoints");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 7, "keypoints");// ========= 8. 计算 NARF 描述子 =========std::vector<int> keypoint_indices2;keypoint_indices2.resize(keypoint_indices.points.size());for (unsigned int i = 0; i < keypoint_indices.size(); ++i)keypoint_indices2[i] = keypoint_indices.points[i];  // 转为 std::vector<int>// 创建 NARF 描述子计算器pcl::NarfDescriptor narf_descriptor(&range_image, &keypoint_indices2);narf_descriptor.getParameters().support_size = support_size;           // 支持区域narf_descriptor.getParameters().rotation_invariant = rotation_invariant; // 是否旋转不变// 存储描述子(每个关键点一个 36 维向量)pcl::PointCloud<pcl::Narf36> narf_descriptors;narf_descriptor.compute(narf_descriptors);  // 计算描述子std::cout << "为 " << keypoint_indices.points.size() << " 个关键点提取了 "<< narf_descriptors.size() << " 个 NARF 描述子。\n";// ========= 9. 主循环:保持窗口打开 =========while (!viewer.wasStopped()){range_image_widget.spinOnce();  // 刷新深度图窗口viewer.spinOnce();              // 刷新 3D 查看器pcl_sleep(0.01);                // 短暂休眠,避免 CPU 占用过高}return 0;
}
http://www.dtcms.com/a/318141.html

相关文章:

  • 服务器巡检项目
  • 大模型显存占用分析:以Qwen2.5-7B-Instruct为例,深度剖析推理、LoRA与全量微调
  • 友思特方案 | 如何提高3D成像设备的部署和设计优势
  • Python应用指南:获取风闻评论数据并解读其背后的情感倾向(二)
  • Linux环境下部署SSM聚合项目
  • 微信小程序初次运行项目失败
  • 引入消息队列带来的主要问题
  • 家政小程序系统开发:打造一站式家政服务平台
  • CSS Flexbox 的一个“坑”
  • 【动态规划 | 01背包】动态规划经典:01背包问题详解
  • 解析 div 禁止换行与滚动条组合-CSS运用
  • 模电知识点总结
  • 30ssh远程连接与远程执行命令
  • python实现获取k8s的pod信息
  • 华为云安全组默认规则
  • [两数之和II]
  • 保姆级教程:从0手写RAG智能问答系统,接入Qwen大模型|Python实战
  • Django创建抽象模型类
  • Ethereum:Hardhat Ignition 点燃智能合约部署新体验
  • Linux发行版分类与Centos替代品
  • React:受控组件和非受控组件
  • 将ssm聚合项目部署到云服务器上
  • MyBatis基础操作完整指南
  • 计数组合学7.14(对偶 RSK 算法)
  • 四、Envoy动态配置
  • 工业协议转换终极武器:EtherCAT转PROFINET网关的连接举例
  • 直播SDK商业化 vs 开源路线:工程稳定性、成本与演进能力全对比
  • 嵌入式开发学习———Linux环境下IO进程线程学习(五)
  • Flink CDC如何保障数据的一致性?
  • 云计算一阶段Ⅱ——12. SELinux 加固 Linux 安全