예제 #1
0
def test_structure_tensor_eigenvalues_3d():
    image = np.pad(cube(9), 5) * 1000
    boundary = (np.pad(cube(9), 5) - np.pad(cube(7), 6)).astype(bool)
    A_elems = structure_tensor(image, sigma=0.1)
    e0, e1, e2 = structure_tensor_eigenvalues(A_elems)
    # e0 should detect facets
    assert np.all(e0[boundary] != 0)
def water_interface_extraction2(wet, nwet, void):
    wet = ndimage.binary_dilation(input=wet, structure=cube(4).astype(np.bool))
    nwet = ndimage.binary_dilation(input=nwet,
                                   structure=cube(4).astype(np.bool))
    interface = np.bitwise_and(wet, nwet)
    interface = np.bitwise_and(interface, void)
    return interface
예제 #3
0
 def region_growing_from_input(self, color, bone_from_scan=None):
     """
     This function runs the region growing algorithm
     :param color: the color you want for the bone
     :param bone_from_scan: If the same scan were used inside another bone
     """
     collect()
     # initilize
     if not bone_from_scan:
         self.load_original_data()
     else:
         self.copy_original_from_bone(bone_from_scan)
     checked = zeros(self._original_img_data.shape)
     seg = zeros(self._original_img_data.shape)
     need_to_check = []
     # Color the seeds and check for neighbors
     for seed in self._seeds_points:
         seg[seed] = color
         checked[seed] = 1
         neighbors = self._get_neighbors(seed, checked,
                                         self._original_img_data.shape)
         for neighbor in neighbors:
             if self._get_threshold(self._original_img_data[neighbor],
                                    BONE_BOUND_VALUES[0],
                                    BONE_BOUND_VALUES[1]):
                 need_to_check.append(neighbor)
     # Region Growing - while there's a neighbor, color it and keep going
     while need_to_check:
         pt = need_to_check.pop()
         if checked[pt] == 1:
             continue
         else:
             checked[pt] = 1
             neighbors = self._get_neighbors(pt, checked,
                                             self._original_img_data.shape)
             for neighbor in neighbors:
                 if self._get_threshold(self._original_img_data[neighbor],
                                        BONE_BOUND_VALUES[0],
                                        BONE_BOUND_VALUES[1]):
                     need_to_check.append(neighbor)
             seg[pt] = color
     # Closing holes
     del need_to_check, checked
     for i in range(self._dilation):
         seg = dilation(seg, cube(3, uint8))
     for i in range(self._dilation - 1):
         seg = erosion(seg, cube(3, uint8))
     self._segmentation_data = seg
     del seg
     collect()
예제 #4
0
def local_thickness(im):
    r"""
    For each voxel, this functions calculates the radius of the largest sphere
    that both engulfs the voxel and fits entirely within the foreground. This
    is not the same as a simple distance transform, which finds the largest
    sphere that could be *centered* on each voxel.

    Parameters
    ----------
    im : array_like
        A binary image with the phase of interest set to True

    Returns
    -------
    An image with the pore size values in each voxel

    Notes
    -----
    The term *foreground* is used since this function can be applied to both
    pore space or the solid, whichever is set to True.

    """
    from skimage.morphology import cube
    if im.ndim == 2:
        from skimage.morphology import square as cube
    dt = spim.distance_transform_edt(im)
    sizes = sp.unique(sp.around(dt, decimals=0))
    im_new = sp.zeros_like(im, dtype=float)
    for r in tqdm(sizes):
        im_temp = dt >= r
        im_temp = spim.distance_transform_edt(~im_temp) <= r
        im_new[im_temp] = r
    # Trim outer edge of features to remove noise
    im_new = spim.binary_erosion(input=im, structure=cube(1))*im_new
    return im_new
예제 #5
0
def _get_axial_shifts(ndim=2, include_diagonals=False):
    r'''
    Helper function to generate the axial shifts that will be performed on
    the image to identify bordering pixels/voxels
    '''
    if ndim == 2:
        if include_diagonals:
            neighbors = square(3)
        else:
            neighbors = diamond(1)
        neighbors[1, 1] = 0
        x, y = np.where(neighbors)
        x -= 1
        y -= 1
        return np.vstack((x, y)).T
    else:
        if include_diagonals:
            neighbors = cube(3)
        else:
            neighbors = octahedron(1)
        neighbors[1, 1, 1] = 0
        x, y, z = np.where(neighbors)
        x -= 1
        y -= 1
        z -= 1
        return np.vstack((x, y, z)).T
예제 #6
0
def create_boundary(labels, regions, width=10):
    """Return new label numpy array including labels for boundary zone

    Args:
        labels: 3d numpy array
            labels information
        regions: list
            list containing the label of region(tissue) that we are interested to do dilation on
            In my case, labels could be either 0, 1, and 0 represents background, so regions=[1]
        width: int
            how much distance would you like to dilate

    Find the boundary region for each region by using dilation method.
    Take the union of all separate boundary regions as target region and assign it with new label with label of given
    region + len(regions).
    """
    labels_dilated = labels.copy()
    nb_region = len(regions)

    id_protected = np.in1d(labels.ravel(), regions).reshape(labels.shape)

    kernel = cube(2 * width + 1)

    for region in regions:
        labels_binary = np.zeros(labels.shape, dtype=labels.dtype)
        labels_binary[np.where(labels == region)] = 1

        lab_boundary = dilation(labels_binary, kernel) - labels_binary
        idx_boundary = (lab_boundary == 1)

        labels_dilated[idx_boundary & ~id_protected] = region + nb_region

    return labels_dilated
