예제 #1
0
def grow_facet(fit, plane, label, support, max_distance=0.90, debugging=True):
    """
    Find voxels of the object which belong to a facet using the facet plane equation and the distance to the plane.

    :param fit: coefficients of the plane (tuple of 3 numbers)
    :param plane: 3D binary array of the shape of the data
    :param label: the label of the plane processed
    :param support: binary support of the object
    :param max_distance: in pixels, maximum allowed distance to the facet plane of a voxel
    :param debugging: set to True to see plots
    :return: the updated plane, a stop flag
    """
    from scipy.signal import convolve
    nbz, nby, nbx = plane.shape
    indices = np.nonzero(plane)
    if len(indices[0]) == 0:
        no_points = 1
        return plane, no_points
    kernel = np.ones((3, 3, 3))

    start_z = max(indices[0].min() - 20, 0)
    stop_z = min(indices[0].max() + 21, nbz)
    start_y = max(indices[1].min() - 20, 0)
    stop_y = min(indices[1].max() + 21, nby)
    start_x = max(indices[2].min() - 20, 0)
    stop_x = min(indices[2].max() + 21, nbx)

    # find nearby voxels using the coordination number
    obj = np.copy(plane[start_z:stop_z, start_y:stop_y, start_x:stop_x])
    coord = np.rint(convolve(obj, kernel, mode='same'))
    coord = coord.astype(int)
    coord[np.nonzero(coord)] = 1

    # update plane with new voxels
    temp_plane = np.copy(plane)
    temp_plane[start_z:stop_z, start_y:stop_y, start_x:stop_x] = coord
    # remove voxels not belonging to the support
    temp_plane[support == 0] = 0
    # check distance of new voxels to the plane
    new_indices = np.nonzero(temp_plane)

    plane, no_points = distance_threshold(fit=fit,
                                          indices=new_indices,
                                          shape=temp_plane.shape,
                                          max_distance=max_distance)

    if debugging and len(new_indices[0]) != 0:
        indices = np.nonzero(plane)
        gu.scatter_plot(array=np.asarray(indices).T,
                        labels=('x', 'y', 'z'),
                        title='Plane' + str(label) +
                        ' after 1 cycle of facet growing')
        print(str(len(indices[0])) + ' after 1 cycle of facet growing')
    return plane, no_points
예제 #2
0
def plane_fit(indices, label='', threshold=1, debugging=False):
    """
    Fit a plane to the voxels defined by indices.

    :param indices: a (3xN) numpy array, x values being the 1st row, y values the 2nd row and z values the 3rd row
    :param label: int, label of the plane used for the title in the debugging plot
    :param threshold: the fit will be considered as good if the mean distance of the voxels to the plane is smaller than
     this value
    :param debugging: True to see plots
    :return: a tuple of coefficient (a, b, c, d) such that ax+by+cz+d=0, the matrix of covariant values
    """
    valid_plane = True
    indices = np.asarray(indices)
    params3d, pcov3d = curve_fit(plane, indices[0:2, :], indices[2, :])
    std_param3d = np.sqrt(np.diag(pcov3d))
    params = (-params3d[0], -params3d[1], 1, -params3d[2])
    std_param = (std_param3d[0], std_param3d[1], 0, std_param3d[2])

    if debugging:
        _, ax = gu.scatter_plot(np.transpose(indices),
                                labels=('axis 0', 'axis 1', 'axis 2'),
                                title='Points and fitted plane ' + str(label))
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()
        meshx, meshy = np.meshgrid(np.arange(xlim[0], xlim[1] + 1, 1),
                                   np.arange(ylim[0], ylim[1] + 1, 1))
        # meshx varies horizontally, meshy vertically
        meshz = plane(np.vstack(
            (meshx.flatten(), meshy.flatten())), params3d[0], params3d[1],
                      params3d[2]).reshape(meshx.shape)
        ax.plot_wireframe(meshx, meshy, meshz, color='k')
        plt.pause(0.1)

    # calculate the mean distance to the fitted plane
    distance = plane_dist(indices=indices, params=params)
    print(
        f'plane fit using z=a*x+b*y+c: dist.mean()={distance.mean():.2f},  dist.std()={distance.std():.2f}'
    )

    if distance.mean() > threshold and distance.mean() / distance.std() > 1:
        # probably z does not depend on x and y, try to fit  y = a*x + b
        print('z=a*x+b*y+c: z may not depend on x and y')
        params2d, pcov2d = curve_fit(line, indices[0, :], indices[1, :])
        std_param2d = np.sqrt(np.diag(pcov2d))
        params = (-params2d[0], 1, 0, -params2d[1])
        std_param = (std_param2d[0], 0, 0, std_param2d[1])
        if debugging:
            _, ax = gu.scatter_plot(np.transpose(indices),
                                    labels=('axis 0', 'axis 1', 'axis 2'),
                                    title='Points and fitted plane ' +
                                    str(label))
            xlim = ax.get_xlim()
            zlim = ax.get_zlim()
            meshx, meshz = np.meshgrid(np.arange(xlim[0], xlim[1] + 1, 1),
                                       np.arange(zlim[0], zlim[1] + 1, 1))
            meshy = line(x_array=meshx.flatten(), a=params2d[0],
                         b=params2d[1]).reshape(meshx.shape)
            ax.plot_wireframe(meshx, meshy, meshz, color='k')
            plt.pause(0.1)
        # calculate the mean distance to the fitted plane
        distance = plane_dist(indices=indices, params=params)
        print(
            f'plane fit using y=a*x+b: dist.mean()={distance.mean():.2f},  dist.std()={distance.std():.2f}'
        )

        if distance.mean(
        ) > threshold and distance.mean() / distance.std() > 1:
            # probably y does not depend on x, that means x = constant
            print('y=a*x+b: y may not depend on x')
            constant = indices[0, :].mean()
            params = (1, 0, 0, -constant)
            std_param = (0, 0, 0, indices[0, :].std())
            if debugging:
                _, ax = gu.scatter_plot(np.transpose(indices),
                                        labels=('axis 0', 'axis 1', 'axis 2'),
                                        title='Points and fitted plane ' +
                                        str(label))
                ylim = ax.get_ylim()
                zlim = ax.get_zlim()
                meshy, meshz = np.meshgrid(np.arange(ylim[0], ylim[1] + 1, 1),
                                           np.arange(zlim[0], zlim[1] + 1, 1))
                meshx = np.ones(meshy.shape) * constant
                ax.plot_wireframe(meshx, meshy, meshz, color='k')
                plt.pause(0.1)
            # calculate the mean distance to the fitted plane
            distance = plane_dist(indices=indices, params=params)
            print(
                f'plane fit using x=constant: dist.mean()={distance.mean():.2f},  dist.std()={distance.std():.2f}'
            )

    if distance.mean() > threshold and distance.mean() / distance.std() > 1:
        # probably the distribution of points is not flat
        print(
            'distance.mean() > 1, probably the distribution of points is not flat'
        )
        valid_plane = False
    return params, std_param, valid_plane
