[英]Removing duplicates of 3D points in a vector in C++
由于计算的结果,我正在处理点云,即点的向量,其中包含重复的点(最多为云的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);
}
这是输出点云(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
难道是独特的无法正常工作,还是我的同等条件有误?
这些点本身也包含法线坐标,但是它们对于剔除并不重要,因此我没有在代码中使用它们。
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.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,然后排序+唯一(+擦除)就可以了。
要删除重复项 :您可以执行以下操作:
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 x1
和float 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.计算机不能完美地映射真实的浮点数,这一事实的结果以截断和舍入表示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.