基于PCL实现多边形框选点云并进行裁剪(附C++源码)

一.算法效果

通过在PCL可视化界面上绘制2D封闭多边形来提取位于该封闭多边形内部或者外部的点,算法效果如下:
在这里插入图片描述

图1多边形裁剪点云效果图

二.算法原理

PNPoly算法

  2D多边形框选裁剪点云,实际上可以简化为点和多边形的位置问题,即判断点在多边形内部还是外部。 W. Randolph Franklin提出的PNPoly算法,仅用几行代码就完美的解决了上述问题。
在这里插入图片描述

图2PNPoly算法原理示意图

  PNPoly算法采用射线法判断点是否在多边形内部。假设待测点在多边形内部,从待测点引出一条水平向右的射线,则射线必然会与多边形有至少一个交点。该射线与多边形第一次相交时将“冲出”多边形,第二次相交将“进入”多边形,依此类推。若射线与多边形有奇数个交点,则该点在多边形内部,反之则在外部。
  PNPoly算法核心代码如下:

int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
   
  int i, j, c = 0;
  for (i = 0, j = nvert-1; i < nvert; j = i++) {
   
    if ( ((verty[i]>testy) != (verty[j]>testy)) &&
     (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
       c = !c;
  }
  return c;
}
  • nvert 代表多边形顶点个数;
  • testx, testy代表待测试点的横坐标和纵坐标;
  • *vertx,*verty分别指向储存多边形横纵坐标数组的首地址;
  • i,j分别代表当前多边形顶点索引;
  • c表示点是否在多边形内部,默认为0,即点在多边形外部;

算法分两步判断待测点和多边形的关系:

  1. 排除那些不相交的边。找出被测试点的纵坐标testy在多边形两个相邻点纵坐标范围之内的边;
  2. 直线相交性检测。测试待测点test发出的向右的射线是否与多边形两个相邻点构成的直线相交,每相交一次,则对c值取反。判断横线穿越多边形的次数是否为奇数,如果是奇数,此时c值为1,该点在多边形内;如果是偶数,c值为0,点在在多边形外。

直线相交性判断

在这里插入图片描述

图3直线相交示意图

 如图3,直线ab与过p点的水平向右射线相交于点c,可知直线ac斜率与直线ab斜率相等,即
在这里插入图片描述
点p发出的水平向右的射线与直线ab相交,则有p点横坐标x<x’,即可获得PNPoly中的第二个判断条件。

三.C++代码实现

1.环境配置

VS2019 + PCL1.12.1

2.C++代码

#include <iostream>

#include "vtkCamera.h"
#include <vtkRenderWindow.h>
#include <pcl/filters/project_inliers.h>
#include <pcl/visualization/mouse_event.h> //鼠标事件
#include <pcl/visualization/keyboard_event.h>//键盘事件
#include <pcl/visualization/pcl_visualizer.h>
#include "point_cloud/include/io/cloud_io.h"

//点云初始化
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>());          //输入点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_polygon(new pcl::PointCloud<pcl::PointXYZ>);       //多边形点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in_plygon(new pcl::PointCloud<pcl::PointXYZ>);     //多边形内部点云

pcl::PointXYZ curP, lastP;                                                                   //当前点坐标,上一线段终点坐标
bool flag = false;                                                                           //判断是不是第一次点击
bool isPickingMode = false;                                                                  //是否为框选模式
unsigned int line_id = 0;                                                                    //多边形直线索引

pcl::visualization::PCLVisualizer::Ptr interactionCustomizationVis();

//键盘事件
int PNPoly(int poly_sides, double* poly_X, double* poly_Y, double x, double y);
void projectInliers(void*);
void keyboardEventOccurred(const pcl::visualization::KeyboardEvent& event, void* viewer_void);

//鼠标事件
void getScreentPos(double* displayPos, double* world, void* viewer_void);
void mouseEventOccurred(const pcl::visualization::MouseEvent& event, void* viewer_void);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cynthia.Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值