简体   繁体   English

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

[英]Removing duplicates of 3D points in a vector in C++

I am dealing with a point cloud, ie a vector of points, as a result of computation, which contains duplicate points (up to 10% of the size of the cloud). 由于计算的结果,我正在处理点云,即点的向量,其中包含重复的点(最多为云的10%)。

My implementation was to sort those points according to x,y, and z value and then use the std::unique function. 我的实现是根据x,y和z值对这些点进行排序,然后使用std::unique函数。 The resulting cloud however still contains duplicates, even though the sorting itself seems to be working. 但是,即使排序本身似乎可以正常工作,生成的云仍包含重复项。

Here's the crucial code 这是关键代码

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);
}

And here is a partial extraction of the output pointcloud (x,y, and z coordinates): 这是输出点云(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

So is unique not working properly or is there a mistake in my equal condition? 难道是独特的无法正常工作,还是我的同等条件有误?

The points itself also contain normal coordinates, but they are not important for culling, so I did not use them in the code. 这些点本身也包含法线坐标,但是它们对于剔除并不重要,因此我没有在代码中使用它们。

std::unique doesn't remove anything, it only moves elements around and returns an iterator "past the end" of the unique interval in the modified collection. std::unique不会删除任何内容,它只会移动元素并返回修改后的集合中唯一间隔的“过去”的迭代器。
(The actual contents of the collection past the returned iterator is unspecified.) (未指定通过返回的迭代器的集合的实际内容。)

You need to remove the duplicates explicitly: 您需要显式删除重复项:

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

You also need to be careful about floating point comparisons. 您还需要注意浮点比较。

Your problem is that comparing floating point numbers for equality is always a difficult exercise. 您的问题是比较浮点数是否相等总是一项困难的工作。 You will probably find that your points are (for example) actually: 您可能会发现您的观点实际上是(例如):

1.965100000001 108.77433 2350.9841
1.965099999999 108.77433 2350.9841

... and those aren't equal. ...而这些并不相等。

If you want to treat points as "equal" if they are within 0.00001 of each other, you get the problem that your "equality" condition is not transitive. 如果要将点彼此之间的距离都在0.00001以内,则将它们视为“相等”,则会遇到“等式”条件不传递的问题。 (0.0000,0,0) is "close" to (0.000009999,0,0) and to (-0.00009999,0,0), but those latter two points are "far" from each other. (0.0000,0,0)与(0.000009999,0,0)和(-0.00009999,0,0)“接近”,但是后两个点彼此“相距很远”。 This is a hard problem to solve in general. 通常这是一个很难解决的问题。 Good luck! 祝好运!

If you know something about the values of the coordinates (for example, that they are in millimetres, and values are accurate to 100 nanometres), you could round to the nearest 100 nm, and store as long long. 如果您对坐标值有所了解(例如,它们以毫米为单位,并且值精确到100纳米),则可以四舍五入到最接近的100 nm,并存储尽可能长的时间。 So: 所以:

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 ))
    {}
};

Convert your point cloud to IntPoint, and then your sort + unique (+erase), should work. 将您的点云转换为IntPoint,然后排序+唯一(+擦除)就可以了。

To erase the duplicates : you could do: 要删除重复项 :您可以执行以下操作:

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

or just create a set, which by definition contains only unique elements, out of the vector's elements: 或仅创建一个集合,根据定义,该集合仅包含向量元素中的唯一元素:

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

To compare floating point numbers : considering the mathematical properties 1 of the floating point numbers, together with the problems 2 inherited by their machine binary representation you end up with only one solution when comparing floating point numbers, namely, comparing them within a value of accuracy, epsilon . 比较浮点数 :考虑浮点数的数学特性1以及它们的机器二进制表示形式所继承的问题2 ,在比较浮点数时只能得到一个解决方案,即在精度范围内进行比较, epsilon

Thus, if you want to compare and order float x1 and float x2 , which are your coordinates, you do it by: 因此,如果您要比较和排序float x1float x2 ,它们是您的坐标,则可以通过以下方式进行操作:

x1 - x2 < epsilon

where epsilon is the accuracy you are looking for. epsilon是您正在寻找的精度。 In your case, just for illustration, the function equalPoint() could be modified to: 在您的情况下,仅出于说明目的,可以将功能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. They can differ by a very small quantity, unlike the integers, that are rounded and which could be easily compared. 1.与整数不同,它们可以相差很小,可以四舍五入并且可以轻松比较。

2. The computers doesn't map perfectly the real floating point numbers, the result of this fact is expressed in truncation, rounding. 2.计算机不能完美地映射真实的浮点数,这一事实的结果以截断和舍入表示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM