PCA: fix degenerate cases and doc.

This commit is contained in:
Pierre Alliez 2009-02-27 12:57:44 +00:00
parent 248d4447db
commit f9a2279974
2 changed files with 25 additions and 31 deletions

View File

@ -13,11 +13,11 @@
\ccDefinition
The function \ccRefName\ computes the best fitting 3D line or plane (in the least squares sense) of a set of 3D objects such as points, segments, triangles, spheres, balls, cuboids or tetrahedra. \\
Function \ccRefName\ computes the best fitting 3D line or plane (in the least squares sense) of a set of 3D objects such as points, segments, triangles, spheres, balls, cuboids or tetrahedra. \\
The best fitting linear sub-space (line or plane) minimizes the sum of squared distances from all points comprising these objects to their orthogonal projections onto this linear subspace. It can be shown that the best line or plane goes through the centroid of the set. This problem is equivalent to search for the linear sub-space which maximizes the variance of projected points (sum of squared distances to the centroid). Internally we solve this problem by eigen decomposition of the covariance matrix of the whole set. Note that the $3 \times 3$ covariance matrix is computed internally in closed form and not by point sampling the objects. Eigenvectors corresponding to large eigenvalues are the directions in which the data has strong component, or equivalently large variance.\\
The best fitting linear sub-space (here line or plane) minimizes the sum of squared distances from all points comprising these objects to their orthogonal projections onto this linear subspace. It can be shown that the best line or plane goes through the centroid of the set. This problem is equivalent to search for the linear sub-space which maximizes the variance of projected points (sum of squared distances to the centroid). Internally we solve this problem by eigen decomposition of the covariance matrix of the whole set. Note that the $3 \times 3$ covariance matrix is computed internally in closed form and not by point sampling the objects. Eigenvectors corresponding to large eigenvalues are the directions in which the data has strong component, or equivalently large variance.\\
The fitting quality property is characterized by the values of the three eigenvalues. When all three values are distinct the best linear subspace is uniquely determined, be it a line or a plane. When all three eigenvalues are equal there is no preferable sub-space and any line or plane going through the centroid share the same fitting property. A best fitting line is uniquely determined as soon as the largest eigenvalue is different from the two others, otherwise all lines contained in the best fitting plane share the same fitting property. A best fitting plane is uniquely determined as soon as the smallest eigenvalue is different from the two others, otherwise all planes going through the best fitting line share the same fitting property.
The fitting quality property is characterized by the values of the three eigenvalues. When all three values are distinct the best linear subspace is uniquely determined, be it a line or a plane. When all three eigenvalues are equal there is no preferable sub-space and any line or plane going through the centroid share the same fitting property (a horizontal plane or a line along the x axis are returned by default). A best fitting line is uniquely determined as soon as the largest eigenvalue is different from the two others, otherwise all lines contained in the best fitting plane share the same fitting property. A best fitting plane is uniquely determined as soon as the smallest eigenvalue is different from the two others, otherwise all planes going through the best fitting line share the same fitting property.
\ccInclude{CGAL/linear_least_squares_fitting_3.h}
@ -32,9 +32,7 @@ The fitting quality property is characterized by the values of the three eigenva
{ computes the best fitting 3D line of a 3D object set in the range
[\ccc{first},\ccc{beyond}). The value returned is a fitting quality
between $0$ and $1$, where $0$ means that the variance is the same
along any line (a horizontal line going through the centroid is output
by default), and $1$ means that the variance is null orthogonally
to the best fitting line (hence the fit is perfect). }
along any line contained within the best fitting plane, and $1$ means that the variance is null orthogonally to the best fitting line (hence the fit is perfect). }
The class \ccc{K} is the kernel in which the type \ccc{InputIterator::value_type} is defined. It can be omitted and deduced automatically from the value type.
@ -63,9 +61,7 @@ The tag \ccc{tag} identifies the dimension to be considered from the objects. Fo
{ computes the best fitting 3D plane of a 3D object set in the range
[\ccc{first},\ccc{beyond}). The value returned is a fitting quality
between $0$ and $1$, where $0$ means that the variance is the same
along any plane (a horizontal plane going through the centroid is output
by default), and $1$ means that the variance is null orthogonally
to the best fitting plane (hence the fit is perfect). }
along any plane going through the best fitting line, and $1$ means that the variance is null orthogonally to the best fitting plane (hence the fit is perfect). }
The class \ccc{K} is the kernel in which the type \ccc{InputIterator::value_type} is defined. It can be omitted and deduced automatically from the value type. The tag \ccc{tag} identifies the dimension to be considered from the objects (see above).

View File

@ -599,7 +599,6 @@ assemble_covariance_matrix_3(InputIterator first,
covariance[3] += mass * (-1.0 * c.z() * c.x());
covariance[4] += mass * (-1.0 * c.z() * c.y());
covariance[5] += mass * (-1.0 * c.z() * c.z());
}
// assemble covariance matrix from a segment set
@ -705,9 +704,16 @@ fitting_plane_3(const typename K::FT covariance[6], // covariance matrix
FT eigen_vectors[9];
eigen_symmetric<FT>(covariance,3,eigen_vectors,eigen_values);
// check unicity and build fitting line accordingly
if(eigen_values[0] != eigen_values[1] &&
eigen_values[0] != eigen_values[2])
// degenerate case (three similar eigenvalues)
if(eigen_values[0] == eigen_values[1] &&
eigen_values[0] == eigen_values[2])
{
// assemble a default horizontal plane that goes
// through the centroid.
plane = Plane(c,Vector(0.0,0.0,1.0));
return (FT)0.0;
}
else
{
// regular case
Vector normal(eigen_vectors[6],
@ -716,14 +722,6 @@ fitting_plane_3(const typename K::FT covariance[6], // covariance matrix
plane = Plane(c,normal);
return (FT)1.0 - eigen_values[2] / eigen_values[0];
} // end regular case
else
{
// isotropic case (infinite number of directions)
// by default: assemble a horizontal plane that goes
// through the centroid.
plane = Plane(c,Vector(0.0,0.0,1.0));
return (FT)0.0;
}
}
// compute the eigen values and vectors of the covariance
@ -749,21 +747,21 @@ fitting_line_3(const typename K::FT covariance[6], // covariance matrix
FT eigen_vectors[9];
eigen_symmetric<FT>(covariance,3,eigen_vectors,eigen_values);
// check unicity and build fitting line accordingly
if(eigen_values[0] != eigen_values[1])
// isotropic case (infinite number of directions)
if(eigen_values[0] == eigen_values[1] &&
eigen_values[0] == eigen_values[2])
{
// assemble a default line along x axis which goes
// through the centroid.
line = Line(c,Vector(1.0,0.0,0.0));
return (FT)0.0;
}
else
{
// regular case
Vector direction(eigen_vectors[0],eigen_vectors[1],eigen_vectors[2]);
line = Line(c,direction);
return (FT)1.0 - eigen_values[1] / eigen_values[0];
} // end regular case
else
{
// isotropic case (infinite number of directions)
// by default: assemble a horizontal plane that goes
// through the centroid.
line = Line(c,Vector(1.0,0.0,0.0));
return (FT)0.0;
}
}