在C ++中删除向量中的3D点的重复

时间:2015-12-27 14:05:34

标签: c++ point-cloud-library point-clouds

我正在处理一个点云,即一个点的矢量,作为计算的结果,它包含重复点(最多可达云的10%)。

我的实现是根据x,y和z值对这些点进行排序,然后使用std::unique函数。然而,生成的云仍然包含重复项,即使排序本身似乎有效。

这是关键代码

bool comparePoint(pcl::PointXYZINormal p1, pcl::PointXYZINormal p2){
if (p1.x != p2.x)
    return p1.x > p2.x;
else if (p1.y != p2.y)
    return  p1.y > p2.y;
else
    return p1.z > p2.z;
}

bool equalPoint(pcl::PointXYZINormal p1, pcl::PointXYZINormal p2){
    if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z)
        return true;
    return false;
}
void KDsearch::cullDuplePoints(){
    std::sort(points.begin(), points.end(), comparePoint);
    std::unique(points.begin(), points.end(), equalPoint);
}

这是输出pointcloud(x,y和z坐标)的部分提取:

1.96828 -535.09515 2794.8391
1.96627 -636.95264 2914.0366
1.96627 -636.95264 2914.0366
1.9651 108.77433 2350.9841
1.9651 108.77433 2350.9841
1.9642299 -206.19427 5618.4629
1.9642299 -206.19427 5618.4629
1.96386 -1880.3784 1346.0654

所以唯一不正常工作还是在我的平等条件下有错误?

点本身也包含普通坐标,但它们对于剔除并不重要,所以我没有在代码中使用它们。

3 个答案:

答案 0 :(得分:18)

std::unique不会删除任何内容,它只会移动元素并返回迭代器"结束"修改后的集合中的唯一区间 (未指定返回迭代器的集合的实际内容。)

您需要明确删除重复项:

std::sort(points.begin(), points.end(), comparePoint);
auto unique_end = std::unique(points.begin(), points.end(), equalPoint);
points.erase(unique_end, points.end());

您还需要注意浮点比较。

答案 1 :(得分:10)

你的问题是,比较浮点数是否相等总是一项艰难的工作。你可能会发现你的观点(例如)实际上是:

1.965100000001 108.77433 2350.9841
1.965099999999 108.77433 2350.9841

......那些不相等。

如果您希望将点数视为“相等”,如果它们在0.00001之间,则会出现“平等”条件不可传递的问题。 (0.0000,0,0)“接近”(0.000009999,0,0)和(-0.00009999,0,0),但后两个点彼此“远”。这是一般难以解决的问题。祝你好运!

如果您对坐标的值有所了解(例如,它们以毫米为单位,并且值精确到100纳米),则可以舍入到最接近的100 nm,并存储很长的时间。所以:

struct IntPoint {
   const static double ScaleFactor = 10000;
   long long x,y,z;
   IntPoint(const pcl::PointXYZINormal &p)
      : x(llround(p.x*ScaleFactor ))
      , y(llround(p.y*ScaleFactor ))
      , z(llround(p.z*ScaleFactor ))
    {}
};

将您的点云转换为IntPoint,然后您的排序+唯一(+擦除)应该有效。

答案 2 :(得分:3)

要删除重复项:您可以执行以下操作:

sort(point.begin(), point.end());
point.erase(unique(point.begin(), point.end()), point.end());

或者只是创建一个集合,根据定义,它只包含向量元素中的唯一元素:

std::set<type> all_unique(point.begin(), point.end());

比较浮点数:考虑浮点数的数学属性 1 ,以及机器继承的问题 2 二进制表示在比较浮点数时最终只有一个解决方案,即在准确度值epsilon内进行比较。

因此,如果您想比较并订购float x1float x2,这是您的坐标,请按以下方式执行:

x1 - x2 < epsilon

其中epsilon是您正在寻找的准确度。在您的情况下,仅作为说明,函数equalPoint()可以修改为:

bool equalPoint(pcl::PointXYZINormal p1, pcl::PointXYZINormal p2){
    // equal up to the third digit after the decimal point
    float eps = 0.001;

    if ((p1.x -p2.x) < eps && (p1.y - p2.y) < eps && (p1.z - p2.z) < eps)
        return true;

    return false;
}

1。与整数不同,它们可以有很小的不同,它们是圆整的,可以很容易地进行比较。

2。计算机没有完美映射真实的浮点数,这个事实的结果用截断,舍入来表示。