I'm currently working with the skspatial
package in Python3. I currently have two functions:
skspatial.objects.Cylinder.best_fit
to try to best fit the points into a cylinder- A function that returns the bounding box of the scattered points. This function returns a custom class that should "extend" the
skspatial.objects
with aCuboid
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:
skspatial.objects.Cylinder.best_fit
to try to best fit the points into a cylinder- A function that returns the bounding box of the scattered points. This function returns a custom class that should "extend" the
skspatial.objects
with aCuboid
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
1 Answer
Reset to default 1I'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:
Define an error counter variable
errors = 0
.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)
.
- 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)
- 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 pointsa
andb
:
a, b = shape.intersect_line(point_center_line)
- Construct a line from these two points
a
, andb
. This line has the length2 * (length_of_point_center_line +- delta)
.delta
is the length of the line from a or b (whichever is closer) to the individualpoint
. 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
- 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条)