예제 #7
0
def removeBackground_(data, selem=cube(6)):
    img = data
    for i in range(img.shape[0]):
        img[i, :, :] = median(img[i, :, :])
    background = opening(img)
    sansBackground = img - background
    return sansBackground
예제 #8
0
def surface_distance_abs(seg, ref):
    import skimage.morphology as skm
    if (np.sum(seg) == 0):
        return 0
    se = skm.cube(3)
    seg_surface = seg - skm.erosion(seg, se)
    ref_surface = ref - skm.erosion(ref, se)
    dist = []
    ix, iy, iz = np.where(ref_surface)
    p_ref = np.array([ix, iy, iz])
    indx, indy, indz = np.where(seg_surface)
    for i in range(len(indx)):
        p = np.array([[indx[i]], [indy[i]], [indz[i]]])
        dists = np.sqrt(np.sum((np.repeat(p, p_ref.shape[1], 1) - p_ref)**2,
                               0))
        dist.append(np.min(dists))
    ix, iy, iz = np.where(seg_surface)
    p_seg = np.array([ix, iy, iz])
    indx, indy, indz = np.where(ref_surface)
    for i in range(len(indx)):
        p = np.array([[indx[i]], [indy[i]], [indz[i]]])
        dists = np.sqrt(np.sum((np.repeat(p, p_seg.shape[1], 1) - p_seg)**2,
                               0))
        dist.append(np.min(dists))

    return round(sum(dist) / len(dist), 3)
예제 #9
0
파일: nilearn-helper.py 프로젝트: xgrg/alfa
def plot_tbss(img, mean_FA_skeleton, start, end, row_l=6, step=1, title='',
    axis='z', pngfile=None):
    ''' Inspired from plot_two_maps. Plots a TBSS contrast map over the
    skeleton of a mean FA map'''

    # Dilate tbss map
    import numpy as np
    from skimage.morphology import cube, dilation
    from nilearn import image
    d = np.array(image.load_img(img).dataobj)
    dil_tbss = dilation(d, cube(2))
    dil_tbss_img = image.new_img_like(img, dil_tbss)

    slice_nb = int(abs(((end - start) / float(step))))
    images = []

    for line in range(int(slice_nb/float(row_l) + 1)):
        opt = {'title':{True:title,
                        False:None}[line==0],
               'colorbar':False,
               'black_bg':True,
               'display_mode':axis,
               'threshold':0.2,
               'cmap': cm.Greens,
               'cut_coords':range(start + line * row_l * step,
                                       start + (line+1) * row_l * step,
                                       step)}
        method = 'plot_stat_map'
        opt.update({'stat_map_img': mean_FA_skeleton})

        t = getattr(plotting, method).__call__(**opt)


        try:
            # Add overlay
            t.add_overlay(dil_tbss_img, cmap=cm.hot, threshold=0.95, colorbar=True)
        except TypeError:
            print img, 'probably empty tbss map'
            pass

        # Converting to PIL and appending it to the list
        buf = io.BytesIO()
        t.savefig(buf)
        buf.seek(0)
        im = Image.open(buf)
        images.append(im)

    # Joining the images
    imsize = images[0].size
    out = Image.new('RGBA', size=(imsize[0], len(images)*imsize[1]))
    for i, im in enumerate(images):
        box = (0, i * imsize[1], imsize[0], (i+1) * imsize[1])
        out.paste(im, box)

    if pngfile is None:
        import tempfile
        pngfile = tempfile.mkstemp(suffix='.png')[1]
    print 'Saving to...', pngfile, '(%s)'%title

    out.save(pngfile)
예제 #10
0
def getfovLabel(coord, mask, seg, seed_mask, fov_shape):
    """ 由patch的当前分割结果, 结合整体分割map, 得到下一个
        未分割实例的seed点
    """
    mask_fov = fromSeed2Data(coord, mask, fov_shape)
    seg_fov = fromSeed2Data(coord, seg, fov_shape)
    seed_mask_fov = fromSeed2Data(coord, seed_mask, fov_shape)

    mask1 = np.zeros(mask_fov.shape)
    mask1[seg_fov > 0] = mask_fov[seg_fov > 0]
    # mask_fov[seg_fov==0] = 0
    mask1 = dilation(mask1, cube(3))
    seed_map = ((mask1 == 0) & (seg_fov > 0)).astype(int)  # 剩下未分割的区域

    seed_mask_fov_a = np.zeros(seed_mask_fov.shape)
    seed_mask_fov_a[seed_mask_fov > 0] = seed_mask_fov[seed_mask_fov > 0]
    # seed_mask_fov_a = dilation(seed_mask_fov_a, cube(5))
    # prev_seed = ((seed_map>0) & (seed_mask_fov>0)).astype(int)
    prev_seed = ((seed_map > 0) & (seed_mask_fov_a > 0)).astype(int)

    if np.sum(prev_seed) > 0:
        coords = np.stack(np.where(prev_seed > 0), axis=0).T
    else:
        coords = np.stack(np.where(seed_map > 0), axis=0).T
    sel = np.random.choice(len(coords), size=1)[0]

    coord = coords[sel]
    label = seed_mask_fov_a[..., coord[0], coord[1], coord[2]]

    return label, coord
