0

I'm working on a piece of legacy software, which has code that takes a mesh/3d point/radius/direction, and computes a list of vertices that are selected.

public static List<int> GetSelectedVertices(PointCloud model, Vec3 markPoint, Vec3 direction, float selectionRadius)
 {
     List<int> outputVertices = new List<int>();
     Vec3 normal = GetNormal(direction);
     foreach(int vertexId in model.VertexIds)
     {
         Vec3 facetPosition = model.GetFacetPosition(vertexId);
         Vec3 vec3d = facetPosition - markPoint;
         
         var computation = vec3d.X * vector3.X + vec3d.Y * vec3d.Y + vec3d.Z * vec3d.Z - 
            FloatSquare(vec3d.X * normal.X + vec3d.Y * normal.Y + vec3d.Z * normal.Z)
            
        if(computation < selectionRadius)
        {
            outputVertices.Add(vertexId);
        }
     }
     
     return outputVertices;
 }
 
 public static float FloatSquare(float input)
 {
     return input * input;
 }
 
 public static Vec3 GetNormal(Vec3 input)
 {
     double num = 1.0 / Math.Sqrt(input.X * input.X + input.Y * input.Y + input.Z * input.Z);
     return new Vec3(num * input.X, num * input.Y, num * input.Z);
 }

