在C++中删除矢量中三维点的重复项
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
那么,是unique不能正常工作,还是在我的同等条件下出现了错误?
点本身也包含法线坐标,但它们对于剔除并不重要,所以我没有在代码中使用它们。
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.000000009999,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.计算机不能完美地映射真实的浮点数,这一事实的结果用截断、舍入来表示
- 将数组的地址分配给变量并删除
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C/C++编译器通常会删除重复的库吗
- 从链接列表c++中删除一个项目
- C++如何通过用户输入删除列表元素
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 是否需要删除包含对象的"pair"?
- 如何在自删除后将对象设置为nullptr
- 迭代时从向量和内存中删除对象
- 使用函数"remove"删除重复元素
- 如何从多映射中删除特定的重复项
- 运算符C++ "delete []"仅删除 2 个前值
- 删除指向指针的指针是运行时错误吗
- 将指针设置为"nullptr"并不能防止双重删除?
- 为什么示例代码访问IUnknown中已删除的内存
- 如何通过 getter 函数删除矢量的元素?
- 从控制台中删除最后打印的元素
- C++中的线程安全删除
- 如何从存储在std::映射中的std::集中删除元素
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数