def assign_pore(pore_object, fiber_object, label):
    mask = pore_object == label
    mask = ndimage.binary_dilation(input=mask, structure=cube(5))
    fiber_contacts = np.unique(fiber_object[mask])
    result = np.zeros(5, dtype=np.uint16)
    result[fiber_contacts + 1] = 1
    result[0] = label
    return result
def solid_interface_extraction(wet, solid):
    # swap dilation for v13b
    # wet = ndimage.binary_dilation(input = wet, structure = cube(3).astype(np.bool))
    solid = ndimage.binary_dilation(input=solid,
                                    structure=cube(4).astype(np.bool))
    interface = np.bitwise_and(wet, solid)
    # interface = np.bitwise_and(interface, void)
    return interface
예제 #13
0
def multipleSeedsRG(CT_scan, ROI):
    """
    this function preforms a liver segmentataion by using the following algorithm:
    1. Extract N seeds points inside the ROI.
    2. Perform Seeded Region Growing with N initial points
    :param CT_scan: a CT_scan
    :param ROI: ROI
    :return: Liver segmentation
    """
    img = nib.load(CT_scan)
    img_data = img.get_data()
    visit = np.zeros_like(img_data)

    # entering first neighbor:
    findSeeds(CT_scan, ROI)
    seeds_name = CT_scan.split(".")[0] + "_Seeds.nii.gz"
    seeds = nib.load(seeds_name)
    seeds_data = seeds.get_data()
    visit[seeds_data == 1] = 1
    cube = morphology.dilation(seeds_data, morphology.cube(3, np.uint8))
    neighbors = np.subtract(cube, seeds_data)
    neighbors[visit == 1] = 0
    visit[neighbors == 1] = 1

    num_of_iterations = 0
    while np.sum(neighbors) > 0 and num_of_iterations < 40:
        num_of_iterations += 1
        neighbors_only_values = np.zeros_like(img_data)
        neighbors_only_values[neighbors == 1] = img_data[
            neighbors == 1]  # the value of each
        # neighbor where there is one and 0 where there is no neighbor
        mean = np.mean(img_data[
            seeds_data == 1])  # the mean value of all values of all the seed
        # in the image
        seeds_data[
            np.absolute(np.subtract(mean, neighbors_only_values)) < 40] = 1

        # update neighbors:
        cube = morphology.dilation(seeds_data, morphology.cube(3, np.uint8))
        neighbors = np.subtract(cube, seeds_data)
        neighbors[visit == 1] = 0
        visit[neighbors == 1] = 1

    scan_name = CT_scan.split(".")[0]
    nib.save(seeds, scan_name + "_LiverSegBeforeClean.nii.gz")
    cleanLiver(CT_scan)
예제 #14
0
def trim_nearby_peaks(peaks, dt):
    r"""
    Finds pairs of peaks that are nearer to each other than to the solid phase,
    and removes the peak that is closer to the solid.

    Parameters
    ----------
    peaks : ND-array
        A boolean image containing True values to mark peaks in the distance
        transform (``dt``)

    dt : ND-array
        The distance transform of the pore space for which the true peaks are
        sought.

    Returns
    -------
    image : ND-array
        An array the same size as ``peaks`` containing a subset of the peaks
        in the original image.

    Notes
    -----
    Each pair of peaks is considered simultaneously, so for a triplet of peaks
    each pair is considered.  This ensures that only the single peak that is
    furthest from the solid is kept.  No iteration is required.
    """
    peaks = sp.copy(peaks)
    if dt.ndim == 2:
        from skimage.morphology import square as cube
    else:
        from skimage.morphology import cube
    peaks, N = spim.label(peaks, structure=cube(3))
    crds = spim.measurements.center_of_mass(peaks,
                                            labels=peaks,
                                            index=sp.arange(1, N + 1))
    crds = sp.vstack(crds).astype(int)  # Convert to numpy array of ints
    # Get distance between each peak as a distance map
    tree = sptl.cKDTree(data=crds)
    temp = tree.query(x=crds, k=2)
    nearest_neighbor = temp[1][:, 1]
    dist_to_neighbor = temp[0][:, 1]
    del temp, tree  # Free-up memory
    dist_to_solid = dt[tuple(crds.T)]  # Get distance to solid for each peak
    hits = sp.where(dist_to_neighbor < dist_to_solid)[0]
    # Drop peak that is closer to the solid than it's neighbor
    drop_peaks = []
    for peak in hits:
        if dist_to_solid[peak] < dist_to_solid[nearest_neighbor[peak]]:
            drop_peaks.append(peak)
        else:
            drop_peaks.append(nearest_neighbor[peak])
    drop_peaks = sp.unique(drop_peaks)
    # Remove peaks from image
    slices = spim.find_objects(input=peaks)
    for s in drop_peaks:
        peaks[slices[s]] = 0
    return (peaks > 0)