Given a list of vertices and their positions(highlighted in red in the image below, I want to compute a 3D point & radius that would allow GetSelectedVertices to encompass as many of the input vertices as possible, while minimizing inclusion of unnecessary vertices(i.e. any vertices that are not highlighted in red). Also, the ability to define a maximum radius would be extremely helpful.

3D mesh with some vertices in red

Unfortunately I'm not allowed to change the GetSelectedVertices implementation, and minimizing the selection of unnecessary vertices is highly important.

I've currently tried two approaches, with lackluster results:

  1. Divide and conquer approach, where I split a bounding box into tiny segments and try each one(too slow, and suboptimal)
  2. Selecting the highest vertex, or the vertex closest to the bounding box center(too inaccurate)

Are there any well-known solutions to similar problems, or other approaches I could take?

Edits:

  1. Encompassing some unselected vertices is perfectly ok, but there is a cost to them. As a heuristic, something like 20% growth is acceptable. I.e. If you were to grow my selection by 20%, any newly selected facets are perfectly fine to encompass.
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • "that encompasses all points", "to encompass as many of the input vertices as possible", which one is it? Also a 3D point & radius is called a sphere. This looks like an optimization problem to me, but I can't find the objective function. Is it perhaps the number of selected vertices in the sphere minus the number of other vertices in the sphere? – Nelfeal Sep 30 '22 at 18:31
  • When you allow unbounded radii, are you looking to select all red vertices and the minimal amount of non-red? Or is there a weighting to red and cost to not-red vertices you want to maximize the sum of? – Derek Lee Sep 30 '22 at 18:32
  • @Nelfeal Thanks for pointing that out - I'll update the title. It should be "encompass as many of the input vertices as possible". – Jacob Myers Sep 30 '22 at 18:33
  • @DerekLee I'll update the post to clarify this too. Selecting some not-red vertices is actually perfectly ok, but there is a cost to them. For lack of a better way to describe it: something like 20% growth is acceptable. That it is to say: If you were to grow the red selection by 20%, any of the newly selected vertices within that growth region are perfectly acceptable! – Jacob Myers Sep 30 '22 at 18:33
  • I'm even more confused now. What makes a sphere that encompass *all* vertices unsuitable? You say there's a cost to not-red or unselected or unnecessary vertices (please stick to one term). What is this cost? How do you "grow" a selection by 20%? – Nelfeal Sep 30 '22 at 18:42
  • @Nelfeal A sphere that encompasses all vertices is not unsuitable - I was just under the impression that you were referring to a 3D bounding sphere. If I were to compute a bounding sphere of all red(sticking with this term) vertex points, afaik that would encompass too many non-red vertices. – Jacob Myers Sep 30 '22 at 18:43
  • Can you explain in more detail your attempt with the bounding box? My intuition says that something similar to selecting the center of the bounding box and finding the largest sphere contained in the bounding box would work heuristically for objects that are shaped roughly like a cube. – Derek Lee Sep 30 '22 at 18:44
  • @Nelfeal In terms of what I meant by "growing" the selection / red area: Picture walking along the outer vertices(any vertex which is not surrounded entirely by other red vertices) of the red area, and making them red too. This would expand the selection. To achieve something like 20% growth, you'd have to repeat this a few times potentially – Jacob Myers Sep 30 '22 at 18:47
  • @DerekLee In my attempt with the bounding box, I computed a rectangular bounding for the positions of all red vertices. Then, I divided the bounding box into 50 segments along the Z axis. Those 50 segments were then subdivided across the X & Y axis. I then took the center of each segment, fed it to the GetSelectedVertices function, and selected the 3D mark point which the highest amount of 'red' facets included. > box would work heuristically for objects that are shaped roughly like a cube Some of these objects can vary in size - from spherical to rectangular, or other options – Jacob Myers Sep 30 '22 at 18:52
  • I guess I wasn't clear with "a sphere that encompasses *all* vertices"; to me that means a bounding sphere, and I can see how that would include too many non-red (let's say gray as in the picture?) vertices, which would make it unsuitable. So if I understand correctly, you want a sphere as big as possible such that there more than 80% of the vertices inside are red. Is that it? – Nelfeal Sep 30 '22 at 18:53
  • @DLee Heuristically it sort of works, but there is a very high performance cost, due to these red selections containing tens of thousands of vertices. I imagine there has to be a more optimized way of approaching this – Jacob Myers Sep 30 '22 at 18:54
  • @Nelfeal Correct, I want a sphere that encompasses more than 80%(probably closer to 95%) of the vertices that are red. The only other catch here is that this sphere would have to play nice with the GetSelectedVertices algorithm(which is not allowed to change due to some technical constraints). My 3D math knowledge is extremely rough, but my understanding is that GetSelectedVertices doesn't quite compute *just* a spherical selection(since they also throw in a 3D direction, and the dot product thing). Although, the direction can be substituted with a constant fwiw – Jacob Myers Sep 30 '22 at 18:58
  • @JacobMyers I don't think I'm completely following the algorithm you described. What value are you using for the radius when testing these centers? My idea was more simple: compute the bounding box in O(n) by iterating over all the red vertices, compute the center of it, and then select a radius equal to the min distance to one of the sides of the bounding box. You could also pick the max distance side, or middle distance side, or try multiple and pick the best based on the tradeoff of red and grey points. – Derek Lee Sep 30 '22 at 19:02
  • @DerekLee For my purposes, I have a reasonable max radius for each list of vertices(typically ~6-12, unsure what unit of measurement) My concern with the bounding box approach is that: 1. The objects may fit very poorly into a rectangular or spherical bounding box(the shape can change) 2. This still falls back to a brute force approach – Jacob Myers Sep 30 '22 at 19:33
  • This `GetSelectedVertices` function looks suspicious to me. AFAICT the volume defined by `computation < selectionRadius` is a cylinder of infinite height and radius `sqrt(selectionRadius)`. You can visualize it by plotting `z = (-sqrt(a^2 r + a^2 (-y^2) + 2 a b x y + b^2 r - b^2 x^2) - a x sqrt(-a^2 - b^2 + 1) - b y sqrt(-a^2 - b^2 + 1))/(a^2 + b^2)` into a 3D graphing calculator (such as [Geogebra](https://www.geogebra.org/3d)) and keeping `a` and `b` positive and `a+b<=1`. This is obtained by simplifying `x^2+y^2+z^2-(x*a+y*b+z*c)^2=r, a^2+b^2+c^2=1` (`[a,b,c]` is `normal` in the code). – Nelfeal Sep 30 '22 at 19:41
  • Btw a volume that contains more than x% of the red vertices is different from a volume inside which x% of vertices are red. – Nelfeal Sep 30 '22 at 20:09
  • `GetSelectedVertices` as given won't compile. We really need OP to explain what they need to make progress. – Gene Oct 01 '22 at 00:56

2 Answers2

0

I would ignore mesh data and use just PCL (points)... first I would start with:

  1. set center to avg point of selected points
  2. set radius that is minimal and encloses all selected points

Now you can exploit tooth geometry if you know the orientation of tooth main axis then the center of bounding sphere will lie on it (tooth central axis) so you just fit the center position along this axis in direction from avg point upwards for lower teeth and downwards fro upper teeth. So you end up with just 2 nested fits.

For that you can use search like this:

and use number of unselected points inside bounding sphere as error function for the fit of center and radius size for the radius fit.

The max values for the search can be obtained from BBOX size (some safe multiple of it)

btw I already dealt with similar problem (also for teeth scan like this) however it was in chat only see:

If you go through the whole stuff there are ideas and IIRC also code for obtaining the tooth axis (have also found my original project for it)

Spektre
  • 49,595
  • 11
  • 110
  • 380
0

Use logistic regression. If O = (Ox, Oy, Oz) is the unknown center of the sphere and R is the unknown radius, then define the quadratic function

S(x, y, z, Ox, Oy, Oz, R) = (x - Ox)^2 + (y - Oy)^2 + (z - Oz)^2 - R^2

To abbreviate the notations, let P = (x, y, z) and O = (Ox, Oy, Oz) so the function S can be denoted as

S(x, y, z, Ox, Oy, Oz, R) = S(P, O, R) = ||P - O||^2 - R^2

Let the 3D data points be P[1], P[2], ..., P[i], ..., P[n] labeled y[1], y[2], ..., y[i], ..., y[n] where y[i] = 1 if the point P[i] is red point, i.e. a point that should be inside the sphere, while y[i] = 0 if the point P[i] is not red, i.e. it should be grey and should be outside the sphere.

Form the logistic regression function

f(P, O, R) = 1 / (1 + exp( S(P, O, R) )) = 1 / (1 + exp( ||P - O||^2 - R^2 ))

With its help, form the maximum likelihood function

L(O, R) = sum{i=0 to n} y[i] * ln( f(P[i], O, R) ) + (1 - y[i]) * ln( 1 - f(P[i], O, R) )

Find (O, R) that maximize the function L(O, R), i.e. solve

(Ox, Oy, Oz, R) = argmax L(Ox, Oy, Oz, R)

This is frequently done by gradient descent method, i.e. you want to solve the system of equations

grad L(O, R) = 0

or component-wise:

d/dOx( L(Ox, Oy, Oz, R)  )  = 0
d/dOy( L(Ox, Oy, Oz, R)  )  = 0
d/dOz( L(Ox, Oy, Oz, R)  )  = 0
d/dR ( L(Ox, Oy, Oz, R)  )  = 0

and therefore you iterate

h = small step
while ||grad L(O, R)||^2 > very small number:
   (O, R)  =  (O, R)  - h * grad L(O, R)

For more details on logistic regression and some more formulas, see the logistic regression Wikipage.

Futurologist
  • 1,874
  • 2
  • 7
  • 9