python - Determine most accurate best-fit algorithm for scattered points - Stack Overflow

I'm currently working with the skspatial package in Python3. I currently have two functions:skspat

I'm currently working with the skspatial package in Python3. I currently have two functions:

  1. skspatial.objects.Cylinder.best_fit to try to best fit the points into a cylinder
  2. A function that returns the bounding box of the scattered points. This function returns a custom class that should "extend" the skspatial.objects with a Cuboid object with similar methods, but in reality is only a bounding box.

My question is the following: Is there a way to determine which of these two shapes better encompass the scattered points? They both return valid cylinder or Cuboid objects on their own for the same set of scattered points, but only one of them actually fits the points better.

In case it matters for this question, the scattered points only represent the surface of whatever shape they actually are on, so there are no points "inside" the object.

I'm currently working with the skspatial package in Python3. I currently have two functions:

  1. skspatial.objects.Cylinder.best_fit to try to best fit the points into a cylinder
  2. A function that returns the bounding box of the scattered points. This function returns a custom class that should "extend" the skspatial.objects with a Cuboid object with similar methods, but in reality is only a bounding box.

My question is the following: Is there a way to determine which of these two shapes better encompass the scattered points? They both return valid cylinder or Cuboid objects on their own for the same set of scattered points, but only one of them actually fits the points better.

In case it matters for this question, the scattered points only represent the surface of whatever shape they actually are on, so there are no points "inside" the object.

Share Improve this question asked Nov 19, 2024 at 15:25 CRoemheldCRoemheld 9497 silver badges30 bronze badges 4
  • Define better – Woodford Commented Nov 19, 2024 at 15:27
  • I don't have a specific metric in mind to evaluate this, but maybe something like a percentage of points that are actually on the surface of the shape (with some tolerance of course)? E.g., given points that are from a cylinder surface, the percentage of the cylinder shape would be higher that that of the bounding box. – CRoemheld Commented Nov 19, 2024 at 15:31
  • If you don't have a specific metric in mind, "better" is purely subjective. To be honest, this is really a maths question not a programming question. – Stephen C Commented Nov 19, 2024 at 15:58
  • @StephenC I've decided to give my custom metric a go and implemented it. The approach is described in my answer below. – CRoemheld Commented Nov 20, 2024 at 13:40
Add a comment  | 

1 Answer 1

Reset to default 1

I've decided to test my own metric with the explanation I gave in the comments above.

The approach is as follows: Assuming we know that either shape (cylinder or cuboid) is the goal (and technically, all shapes that can be point-reflected/mirrored in 3D space given its center coordinate), then we can determine the percentage of points that are not on the surface of either shape:

  1. Define an error counter variable errors = 0.

  2. Determine the center of the shape.

For the cylinder, it would be Point(cylinder.point + cylinder.vector * 0.5). For the cuboid, it would be the middle of the line from the (x_min, y_min, z_min) point to the (x_max, y_max, z_max) point. In skspatial, this would be done by Line.from_points(p_min, p_max).to_point(0.5).

  1. Main loop: For each point in the point cloud, draw a line from the previously calculated center point to the individual point:
point_center_line = Line.from_points(center, point)
  1. Obtain the two intersection points that are returned when intersecting the point_center_line with the cylinder or cuboid shape. Since our shapes are "hollow", and the line is going through the center of the shape, there will always be 2 intersection points a and b:
a, b = shape.intersect_line(point_center_line)
  1. Construct a line from these two points a, and b. This line has the length 2 * (length_of_point_center_line +- delta). delta is the length of the line from a or b (whichever is closer) to the individual point. The +- is because that point is either still within the shape itself or just outside.

We now can check if delta is within the specified tolerance or not:

delta = abs(length_of_point_center_line - length_of_a_b_line / 2)
if delta > tolerance:
    errors += 1
  1. Loop end. Now, we can calculate the percentage: errors / number_of_points

This will give for a point cloud, that actually is from a cylinder shaped object, the following output in my use case:

Fitting error for Cuboid.best_fit: 0.951777280636341
Fitting error for Cylinder.best_fit: 0.0019885657469550086

Since the cuboid completely fits the cylinder point cloud, there are only a few points where the cylinder points actually are on the surface of the cuboid. However, for the cylinder, most points are within the tolerance to the surface, and only 0.19% of points are outside that tolerance.

With this, I can simply check for the return value and take the function that has the lower percentage.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742418746a4440254.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信