예제 #15
0
def trim_saddle_points(peaks, dt, max_iters=10):
    r"""
    Removes peaks that were mistakenly identified because they lied on a
    saddle or ridge in the distance transform that was not actually a true
    local peak.

    Parameters
    ----------
    peaks : ND-array
        A boolean image containing True values to mark peaks in the distance
        transform (``dt``)

    dt : ND-array
        The distance transform of the pore space for which the true peaks are
        sought.

    max_iters : int
        The maximum number of iterations to run while eroding the saddle
        points.  The default is 10, which is usually not reached; however,
        a warning is issued if the loop ends prior to removing all saddle
        points.

    Returns
    -------
    image : ND-array
        An image with fewer peaks than the input image
    """
    peaks = sp.copy(peaks)
    if dt.ndim == 2:
        from skimage.morphology import square as cube
    else:
        from skimage.morphology import cube
    labels, N = spim.label(peaks)
    slices = spim.find_objects(labels)
    for i in range(N):
        s = extend_slice(s=slices[i], shape=peaks.shape, pad=10)
        peaks_i = labels[s] == i + 1
        dt_i = dt[s]
        im_i = dt_i > 0
        iters = 0
        peaks_dil = sp.copy(peaks_i)
        while iters < max_iters:
            iters += 1
            peaks_dil = spim.binary_dilation(input=peaks_dil,
                                             structure=cube(3))
            peaks_max = peaks_dil * sp.amax(dt_i * peaks_dil)
            peaks_extended = (peaks_max == dt_i) * im_i
            if sp.all(peaks_extended == peaks_i):
                break  # Found a true peak
            elif sp.sum(peaks_extended * peaks_i) == 0:
                peaks_i = False
                break  # Found a saddle point
        peaks[s] = peaks_i
        if iters >= max_iters:
            print('Maximum number of iterations reached, consider' +
                  'running again with a larger value of max_iters')
    return peaks
예제 #16
0
def simple_otsu(im, trim_solid=True):
    r"""
    Uses Otsu's method to find a threshold, then uses binary opening and
    closing to remove noise.

    Parameters
    ----------
    im : ND-image
        The greyscale image of the porous medium to be binarized.

    trim_solid : Boolean
        If True (default) then all solid voxels not connected to an image
        boundary are trimmed.

    Returns
    -------
    An ND-image the same size as ``im`` but with True and False values
    indicating the binarized or segmented phases.

    Examples
    --------

    >>> im = ps.generators.blobs([300, 300], porosity=0.5)
    >>> im = ps.generators.add_noise(im)
    >>> im = spim.gaussian_filter(im, sigma=1)
    >>> im = simple_otsu(im)

    """
    if im.ndim == 2:
        ball = disk
        cube = square
    im = sp.pad(array=im, pad_width=1, mode='constant', constant_values=1)
    val = filters.threshold_otsu(im)
    im = im >= val
    # Remove speckled noise from void and solid phases
    im = spim.binary_closing(input=im, structure=ball(1))
    im = spim.binary_opening(input=im, structure=ball(1))
    # Clean up edges
    im = spim.binary_closing(input=im, structure=cube(3))
    im = spim.binary_opening(input=im, structure=cube(3))
    im = im[[slice(1, im.shape[d] - 1) for d in range(im.ndim)]]
    temp = clear_border(~im)
    im = im + temp
    return im
def interface_extraction(wet, void):
    dry = np.bitwise_and(void, ~wet)
    # wet = ndimage.binary_dilation(input = wet, structure = cube(3).astype(np.bool))
    dry = ndimage.binary_dilation(input=dry, structure=cube(4).astype(np.bool))

    interface = np.bitwise_and(wet, dry)
    interface = np.bitwise_and(interface, void)
    # interface = skimage.morphology.binary_erosion(interface, selem=ball(1).astype(np.bool))
    # interface = skimage.morphology.binary_dilation(interface, selem=ball(1).astype(np.bool))
    return interface
예제 #18
0
def __postProcessing(mask):
    pred_mask = binary_closing(np.squeeze(mask), cube(2))

    try:
        labels = label(pred_mask)
        pred_mask = (labels == np.argmax(np.bincount(labels.flat)[1:]) +
                     1).astype(np.uint16)
    except:
        pred_mask = pred_mask

    return pred_mask
예제 #19
0
def condition(patch_mask, seg_pad, coord, fov_shape):
    fov_mask = fromSeed2Data(coord, patch_mask, fov_shape)
    fov_seg = fromSeed2Data(coord, seg_pad, fov_shape)

    mask1 = np.zeros(fov_mask.shape)
    mask1[fov_seg > 0] = fov_mask[fov_seg > 0]
    # fov_mask[fov_seg==0] = 0
    # c = (not np.all((mask1>0) & (fov_seg>0))) and (np.any(fov_seg>0))
    mask1 = dilation(mask1, cube(3))
    c = ((mask1 == 0) & (fov_seg > 0)).astype(int)
    return np.sum(c)
