def explore_verticality_coef(fixture, draw, bins, size=SIZE): """ Parameters ---------- fixture : str Name of the fixture, amongst 'line', 'plane', 'sphere', 'ztube', 'wall' or 'roof' draw : int Number of random point cloud draws bins : numpy.array Returned histogram categories size : int Number of points in the point cloud Returns ------- numpy.array Distribution of the verticality coefficient metric over a sample of point cloud """ verticality_coef_list = [] for d in range(draw): data = select_fixture(fixture, size) pca = PCA().fit(data) verticality_coef_list.append(features.verticality_coefficient(pca)) return np.histogram(verticality_coef_list, bins=bins)
def test_verticality_coefficient_roof(roof): """Test verticality coefficient for a sphere-shaped point cloud As the point cloud is not constrained over x-, y- or z- axis, the verticality coefficient may take any value between 0 and 1. The test scope is limited to the definition domain. """ pca = PCA().fit(roof) vcoef = verticality_coefficient(pca) assert vcoef >= 0 and vcoef <= 0.01
def test_verticality_coefficient_plane(plane): """Test verticality coefficient for a plane-shaped point cloud As data are spread over x and y-axis, the two first eigenvectors are supposed to have small z-components, hence the third eigenvector has a high z-component. So the verticality coefficient must be small (let say, smaller than 0.01). """ pca = PCA().fit(plane) vcoef = verticality_coefficient(pca) assert vcoef >= 0 and vcoef < 0.01
def test_verticality_coefficient_line(line): """Test verticality coefficient for a line-shaped point cloud As the point cloud is constrained only over the x-axis, the first eigenvector is strongly influenced by the x-components. However the other eigenvectors may have any shape, hence the verticality coefficient may take any value between 0 and 1. The test scope is limited to the definition domain. """ pca = PCA().fit(line) vcoef = verticality_coefficient(pca) assert vcoef >= 0 and vcoef <= 1
def test_3D_properties_plane_and_sphere_comparison(plane, sphere): """Compare all 3D properties between a sphere and a plane. """ index = 42 reference_point_plane = plane[index] reference_point_sphere = sphere[index] dist_plane, neighbors_plane = _neighbors(plane, reference_point_plane) dist_sphere, neighbors_sphere = _neighbors(sphere, reference_point_sphere) radius_plane = radius_3D(dist_plane) radius_sphere = radius_3D(dist_sphere) assert radius_sphere > radius_plane density_plane = density_3D(radius_plane, len(neighbors_plane)) density_sphere = density_3D(radius_sphere, len(neighbors_sphere)) assert density_plane > density_sphere z_range_plane = val_range(plane[neighbors_plane, 2]) z_range_sphere = val_range(sphere[neighbors_sphere, 2]) assert z_range_sphere > z_range_plane std_deviation_plane = std_deviation(plane[neighbors_plane, 2]) std_deviation_sphere = std_deviation(sphere[neighbors_sphere, 2]) assert std_deviation_sphere > std_deviation_plane vcoef_plane = verticality_coefficient(PCA().fit(plane)) vcoef_sphere = verticality_coefficient(PCA().fit(sphere)) assert vcoef_plane < vcoef_sphere
def process_full(neighbors, dist_to_neighbors, extra): """Build the full feature set for a single point Parameters ---------- neighbors : numpy.array Coordinates of all points within the point neighborhood; must be a 2D-shaped array with `point_cloud.shape[1] == 3` dist_to_neighbors : numpy.array Gives distance between the point and all its neighbors extra : ExtraFeatures Names and values of extra input features, e.g. the RGB color Returns ------ list, OrderedDict generator (features for each point) """ num_neighbors = neighbors.shape[0] - 1 x, y, z = neighbors[0] rad_2D = radius_2D(neighbors[0, :2], neighbors[:, :2]) rad_3D = radius_3D(dist_to_neighbors) if len(neighbors) <= 2: return ( FeatureTuple( x, y, z, np.nan, np.nan, # alpha, beta rad_3D, val_range(neighbors[:, 2]), # z_range std_deviation(neighbors[:, 2]), # std_dev density_3D(rad_3D, len(neighbors)), np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, rad_2D, density_2D(rad_2D, len(neighbors)), np.nan, # eigenvalue_sum_2D np.nan, # eigenvalue_ratio_2D ), extra ) else: pca = fit_pca(neighbors) # PCA on the x,y,z coords eigenvalues_3D = pca.singular_values_ ** 2 norm_eigenvalues_3D = sum_normalize(eigenvalues_3D) alpha, beta = triangle_variance_space(norm_eigenvalues_3D) pca_2d = fit_pca(neighbors[:, :2]) # PCA just on the x,y coords eigenvalues_2D = pca_2d.singular_values_ ** 2 return ( FeatureTuple( x, y, z, num_neighbors, alpha, beta, rad_3D, val_range(neighbors[:, 2]), # z_range std_deviation(neighbors[:, 2]), # std_dev density_3D(rad_3D, len(neighbors)), verticality_coefficient(pca), curvature_change(norm_eigenvalues_3D), linearity(norm_eigenvalues_3D), planarity(norm_eigenvalues_3D), scattering(norm_eigenvalues_3D), omnivariance(norm_eigenvalues_3D), anisotropy(norm_eigenvalues_3D), eigenentropy(norm_eigenvalues_3D), val_sum(eigenvalues_3D), # eigenvalue sum rad_2D, density_2D(rad_2D, len(neighbors)), val_sum(eigenvalues_2D), # eigenvalue_sum_2D eigenvalue_ratio_2D(eigenvalues_2D) ), extra )