예제 #3
0
surface = np.copy(support)
surface[coordination_matrix > 22] = 0  # remove the bulk 22
bulk = support - surface
del coordination_matrix
gc.collect()

########################################################
# define edges using the coordination number of voxels #
########################################################
edges = pu.calc_coordination(support, kernel=np.ones((9, 9, 9)), debugging=False)
edges[support == 0] = 0
if debug:
    gu.multislices_plot(edges, invert_yaxis=True, vmin=0, title='Coordination matrix')
edges[edges > edges_coord] = 0  # remove facets and bulk
edges[np.nonzero(edges)] = 1  # edge support
gu.scatter_plot(array=np.asarray(np.nonzero(edges)).T, markersize=2, markercolor='b', labels=('x', 'y', 'z'),
                title='edges')

########################################################
# define corners using the coordination number of voxels #
########################################################
corners = pu.calc_coordination(support, kernel=np.ones((9, 9, 9)), debugging=False)
corners[support == 0] = 0
if debug:
    gu.multislices_plot(corners, invert_yaxis=True, vmin=0, title='Coordination matrix')
corners[corners > corners_coord] = 0  # remove edges, facets and bulk
corners[np.nonzero(corners)] = 1  # corner support
gu.scatter_plot(array=np.asarray(np.nonzero(corners)).T, markersize=2, markercolor='b', labels=('x', 'y', 'z'),
                title='corners')

######################################
# Initialize log files and .vti file #
예제 #4
0
gc.collect()

########################################################
# define edges using the coordination number of voxels #
########################################################
edges = pu.calc_coordination(support,
                             kernel=np.ones((9, 9, 9)),
                             debugging=False)
edges[support == 0] = 0
if debug:
    gu.multislices_plot(edges, vmin=0, title='Coordination matrix')
edges[edges > edges_coord] = 0  # remove facets and bulk
edges[np.nonzero(edges)] = 1  # edge support
gu.scatter_plot(array=np.asarray(np.nonzero(edges)).T,
                markersize=2,
                markercolor='b',
                labels=('axis 0', 'axis 1', 'axis 2'),
                title='edges')

########################################################
# define corners using the coordination number of voxels #
########################################################
corners = pu.calc_coordination(support,
                               kernel=np.ones((9, 9, 9)),
                               debugging=False)
corners[support == 0] = 0
if debug:
    gu.multislices_plot(corners, vmin=0, title='Coordination matrix')
corners[corners > corners_coord] = 0  # remove edges, facets and bulk
corners[np.nonzero(corners)] = 1  # corner support
gu.scatter_plot(array=np.asarray(np.nonzero(corners)).T,