예제 #20
0
def nuclearDetectionList(selem=6, min_sigma=0.25, max_sigma=5, threshold=0.04,
                         writeOut=False, directoryPath=None, name=None, cube_selem=True):
    """
    FUNCTION: write a list of function dictionaries (as per Chain; ChainMethod)
    ARGUMENTS:
        selem: structure element for morphological opening. If cube_selem, skimage.morphology.cube() will be applied to
            this arg. In this case, selem should be int.
        min_sigma: standard deviation of the smallest Gaussian kernel to be used in the scale-space representation
            in Laplacian of Gaussian blob detection (skimage.feature.blob_log()). Determines the smallest blobs
            that can be detected.
        max_sigma: standard deviation of the largest Gaussian kernel to be used in the scale-space representation
            in Laplacian of Gaussian blob detection (skimage.feature.blob_log()). Determines the largest blobs
            that can be detected.
        threshold: lower threshold of LoG local minima that will be detected as a blob. Determines the lowest intensity
            of blob that can be detected
        writeOut: should images labeling blob coordinates be written out? (bool)
        directoryPath: if writeOut, this is the directory to which the blob images will be saved.
        name: if writeOut, this name will be saved as part of the blob image file names. Will probably reflect the
            parameters chosen. If writeOut and name is None, this will be automatically defined.
        cube_selem: should skimage.morphology.cube() be applied to the inputted selem? (bool)
    DEPENDENCIES: numpy as np (when implemented in chain)
    Native: (1)medianFilter3D()/skimage.filters.median(); (2)removeBackground()/skimage.morphology.opening();
        getBlobs_LoG()/(3)skimage.feature.blob_log(); (4)writeBlobsImg()/skimage.draw.circle_perimeter
        1) Median filter sequentially applied to x-y planes along z
        2) Applies morphological opening to generate a background image. This is subtracted from the original and the
            result is returned.
        3) A Laplacian of Gaussian kernel returns an image whereby local minima reflect blobs (~ spherical areas of
            highest local intensity) similar to the size of the kernels sigma. When applied across a scale space, blobs
            of a variety of sizes can be identified. In order to define blobs, some absolute threshold for magnitude of
            minima is chosen. Returns np.ndarray with shape (n, 4) where columns are z, y, x, sigma.
        4) Writes images demarcating the locations of blobs by writing a series of x-y images in which the centre of a
            blob in that plane is encircled by a circle of radius equal to the sigma recorded for the blob.
    RETURNS: list ([{...}, {...}, {...}])
    """
    _selem = selem
    if cube_selem:
        selem = cube(selem)
    med = {'function': medianFilter3D, 'suffix': 'MF', 'writeOut': None}
    remBack = {'function': removeBackground, 'suffix': 'sansBk', 'writeOut': None, 'args': [selem]}
    if writeOut:
        if name is None:
            name = 'o{}_min{}_max{}_thr{}'.format(_selem, min_sigma, max_sigma, threshold)
        blobs = {'function': getBlobs_LoG, 'suffix': 'blob_log',
                 'kwargs': {'min_sigma': min_sigma, 'max_sigma': max_sigma, 'threshold': threshold},
                 'writeOut': {'function': writeBlobsImg, 'priorLink_kw': 'img', 'newLink_kw': 'blobs',
                              'writeInfo_kw': 'file_', 'kwargs': {'outDir': directoryPath, 'name': name}}}
    else:
        blobs = {'function': getBlobs_LoG, 'suffix': 'blob_log',
                 'kwargs': {'min_sigma': min_sigma, 'max_sigma': max_sigma, 'threshold': threshold},
                 'writeOut': None}
    funcList = [med, remBack, blobs]
    return funcList
예제 #21
0
def mkIsoStruct(dilate_factor, aspect):
    '''
    Builds isotropic structuring element for dilation.
    
    Args:
      dilate_factor (int): number of px for isotropic 2D dilation.
      aspect (tuple(float)): voxel side ratios.
    
    Returns:
      np.ndarray: structureing element for 3D anisotropic dilation.
    '''

    # XY dilation factor
    df_xy = int(dilate_factor * 2 + 1)
    if 0 == aspect[0]:
        se = cube(df_xy)
        se = se[0]
        new_shape = [1]
        [new_shape.append(d) for d in se.shape]
        se = se.reshape(new_shape)
        return (se)

    # Z dilation factor
    df_z = int(dilate_factor * aspect[1] / aspect[0] * 2 + 1)

    if df_z == df_xy:
        # Isotropic
        return (cube(df_z))
    elif df_z > df_xy:
        # Larger Z side
        se = cube(df_z)
        se = se[:, 0:df_xy, 0:df_xy]
    else:
        # Larger XY side
        se = cube(df_xy)
        se = se[0:df_z]

    # Output
    return (se)
예제 #22
0
def morph_process(mask, elem_len=1, radius=10, save_labeled=None):
    # 1. closing and opening process of vesicle mask. 2. label the vesicles.
    # 3. exclude fasle vesicles by counting their volumes and thresholding, return only vesicle binary mask
    # 4. extract boundaries and labels them
    # 5. extract labeled individual vesicle boundary, convert into points vectors and output them.
    from skimage.morphology import opening, closing, erosion, cube
    from skimage.measure import label
    with mrcfile.open(mask) as f:
        tomo_mask = f.data
    # transform mask into uint8
    bimask = np.round(tomo_mask).astype(np.uint8)
    #closing_opening = closing(opening(bimask,cube(elem_len)),cube(elem_len+2))
    #closing_opening = opening(closing(bimask, cube(elem_len+2)),cube(elem_len))
    closing_opening = closing(opening(bimask, cube(elem_len)), cube(elem_len))
    # label all connected regions
    labeled = label(closing_opening)
    idx = get_indices_sparse(labeled)
    num = np.max(labeled)
    for i in range(1, num + 1):
        if idx[i][0].shape[0] < radius**3 * 4:
            labeled[idx[i][0], idx[i][1], idx[i][2]] = 0
    filtered = (labeled >= 1).astype(np.uint8)
    print('complete filtering')
    boundaries = filtered - erosion(filtered, cube(3))
    # label the boundaries of vesicles
    bd_labeled = label(boundaries)
    #the number of labeled vesicle
    num = np.max(bd_labeled)
    #vesicle list elements: np.where return point cloud positions whose shape is (3,N)
    idx = get_indices_sparse(bd_labeled)
    vesicle_list = [
        np.swapaxes(np.array(idx[i]), 0, 1) for i in range(1, num + 1)
    ]
    # for i in range(1,num+1):
    #     cloud = np.array(np.where(bd_labeled == i))
    #     cloud = np.swapaxes(cloud,0,1)
    #     vesicle_list.append(cloud)

    return vesicle_list
예제 #23
0
def FillHoles(InputTensor,FillingStructure = cube(4)):
    # Convert tensor to numpy array
    InputNumpyArray = InputTensor.numpy()
    # The closing of an input image by erosion and dilation of the image by a structuring element.
    # Closing fills holes smaller than the structuring element
    ClosedArray     = binary_closing(InputNumpyArray,structure=FillingStructure ).astype(int)
    # Fill the holes in binary objects
    OutputArray     = binary_fill_holes(ClosedArray, structure=FillingStructure ).astype(int)   
    # convert numpy array to tensor
    TensorOutput    = torch.from_numpy(OutputArray)
    
    return TensorOutput
    
예제 #24
0
def selective_seeds_generate(centerline, junc, num_seeds=20):
    junc_mask = dilation(junc, cube(8))
    p = centerline
    mask = np.logical_and(junc, centerline)
    p[mask] = 20
    p = p.astype(float) / np.sum(p)

    seeds = np.zeros_like(centerline)
    inds = np.arange(seeds.size)[(centerline > 0).flatten()]
    inds_sel = np.random.choice(inds, num_seeds, replace=False, p.flatten())
    #xs,ys,zs = np.unravel_index(inds_sel,seeds.shape)
    #seeds[xs,ys,zs] = 1
    #return seeds
    return inds_sel
예제 #25
0
def fun_generar_vol_random(tipo_forma, tam_limite, transp_forma):
    # Base volume generation
    if (tipo_forma == 1):
        # Random size
        tam_aux = rnd.randint(tam_limite[0], tam_limite[1])
        # Shape creation
        vol_forma = morphology.cube(tam_aux)

    elif (tipo_forma == 2):
        # Random size
        tam_aux = rnd.randint(tam_limite[0], tam_limite[1])
        # Shape creation
        vol_forma = morphology.ball(tam_aux)

    elif (tipo_forma == 3):
        # Random size
        tam_forma = (rnd.randint(tam_limite[0], tam_limite[1]),
                     rnd.randint(tam_limite[0], tam_limite[1]),
                     rnd.randint(tam_limite[0] * 2, tam_limite[1] * 2))
        # Shape creation
        vol_forma = fun_cilindro(tam_forma)

    elif (tipo_forma == 4):
        # Random size
        tam_aux = rnd.randint(tam_limite[0], tam_limite[1])
        # Shape creation
        vol_forma = morphology.octahedron(tam_aux)

    elif (tipo_forma == 5):
        # Random size
        tam_forma = (rnd.randint(tam_limite[0], tam_limite[1]),
                     rnd.randint(tam_limite[0], tam_limite[1]),
                     rnd.randint(tam_limite[0] * 2, tam_limite[1] * 2))
        # Shape creation
        vol_forma = fun_estrella_cil_vol(tam_forma)

    elif (tipo_forma == 6):
        # Random size
        tam_aux = rnd.randint(tam_limite[0], tam_limite[1])
        # Shape creation
        vol_forma = fun_estrella_rot_vol(tam_aux)

    # Shape label population
    label_forma = np.multiply(vol_forma, tipo_forma)
    # Transparency
    vol_forma = np.multiply(vol_forma, transp_forma)
    tam_forma = vol_forma.shape

    return (tam_forma, vol_forma, label_forma)
예제 #26
0
def find_disconnected_voxels(im, conn=None):
    r"""
    This identifies all pore (or solid) voxels that are not connected to the
    edge of the image.  This can be used to find blind pores, or remove
    artifacts such as solid phase voxels that are floating in space.

    Parameters
    ----------
    im : ND-image
        A Boolean image, with True values indicating the phase for which
        disconnected voxels are sought.

    conn : int
        For 2D the options are 4 and 8 for square and diagonal neighbors, while
        for the 3D the options are 6 and 26, similarily for square and diagonal
        neighbors.  The default is max

    Returns
    -------
    image : ND-array
        An ND-image the same size as ``im``, with True values indicating
        voxels of the phase of interest (i.e. True values in the original
        image) that are not connected to the outer edges.

    Notes
    -----
    image : ND-array
        The returned array (e.g. ``holes``) be used to trim blind pores from
        ``im`` using: ``im[holes] = False``

    """
    if im.ndim != im.squeeze().ndim:
        warnings.warn('Input image conains a singleton axis:' + str(im.shape) +
                      ' Reduce dimensionality with np.squeeze(im) to avoid' +
                      ' unexpected behavior.')
    if im.ndim == 2:
        if conn == 4:
            strel = disk(1)
        elif conn in [None, 8]:
            strel = square(3)
    elif im.ndim == 3:
        if conn == 6:
            strel = ball(1)
        elif conn in [None, 26]:
            strel = cube(3)
    labels, N = spim.label(input=im, structure=strel)
    holes = clear_border(labels=labels) > 0
    return holes
예제 #27
0
def binarize(i, thr):
    """Binarize an image using the provided threshold.

    Args:
      i (np.array): image.
      thr (float or int): intensity threshold.

    Returns:
      np.array: thresholded image.
    """

    if 2 == len(i.shape):
        i = closing(i > thr, square(3))
    elif 3 == len(i.shape):
        i = closing(i > thr, cube(3))
    return (i)
예제 #28
0
def threshold_adaptive(i,
                       block_size,
                       doClosing=True,
                       method=None,
                       mode=None,
                       param=None):
    """Adaptive threshold.

    Args:
      i (np.array): image.
      block_size (int): neighbourhood, if even then it is incremented by 1.
      doClosing (bool): to trigger closing operation after local thresholding.
      method, mode, param: additional parameters for threshold_local.

    Returns:
      np.array: thresholded image.
    """

    # Increment neighbourhood size
    if 0 == block_size % 2:
        block_size += 1

    # Local threshold mask
    lmask = i.copy()

    # Apply threshold per slice
    if 3 == len(i.shape):
        for slice_id in range(i.shape[0]):
            lmask[slice_id, :, :] = filters.threshold_local(i[slice_id, :, :],
                                                            block_size,
                                                            method=method,
                                                            mode=mode,
                                                            param=param)
        lmask = i >= lmask
        if doClosing: lmask = closing(lmask, cube(3))
    else:
        lmask = filters.threshold_local(i,
                                        block_size,
                                        method=method,
                                        mode=mode,
                                        param=param)
        lmask = i >= lmask
        if doClosing: lmask = closing(lmask, square(3))

    # Output
    return (lmask)
def class_map_zero_pixel_closing(class_map, zero_pixel_pos_list, range):

    increase_range = True
    if len(zero_pixel_pos_list) == 0:
        return class_map
    else:
        clean_map = class_map
        class_map = closing(class_map, cube(range)).astype(np.int8)
        for (x, y, z) in zero_pixel_pos_list:
            clean_map[x, y, z] = class_map[x, y, z]
            if class_map[x, y, z] != 0:
                zero_pixel_pos_list.remove((x, y, z))
                increase_range = False
        if increase_range:
            range += 1

        return class_map_zero_pixel_closing(clean_map, zero_pixel_pos_list,
                                            range)
예제 #30
0
def objects():
    from skimage.morphology import (square, rectangle, diamond, disk, cube,
                                    octahedron, ball, octagon, star)
    from mpl_toolkits.mplot3d import Axes3D
    # Generate 2D and 3D structuring elements.
    struc_2d = {
        "square(15)": square(15),
        "rectangle(15, 10)": rectangle(15, 10),
        "diamond(7)": diamond(7),
        "disk(7)": disk(7),
        "octagon(7, 4)": octagon(7, 4),
        "star(5)": star(5)
    }

    struc_3d = {
        "cube(11)": cube(11),
        "octahedron(5)": octahedron(5),
        "ball(5)": ball(5)
    }

    # Visualize the elements.
    fig = plt.figure(figsize=(8, 8))

    idx = 1
    for title, struc in struc_2d.items():
        ax = fig.add_subplot(3, 3, idx)
        ax.imshow(struc, cmap="Paired", vmin=0, vmax=12)
        for i in range(struc.shape[0]):
            for j in range(struc.shape[1]):
                ax.text(j, i, struc[i, j], ha="center", va="center", color="w")
        ax.set_axis_off()
        ax.set_title(title)
        idx += 1

    for title, struc in struc_3d.items():
        ax = fig.add_subplot(3, 3, idx, projection=Axes3D.name)
        ax.voxels(struc)
        ax.set_title(title)
        idx += 1

    fig.tight_layout()
    plt.show()
예제 #31
0
def vesicle_rendering(vesicle_file, tomo_dims):
    # vesicle file can be json or a info list
    from tomoSgmt.utils import make_ellipsoid as mk
    from skimage.morphology import closing, cube
    if type(vesicle_file) is str:
        with open(vesicle_file) as f:
            ves = json.load(f)
        vesicle_info = ves['vesicles']
    else:
        vesicle_info = vesicle_file
    vesicle_tomo = np.zeros(np.array(tomo_dims) + np.array([30, 30, 30]),
                            dtype=np.uint8)
    for i, vesicle in enumerate(vesicle_info):
        print(i)
        ellip_i = mk.ellipsoid_point(np.array(vesicle['radii']),
                                     np.array(vesicle['center']),
                                     np.array(vesicle['evecs']))
        #ellip_i is an array (N,3) of points of a filled ellipsoid
        vesicle_tomo[ellip_i[:, 0], ellip_i[:, 1], ellip_i[:, 2]] = 1
    vesicle_tomo = closing(vesicle_tomo, cube(3))
    return vesicle_tomo[0:tomo_dims[0], 0:tomo_dims[1], 0:tomo_dims[2]]
def neigh_br(arr_nodes, arr_br):
    """
    Creates a graph with nodes from the array of nodes and branches
    by considering the branches that adjoin to the current node.
    The labels of these branches are set as an attribute of the
    node.
    
    Parameters
    ---------
    arr_nodes : array of labeled regions that are considered as nodes
    arr_br : array of labeled regions considered as branches
    
    Returns
    ------
    G : a graph of nodes with the attribute 'neigh' 
    
    Examples
    -------
    >>>arr_nodes = label_nodes(num)
    >>>arr_nodes
    array([[[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]],
           [[0, 0, 0],
            [1, 1, 0],
            [1, 0, 0],
            [0, 0, 0]],
           [[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]]], dtype=uint8) 
    >>>arr_br = label_br(num)
    >>>arr_br
    array([[[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]],
           [[1, 0, 0],
            [0, 0, 2],
            [0, 0, 0],
            [3, 0, 0]],
           [[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]]], dtype=uint8) 
    >>>G = neigh_br(arr_nodes, arr_br)
    >>>G.nodes()
    [1]
    >>>nx.get_node_attributes(G, 'neigh')
    {1: array([1, 2, 3])}
    
    """
    G = nx.MultiGraph()
    nodes = np.unique(arr_nodes)[1:]
    find_nodes = ndimage.find_objects(arr_nodes)
    start = np.zeros(3)
    stop = np.zeros(3)
    cube = morphology.cube(3)
    for j in nodes:
        sl = find_nodes[j-1]
        for i in range(3):
            start[i] = sl[i].start - 1
            stop[i] = sl[i].stop + 1
        #volume with node
        vol_c_n = arr_nodes[start[0]:stop[0], start[1]:stop[1],
                       start[2]:stop[2]] 
        #dilation to find the joint branches               
        dil = ndimage.binary_dilation(vol_c_n, cube)
        dil = dil.astype('uint8')
        vol_c = arr_br[start[0]:stop[0], start[1]:stop[1],
                       start[2]:stop[2]] 
        #find the labels of connected branches
        n = np.unique(vol_c * dil)[1:]
        G.add_node(j, neigh=n)
    
    return G
def neigh_br(arr_nodes, arr_br):
    """
    Creates a graph with nodes from the array of nodes and branches
    by considering the branches that adjoin to the current node.
    The labels of these branches are set as an attribute of the
    node.
    
    Parameters
    ---------
    arr_nodes : array of labeled regions that are considered as nodes
    arr_br : array of labeled regions considered as branches
    
    Returns
    ------
    G : a graph of nodes with the attribute 'neigh' 
    
    Examples
    -------
    >>>arr_nodes = label_nodes(num)
    >>>arr_nodes
    array([[[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]],
           [[0, 0, 0],
            [1, 1, 0],
            [1, 0, 0],
            [0, 0, 0]],
           [[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]]], dtype=uint8) 
    >>>arr_br = label_br(num)
    >>>arr_br
    array([[[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]],
           [[1, 0, 0],
            [0, 0, 2],
            [0, 0, 0],
            [3, 0, 0]],
           [[0, 0, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]]], dtype=uint8) 
    >>>G = neigh_br(arr_nodes, arr_br)
    >>>G.nodes()
    [1]
    >>>nx.get_node_attributes(G, 'neigh')
    {1: array([1, 2, 3])}
    
    """
    G = nx.Graph()
    el = morphology.cube(3)
    nodes = np.unique(arr_nodes)[1:]
    for j in nodes:
        mask = arr_nodes==j
        dil = morphology.binary_dilation(mask, el)
        vol_c = arr_br * (dil.astype('uint8'))
        G.add_node(j, neigh=np.unique(vol_c)[1:])
    return G