Exemple #1
0
def holes_filling(input, _):

    struct_1 = np.array([
        [1], [1], [1]
    ])

    struct_2 = np.array([
        [1, 1, 1]
    ])

    structure = np.array([
        [0, 1, 0],
        [1, 1, 1],
        [0, 1, 0]
    ])

    mask = complementary(input)

    #iter = 0
    X0 = np.zeros(input.shape)
    while True:
        d1 = ndimage.binary_dilation(X0, struct_1, border_value=1, mask=mask)
        d2 = ndimage.binary_dilation(X0, struct_2, border_value=1, mask=mask)
        X1 = union(d1, d2)

        if np.array_equal(X0, X1): break
        X0 = X1
        #iter += 1

    return complementary(X0)
Exemple #2
0
def lnlike(theta , p):
        
         
         cx, cy , F, B = theta
         Kp = sampler.imatrix_new(25, H, cx, cy)
         #Kp = sampler_new.imatrix_new(25, H , cx[p] , cy[p])
         model = F*np.dot(fl+X,Kp) + B
         resi = (data[p,:] - model).reshape(25,25)
         res = (data[p,:] - model)*100/data[p,:]
         res = res.reshape(25,25)
        
         chisq = (data[p,:] - model)**2./(f+g*np.abs(model)) + np.log(f+g*np.abs(model))
         chi= (data[p,:] - model)/(f+g*np.abs(model)+q*(model)**2.)**0.5
         maskp = mask[p,:]
         
         chisq = chisq.reshape(25,25)
         chi = chi.reshape(25,25)
         maskp = maskp.reshape(25,25) 
         

         mast = np.abs(chi)**2. > 3      
         mast = ndimage.binary_dilation(mast) 
         mast = ndimage.binary_dilation(mast) 
         bad =  maskp != 0
         
         unhealthy = bad * mast      

         chisq = chisq[unhealthy == False]

         return np.sum(chisq)
def find_initial_worm(small_image, well_mask):
    # plan here is to find known good worm edges with Canny using a stringent threshold, then
    # relax the threshold in the vicinity of the good edges.
    # back off another pixel from the well edge to avoid gradient from the edge
    shrunk_mask = ndimage.binary_erosion(well_mask, structure=S)
    smoothed, gradient, sobel = canny.prepare_canny(small_image, 2, shrunk_mask)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    # Calculate stringent and medium-stringent thresholds. The stringent threshold
    # is the 200th-brightest edge pixel, and the medium is the 450th-brightest pixel
    highp = 100 * (1-200/local_maxima.sum())
    highp = max(highp, 94)
    mediump = 100 * (1-450/local_maxima.sum())
    mediump = max(mediump, 94)
    low_worm, medium_worm, high_worm = numpy.percentile(gradient[local_maxima], [94, mediump, highp])
    stringent_worm = canny.canny_hysteresis(local_maxima, gradient, low_worm, high_worm)
    # Expand out 20 pixels from the stringent worm edges to make our search space
    stringent_area = ndimage.binary_dilation(stringent_worm, mask=well_mask, iterations=20)
    # now use the relaxed threshold but only in the stringent area
    relaxed_worm = canny.canny_hysteresis(local_maxima, gradient, low_worm, medium_worm) & stringent_area
    # join very close-by objects, and remove remaining small objects
    candidate_worm = ndimage.binary_dilation(relaxed_worm, structure=S)
    candidate_worm = ndimage.binary_erosion(candidate_worm)
    candidate_worm = mask.remove_small_area_objects(candidate_worm, 30, structure=S)
    # Now figure out the biggest blob of nearby edges, and call that the worm region
    glommed_candidate = ndimage.binary_dilation(candidate_worm, structure=S, iterations=2)
    glommed_candidate = ndimage.binary_erosion(glommed_candidate, iterations=2)
    # get just outline, not any regions filled-in due to closing
    glommed_candidate ^= ndimage.binary_erosion(glommed_candidate)
    glommed_candidate = mask.get_largest_object(glommed_candidate, structure=S)
    worm_area = ndimage.binary_dilation(glommed_candidate, mask=well_mask, structure=S, iterations=12)
    worm_area = mask.fill_small_radius_holes(worm_area, max_radius=15)
    candidate_edges = relaxed_worm & candidate_worm & worm_area
    return candidate_edges, worm_area
Exemple #4
0
def binary_dilation(image, selem=None, out=None):
    """Return fast binary morphological dilation of an image.

    This function returns the same result as greyscale dilation but performs
    faster for binary images.

    Morphological dilation sets a pixel at ``(i,j)`` to the maximum over all
    pixels in the neighborhood centered at ``(i,j)``. Dilation enlarges bright
    regions and shrinks dark regions.

    Parameters
    ----------

    image : ndarray
        Binary input image.
    selem : ndarray, optional
        The neighborhood expressed as a 2-D array of 1's and 0's.
        If None, use cross-shaped structuring element (connectivity=1).
    out : ndarray of bool, optional
        The array to store the result of the morphology. If None, is
        passed, a new array will be allocated.

    Returns
    -------
    dilated : ndarray of bool or uint
        The result of the morphological dilation with values in
        ``[False, True]``.
    """
    if out is None:
        out = np.empty(image.shape, dtype=np.bool)
    ndi.binary_dilation(image, structure=selem, output=out)
    return out
def filterImage(image):
    """
    Filters the given image and returns a binary representation of it.
    """
    
    # otsu to bring out edges
    t_loc_otsu = otsu(image[:, :, 1])
    loc_otsu = np.zeros_like(image, dtype=np.bool)
    loc_otsu[:, :, 1] = image[:, :, 1] <= t_loc_otsu + 5
    image[loc_otsu] = 0
    
    # bring out single particles and smooth the rest
    foot = circarea(8)
    green = rank_filter(image[:,:,1], foot, rank=44)
    nonzero = green > 10
    weak = (green > 20) & (green < green[nonzero].mean())
    green[weak] += 40
    
    # remove pollution
    gray = cv2.medianBlur(green, ksize=13)
    
    # black and white representation of particles and surroundings
    binary = gray < 25
    
    # dilatation and erosion
    dilated1 = ndimage.binary_dilation(binary, iterations=6)
    erosed = ndimage.binary_erosion(dilated1, iterations=_EROSIONFACTOR+3)
    dilated = ndimage.binary_dilation(erosed, iterations=_EROSIONFACTOR)
    return dilated
Exemple #6
0
    def clean_classified_image(self):
        """
        clean the binary image resulting from pixel classification using morphological operators 
        """
        if self.class_image is None:
            self.classify_image()

        bim = self.class_image
        feature_mask = self.features_object.mask_image
        if feature_mask is not None:
            bim = bim & feature_mask

        bim = ni.binary_fill_holes(bim)
        min_gap = 0
        for n in range(min_gap):
            bim = ni.binary_dilation(bim)
            #bim = ni.binary_closing(bim)
        #bim = ni.binary_fill_holes(bim)
        min_radius = 8
        for n in range(min_radius):
            bim = ni.binary_erosion(bim)
            #bim = ni.binary_opening(bim)
        for n in range(min_radius):
            bim = ni.binary_dilation(bim)
        #bim = ni.binary_dilation(bim)
        #bim = ni.binary_erosion(bim)
        self.clean_class_image = bim.astype(np.uint8) * 255
def dilation():
    image_list = get_one_imagefrom_mnist()
    image_array =np.asarray(image_list)
    image =image_array.reshape(28, 28)
    
    ndimage.binary_dilation(image).astype(int)
    plt.imshow(image, cmap=cm.binary)
    plt.show()
def split_up_binary_regions(seq_block, opening_param = 3, mshape = ((0,1,0),(1,1,1),(0,1,0)), min_size = 20):

    # for each region:
    #                  dilate, relabel, create stack with eroded single regions
    #                  delete overlapping pixels, recombine, assigning unique labels

    zdim, xdim, ydim = seq_block.shape
    splitblock = np.zeros_like(seq_block)

    for sidx in range(zdim):
        num_labels = int(np.max(seq_block[sidx]))
        if num_labels <= 1:
            continue
        max_label = num_labels
        for lidx in range(num_labels):
            comp = extract_region(seq_block[sidx], lidx+1)
            if np.sum(comp) < min_size:
                continue
            component = ndi.binary_erosion(comp,structure = mshape,iterations = opening_param)
            component, numnewcomponents = ndi.label(component)
            if numnewcomponents == 1:  # component is not split up by erosion
                #component[component>0] = 1
                #component = ndi.binary_dilation(component,structure = mshape,iterations = opening_param)
                splitblock[sidx][comp > 0] = int(lidx+1)
            else:
                compstack = np.zeros((numnewcomponents,xdim,ydim))
                for cidx in range(numnewcomponents):
                    compstack[cidx] = ndi.binary_dilation(extract_region(component, cidx+1),structure = mshape,iterations = opening_param)
                    compstack[cidx] = ndi.binary_dilation(compstack[cidx],structure = ((0,1,0),(1,1,1),(0,1,0)),iterations = 2)
                overlapmask = np.sum(compstack, axis = 0)
                comp[overlapmask > 1] = 0
                comp, numnewcomponents2 = ndi.label(comp)
                #if numnewcomponents != numnewcomponents2:
                    #print "Lost something on the way: C1 = " + str(numnewcomponents) + ", C2 = " + str(numnewcomponents2)

                for cidx in range(numnewcomponents2):
                    component = extract_region(comp, cidx+1)
                    if np.sum(component) < min_size:
                        continue
                    #compstack[cidx] = compstack[cidx] * overlapmask
                    #if np.sum(compstack[cidx]) > 0:
                    max_label = max_label + 1
                    #compstack[cidx] = compstack[cidx] * max_label
                    splitblock[sidx] = splitblock[sidx] + component.astype(int) * int(max_label)

                #splitblock[sidx] = splitblock[sidx] + np.sum(compstack,axis = 0).astype(int)

        # relabel components to unique labels
        all_labels = np.sort(np.unique(splitblock[sidx]))
        dum = np.zeros_like(splitblock[sidx])
        l_idx = 1
        for label in all_labels:
            if label >0:
                dum[splitblock[sidx]==label] = l_idx
                l_idx = l_idx + 1

    return splitblock
def refine_worm(image, initial_area, candidate_edges):
    # find strong worm edges (roughly equivalent to the edges found by find_initial_worm,
    # which are in candidate_edges): smooth the image, do canny edge-finding, and
    # then keep only those edges near candidate_edges
    smooth_image = restoration.denoise_tv_bregman(image, 140).astype(numpy.float32)
    smoothed, gradient, sobel = canny.prepare_canny(smooth_image, 8, initial_area)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    candidate_edge_region = ndimage.binary_dilation(candidate_edges, iterations=4)
    strong_edges = local_maxima & candidate_edge_region

    # Now threshold the image to find dark blobs as our initial worm region
    # First, find areas in the initial region unlikely to be worm pixels
    mean, std = mcd.robust_mean_std(smooth_image[initial_area][::4], 0.85)
    non_worm = (smooth_image > mean - std) & initial_area
    # now fit a smoothly varying polynomial to the non-worm pixels in the initial
    # region of interest, and subtract that from the actual image to generate
    # an image with a flat illumination field
    background = polyfit.fit_polynomial(smooth_image, mask=non_worm, degree=2)
    minus_bg = smooth_image - background
    # now recalculate a threshold from the background-subtracted pixels
    mean, std = mcd.robust_mean_std(minus_bg[initial_area][::4], 0.85)
    initial_worm = (minus_bg < mean - std) & initial_area
    # Add any pixels near the strong edges to our candidate worm position
    initial_worm |= ndimage.binary_dilation(strong_edges, iterations=3)
    initial_worm = mask.fill_small_radius_holes(initial_worm, 5)

    # Now grow/shrink the initial_worm region so that as many of the strong
    # edges from the canny filter are in contact with the region edges as possible.
    ac = active_contour.EdgeClaimingAdvection(initial_worm, strong_edges,
        max_region_mask=initial_area)
    stopper = active_contour.StoppingCondition(ac, max_iterations=100)
    while stopper.should_continue():
        ac.advect(iters=1)
        ac.smooth(iters=1, depth=2)
    worm_mask = mask.fill_small_radius_holes(ac.mask, 7)

    # Now, get edges from the image at a finer scale
    smoothed, gradient, sobel = canny.prepare_canny(smooth_image, 0.3, initial_area)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    strong_sum = strong_edges.sum()
    highp = 100 * (1 - 1.5*strong_sum/local_maxima.sum())
    lowp = max(100 * (1 - 3*strong_sum/local_maxima.sum()), 0)
    low_worm, high_worm = numpy.percentile(gradient[local_maxima], [lowp, highp])
    fine_edges = canny.canny_hysteresis(local_maxima, gradient, low_worm, high_worm)

    # Expand out the identified worm area to include any of these finer edges
    closed_edges = ndimage.binary_closing(fine_edges, structure=S)
    worm = ndimage.binary_propagation(worm_mask, mask=worm_mask|closed_edges, structure=S)
    worm = ndimage.binary_closing(worm, structure=S, iterations=2)
    worm = mask.fill_small_radius_holes(worm, 5)
    worm = ndimage.binary_opening(worm)
    worm = mask.get_largest_object(worm)
    # Last, smooth the shape a bit to reduce sharp corners, but not too much to
    # sand off the tail
    ac = active_contour.CurvatureMorphology(worm, max_region_mask=initial_area)
    ac.smooth(depth=2, iters=2)
    return strong_edges, ac.mask
Exemple #10
0
    def removeGrid(self,cs,removeGrid):
        """
        Detect the grid of the phantom and remove it from the image
        """
        shift = int(1./self.pixDim(cs)+.5)
        
        # try to find a threshold on pixelvalue to define a value representing the grid
        maskval = 0.75*cs.pixeldataIn.mean()
        # make a mask of grid-like values
        mask = (cs.pixeldataIn < maskval)

        # hole closing of the mask
        mask = scind.binary_closing(mask,structure=np.ones((5,5)))
        mask = scind.binary_opening(mask,structure=np.ones((5,5)))
        mask = scind.binary_dilation(mask)
        # new since 20150211
        mask = scind.binary_dilation(mask)

        # fill the gridlines with the median values of the pixels around it
        medimage = np.roll(cs.pixeldataIn,shift,axis=0).astype(float)
        dest = cs.pixeldataIn+mask*(medimage-cs.pixeldataIn)
        # repeat to remove propagated mask # new since 20150211
        medimage = np.roll(dest,shift,axis=0).astype(float)
        dest = cs.pixeldataIn+mask*(medimage-cs.pixeldataIn)
        medimage = None
        cs.gridimage = mask.astype(float)
        mask = None
        
        # find gridobject
        gridobject         = scind.binary_fill_holes(cs.gridimage)
        label_im,nb_labels = scind.label(gridobject)
        sizes = scind.sum(gridobject, label_im, range(nb_labels + 1))
        gridobject = None
        
        #Clean up small connect components:
        mask_size = sizes < max(sizes) #(100/self.pixDim())**2
        remove_pixel = mask_size[label_im]
        label_im[remove_pixel] = 0

        # Now reassign labels with np.searchsorted:
        labels = np.unique(label_im)
        label_im = np.searchsorted(labels, label_im)

        medimage = np.roll(dest,shift,axis=0).astype(float)
        dest += cs.gridimage*(medimage-dest)
        medimage = None
        cs.gridimage *= label_im
        if -1>0: # remove everything outside grid
            wid = dest.shape[0]
            hei = dest.shape[1]
            mv = np.mean(dest[wid/4:3*wid/4,hei/4:3*hei/4])
            dest = label_im*(dest-mv)+mv

        if removeGrid:
            cs.pixeldataIn = dest
def is_adjacent(array1, array2, borderWidth=2):
    """
    decide if two patches are adjacent within border width
    """

    p1d = ni.binary_dilation(array1, iterations=borderWidth - 1).astype(np.int8)
    p2d = ni.binary_dilation(array2, iterations=borderWidth - 1).astype(np.int8)

    if np.amax(p1d + p2d) > 1:
        return True
    else:
        return False
Exemple #12
0
def sg_filter(s1, winsize1=15, winsize2=11):
    s1m = ni.median_filter(s1, 11)
    #s1m = s1

    #winsize1 = 15
    #winsize2 = 11

    f1 = savgol_filter(s1m, winsize1, 3)

    f1_std = np.nanstd(s1-f1)

    if 0: # calculate weight
        f1_mask = np.abs(s1-f1) > 2.*f1_std
        f1_mask2 = ni.binary_opening(f1_mask, iterations=int(winsize2*0.2))
        f1_mask3 = ni.binary_closing(f1_mask2, iterations=int(winsize2*0.2))
        f1_mask4 = ni.binary_dilation(f1_mask3, iterations=int(winsize2))

        weight = ni.gaussian_filter(f1_mask4.astype("d"), winsize2)
    else:
        fd2 = savgol_filter(s1m, winsize1, 3, deriv=2)
        fd2_std = np.std(fd2)
        f1_mask = np.abs(fd2) > 2.*fd2_std

        f1_mask = f1_mask | (s1m < s1m.max()*0.4)

        f1_mask4 = ni.binary_dilation(f1_mask, iterations=int(winsize2))
        #f1_mask4[:300] = True
        #f1_mask4[-300:] = True
        weight = ni.gaussian_filter(f1_mask4.astype("d"), winsize2*.5)

    # find a region where deviation is significant

    if np.any(weight):
        weight/=weight.max()
        f2 = savgol_filter(s1m, winsize2, 5)
        f12 = f1*(1.-weight) + f2*weight
    else:
        f12 = f1
        weight = np.zeros(f12.shape)


    if 0:
        ax1.cla()
        ax2.cla()
        ax1.plot(f12)
        ax2.plot(s1 - f1, color="0.5")
        ax2.plot(s1 - f12)
        ax2.plot(weight * f1_std*2)

        ax2.set_ylim(-0.02, 0.02)

    return f12, f1_std
def process_blob(cim):
    #cim = ndimage.binary_erosion(cim>0)
    for i in range(4):
        cim = ndimage.binary_erosion(cim>0)
        cim=ndimage.binary_dilation(cim>0)

    filterk = np.ones(Param.process_conv_size);
    cim = ndimage.convolve(cim, filterk, mode='constant', cval=0.0)

    for i in range(Param.num_dilation):
        cim = ndimage.binary_dilation(cim>0)
    for i in range(Param.num_erosion):
        cim = ndimage.binary_erosion(cim>0)
    return cim
def ClusterObjects(farn, struct_elem):
    magn_img = farn.magnitude_image
    dir_img = farn.direction_image    
    
    bin_img = np.zeros(shape=(magn_img.shape[0], magn_img.shape[1]), dtype=np.uint8)
    bin_img[magn_img < 25] = 0
    bin_img[magn_img >= 25] = 1
    
    bin_img = ndimage.binary_dilation(bin_img, structure=struct_elem, iterations=3).astype(bin_img.dtype)

    labels, nb_labels = Morphology.ConnenctedComponents(bin_img)    
    filt_labels, areas, nb_new_labels = Morphology.FilterArea(bin_img, labels, nb_labels, 480)
    
    
    temp_magn = ndimage.mean(magn_img, filt_labels, range(nb_new_labels + 1))
    temp_dir = ndimage.mean(dir_img, filt_labels, range(nb_new_labels + 1))
    
    data = np.concatenate((np.reshape(temp_magn, (-1,1)), np.reshape(temp_dir, (-1,1))), axis=1)
    
    clusters = -1
    if nb_new_labels >= 1:
        Y = pdist(data, 'euclidean')
        agglo = AgglomerativeClustering.Agglomerative(Y, 50.)
        agglo.AggloClustering(criterion = 'distance', method = 'single', metric = 'euclidean', normalized = False)

        clusters = agglo.clusters
             
    bin_img[filt_labels == 0] = 0
    bin_img[filt_labels >= 1] = 1
    
    
    
    return bin_img, nb_new_labels, temp_magn, temp_dir, data, clusters
Exemple #15
0
def bg_mask(in_file, in_mask, out_file=None):
    """
    Rough mask of background from brain masks
    """
    import nibabel as nb
    import numpy as np
    from scipy.ndimage import binary_dilation
    import scipy.ndimage as nd
    import os.path as op

    if out_file is None:
        fname, ext = op.splitext(op.basename(in_file))
        if ext == ".gz":
            fname, ext2 = op.splitext(fname)
            ext = ext2 + ext
        out_file = op.abspath("%s_bgmask%s" % (fname, ext))

    im = nb.load(in_file)
    hdr = im.get_header().copy()
    hdr.set_data_dtype(np.uint8)
    hdr.set_xyzt_units('mm')
    imdata = im.get_data()
    msk = nb.load(in_mask).get_data()
    msk = 1 - binary_dilation(msk,
                              structure=np.ones((20, 20, 20)))
    nb.Nifti1Image(msk.astype(np.uint8),
                   im.get_affine(), hdr).to_filename(out_file)
    return out_file
 def remove_unresponsive_and_fluctuating_stripe(self, sinogram, snr, size):
     """
     Algorithm 6 in the paper. Remove unresponsive or fluctuating stripes.
     ---------
     Parameters: - sinogram: 2D array.
                 - snr: ratio used to discriminate between useful
                     information and noise
                 - size: window size of the median filter.
     ---------
     Return:     - stripe-removed sinogram.
     """
     (nrow, _) = sinogram.shape
     sinosmoothed = np.apply_along_axis(uniform_filter1d, 0, sinogram, 10)
     listdiff = np.sum(np.abs(sinogram - sinosmoothed), axis=0)
     nmean = np.mean(listdiff)
     listdiffbck = median_filter(listdiff, size)
     listdiffbck[listdiffbck == 0.0] = nmean
     listfact = listdiff / listdiffbck
     listmask = self.detect_stripe(listfact, snr)
     listmask = binary_dilation(listmask, iterations=1).astype(listmask.dtype)
     listmask[0:2] = 0.0
     listmask[-2:] = 0.0
     listx = np.where(listmask < 1.0)[0]
     listy = np.arange(nrow)
     matz = sinogram[:, listx]
     finter = interpolate.interp2d(listx, listy, matz, kind='linear')
     listxmiss = np.where(listmask > 0.0)[0]
     if len(listxmiss) > 0:
         matzmiss = finter(listxmiss, listy)
         sinogram[:, listxmiss] = matzmiss
     return sinogram
 def remove_large_stripe(self, matindex, sinogram, snr, size):
     """
     Algorithm 5 in the paper. Use to remove large stripes
     ---------
     Parameters: - sinogram: 2D array.
                 - snr: ratio used to discriminate between useful
                     information and noise.
                 - size: window size of the median filter.
     ---------
     Return:     - stripe-removed sinogram.
     """
     badpixelratio = 0.05
     (nrow, ncol) = sinogram.shape
     ndrop = np.int16(badpixelratio * nrow)
     sinosorted = np.sort(sinogram, axis=0)
     sinosmoothed = median_filter(sinosorted, (1, size))
     list1 = np.mean(sinosorted[ndrop:nrow - ndrop], axis=0)
     list2 = np.mean(sinosmoothed[ndrop:nrow - ndrop], axis=0)
     listfact = list1 / list2
     listmask = self.detect_stripe(listfact, snr)
     listmask = binary_dilation(listmask, iterations=1).astype(listmask.dtype)
     matfact = np.tile(listfact,(nrow,1))
     sinogram = sinogram / matfact
     sinogram1 = np.transpose(sinogram)
     matcombine = np.asarray(np.dstack((matindex, sinogram1)))
     matsort = np.asarray(
         [row[row[:, 1].argsort()] for row in matcombine])
     matsort[:, :, 1] = np.transpose(sinosmoothed)
     matsortback = np.asarray(
         [row[row[:, 0].argsort()] for row in matsort])
     sino_corrected = np.transpose(matsortback[:, :, 1])
     listxmiss = np.where(listmask > 0.0)[0]
     sinogram[:, listxmiss] = sino_corrected[:, listxmiss]
     return sinogram
Exemple #18
0
def _rs_dead(sinogram, snr, size, matindex):
    """
    Remove unresponsive and fluctuating stripes.
    """
    sinogram = np.copy(sinogram)  # Make it mutable
    (nrow, _) = sinogram.shape
    sinosmoothed = np.apply_along_axis(uniform_filter1d, 0, sinogram, 10)
    listdiff = np.sum(np.abs(sinogram - sinosmoothed), axis=0)
    nmean = np.mean(listdiff)
    listdiffbck = median_filter(listdiff, size)
    listdiffbck[listdiffbck == 0.0] = nmean
    listfact = listdiff / listdiffbck
    listmask = _detect_stripe(listfact, snr)
    listmask = binary_dilation(listmask, iterations=1).astype(listmask.dtype)
    listmask[0:2] = 0.0
    listmask[-2:] = 0.0
    listx = np.where(listmask < 1.0)[0]
    listy = np.arange(nrow)
    matz = sinogram[:, listx]
    finter = interpolate.interp2d(listx, listy, matz, kind='linear')
    listxmiss = np.where(listmask > 0.0)[0]
    if len(listxmiss) > 0:
        matzmiss = finter(listxmiss, listy)
        sinogram[:, listxmiss] = matzmiss
    # Use algorithm 5 to remove residual stripes
    sinogram = _rs_large(sinogram, snr, size, matindex)
    return sinogram
Exemple #19
0
 def step(self):
     """Perform a single step of the morphological snake evolution."""
     # Assign attributes to local variables for convenience.
     u = self._u
     gI = self._data
     dgI = self._ddata
     theta = self._theta
     v = self._v
     
     if u is None:
         raise ValueError, "the levelset is not set (use set_levelset)"
     
     res = np.copy(u)
     
     # Balloon.
     if v > 0:
         aux = binary_dilation(u, self.structure)
     elif v < 0:
         aux = binary_erosion(u, self.structure)
     if v!= 0:
         res[self._threshold_mask_v] = aux[self._threshold_mask_v]
     
     # Image attachment.
     aux = np.zeros_like(res)
     dres = np.gradient(res)
     for el1, el2 in zip(dgI, dres):
         aux += el1*el2
     res[aux > 0] = 1
     res[aux < 0] = 0
     
     # Smoothing.
     for i in xrange(self.smoothing):
         res = curvop(res)
     
     self._u = res
Exemple #20
0
 def InDecPatch(self,which,amount):
     s = ndimage.generate_binary_structure(2,1) # taxi-cab struct
     if which == 0:
         ras = ndimage.binary_dilation(self.cl_array,s,iterations=amount,border_value=0)
     else:
         ras = ndimage.binary_erosion(self.cl_array,s,iterations=amount,border_value=0)
     return(ras)
Exemple #21
0
def _rs_large(sinogram, snr, size, matindex):
    """
    Remove large stripes by: locating stripes, normalizing to remove
    full stripes, using the sorting technique to remove partial stripes.    
    """
    badpixelratio = 0.05
    (nrow, ncol) = sinogram.shape
    ndrop = np.int16(badpixelratio * nrow)
    sinosorted = np.sort(sinogram, axis=0)
    sinosmoothed = median_filter(sinosorted, (1, size))
    list1 = np.mean(sinosorted[ndrop:nrow - ndrop], axis=0)
    list2 = np.mean(sinosmoothed[ndrop:nrow - ndrop], axis=0)
    listfact = list1 / list2
    # Locate stripes
    listmask = _detect_stripe(listfact, snr)
    listmask = binary_dilation(listmask, iterations=1).astype(listmask.dtype)
    matfact = np.tile(listfact, (nrow, 1))
    # Normalize
    sinogram = sinogram / matfact
    sinogram1 = np.transpose(sinogram)
    matcombine = np.asarray(np.dstack((matindex, sinogram1)))
    matsort = np.asarray(
        [row[row[:, 1].argsort()] for row in matcombine])
    matsort[:, :, 1] = np.transpose(sinosmoothed)
    matsortback = np.asarray(
        [row[row[:, 0].argsort()] for row in matsort])
    sino_corrected = np.transpose(matsortback[:, :, 1])
    listxmiss = np.where(listmask > 0.0)[0]
    sinogram[:, listxmiss] = sino_corrected[:, listxmiss]
    return sinogram
Exemple #22
0
def get_objects_edges(objects):
    m = objects[0].get_mask()
    m[::] = False
    for o in objects:
            m += o.get_mask()
    md = ndimage.binary_dilation(m)
    return md - m
Exemple #23
0
def multi_label_edge_detection(data):
    f = nd.generate_binary_structure(len(data.shape), 1)
    bound = (nd.grey_erosion(data,footprint=f) != nd.grey_dilation(data,footprint=f)) - \
            (nd.binary_dilation(data.astype(np.bool)) - data.astype(np.bool))     # the unwanted thick bounds
    data=bound.astype(data.dtype)
    
    return data
Exemple #24
0
def test_mask():
    vol = np.zeros((30, 30, 30))
    vol[15, 15, 15] = 1
    struct = generate_binary_structure(3, 1)
    voln = binary_dilation(vol, structure=struct, iterations=4).astype('f4')
    initial = np.sum(voln > 0)
    mask = voln.copy()
    thresh = otsu(mask)
    mask = mask > thresh
    initial_otsu = np.sum(mask > 0)
    assert_equal(initial_otsu, initial)

    mins, maxs = bounding_box(mask)
    voln_crop = crop(mask, mins, maxs)
    initial_crop = np.sum(voln_crop > 0)
    assert_equal(initial_crop, initial)

    applymask(voln, mask)
    final = np.sum(voln > 0)
    assert_equal(final, initial)

    # Test multi_median.
    median_test = np.arange(25).reshape(5, 5)
    median_control = median_test.copy()
    medianradius = 3
    median_test = multi_median(median_test, medianradius, 3)

    medarr = np.ones_like(median_control.shape) * ((medianradius * 2) + 1)
    median_filter(median_control, medarr, output=median_control)
    median_filter(median_control, medarr, output=median_control)
    median_filter(median_control, medarr, output=median_control)
    assert_equal(median_test, median_control)
Exemple #25
0
def dilated_region(self, region, indpsf):
    '''Specify a optimization region that extends around the ``region``.

    This requires that the fitter has an attribute ``dilatation_region``, which can be

    - an int: In this case a square matrix of size 2 * n + 1 is used.
    - a matrix (see `scipy.ndimage.binary_dilation` for details.

    Examples
    --------

    >>> from psfsubtraction.fitpsf import fitters
    >>> from psfsubtraction.fitpsf import optregion
    >>> region = np.array([[True, False, False], \
                           [False, False, False], \
                           [False, False, False]])
    >>> class DilationFitter(fitters.SimpleSubtraction):
    ...     optregion = optregion.dilated_region
    ...     dilation_region = 1
    >>> dummy_image = np.ones((3, 3)) # boring image, but good enough for the example
    >>> dummy_psfs = np.ones((3,3,4)) # even more boring psf array.
    >>> myfitter = DilationFitter(dummy_psfs, dummy_image)
    >>> myfitter.optregion(region, [0]).reshape((3, 3))
    array([[ True,  True, False],
           [ True,  True, False],
           [False, False, False]])
    '''
    if not hasattr(self, 'dilation_region'):
        raise OptionalAttributeError('Fitter must speficy the `self.dilation_region`\n'
                                     + 'which is either and int or a square matrix.')
    if np.isscalar(self.dilation_region):
        selem = np.ones((2 * self.dilation_region + 1, 2 * self.dilation_region + 1))
    else:
        selem = self.dilation_region
    return self.dim2to1(binary_dilation(self.dim1to2(region), selem))
Exemple #26
0
def generate_scatter_volume(roi, prf, threshold, iterations):
    
    scatter = np.zeros_like(roi,dtype='double')
    
    # get indices
    xi,yi,zi = np.nonzero((roi>0) & (prf[...,-3]>threshold))
    
    for voxel in range(len(xi)):
        
        # get index
        xind = xi[voxel]
        yind = yi[voxel]
        zind = zi[voxel]
        
        # set target to 1
        mask = np.zeros_like(roi)
        mask[xind,yind,zind] = 1
        
        # get neighborhood
        hood = ndimage.binary_dilation(mask,iterations=iterations)
        hood[xind,yind,zind] = 0
        
        fit = prf[mask==1][0]
        fits = prf[hood==1]
        scatter[xind,yind,zind] = np.mean(np.sqrt((fits[:,0]-fit[np.newaxis,0])**2 + (fits[:,1]-fit[np.newaxis,1])**2))/2
    
    return scatter
 def process_frames(self, data):
     """
     Algorithm 5 in the paper. Remove large stripes by: locating stripes,
     normalizing to remove full stripes, using the sorting technique to
     remove partial stripes.
     """
     sinogram = np.copy(data[0])
     badpixelratio = 0.05 # To avoid false detection        
     ndrop = np.int16(badpixelratio * self.height1)
     sinosorted = np.sort(sinogram, axis=0)
     sinosmoothed = median_filter(sinosorted, (1, self.size))
     list1 = np.mean(sinosorted[ndrop:self.height1 - ndrop], axis=0)
     list2 = np.mean(sinosmoothed[ndrop:self.height1 - ndrop], axis=0)
     listfact = list1 / list2
     listmask = self.detect_stripe(listfact, self.snr)
     listmask = binary_dilation(listmask, iterations=1).astype(listmask.dtype)
     matfact = np.tile(listfact,(self.height1,1))
     sinogram = sinogram / matfact
     sinogram1 = np.transpose(sinogram)
     matcombine = np.asarray(np.dstack((self.matindex, sinogram1)))
     matsort = np.asarray(
         [row[row[:, 1].argsort()] for row in matcombine])
     matsort[:, :, 1] = np.transpose(sinosmoothed)
     matsortback = np.asarray(
         [row[row[:, 0].argsort()] for row in matsort])
     sino_corrected = np.transpose(matsortback[:, :, 1])
     listxmiss = np.where(listmask > 0.0)[0]
     sinogram[:, listxmiss] = sino_corrected[:, listxmiss]
     return sinogram
def connectedCompFeat(conn, firstBinClosing, secondDilatation, threshHold, max_size, RF_on_off, rawUint8):
    print "clearedImGauss.. "
    # Threshold
    rawBinary = np.where(rawUint8 > threshHold, 1, 0)
    # Remove small black particles
    binClosingVigra = vigra.filters.discClosing(rawBinary.astype(np.uint8), firstBinClosing)
    # change background
    tempColorRotate = (binClosingVigra.astype(np.uint8) -1)
    # remove connected Components smaller 90 000 pixels
    labels, count = ndimage.label(tempColorRotate.astype(np.bool))
    sizes = np.bincount(labels.ravel())
    mask_sizes = sizes > max_size
    mask_sizes[0]=0
    print "---------------"
    clearedImage = mask_sizes[labels]
    # regrow areas
    clearedImage = ndimage.binary_dilation(clearedImage, iterations=secondDilatation)
    # clearedImageEr = vigra.filters.discErosion(clearedImage.astype(np.uint8), 2)
    # expand areas smoothely
    clearedImageGauss = vigra.filters.gaussianSmoothing(clearedImage.astype(np.float32), 7)
    if RF_on_off == True:
        clearedImageGauss = np.ravel(clearedImageGauss.T)
        clearedImageGauss = clearedImageGauss.reshape(clearedImageGauss.shape[0], 1)
    print "cleared Image Gauss fct: ", clearedImageGauss.shape
    conn.send(clearedImageGauss)
    conn.close()
Exemple #29
0
    def dilate(self, n_pixels=1):
        r"""
        Returns a copy of this :map:`MaskedImage` in which its mask has
        been expanded by n pixels along its boundary.

        Parameters
        ----------
        n_pixels : int, optional
            The number of pixels by which we want to expand the mask along
            its own boundary.

        Returns
        -------
         : :map:`MaskedImage`
            The copy of the masked image in which the mask has been expanded
            by n pixels along its boundary.
        """
        global binary_dilation
        if binary_dilation is None:
            from scipy.ndimage import binary_dilation  # expensive
        # Erode the edge of the mask in by one pixel
        dilated_mask = binary_dilation(self.mask.mask, iterations=n_pixels)

        image = self.copy()
        image.mask = BooleanImage(dilated_mask)
        return image
Exemple #30
0
def _extrapolate_out_mask(data, mask, iterations=1):
    """ Extrapolate values outside of the mask.
    """
    if iterations > 1:
        data, mask = _extrapolate_out_mask(data, mask,
                                          iterations=iterations - 1)
    new_mask = ndimage.binary_dilation(mask)
    larger_mask = np.zeros(np.array(mask.shape) + 2, dtype=np.bool)
    larger_mask[1:-1, 1:-1, 1:-1] = mask
    # Use nans as missing value: ugly
    masked_data = np.zeros(larger_mask.shape + data.shape[3:])
    masked_data[1:-1, 1:-1, 1:-1] = data.copy()
    masked_data[np.logical_not(larger_mask)] = np.nan
    outer_shell = larger_mask.copy()
    outer_shell[1:-1, 1:-1, 1:-1] = np.logical_xor(new_mask, mask)
    outer_shell_x, outer_shell_y, outer_shell_z = np.where(outer_shell)
    extrapolation = list()
    for i, j, k in [(1, 0, 0), (-1, 0, 0), 
                    (0, 1, 0), (0, -1, 0),
                    (0, 0, 1), (0, 0, -1)]:
        this_x = outer_shell_x + i
        this_y = outer_shell_y + j
        this_z = outer_shell_z + k
        extrapolation.append(masked_data[this_x, this_y, this_z])

    extrapolation = np.array(extrapolation)
    extrapolation = (np.nansum(extrapolation, axis=0)
                     / np.sum(np.isfinite(extrapolation), axis=0))
    extrapolation[np.logical_not(np.isfinite(extrapolation))] = 0
    new_data = np.zeros_like(masked_data)
    new_data[outer_shell] = extrapolation
    new_data[larger_mask] = masked_data[larger_mask]
    return new_data[1:-1, 1:-1, 1:-1], new_mask
def dilatacion(Im, estructura):
    #est = np.zeros((3,3), dtype = np.int)
    #est[:,1] = 1
    #est[1,:] = 1
    Im = ndimage.binary_dilation(Im, estructura).astype('uint8')
    return Im
def calc_shift_direct(ft_1, ft_2, origin=0, debug_cross_cor=None):
    """
        Does the actual fft cross correlation.
        Clean up - including cropping, thresholding, mask dilation.
        Performs n dimension gaussian fit and returns center.
    """
    ft_1 = ndimage.fourier_gaussian(ft_1, 0.5)
    ft_2 = ndimage.fourier_gaussian(ft_2, 0.5)
    # module level for multiprocessing
    tmp = ft_1 * np.conj(ft_2)    
    del ft_1, ft_2
    cross_corr = np.abs(np.fft.ifftshift(np.fft.irfftn(tmp)))
    flat_dims = np.where(np.asarray(cross_corr.shape) == 1)[0]
    if len(flat_dims) > 0:
        cross_corr = cross_corr.squeeze()

    if cross_corr.sum() == 0:
        return origin * np.nan
    
#    threshold = np.ptp(cross_corr) * 0.5 + np.min(cross_corr)
    
    # cheat and striaght up crop out 3/4 of the image if it's large
    # i.e. drift not allow to span 1/4 the image width
    cropping = [slice(dim*6//16, -dim*6//16) if dim >= 16 else slice(None, None) for dim in cross_corr.shape]
    cross_corr_mask = np.zeros(cross_corr.shape)
    cross_corr_mask[cropping] = True
    
#    threshold = np.percentile(cross_corr[cropping], 95)
    
    threshold = np.ptp(cross_corr[cross_corr_mask.astype(bool)]) * 0.75 + np.min(cross_corr[cross_corr_mask.astype(bool)])
    
    cross_corr_mask *= cross_corr > threshold
    
    # difficult to adjust for complete despeckling. slow?
#    cross_corr_mask = ndimage.binary_erosion(cross_corr_mask, structure=np.ones((1,)*cross_corr_mask.ndim), iterations=1, border_value=1, )
#    cross_corr_mask = ndimage.binary_dilation(cross_corr_mask, structure=np.ones((3,)*cross_corr_mask.ndim), iterations=1, border_value=0, )
#    print("mask {}".format(cross_corr_mask.sum()))
    
    labeled_image, labeled_counts = ndimage.label(cross_corr_mask)
    if labeled_counts > 1: 
        max_index = np.argmax(ndimage.mean(cross_corr_mask, labeled_image, range(1, labeled_counts+1))) + 1
        cross_corr_mask = labeled_image == max_index
    
    cross_corr_mask = ndimage.binary_dilation(cross_corr_mask, structure=np.ones((5,)*cross_corr_mask.ndim), iterations=1, border_value=0, )
    
    cross_corr_thresholded = cross_corr * cross_corr_mask
#    
    if not debug_cross_cor is None:
        i, (path, dtype, shape) = debug_cross_cor
        cc_images = np.memmap(path, mode="r+", dtype=dtype, shape=shape)
        cross_corr_thresholded_repadded = cross_corr_thresholded.view()
        for d in flat_dims:
            cross_corr_thresholded_repadded = np.expand_dims(cross_corr_thresholded_repadded, d)
        short_axis = np.argmin(cross_corr_thresholded_repadded.shape)
        cc_images[i] = cross_corr_thresholded_repadded.mean(axis=short_axis)
        del cc_images
    
    dims = range(len(cross_corr.shape))
    
    # crop out masked area
    bounds = np.zeros((len(dims), 2), dtype=np.int)
    for d in dims:
        dims_tmp = list(dims)
        dims_tmp.remove(d)
        mask_1d = np.any(cross_corr_mask, axis=tuple(dims_tmp))
        bounds[d] = np.where(mask_1d)[0][[0, -1]] + [0, 1]
        cross_corr_thresholded = cross_corr_thresholded.take(np.arange(*bounds[d]), axis=d)    

#    offset = np.zeros(len(dims))
#    for d, length in enumerate(cross_corr_thresholded.shape):
#        dims_tmp = list(dims)
#        dims_tmp.remove(d)
#        offset[d] = np.sum(np.arange(length) * cross_corr_thresholded.sum(axis=tuple(dims_tmp)))
#    offset /= cross_corr_thresholded.sum()
#    offset += bounds[:, 0]
    
    cross_corr_thresholded[cross_corr_thresholded==0] = np.nan
#    cross_corr_thresholded -= np.nanmin(cross_corr_thresholded)
    cross_corr_thresholded /= np.nanmax(cross_corr_thresholded)

#    ### Gaussian fit
##    p0 = [np.nanmax(cross_corr_thresholded), np.nanmin(cross_corr_thresholded)]
#    p0 = [1, 0]
#    grids = list()
#    for i, d in enumerate(cross_corr_thresholded.shape):
#        grids.append(np.arange(d))
#        p0.extend([(d-1)*0.5, 0.5*d])
##    print grids
##    print p0
#    res = optimize.least_squares(guassian_nd_error, p0, args=(grids, cross_corr_thresholded))
##    print res.x 
    
    ### Rbf peak finding
    p0 = []
    grids = list()
    for i, d in enumerate(cross_corr_thresholded.shape):
        grids.append(np.arange(d))
        p0.append(0.5*d)
    rbf_interpolator = build_rbf(grids, cross_corr_thresholded)
    res = optimize.minimize(rbf_nd_error, p0, args=rbf_interpolator)
    
    offset = list()
    for i in np.arange(len(cross_corr_thresholded.shape)):
#        offset.append(res.x[2*i+2])
        offset.append(res.x[i])
    offset += bounds[:, 0]
#    print offset
    
    if len(flat_dims) > 0:
        offset = np.insert(offset, flat_dims, 0)
        
    return offset - origin
Exemple #33
0
def main(pred_file, result_folder='.', **kwargs):
    assert os.path.exists(pred_file), \
        'Prediction file {} does not exists. Please check!'.format(pred_file)

    sample = os.path.basename(pred_file).split('.')[0]
    if sample == 'GMR_38F04_AE_01-20181005_63_G5':
        return
    if sample == 'BJD_127B01_AE_01-20171124_64_H5':
        return
    result_file = os.path.join(result_folder, sample + '.zarr')
    aff_key = kwargs['aff_key']
    fg_key = kwargs.get('fg_key')

    # read input shape
    if pred_file.endswith('.zarr'):
        in_f = zarr.open(pred_file, mode='r')
    else:
        raise NotImplementedError
    aff_shape = in_f[aff_key].shape
    channel_order = [slice(0, aff_shape[0])]
    pred_keys = [aff_key]

    if kwargs['overlapping_inst']:
        numinst_shape = in_f[fg_key].shape
        channel_order.append(slice(0, numinst_shape[0]))
        pred_keys += [fg_key]
        assert aff_shape[1:] == numinst_shape[1:], \
            'Please check: affinity and numinst shape do not match!'
    input_shape = aff_shape[1:]  # without first channel dimension

    # check if blocks should only be within bounding box
    if kwargs.get('only_bb'):
        mid = np.prod(kwargs['patchshape']) // 2
        mask = np.array(in_f[aff_key][mid])
        mask = mask > kwargs['patch_threshold']
        if np.sum(mask) == 0:
            logger.warning("bb empty")
            return
        if kwargs.get('ignore_small_comps', 0) > 0:
            labeled = ndimage.label(mask, np.ones([3] * len(input_shape)))[0]
            labels, counts = np.unique(labeled, return_counts=True)
            labels = labels[counts <= kwargs.get('ignore_small_comps')]
            labeled = replace(labeled, np.array(labels),
                              np.array([0] * len(labels)))
            print('num small comps: ', len(labels))
            # for label in labels:
            #     mask[labeled == label] = 0
            mask = labeled > 0
        min = np.min(np.transpose(np.nonzero(mask)), axis=0)
        max = np.max(np.transpose(np.nonzero(mask)), axis=0)
        # TODO for l1 data
        # min = np.array([31, 31, 0])
        # max = np.array([input_shape[0]-30, input_shape[1]-30, input_shape[2]])
        shape = max - min + 1
        bb_offset = min
    else:
        shape = input_shape
        bb_offset = [0] * len(shape)
    if len(shape) == 2:
        shape = (1, ) + tuple(shape)
        bb_offset = [0] * len(shape)
    logger.info("input shape: %s, bb cropped shape: %s, offset: %s",
                input_shape, shape, bb_offset)

    if pred_file.endswith('.hdf'):
        in_f.close()

    # create offset lists
    offsets = get_chessboard_offsets(shape, kwargs['chunksize'])
    #offsets = [offset + bb_offset for offset in offsets]
    logger.info('num blocks: %s', len(offsets))
    logger.info("%s", offsets)

    # create temporary zarr dataset for blocks (2^dim x shape)
    tmp_key = 'volumes/tmp_worker'
    skip_tmp_worker = False
    if not os.path.exists(result_file):
        compressor = Blosc(cname='zstd', clevel=3, shuffle=Blosc.BITSHUFFLE)
        f = zarr.open(result_file, mode='w')
        f.create_dataset(tmp_key,
                         shape=(2**len(shape), ) + tuple(shape),
                         compressor=compressor,
                         dtype=np.uint32,
                         chunks=(1, ) + tuple(kwargs['chunksize']))
    else:
        f = zarr.open(result_file, mode='r')
        if tmp_key in f:
            skip_tmp_worker = True

    def init(l):
        global mutex
        mutex = l

    if not skip_tmp_worker:
        mutex = Lock()
        if kwargs['num_parallel_blocks'] > 1:
            pool = Pool(processes=kwargs['num_parallel_blocks'],
                        initializer=init,
                        initargs=(mutex, ))
            pool.map(
                functools.partial(blockwise_vote_instances, pred_file,
                                  pred_keys, result_file, tmp_key, shape,
                                  channel_order, bb_offset, kwargs), offsets)
            pool.close()
            pool.join()
        else:
            kwargs['mutex'] = mutex
            for idx, offset in enumerate(offsets):
                # if idx < 7 or idx > 8:
                #     continue
                logger.info("start block idx: %s/%s (file %s)", idx,
                            len(offsets), sample)
                blockwise_vote_instances(pred_file, pred_keys, result_file,
                                         tmp_key, shape, channel_order,
                                         bb_offset, kwargs, offset)
    else:
        logger.info("skipping tmp_worker (blocks already exist?)")

    # stitch blocks
    res_key = kwargs.get('res_key', 'vote_instances')
    logger.info("%s", kwargs)
    instances = stitch_vote_instances(result_file, tmp_key, res_key,
                                      input_shape, bb_offset, **kwargs)

    # save mip
    save_mip = kwargs.get('save_mip', False)
    if save_mip:
        colored = color(np.max(instances, axis=0))
        io.imsave(os.path.join(result_folder, sample + '.png'),
                  colored.astype(np.uint8))

    # remove small components
    remove_small_comps = kwargs.get('remove_small_comps', 0)
    if remove_small_comps > 0:

        instances = remove_small_components(instances, remove_small_comps)
        instances = relabel(instances)
        io.imsave(os.path.join(result_folder, sample + '.tif'),
                  instances.astype(np.uint16),
                  plugin='tifffile')
        if save_mip:
            colored = color(np.max(instances, axis=0))
            io.imsave(os.path.join(result_folder, sample + '_cleaned.png'),
                      colored.astype(np.uint8))

    if kwargs['output_format'] == 'hdf':
        hf = h5py.File(os.path.join(result_folder, sample + '.hdf'), 'w')
        hf.create_dataset(res_key,
                          data=instances.astype(np.uint16),
                          dtype=np.uint16,
                          compression='gzip')
        if kwargs.get("dilate_instances", False):
            logger.info("dilating")
            instdil = np.copy(instances)
            for lbl in np.unique(instances):
                if lbl == 0:
                    continue
                label_mask = instdil == lbl
                dilated_label_mask = ndimage.binary_dilation(label_mask,
                                                             iterations=1)
                instdil[dilated_label_mask] = lbl
            hf.create_dataset(res_key + "_dil_1",
                              data=instdil.astype(np.uint16),
                              dtype=np.uint16,
                              compression='gzip')
       str(power_array[-1]))
 #Calculate flexure difference using cross-correlation
 chisq_flexure = np.zeros(
     n_flexure)  #Define array to store the chisq for the flexure
 for order in range(
         skip_first_orders, n_orders - skip_last_orders
 ):  #Loop through all orders in specified order range
     sci_order = data_sci[
         order, :]  #Grab subset of science and A0V data for this order
     a0v_flattened_order = data_a0v_flattened[order, :]
     smoothed_sci_order = normalize_continuum(
         sci_order, size=75
     )  #Contiunuum normalize the science data to place the telluric lines in it on the same flux scale as the flattened A0V data
     cuts = np.isfinite(a0v_flattened_order) & np.isfinite(
         sci_order) & binary_dilation(
             (a0v_flattened_order > min_a0v)
             & (a0v_flattened_order < max_a0v)
         ) & x_cuts  #Set cuts for which pixels to use
     if np.any(
             cuts == True
     ):  #Error catch to ignore orders with no useful telluric lines
         for i in range(
                 n_flexure
         ):  #Loop to check all flexure values for this order and iteration
             chisq_flexure[i] += bn.nansum(
                 (srebin(x, x + flexure_array[i],
                         a0v_flattened_order)[cuts]**best_fit_power -
                  smoothed_sci_order[cuts])**2
             )  #Calculate chisq for flexure using the difference between the A0V and a continuum normalized science spectrum
 best_fit_flexure = flexure_array[chisq_flexure == bn.nanmin(
     chisq_flexure)][0]
 #Calculate airmass (powerlaw) difference using cross-correlation
Exemple #35
0
def prepareImage(img, cimg, returnMaxDims=False):

    BrightImg = cimg

    NormalizedImg = rgb2gray(img)
    seed = np.copy(NormalizedImg)
    seed[1:-1, 1:-1] = NormalizedImg.min()
    mask = NormalizedImg
    fill = -skimage.morphology.reconstruction(seed, mask, method='dilation')

    #fig = plt.figure()
    #plt.imshow(fill,cmap = plt.get_cmap('gray'))

    seed2 = np.copy(fill)
    seed2[1:-1, 1:-1] = fill.min()
    mask = fill

    dilated = skimage.morphology.reconstruction(seed2, mask, method='dilation')
    fill = fill - dilated
    thresh = skimage.filters.threshold_otsu(fill)
    fill = fill > thresh
    #fill = skimage.feature.canny(fill,sigma = 2.5, low_threshold=10, high_threshold=50)

    fill = image.binary_dilation(fill, structure=np.ones((3, 3)))
    fill = image.binary_fill_holes(fill)
    fill = image.binary_erosion(fill, structure=np.ones((7, 7)))

    #fig = plt.figure()
    #plt.imshow(fill,cmap = plt.get_cmap('gray'))

    distance = image.distance_transform_edt(fill)
    distance = image.gaussian_filter(distance, 1.1)
    local_maxi = peak_local_max(distance,
                                indices=False,
                                footprint=np.ones((7, 7)),
                                labels=fill)
    markers = image.label(local_maxi)[0]
    labels = watershed(-distance, markers, mask=fill)
    label_image = skimage.measure.label(labels)
    #print(np.unique(labels))
    TempCoins = np.zeros(
        (len(np.unique(labels)), 100, 100, 3)).astype(np.uint8)
    counter = 0
    for region in skimage.measure.regionprops(label_image):
        xLen = np.abs(-min(region.coords[:, 0]) + max(region.coords[:, 0]))
        yLen = np.abs(-min(region.coords[:, 1]) + max(region.coords[:, 1]))
        if (region.area >= 900 and xLen <= 100 and yLen <= 100
                and xLen / yLen < 2 and xLen / yLen > 1 / 2):
            #mySlice = (slice(min(region.coords[:,0]) , max(region.coords[:,0]) ),
            #           slice(min(region.coords[:,1]) , max(region.coords[:,1]) ) )
            #TempCoins[counter, int((100-xLen)/2) : int((100-xLen)/2) + xLen
            #            , int((100-yLen)/2): int((100-yLen)/2) + yLen,:] = BrightImg[mySlice]
            if (xLen > yLen):
                currentImg = BrightImg[
                    min(region.coords[:, 0]):max(region.coords[:, 0]),
                    min(region.coords[:, 1]):(min(region.coords[:, 1]) + xLen)]
            else:
                currentImg = BrightImg[
                    min(region.coords[:, 0]):(min(region.coords[:, 0]) + yLen),
                    min(region.coords[:, 1]):max(region.coords[:, 1])]

            TempCoins[counter] = imresize(currentImg,
                                          size=(100, 100),
                                          interp='bicubic')
            #fig= plt.figure()
            #plt.imshow(TempCoins[counter])
            counter = counter + 1

    Coins = TempCoins[:counter, :, :, :]
    #Debugging - Midway Images
    '''
    fig = plt.figure()
    plt.imshow(cimg)

    fig = plt.figure()
    plt.imshow(fill,cmap = plt.get_cmap('gray'))

    fig = plt.figure()
    plt.imshow(labels,cmap = plt.get_cmap('jet'))
    '''
    #if returnMaxDims:
    #    return maxDims
    return Coins
def windowed_radon(img,
                   radon_matrix,
                   theta=None,
                   method='h_maxima',
                   threshold_rel=2,
                   threshold_rel_global=False,
                   threshold_mean=1.5,
                   return_lines=False,
                   debug=False):
    """
    Get coarse-grained anisotropy tensor for img via windowed Radon transform.
    
    Basic version with no support for curved surfaces, and only one option
    for maxima detection, to make code easier to read.

    See https://doi.org/10.7554/eLife.27454. This function first
    calculates a windowed Radon transform, then detects maxima of the Radon
    transform and finally computes a coarse-grained anisotropy tensor for each
    Radon patch according to tensorify_radon. Alternatively, the function can
    also return the centroid, orientation and intensity of each detected edge
    segment (for verification purposes). This information is returned in a
    2d-array like nested list format, each entry corresponding to the list
    of detected line segments from one particular Radon window.

    By default, the Radon transform is weighted so a to calculate the line
    density along each ray (this is done approximately).

    The crucial step in anisotropy detection is finding the maxima of the
    Radon transform. This is implemented using the h-maxima transform. It
    is necessary to tune the "h"-parameter of the h-maxima transform and check
    that your choice correctly detects all edge segment of interest.

    As an example of why maxima detection is so important, consider the Radon
    transform of an image containing a single line, and average over the
    projection distance delta, (so as to obtain a function of angle only). The
    result is _independent_ of the original line orientation!

    For performance reasons, this function uses a sparse matrix representation
    of the Radon transform, computed in advance using get_radon_tf_matrix.

    Parameters
    ----------
    img : np.array
        Input image.
    radon_matrix : sparse.csc_matrix
        Sparse matrix representing the Radon transform (remember, it's linear).
        Computed by get_radon_tf_matrix. Determines the size of the radon
        window.
    theta : np.array, optional
        Angles at which radon transform is computed. Defaults to
        np.linspace(0, np.pi, edge_length, endpoint=False) where edge_length
        is the window size (defined by the shape of radon_matrix).
    method : str, optional
        Either 'h_maxima' or 'global_maximum' (faster).
    threshold_rel : float, optional
        Threshold for maxima detection in radon transform. For "h_maxima",
        this is the minimal height of maxima in units of the Radon transform's
        standard deviation. For "peak_local_max", it is the minimal height of
        maxima in multiples of the global maximum.
    threshold_mean : float, optional
        2nd auxilliary threshold. All Radon transform maxima must be at least
        threshold_mean * mean(Radon transform). This removes e.g. the global
        maximum always returned by the h maxima transform if it is not
        sufficiently pronounced.
    threshold_rel_global :  float, optional
        Global threshold for h-maxima computation, in units of image
        std deviation. If non-zero, overrules the local h-maxima thresholds.
        Use when large regions of image contain no anisotropy.
    return_lines : bool, optional
        Whether to also return a list of centroids, orientations & intensities
        of all detected edges instead of just the coarse-grained anisotropy
        tensor.

    Returns
    -------
    lines : list of lists of np.arrays of shape (..., 4)
        Returned only if return_lines is True. Lines detected in each window,
        formatted as follows (x_coord, y_coord, 
    m :  np.array of shape (...,..., 2, 2)
        Coarse grained anisotropy tensor. The first two axes are "spatial"
        indices and have the following extent:
            ceil(2*(img_shape - edge_length+1)/(edge_length+1)),
        where edge_length is the radon window size.

    """
    edge_length = np.sqrt(radon_matrix.shape[1]).astype(int)
    e_len = int((edge_length - 1) / 2)
    if theta is None:
        theta = np.linspace(0,
                            np.pi,
                            int(radon_matrix.shape[0] / (edge_length - 4)),
                            endpoint=False)
    e_len_cut = int((radon_matrix.shape[0] / theta.size - 1) / 2)
    delta = np.arange(-e_len_cut, e_len_cut + 1)
    # needed because line_density radon transform returns cut-off

    # director matrix
    q_matrix = np.array([[np.sin(theta)**2, -np.sin(theta) * np.cos(theta)],
                         [-np.sin(theta) * np.cos(theta),
                          np.cos(theta)**2]])

    global_h = threshold_rel_global * img.std()

    # iterate over sub-arrays
    m = []
    lines = []
    for r in np.arange(e_len, img.shape[0] - e_len, e_len + 1):
        m_row = []
        lines_row = []
        for c in np.arange(e_len, img.shape[1] - e_len, e_len + 1):
            patch = img[r - e_len:r + e_len + 1, c - e_len:c + e_len + 1]
            radon_window = radon_matrix.dot(patch.flatten())
            radon_window = radon_window.reshape(2 * e_len_cut + 1, theta.size)
            # compute mean based threshold for maxima
            thr_mean = (radon_window.min() + threshold_mean *
                        (np.median(radon_window) - radon_window.min()))
            if method == 'h_maxima':
                h = (global_h if global_h else
                     radon_window.std() * threshold_rel + 1e-2)
                max_mask = h_maxima(radon_window, h)
                max_mask = binary_dilation(max_mask, iterations=1)
                max_mask *= (radon_window > thr_mean)
            if method == 'global_maximum':
                max_mask = np.zeros(radon_window.shape)
                ind = np.unravel_index(np.argmax(radon_window, axis=None),
                                       radon_window.shape)
                max_mask[ind] = radon_window[ind] > thr_mean
            if method == 'thr_mean':
                max_mask = radon_window > thr_mean

            if return_lines and max_mask.any():
                max_mask = shrink_to_centroid(max_mask)
                # now, get centers of lines for each maximum
                max_intensity = radon_window[max_mask.astype(bool)]
                max_delta = delta[np.where(max_mask)[0]]
                max_theta = theta[np.where(max_mask)[1]]
                # get distance of line segment centroids to image center,
                # component orthogonal to line orientation
                max_center = max_delta * np.stack(
                    [np.cos(max_theta), -np.sin(max_theta)])
                # component parallel to line orientation
                par_com = np.array([
                    get_segment_com(patch, ang, off, pad=2)
                    for ang, off in zip(max_theta, max_delta)
                ])
                # add to coordinates of radon window center
                max_center += par_com * np.stack(
                    [np.sin(max_theta), np.cos(max_theta)])
                max_loc = max_center.T + np.array([c, r])
                lines_row.append(list(zip(max_intensity, max_theta, max_loc)))
            else:
                lines_row.append([])
            if debug:
                print(r, c)
                for l in lines_row[-1]:
                    print('theta', 180 / np.pi * l[1])
                    print('loc', l[2])
                    a, b = np.sin(l[1]), np.cos(l[1])
                    plt.plot(5 * np.array([-a, 0, a]) + l[2][0] + e_len - c,
                             5 * np.array([-b, 0, b]) + l[2][1] + e_len - r,
                             color='red',
                             lw=1)
                plt.imshow(patch * disk(e_len), vmin=0, vmax=1)
                plt.show()
            radon_window = (radon_window * max_mask).sum(axis=0)
            m_row.append((q_matrix * radon_window).sum(axis=2))
        lines.append(lines_row)
        m.append(m_row)
    m = np.stack(m)
    if return_lines:
        return lines, m
    return m
Exemple #37
0
bin_p_values = (log_p_values != 0)
vt = nibabel.load(haxby_files.mask_vt[0]).get_data().astype(bool)
bin_p_values_and_vt = np.logical_and(bin_p_values, vt)

fig_id = plt.subplot(3, 1, 2)
plot_roi(nibabel.Nifti1Image(bin_p_values_and_vt.astype(np.int),
                             fmri_img.get_affine()),
         mean_img,
         title='Intersection with ventral temporal mask',
         cut_coords=(coronal, sagittal, axial),
         axes=fig_id)

# Dilation
fig_id = plt.subplot(3, 1, 3)
from scipy import ndimage
dil_bin_p_values_and_vt = ndimage.binary_dilation(bin_p_values_and_vt)
plot_roi(nibabel.Nifti1Image(dil_bin_p_values_and_vt.astype(np.int),
                             fmri_img.get_affine()),
         mean_img,
         title='Dilated mask',
         cut_coords=(coronal, sagittal, axial),
         axes=fig_id,
         annotate=False)
plt.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0)

# Identification of connected components
plt.figure()
labels, n_labels = ndimage.label(dil_bin_p_values_and_vt)
first_roi_data = (labels == 1).astype(np.int)
second_roi_data = (labels == 2).astype(np.int)
fig_id = plt.subplot(2, 1, 1)
Exemple #38
0
def generateTestCatalog(config, numSourcesPerTile, amplitudeColumnName = 'fixed_y_c', 
                        amplitudeRange = [0.001, 1], amplitudeDistribution = 'linear', selFn = None,
                        avoidanceRadiusArcmin = 20.0, maskDilationPix = 0):
    """Generate a catalog of objects with random positions and amplitudes. This is for testing purposes - 
    see, e.g., :meth:`nemo.maps.sourceInjectionTest`.
    
    Args:
        config (:obj:`nemo.startup.NemoConfig`): Nemo configuration object.
        numSourcesPerTile (:obj:`int`): The maximum number of sources to insert into each tile. The number 
            of sources actually inserted may be less than this depending on the value of 
            `avoidanceRadiusArcmin`.
        amplitudeColumnName (:obj:`str`): Name of the column in the output catalog in which source (or
            cluster) amplitudes will be stored. Typically this should be "deltaT_c" for sources, and
            "fixed_y_c" for clusters.
        amplitudeRange (:obj:`list`): Range for the random amplitudes, in the form [minimum, maximum].
        amplitudeDistribution (:obj:`str`): Either 'linear' or 'log'.
        selFn (:obj:`nemo.completeness.SelFn`, optional): Nemo selection function object, used to access 
            area masks and coordinates info. If not given, a selFn object will be created using the info 
            in the config. Providing this saves time, as the area mask files don't have to be read from 
            disk.
        avoidanceRadiusArcmin (:obj:`float`): Minimum separation between two objects in the output catalog.
            This should be set large enough to avoid crowding and spurious cross-matching problems.
        maskDilationPix (:obj:`int`): Avoid placing objects within this many pixels of the area mask, by
            dilating the holes in the mask by this number of pixels. Avoids problems with e.g., objects
            split across the mask boundary. If not set, gives a small number of objects with larger than
            expected offsets in recovered position in :meth:`nemo.maps.sourceInjectionTest`).

    Returns:
        An :obj:`astropy.table.Table` object containing the catalog.
        
    """
    
    if selFn is None:
        selFn=completeness.SelFn(config.selFnDir, 4.0, configFileName = config.configFileName, 
                                 enableCompletenessCalc = False, setUpAreaMask = True)

    RAs=[]
    decs=[]
    amps=[]
    for tileName in config.tileNames:
        mapData=selFn.areaMaskDict[tileName]
        if mapData.sum() == 0:  # Skip any empty/blank tile
            continue
        wcs=selFn.WCSDict[tileName]
        # Dilate mask to avoid putting objects close to borders or holes
        for i in range(maskDilationPix):
            mapData=1-ndimage.binary_dilation(1-mapData)
        ys, xs=np.where(mapData != 0)
        ys=ys+np.random.uniform(0, 1, len(ys))
        xs=xs+np.random.uniform(0, 1, len(xs))
        indices=np.random.randint(0, len(ys), len(ys))
        coords=wcs.pix2wcs(xs[indices], ys[indices])
        coords=np.array(coords)
        tileRAs=[]
        tileDecs=[]
        keepIndices=[]
        for i in indices:
            rai=coords[i, 0]
            deci=coords[i, 1]
            rDeg=astCoords.calcAngSepDeg(rai, deci, tileRAs, tileDecs)
            keepObj=False
            if len(rDeg) > 0:
                if rDeg.min()*60 > avoidanceRadiusArcmin:
                    keepObj=True
            else:
                keepObj=True
            if keepObj == True:
                tileRAs.append(rai)
                tileDecs.append(deci)
                keepIndices.append(i)
            if len(keepIndices) == numSourcesPerTile:
                break
        RAs=RAs+coords[keepIndices, 0].tolist()
        decs=decs+coords[keepIndices, 1].tolist()
        if amplitudeDistribution == 'linear':
            amp=np.random.uniform(amplitudeRange[0], amplitudeRange[1], len(keepIndices))
        elif amplitudeDistribution == 'log':
            amp=np.power(10, np.random.uniform(np.log10(amplitudeRange)[0], np.log10(amplitudeRange)[1], len(keepIndices)))
        else:
            raise Exception("Must be either 'linear' or 'log'.")
        amps=amps+amp.tolist()
    
    tab=atpy.Table()
    tab.add_column(atpy.Column(np.arange(0, len(amps))+1, "name"))
    tab.add_column(atpy.Column(RAs, "RADeg"))
    tab.add_column(atpy.Column(decs, "decDeg"))
    tab.add_column(atpy.Column(amps, amplitudeColumnName))

    return tab
def preprocess_asegs(aseg_dir,
                     lesion_gt_dir,
                     list_incorrect,
                     list_correct,
                     lesion_label_in_gt=77,
                     dilate=2,
                     recompute=False):

    # align asegs to gt dir (cropping to same dimension)
    cropped_dir = aseg_dir + '_cropped'
    edit_volumes.mri_convert_images_in_dir(aseg_dir,
                                           cropped_dir,
                                           interpolation='nearest',
                                           reference_dir=lesion_gt_dir,
                                           recompute=recompute)

    # correct for aseg labels
    corrected_dir = cropped_dir + '_corrected'
    edit_volumes.correct_labels_in_dir(cropped_dir,
                                       list_incorrect,
                                       list_correct,
                                       corrected_dir,
                                       smooth=False,
                                       recompute=recompute)

    # list gt and aseg, and create result dir
    list_lesion_labels = utils.list_images_in_folder(lesion_gt_dir)
    list_aseg_labels = utils.list_images_in_folder(corrected_dir)
    inpainted_dir = corrected_dir + '_lesion_inpainted'
    utils.mkdir(inpainted_dir)

    # loop over subjects
    for path_lesion_label, path_aseg_label in zip(list_lesion_labels,
                                                  list_aseg_labels):
        path_result = os.path.join(inpainted_dir,
                                   os.path.basename(path_aseg_label))
        if (not os.path.isfile(path_result)) | recompute:

            # paste lesion label
            lesions = utils.load_volume(path_lesion_label)
            aseg_label, aff, h = utils.load_volume(path_aseg_label,
                                                   im_only=False)
            lesion_mask = lesions == lesion_label_in_gt
            aseg_label[lesion_mask] = 77
            utils.save_volume(aseg_label, aff, h, path_result)

    # dilate lesion and ventricle
    dilated_dir = inpainted_dir + '_dilated'
    utils.mkdir(dilated_dir)
    list_inpainted_aseg = utils.list_images_in_folder(inpainted_dir)
    for path_aseg in list_inpainted_aseg:

        path_result = os.path.join(dilated_dir, os.path.basename(path_aseg))
        if (not os.path.isfile(path_result)) | recompute:

            # define lesion, WM, and LV masks
            aseg, aff, h = utils.load_volume(path_aseg, im_only=False)
            WM = aseg == 2
            LV = aseg == 4
            lesion = aseg == 77

            # morphological operations to bridge the gaps between lesions and LV
            morph_struct = utils.build_binary_structure(
                dilate, len(aseg.shape))
            dilated_LV_or_lesion = binary_dilation(LV | lesion, morph_struct)
            filled_LV_or_lesion = binary_erosion(dilated_LV_or_lesion,
                                                 morph_struct)
            LV = LV | (filled_LV_or_lesion & WM)
            aseg[LV] = 4

            # save map
            utils.save_volume(aseg, aff, h, path_result)
Exemple #40
0
 def test_02_06_binary_dilate(self):
     self.binary_tteesstt(
         'dilate',
         lambda x, footprint: scind.binary_dilation(x, footprint),
         scale=7)
Exemple #41
0
def median_otsu(input_volume,
                median_radius=4,
                numpass=4,
                autocrop=False,
                vol_idx=None,
                dilate=None):
    """ Simple brain extraction tool method for images from DWI data

    It uses a median filter smoothing of the input_volumes `vol_idx` and an
    automatic histogram Otsu thresholding technique, hence the name
    *median_otsu*.

    This function is inspired from Mrtrix's bet which has default values
    ``median_radius=3``, ``numpass=2``. However, from tests on multiple 1.5T
    and 3T data     from GE, Philips, Siemens, the most robust choice is
    ``median_radius=4``, ``numpass=4``.

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter(default 4)
    numpass: int
        Number of pass of the median filter (default 4)
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the bounding
        box defined by the masked data. Should be on if DWI is upsampled to 1x1x1
        resolution. (default False)
    vol_idx : None or array, optional
        1D array representing indices of ``axis=3`` of a 4D `input_volume`
        None (the default) corresponds to ``(0,)`` (assumes first volume in 4D array)
    dilate : None or int, optional
        number of iterations for binary dilation

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask
    """
    if len(input_volume.shape) == 4:
        if vol_idx is not None:
            b0vol = np.mean(input_volume[..., tuple(vol_idx)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()
    # Make a mask using a multiple pass median filter and histogram thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = mask > thresh

    if dilate is not None:
        cross = generate_binary_structure(3, 1)
        mask = binary_dilation(mask, cross, iterations=dilate)

    # Auto crop the volumes using the mask as input_volume for bounding box computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)
    return maskedvolume, mask
Exemple #42
0
method_id = [m for m in mlist for s in slist for rdx in range(nrun)]

# Resample images to geometry of template and rescale TSNR value with SQRT(NVol)
imgs = []
for i, e in enumerate(method_id):
    if 'spm' in e:
        img = resample_to_img(filelist[i], template)
    else:
        img = load_img(filelist[i])
    imgs.append(math_img('img * np.sqrt(%d)' % nvol, img=img))

# Create mask (containing only voxels with values in at least half of the images)
img_concat = concat_imgs(imgs)
mask = np.sum(img_concat.get_data()!=0, axis=-1)>=(img_concat.shape[-1] * 0.8)
mask = binary_fill_holes(
        binary_dilation(binary_erosion(mask, iterations=2), iterations=2))
group_mask = new_img_like(img_concat, mask.astype('int'), copy_header=True)

# Create 2nd-level model
design_matrix = design_matrix = pd.get_dummies(method_id)
second_level_model = SecondLevelModel(n_jobs=-1, mask=group_mask)
second_level_model = second_level_model.fit(imgs, design_matrix=design_matrix)

# Compute contrasts, save nifti and plot glass brain
weights = [ [1, 0, 0, 0, 0], [1,-1, 0, 0, 0], [1, 0,-1, 0, 0], [1, 0, 0,-1, 0], [1, 0, 0, 0,-1],
           [-1, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1,-1, 0, 0], [0, 1, 0,-1, 0], [0, 1, 0, 0,-1],
           [-1, 0, 1, 0, 0], [0,-1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1,-1, 0], [0, 0, 1, 0,-1],
           [-1, 0, 0, 1, 0], [0,-1, 0, 1, 0], [0, 0,-1, 1, 0], [0, 0, 0, 1, 0], [0, 0, 0, 1,-1],
           [-1, 0, 0, 0, 1], [0,-1, 0, 0, 1], [0, 0,-1, 0, 1], [0, 0, 0,-1, 1], [0, 0, 0, 0, 1]]

for i, w in enumerate(weights):
Exemple #43
0
def maskCapsomer( capsomer, correction_mask, vector, capsomer_centers ):

    capsomer_mask = np.ones_like( capsomer )
    #equidistance_mask = np.zeros_like( capsomer, dtype=np.bool )

    nhalf = len(capsomer) // 2
    x0, y0, z0 = np.meshgrid(*[np.arange(-nhalf - 0.5, nhalf - 0.5)] * 3, indexing="ij")
    x = x0
    y = -1*y0
    z = -1*z0
    print("Preparing to create mask for current subvolume")
    gold_distance = np.sqrt((x - vector[0])**2 + (y-vector[1])**2 + (z-vector[2])**2)
    
    for index, center in enumerate(capsomer_centers):

        """ Don't compare this subvolume center against itself """
        if not np.array_equal(vector,center.astype(int)):

            """ This makes the evaluator """
            x0, y0, z0 = np.meshgrid(*[np.arange(-nhalf - 0.5, nhalf - 0.5)] * 3, indexing="ij")
            x = x0
            y = (-1*y0)
            z = (-1*z0)

            """ A volume containing distances to the currently evaluated center """
            dist_from_center = np.sqrt((x - center[0])**2 + (y-center[1])**2 + (z-center[2])**2)

            """ Update overall mask """
            mask = gold_distance <= dist_from_center
            #mask_edge = gold_distance == dist_from_center
            #equidistance_mask = equidistance_mask + mask_edge
            capsomer_mask = capsomer_mask * mask.astype(np.int)
            #print( np.unique(equidistance_mask) )

    """ At this point, capsomer_mask contains all voxels belonging to the given capsomer """
    """ In the case of equidistance, those voxels are overrepresented """
    """ We now want to dilate and soften that mask to reduce nyquist artifacts """
    soft_1 = ndimage.binary_dilation(capsomer_mask, iterations=1) - capsomer_mask
    soft_2 = ndimage.binary_dilation(capsomer_mask, iterations=2) - (capsomer_mask + soft_1)
    soft_3 = ndimage.binary_dilation(capsomer_mask, iterations=3) - (capsomer_mask + soft_1 + soft_2)
    soft_1 = np.cos((1*np.pi)/8) * soft_1.astype(np.float32)
    soft_2 = np.cos((2*np.pi)/8) * soft_2.astype(np.float32)
    soft_3 = np.cos((3*np.pi)/8) * soft_3.astype(np.float32)

    """ Add the soft mask to the capsomer mask """
    capsomer_mask = capsomer_mask.astype(np.float32) + soft_1 + soft_2 + soft_3
    #print( "Unique values in capsomer mask", np.unique(capsomer_mask) )

    """ Only take the capsomer_mask where capsomer map has values """
    capsomer_bool = (capsomer!=0).astype(np.int)
    capsomer_mask = capsomer_mask * capsomer_bool

    """ Multiply by mask """
    capsomer = capsomer * capsomer_mask.astype(np.float32)

    """ Find intersection of equidistance_mask and capsomer_mask """
    #equidistance_mask = equidistance_mask * capsomer_mask.astype(np.bool)

    """ Update the correction_mask """
    correction_mask = correction_mask + capsomer_mask.astype(np.float32)
    #print( "Unique values in correction mask", np.unique(correction_mask) )

    return capsomer, correction_mask
Exemple #44
0
    def run(self, workspace):
        '''Run the module on the image set'''
        seed_objects_name = self.seed_objects_name.value
        skeleton_name = self.image_name.value
        seed_objects = workspace.object_set.get_objects(seed_objects_name)
        labels = seed_objects.segmented
        labels_count = np.max(labels)
        label_range = np.arange(labels_count, dtype=np.int32) + 1

        skeleton_image = workspace.image_set.get_image(skeleton_name,
                                                       must_be_binary=True)
        skeleton = skeleton_image.pixel_data
        if skeleton_image.has_mask:
            skeleton = skeleton & skeleton_image.mask
        try:
            labels = skeleton_image.crop_image_similarly(labels)
        except:
            labels, m1 = cpo.size_similarly(skeleton, labels)
            labels[~m1] = 0
        #
        # The following code makes a ring around the seed objects with
        # the skeleton trunks sticking out of it.
        #
        # Create a new skeleton with holes at the seed objects
        # First combine the seed objects with the skeleton so
        # that the skeleton trunks come out of the seed objects.
        #
        # Erode the labels once so that all of the trunk branchpoints
        # will be within the labels
        #
        #
        # Dilate the objects, then subtract them to make a ring
        #
        my_disk = morph.strel_disk(1.5).astype(int)
        dilated_labels = grey_dilation(labels, footprint=my_disk)
        seed_mask = dilated_labels > 0
        combined_skel = skeleton | seed_mask

        closed_labels = grey_erosion(dilated_labels, footprint=my_disk)
        seed_center = closed_labels > 0
        combined_skel = combined_skel & (~seed_center)
        #
        # Fill in single holes (but not a one-pixel hole made by
        # a one-pixel image)
        #
        if self.wants_to_fill_holes:

            def size_fn(area, is_object):
                return (~is_object) and (area <= self.maximum_hole_size.value)

            combined_skel = morph.fill_labeled_holes(combined_skel,
                                                     ~seed_center, size_fn)
        #
        # Reskeletonize to make true branchpoints at the ring boundaries
        #
        combined_skel = morph.skeletonize(combined_skel)
        #
        # The skeleton outside of the labels
        #
        outside_skel = combined_skel & (dilated_labels == 0)
        #
        # Associate all skeleton points with seed objects
        #
        dlabels, distance_map = propagate.propagate(np.zeros(labels.shape),
                                                    dilated_labels,
                                                    combined_skel, 1)
        #
        # Get rid of any branchpoints not connected to seeds
        #
        combined_skel[dlabels == 0] = False
        #
        # Find the branchpoints
        #
        branch_points = morph.branchpoints(combined_skel)
        #
        # Odd case: when four branches meet like this, branchpoints are not
        # assigned because they are arbitrary. So assign them.
        #
        # .  .
        #  B.
        #  .B
        # .  .
        #
        odd_case = (combined_skel[:-1, :-1] & combined_skel[1:, :-1]
                    & combined_skel[:-1, 1:] & combined_skel[1, 1])
        branch_points[:-1, :-1][odd_case] = True
        branch_points[1:, 1:][odd_case] = True
        #
        # Find the branching counts for the trunks (# of extra branches
        # eminating from a point other than the line it might be on).
        #
        branching_counts = morph.branchings(combined_skel)
        branching_counts = np.array([0, 0, 0, 1, 2])[branching_counts]
        #
        # Only take branches within 1 of the outside skeleton
        #
        dilated_skel = scind.binary_dilation(outside_skel, morph.eight_connect)
        branching_counts[~dilated_skel] = 0
        #
        # Find the endpoints
        #
        end_points = morph.endpoints(combined_skel)
        #
        # We use two ranges for classification here:
        # * anything within one pixel of the dilated image is a trunk
        # * anything outside of that range is a branch
        #
        nearby_labels = dlabels.copy()
        nearby_labels[distance_map > 1.5] = 0

        outside_labels = dlabels.copy()
        outside_labels[nearby_labels > 0] = 0
        #
        # The trunks are the branchpoints that lie within one pixel of
        # the dilated image.
        #
        if labels_count > 0:
            trunk_counts = fix(
                scind.sum(branching_counts, nearby_labels,
                          label_range)).astype(int)
        else:
            trunk_counts = np.zeros((0, ), int)
        #
        # The branches are the branchpoints that lie outside the seed objects
        #
        if labels_count > 0:
            branch_counts = fix(
                scind.sum(branch_points, outside_labels, label_range))
        else:
            branch_counts = np.zeros((0, ), int)
        #
        # Save the endpoints
        #
        if labels_count > 0:
            end_counts = fix(scind.sum(end_points, outside_labels,
                                       label_range))
        else:
            end_counts = np.zeros((0, ), int)
        #
        # Calculate the distances
        #
        total_distance = morph.skeleton_length(dlabels * outside_skel,
                                               label_range)
        #
        # Save measurements
        #
        m = workspace.measurements
        assert isinstance(m, cpmeas.Measurements)
        feature = "_".join((C_OBJSKELETON, F_NUMBER_TRUNKS, skeleton_name))
        m.add_measurement(seed_objects_name, feature, trunk_counts)
        feature = "_".join(
            (C_OBJSKELETON, F_NUMBER_NON_TRUNK_BRANCHES, skeleton_name))
        m.add_measurement(seed_objects_name, feature, branch_counts)
        feature = "_".join(
            (C_OBJSKELETON, F_NUMBER_BRANCH_ENDS, skeleton_name))
        m.add_measurement(seed_objects_name, feature, end_counts)
        feature = "_".join(
            (C_OBJSKELETON, F_TOTAL_OBJSKELETON_LENGTH, skeleton_name))
        m[seed_objects_name, feature] = total_distance
        #
        # Collect the graph information
        #
        if self.wants_objskeleton_graph:
            trunk_mask = (branching_counts > 0) & (nearby_labels != 0)
            intensity_image = workspace.image_set.get_image(
                self.intensity_image_name.value)
            edge_graph, vertex_graph = self.make_objskeleton_graph(
                combined_skel, dlabels, trunk_mask,
                branch_points & ~trunk_mask, end_points,
                intensity_image.pixel_data)

            image_number = workspace.measurements.image_set_number

            edge_path, vertex_path = self.get_graph_file_paths(
                m, m.image_number)
            workspace.interaction_request(self,
                                          m.image_number,
                                          edge_path,
                                          edge_graph,
                                          vertex_path,
                                          vertex_graph,
                                          headless_ok=True)

            if self.show_window:
                workspace.display_data.edge_graph = edge_graph
                workspace.display_data.vertex_graph = vertex_graph
                workspace.display_data.intensity_image = intensity_image.pixel_data
        #
        # Make the display image
        #
        if self.show_window or self.wants_branchpoint_image:
            branchpoint_image = np.zeros(
                (skeleton.shape[0], skeleton.shape[1], 3))
            trunk_mask = (branching_counts > 0) & (nearby_labels != 0)
            branch_mask = branch_points & (outside_labels != 0)
            end_mask = end_points & (outside_labels != 0)
            branchpoint_image[outside_skel, :] = 1
            branchpoint_image[trunk_mask | branch_mask | end_mask, :] = 0
            branchpoint_image[trunk_mask, 0] = 1
            branchpoint_image[branch_mask, 1] = 1
            branchpoint_image[end_mask, 2] = 1
            branchpoint_image[dilated_labels != 0, :] *= .875
            branchpoint_image[dilated_labels != 0, :] += .1
            if self.show_window:
                workspace.display_data.branchpoint_image = branchpoint_image
            if self.wants_branchpoint_image:
                bi = cpi.Image(branchpoint_image, parent_image=skeleton_image)
                workspace.image_set.add(self.branchpoint_image_name.value, bi)
def find_line_segments_ff(image,
                          mask=None,
                          seed_radius=7,
                          border_size=4,
                          n_bins=8,
                          mag_ratio = 0.9,
                          mag_tol=0.3,
                          return_internals=False):
    """ Detect line segments

    The algotithm processds in this steps:
    * Calculate gradients and gradient magnitude and optionally downsample
    * Get seed points as local maximas of magnitude
    * Assign each seed point to an orientation bin based on its orientation
    * For each bin:
      * Calculate gradient magnitude for the bin orientation
      * From each seed point trace pixels using flood function
      * Fit line to the traced pixels and calculate endpoints

    Input
    -----
    image : ndarray
        The input image with shape (H,W). Image is converted to float and
        normalized to 0-1 range.
    block_size : int
        Aggregation factor - image gradients and magnitude is downscaled
        by this factor before detecting lines in oder to increaseprocessing
        speed and reduce possible noise. Higher values lead to less precise
        lines.
    n_bins : int
        Number of orientation bins in which lines are traced.
    mag_ratio : float
        Ratio of 
    mag_tol : float
    return_internals : bool
        Instead of line segments, return internal variables - gradients, etc.

    Output
    ------
    lines: An instance of LineSegments or, if return_internals=True, a dict with
        internal stuff of the line traing algorithm

    Example
    -------

    """
    image = image.astype("f") / image.max()

    logging.debug(f"Calculating gradients and edge magnitudes")
    KX = gauss_deriv_kernel(2,1,direction="x")
    KY = gauss_deriv_kernel(2,1,direction="y")
    dx = ni.correlate(image, KX)
    dy = ni.correlate(image, KY)
    mask_borders(dx, border_size, 0)
    mask_borders(dy, border_size, 0)
    mag = np.sqrt(dx*dx + dy*dy)
    if mask is not None:
        mag *= mask
    
    # if block_size > 1:
    #     block_size = (block_size,)*2  # scalar x -> tuple (x,x)
    #     logging.debug(f"Downsampling image")
    #     dx = block_reduce(dx, block_size, np.mean)
    #     dy = block_reduce(dy, block_size, np.mean)
    #     mag = block_reduce(mag, block_size, np.max)

    logging.debug(f"Calculating oriented gradient magnitude (nbins={n_bins})")
    theta = np.linspace(0, np.pi, n_bins, endpoint=False)   
    # seed_dir = np.array([dx[r,c], dy[r,c]]).T
    grad_dir = np.array([np.sin(theta), np.cos(theta)])
    # affinity = np.abs(seed_dir @ grad_dir)
    # grad_class = np.argmax(affinity, axis=1)    
    grad_mag_arr = np.array([np.abs(dx*wx + dy*wy) for wx,wy in grad_dir.T], "f")
    grad_mag_ind = np.argmax(grad_mag_arr, axis=0)

    logging.debug(f"Searching for seed points")
    mag_top = ni.maximum_filter(mag, seed_radius)
    seed_mask = (mag == mag_top)
    r,c = np.nonzero(seed_mask)
    seed_mag = mag[r,c]
    grad_class = grad_mag_ind[r,c]
    
    mag_threshold = (1-mag_ratio) * seed_mag.max()
    seed_mask = seed_mag > mag_threshold
    logging.debug(f"{seed_mask.sum()} seed points found (total {r.size})")
    r = r[seed_mask]
    c = c[seed_mask]
    seed_mag = seed_mag[seed_mask]
    grad_class = grad_class[seed_mask]

    logging.debug(f"Sorting seed points")
    seed_order = np.argsort(seed_mag)[::-1]
    r = r[seed_order]
    c = c[seed_order]
    seed_mag = seed_mag[seed_order]
    grad_class = grad_class[seed_order]

    logging.debug("Tracing lines")
    found = np.zeros_like(mag,"i")
    components = []

    grad_images = []

    for g, grad_mag in enumerate(grad_mag_arr):
        bin_mask = ni.binary_dilation(grad_mag_ind==g, iterations=2)
        grad_image = grad_mag * bin_mask
        grad_images.append(grad_image)
        #seed_idx = grad_class == g

    #for i,seed in enumerate(zip(r[seed_idx],c[seed_idx]),start=found.max()+1):
    for i,seed in enumerate(zip(r,c,grad_class,seed_mag)):
        a,b,seed_bin,seed_mag = seed
        if found[a,b]:
            continue
        tol = seed_mag * mag_tol
        component = flood(grad_images[seed_bin], (a,b), tolerance=tol, selem=np.ones( (3,3) ) )
        found[component] = i
        inds = np.nonzero(component)
        component_points = np.array((inds[1], inds[0]),"i").T
        components.append({"X": component_points, "seed_point": seed})

    logging.debug("Calculating segment parameters")
    segments = fit_line_segments(components, mag, min_size=10, scale=1)
    
    if return_internals:
        return {
            "dx":dx, "dy":dy, "mag":mag, "mag_ind": grad_mag_ind,
            "seed_points": [r,c],
            "seed_grad_class": grad_class,
            "grad_dir": grad_dir,
            "segment_labels": found,
            "components": components,
            "segments" : segments,
        }
    else:
        return segments
Exemple #46
0
def run_objectwise_metrics(refDSM,
                           refDTM,
                           refMask,
                           testDSM,
                           testDTM,
                           testMask,
                           tform,
                           ignoreMask,
                           merge_radius=2,
                           plot=None,
                           verbose=True):

    # parse plot input
    if plot is None:
        PLOTS_ENABLE = False
    else:
        PLOTS_ENABLE = True
        PLOTS_SAVE_PREFIX = "objectwise_"

    # Number of pixels to dilate reference object mask
    padding_pixels = np.round(merge_radius / getUnitWidth(tform))
    strel = ndimage.generate_binary_structure(2, 1)

    # Dilate reference object mask to combine closely spaced objects
    ref_ndx_orig = np.copy(refMask)
    ref_ndx = ndimage.binary_dilation(ref_ndx_orig,
                                      structure=strel,
                                      iterations=padding_pixels.astype(int))

    # Create index regions
    ref_ndx, num_ref_regions = ndimage.label(ref_ndx)
    ref_ndx_orig, num_ref_regions = ndimage.label(ref_ndx_orig)
    test_ndx, num_test_regions = ndimage.label(testMask)

    # Get Height from DSM-DTM
    ref_height = refDSM.astype(np.float64) - refDTM.astype(np.float64)
    ref_height[ref_ndx == 0] = 0
    test_height = testDSM.astype(np.float64) - testDTM.astype(np.float64)
    test_height[test_ndx == 0] = 0

    # Keep track of how many times each region is used
    test_use_counter = np.zeros([num_test_regions, 1])
    ref_use_counter = np.zeros([num_ref_regions, 1])

    # Calculate instance metrics
    class instance_parameters:
        def __init__(self):
            self.IOU_THRESHOLD = 0.5
            self.MIN_AREA_FILTER = 0
            self.UNCERTAIN_VALUE = 65

    params = instance_parameters()
    metrics_container_no_merge, metrics_container_merge_fp, metrics_container_merge_fn = \
        eval_instance_metrics(ref_ndx, params, test_ndx)
    no_merge_f1 = metrics_container_no_merge.f1_score
    merge_fp_f1 = metrics_container_merge_fp.f1_score
    merge_fn_f1 = metrics_container_merge_fn.f1_score
    num_buildings_performer = np.unique(test_ndx).__len__() - 1
    num_buildings_truth = np.unique(ref_ndx).__len__() - 1

    # Initialize metric list
    metric_list = []
    # Make images to visualize certain metrics
    # Unused regions will be marked as zero, background as -1
    image_out = refMask.astype(float).copy() - 1
    #image_out[image_out == -1] = np.nan
    image_2d_completeness = image_out.copy()
    image_2d_correctness = image_out.copy()
    image_2d_jaccard_index = image_out.copy()
    image_3d_completeness = image_out.copy()
    image_3d_correctness = image_out.copy()
    image_3d_jaccard_index = image_out.copy()
    image_hrmse = image_out.copy()
    image_zrmse = image_out.copy()

    # Initialize min/max area/volume
    max_area = 0
    min_area = 0
    max_volume = 0
    min_volume = 0

    for loop_region in range(1, num_ref_regions + 1):

        # Reference region under evaluation
        ref_objs = (ref_ndx == loop_region) & refMask

        # Find test regions overlapping with ref
        test_regions = np.unique(test_ndx[ref_ndx == loop_region])

        # Find test regions overlapping with ref
        ref_regions = np.unique(ref_ndx_orig[ref_ndx == loop_region])

        # Remove background region, '0'
        if np.any(test_regions == 0):
            test_regions = test_regions.tolist()
            test_regions.remove(0)
            test_regions = np.array(test_regions)

        if np.any(ref_regions == 0):
            ref_regions = ref_regions.tolist()
            ref_regions.remove(0)
            ref_regions = np.array(ref_regions)

        if len(test_regions) == 0:
            continue

        for refRegion in ref_regions:
            # Increment counter for ref region used
            ref_use_counter[refRegion - 1] = ref_use_counter[refRegion - 1] + 1

        # Make mask of overlapping test regions
        test_objs = np.zeros_like(testMask)
        for test_region in test_regions:
            test_objs = test_objs | (test_ndx == test_region)
            # Increment counter for test region used
            test_use_counter[test_region -
                             1] = test_use_counter[test_region - 1] + 1

        # TODO:  Not practical as implemented to enable plots. plots is forced to false.
        [result_geo, result_acc, unitArea] = eval_metrics(refDSM,
                                                          refDTM,
                                                          ref_objs,
                                                          testDSM,
                                                          testDTM,
                                                          test_objs,
                                                          tform,
                                                          ignoreMask,
                                                          plot=None,
                                                          verbose=verbose)

        this_metric = dict()
        this_metric['ref_objects'] = test_regions.tolist()
        this_metric['test_objects'] = ref_regions.tolist()
        this_metric['threshold_geometry'] = result_geo
        this_metric['relative_accuracy'] = result_acc

        # Calculate min and max area/volume
        if this_metric['threshold_geometry']['area'][
                'test_area'] > max_area or loop_region == 1:
            max_area = this_metric['threshold_geometry']['area']['test_area']
        if this_metric['threshold_geometry']['area'][
                'test_area'] < min_area or loop_region == 1:
            min_area = this_metric['threshold_geometry']['area']['test_area']
        if this_metric['threshold_geometry']['volume'][
                'test_volume'] > max_volume or loop_region == 1:
            max_volume = this_metric['threshold_geometry']['volume'][
                'test_volume']
        if this_metric['threshold_geometry']['volume'][
                'test_volume'] < min_volume or loop_region == 1:
            min_volume = this_metric['threshold_geometry']['volume'][
                'test_volume']

        metric_list.append(this_metric)

        # Add scores to images
        for i in ref_regions:
            ind = ref_ndx_orig == i
            image_2d_completeness[ind] = result_geo['2D']['completeness']
            image_2d_correctness[ind] = result_geo['2D']['correctness']
            image_2d_jaccard_index[ind] = result_geo['2D']['jaccardIndex']
            image_3d_completeness[ind] = result_geo['3D']['completeness']
            image_3d_correctness[ind] = result_geo['3D']['correctness']
            image_3d_jaccard_index[ind] = result_geo['3D']['jaccardIndex']
            image_hrmse[ind] = result_acc['hrmse']
            image_zrmse[ind] = result_acc['zrmse']

    # Sort metrics by area
    # Calculate bins for area and volume
    num_bins = 10
    area_range = max_area - min_area
    volume_range = max_volume - min_volume
    area_bin_width = np.round(area_range / num_bins)
    volume_bin_width = np.round(volume_range / num_bins)
    area_bins = []
    volume_bins = []
    for i in range(0, num_bins + 1):
        area_bins.append(np.floor(min_area) + i * area_bin_width)
        volume_bins.append(np.floor(min_volume) + i * volume_bin_width)

    # Create dicts with bins as keys
    iou_2d_area_bins = dict((el, []) for el in area_bins)
    iou_2d_volume_bins = dict((el, []) for el in volume_bins)
    iou_3d_area_bins = dict((el, []) for el in area_bins)
    iou_3d_volume_bins = dict((el, []) for el in volume_bins)

    # Create dicts with areas as keys
    iou_2d_area = {}
    iou_2d_volume = {}
    iou_3d_area = {}
    iou_3d_volume = {}

    # Keys are area/volume, Values are IOU
    for current_metric in metric_list:
        current_area = current_metric['threshold_geometry']['area'][
            'test_area'] * unitArea  # Convert area to meters^2
        current_volume = current_metric['threshold_geometry']['volume'][
            'test_volume']

        # Get IOUS by area/volume
        iou_2d_area.update({
            current_area:
            current_metric['threshold_geometry']['2D']['jaccardIndex']
        })
        iou_2d_volume.update({
            current_volume:
            current_metric['threshold_geometry']['2D']['jaccardIndex']
        })
        iou_3d_area.update({
            current_area:
            current_metric['threshold_geometry']['3D']['jaccardIndex']
        })
        iou_3d_volume.update({
            current_volume:
            current_metric['threshold_geometry']['3D']['jaccardIndex']
        })

        # Create bins
        for area_bin_edge in area_bins:
            if current_area <= area_bin_edge:
                iou_2d_area_bins[area_bin_edge].append(
                    current_metric['threshold_geometry']['2D']['jaccardIndex'])
                iou_3d_area_bins[area_bin_edge].append(
                    current_metric['threshold_geometry']['3D']['jaccardIndex'])
                break
        for volume_bin_edge in volume_bins:
            if current_volume <= volume_bin_edge:
                iou_2d_volume_bins[volume_bin_edge].append(
                    current_metric['threshold_geometry']['2D']['jaccardIndex'])
                iou_3d_volume_bins[volume_bin_edge].append(
                    current_metric['threshold_geometry']['3D']['jaccardIndex'])
                break

    # Average IOUs in bins
    for current_bin in area_bins:
        iou_2d_area_bins[current_bin] = np.mean(iou_2d_area_bins[current_bin])
        iou_3d_area_bins[current_bin] = np.mean(iou_3d_area_bins[current_bin])
    for current_bin in volume_bins:
        iou_2d_volume_bins[current_bin] = np.mean(
            iou_2d_volume_bins[current_bin])
        iou_3d_volume_bins[current_bin] = np.mean(
            iou_3d_volume_bins[current_bin])

    # plot
    if PLOTS_ENABLE:
        print('Input plots...')

        # Save instance level stoplight charts
        plot.make_instance_stoplight_charts(
            metrics_container_no_merge.stoplight_chart,
            saveName=PLOTS_SAVE_PREFIX + "instanceStoplightNoMerge")
        plot.make_instance_stoplight_charts(
            metrics_container_merge_fp.stoplight_chart,
            saveName=PLOTS_SAVE_PREFIX + "instanceStoplightMergePerformer")
        plot.make_instance_stoplight_charts(
            metrics_container_merge_fn.stoplight_chart,
            saveName=PLOTS_SAVE_PREFIX + "instanceStoplightMergeGT")

        # IOU Histograms
        plot.make_iou_histogram(iou_2d_area_bins,
                                'Area (m^2)',
                                '2D Mean IOUs by Area',
                                373,
                                saveName=PLOTS_SAVE_PREFIX +
                                "obj2dIOUbyAreaHistogram")
        plot.make_iou_histogram(iou_2d_volume_bins,
                                'Volume (m^3)',
                                '2D Mean IOUs by Volume',
                                374,
                                saveName=PLOTS_SAVE_PREFIX +
                                "obj2dIOUbyVolumeHistogram")
        plot.make_iou_histogram(iou_3d_area_bins,
                                'Area (m^2)',
                                '3D Mean IOUs by Area',
                                375,
                                saveName=PLOTS_SAVE_PREFIX +
                                "obj3dIOUbyAreaHistogram")
        plot.make_iou_histogram(iou_3d_volume_bins,
                                'Volume (m^3)',
                                '3D Mean IOUs by Volume',
                                376,
                                saveName=PLOTS_SAVE_PREFIX +
                                "obj3dIOUbyVolumeHistogram")
        # Scatter plots
        plot.make_iou_scatter(iou_2d_area,
                              'Area (m^2)',
                              '2D IOUs by Area',
                              373,
                              saveName=PLOTS_SAVE_PREFIX +
                              "obj2dIOUbyAreaScatter")
        plot.make_iou_scatter(iou_2d_volume,
                              'Volume (m^3)',
                              '2D IOUs by Volume',
                              374,
                              saveName=PLOTS_SAVE_PREFIX +
                              "obj2dIOUbyVolumeScatter")
        plot.make_iou_scatter(iou_3d_area,
                              'Area (m^2)',
                              '3D IOUs by Area',
                              375,
                              saveName=PLOTS_SAVE_PREFIX +
                              "obj3dIOUbyAreaScatter")
        plot.make_iou_scatter(iou_3d_volume,
                              'Volume (m^3)',
                              '3D IOUs by Volume',
                              376,
                              saveName=PLOTS_SAVE_PREFIX +
                              "obj3dIOUbyVolumeScatter")

        plot.make(image_2d_completeness,
                  'Objectwise 2D Completeness',
                  351,
                  saveName=PLOTS_SAVE_PREFIX + "obj2dCompleteness",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=1)
        plot.make(image_2d_correctness,
                  'Objectwise 2D Correctness',
                  352,
                  saveName=PLOTS_SAVE_PREFIX + "obj2dCorrectness",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=1)
        plot.make(image_2d_jaccard_index,
                  'Objectwise 2D Jaccard Index',
                  353,
                  saveName=PLOTS_SAVE_PREFIX + "obj2dJaccardIndex",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=1)
        plot.make(image_3d_completeness,
                  'Objectwise 3D Completeness',
                  361,
                  saveName=PLOTS_SAVE_PREFIX + "obj3dCompleteness",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=1)
        plot.make(image_3d_correctness,
                  'Objectwise 3D Correctness',
                  362,
                  saveName=PLOTS_SAVE_PREFIX + "obj3dCorrectness",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=1)
        plot.make(image_3d_jaccard_index,
                  'Objectwise 3D Jaccard Index',
                  363,
                  saveName=PLOTS_SAVE_PREFIX + "obj3dJaccardIndex",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=1)

        plot.make(image_hrmse,
                  'Objectwise HRMSE',
                  371,
                  saveName=PLOTS_SAVE_PREFIX + "objHRMSE",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=2)
        plot.make(image_zrmse,
                  'Objectwise ZRMSE',
                  372,
                  saveName=PLOTS_SAVE_PREFIX + "objZRMSE",
                  colorbar=True,
                  badValue=-1,
                  vmin=0,
                  vmax=1)
        plot.make_obj_error_map(error_map=image_hrmse,
                                ref=refMask,
                                badValue=-1,
                                saveName=PLOTS_SAVE_PREFIX +
                                "HRMSE_Image_Only")
        plot.make_obj_error_map(error_map=image_zrmse,
                                ref=refMask,
                                badValue=-1,
                                saveName=PLOTS_SAVE_PREFIX +
                                "ZRMSE_Image_Only")
    # Make per metric reporting structure
    num_objs = len(metric_list)
    summary = {}
    summary['counts'] = {}
    summary['counts']['ref'] = {
        'total': len(ref_use_counter),
        'used': np.sum(ref_use_counter >= 1).astype(float),
        'unused': np.sum(ref_use_counter == 0).astype(float)
    }

    # Track number of times test objs got reused
    key, val = np.unique(test_use_counter, return_counts=True)

    summary['counts']['test'] = {
        'total': len(test_use_counter),
        'used': np.sum(test_use_counter >= 1).astype(float),
        'unused': np.sum(test_use_counter == 0).astype(float),
        'counts': {
            'key': key.tolist(),
            'value': val.tolist()
        }
    }

    summary['threshold_geometry'] = {}
    summary['threshold_geometry']['2D'] = {}
    summary['threshold_geometry']['2D']['correctness'] = {}
    summary['threshold_geometry']['2D']['completeness'] = {}
    summary['threshold_geometry']['2D']['jaccardIndex'] = {}
    summary['threshold_geometry']['3D'] = {}
    summary['threshold_geometry']['3D']['correctness'] = {}
    summary['threshold_geometry']['3D']['completeness'] = {}
    summary['threshold_geometry']['3D']['jaccardIndex'] = {}
    summary['relative_accuracy'] = {}
    summary['relative_accuracy']['hrmse'] = {}
    summary['relative_accuracy']['zrmse'] = {}

    summary['threshold_geometry']['2D']['correctness']['values'] = np.zeros(
        num_objs)
    summary['threshold_geometry']['2D']['completeness']['values'] = np.zeros(
        num_objs)
    summary['threshold_geometry']['2D']['jaccardIndex']['values'] = np.zeros(
        num_objs)
    summary['threshold_geometry']['3D']['correctness']['values'] = np.zeros(
        num_objs)
    summary['threshold_geometry']['3D']['completeness']['values'] = np.zeros(
        num_objs)
    summary['threshold_geometry']['3D']['jaccardIndex']['values'] = np.zeros(
        num_objs)
    summary['relative_accuracy']['zrmse']['values'] = np.zeros(num_objs)
    summary['relative_accuracy']['hrmse']['values'] = np.zeros(num_objs)

    ctr = 0
    for m in metric_list:
        summary['threshold_geometry']['2D']['correctness']['values'][ctr] = m[
            'threshold_geometry']['2D']['correctness']
        summary['threshold_geometry']['2D']['completeness']['values'][ctr] = m[
            'threshold_geometry']['2D']['completeness']
        summary['threshold_geometry']['2D']['jaccardIndex']['values'][ctr] = m[
            'threshold_geometry']['2D']['jaccardIndex']

        summary['threshold_geometry']['3D']['correctness']['values'][ctr] = m[
            'threshold_geometry']['3D']['correctness']
        summary['threshold_geometry']['3D']['completeness']['values'][ctr] = m[
            'threshold_geometry']['3D']['completeness']
        summary['threshold_geometry']['3D']['jaccardIndex']['values'][ctr] = m[
            'threshold_geometry']['3D']['jaccardIndex']

        summary['relative_accuracy']['zrmse']['values'][ctr] = m[
            'relative_accuracy']['zrmse']
        summary['relative_accuracy']['hrmse']['values'][ctr] = m[
            'relative_accuracy']['hrmse']

        ctr += 1

    # Compute Summaries
    summary['threshold_geometry']['2D']['correctness'] = metric_stats(
        summary['threshold_geometry']['2D']['correctness']['values'])
    summary['threshold_geometry']['2D']['completeness'] = metric_stats(
        summary['threshold_geometry']['2D']['completeness']['values'])
    summary['threshold_geometry']['2D']['jaccardIndex'] = metric_stats(
        summary['threshold_geometry']['2D']['jaccardIndex']['values'])
    summary['threshold_geometry']['3D']['correctness'] = metric_stats(
        summary['threshold_geometry']['3D']['correctness']['values'])
    summary['threshold_geometry']['3D']['completeness'] = metric_stats(
        summary['threshold_geometry']['3D']['completeness']['values'])
    summary['threshold_geometry']['3D']['jaccardIndex'] = metric_stats(
        summary['threshold_geometry']['3D']['jaccardIndex']['values'])
    summary['relative_accuracy']['zrmse'] = metric_stats(
        summary['relative_accuracy']['zrmse']['values'])
    summary['relative_accuracy']['hrmse'] = metric_stats(
        summary['relative_accuracy']['hrmse']['values'])

    # Make summary of metrics
    results = {
        'summary': summary,
        'objects': metric_list,
        'instance_f1': no_merge_f1,
        'instance_f1_merge_fp': merge_fp_f1,
        'instance_f1_merge_fn': merge_fn_f1,
        'num_buildings_gt': num_buildings_truth,
        'num_buildings_perf': num_buildings_performer
    }

    return results, test_ndx, ref_ndx
Exemple #47
0
name_chs = ['V', 'A', 'PV']
out_h5py = './data/h5_rs_one_case/ct01m_c1.h5'
logger = call_logger(log_file=None, 'GenData')

n_class = 2
w_class = [1.0, 0.2]

w_class_in_roi = [2.0, 2.0]

itkimage1 = sitk.ReadImage(fn1)
labels1 = (sitk.GetArrayFromImage(itkimage1)[::-1, :, :] == 1).astype(
    'int')  #dongmai

#labels0 = (1-labels1).astype('int')

labels1_dilate = binary_dilation(labels1, structure=np.ones(
    (5, 5, 5))).astype(labels1.dtype)

labels = labels1.copy()  #np.stack((labels0,labels1),axis = 0)
labels_dilate = (labels1_dilate > 0).astype('int')

#%%
flist = [str(fn) for fn in (Path(dicom_fd) / name_chs[0]).glob('*')]
n_slice = len(flist)
row, col = 512, 512

labels_pos = np.where(labels_dilate == 1)
z_min, z_max = labels_pos[0].min(), labels_pos[0].max()
y_min, y_max = labels_pos[1].min(), labels_pos[1].max()
x_min, x_max = labels_pos[2].min(), labels_pos[2].max()

z_min = max(0, z_min - 16)
Exemple #48
0
 def test_morphology_fft_dilate_3D(self):
     im = self.im
     truth = spim.binary_dilation(im, structure=ball(3))
     test = ps.tools.fftmorphology(im, strel=ball(3), mode='dilation')
     assert np.all(truth == test)
Exemple #49
0
def make_cprops_mask(cube,
                     prior=None,
                     hi_thresh=4.0,
                     lo_thresh=2.0,
                     scale=1.0,
                     n_chan=2,
                     out_of=None,
                     spec_axis=2,
                     min_vol=None,
                     min_area=None,
                     min_vchan=None,
                     timer=False,
                     verbose=False):
    """
    General purpose masking routine. Identify regions above a given
    threshold across several channels. Reject regions based on volume,
    area, and velociy extent. Returns a mask matchedin size to the
    input image.

    Rather than wrap a read/writer or signal-to-noise cube generator
    in here, these are held externally.

    The scale parameter gives the option to invert the cube by using
    -1 or to scale, e.g., by the RMS.
    """

    # ------------------------------------------------------------
    # Generate the candidate mask
    # ------------------------------------------------------------

    if timer:
        start = time.time()
        full_start = time.time()

    # High threshold
    hi_mask = make_spec_mask(cube,
                             thresh=hi_thresh,
                             scale=scale,
                             n_chan=n_chan,
                             out_of=out_of,
                             spec_axis=spec_axis)

    if timer:
        stop = time.time()
        print "High threshold mask took ", stop - start
        start = time.time()

    # Low threshold
    lo_mask = make_spec_mask(cube,
                             thresh=lo_thresh,
                             scale=scale,
                             n_chan=n_chan,
                             out_of=out_of,
                             spec_axis=spec_axis)

    if timer:
        stop = time.time()
        print "Low threshold mask took ", stop - start
        start = time.time()

    # Expand regions that meet the high threshold to includ all
    # connected low threshold regions
    mask = binary_dilation(hi_mask, mask=lo_mask, iterations=-1)

    if timer:
        stop = time.time()
        print "Mask dilation took ", stop - start
        start = time.time()

    # ------------------------------------------------------------
    # Pare small regions
    # ------------------------------------------------------------

    # Note that this step could be accomplished to some degree by
    # using a (binary) opening operator. It's not perfect, it will
    # clip your edges but it might be much faster and better defined.

    if min_area != None or min_vol != None or min_vchan != None:
        reject_regions(mask,
                       min_area=min_area,
                       min_vol=min_vol,
                       min_vchan=min_vchan,
                       spec_axis=spec_axis,
                       inplace=True,
                       timer=timer)

    if timer:
        stop = time.time()
        print "Small region rejection took ", stop - start

    # ------------------------------------------------------------
    # Apply any prior mask supplied
    # ------------------------------------------------------------

    if prior != None:
        mask *= prior

    # ------------------------------------------------------------
    # Return final mask
    # ------------------------------------------------------------

    if timer:
        full_stop = time.time()
        print "Whole masking took ", full_stop - full_start

    return mask
Exemple #50
0
run.load()
pp = g.PreProcessor(run)
pp.extract_valid_region()
pp.filter_zeroes()
# pp.interpolate_zeroes()

coords = pp.Z, pp.X, pp.T
data = pp.U, pp.V, pp.W

all_coords = np.concatenate([c[None] for c in coords])

data = pp.U[:, :, 2000:-2000]

invalid = np.isnan(data)
invalid_with_shell = ndi.binary_dilation(invalid,
                                         iterations=1,
                                         structure=np.ones((3, 3, 3)))
complete_valid_shell = invalid_with_shell & ~invalid

volumes, n = ndi.label(invalid_with_shell)
slices = ndi.find_objects(volumes)


def interpolate_region(slice):
    nans = invalid[slice]
    shell = complete_valid_shell[slice]

    valid_points = np.vstack(c[slice][shell] for c in coords).T
    valid_values = data[slice][shell]

    interpolator = interp.LinearNDInterpolator(valid_points, valid_values)
Exemple #51
0
def segmentNucleiOnly(nuc, varargin={}):
    ## define analysis parameters
    # parameters for nuclei detection
    arg = dict()
    arg['nuc_erode'] = disk(4)  # initial erosion to enhance nuclei centers
    arg['nuc_smooth'] = 14  # filtering to smooth it out
    arg['nuc_suppress'] = 0.05  # suppression of small peaks - units are in a [0 1] space
    arg['nuc_minarea'] = 30  # smaller then this its not a nuclei
    arg['nuc_maxarea'] = float('inf')
    arg['nuc_stretch'] = [1, 99]
    arg['nuc_channel'] = 'DeepBlue'
    arg['mindistancefromedge'] = 150
    arg['shrinkmsk'] = disk(50)
    arg['removetopprcentile'] = 0
    arg['register'] = []  # optional registration object
    arg['registerreference'] = []
    arg['project'] = False
    arg['specificframeonly'] = [
    ]  # will duplicate that frame for all timepoints
    arg['singleframe'] = False  # must be used in conjunction with specificframeonly. IF true will only return single timepoint
    arg['track_method'] = 'none'
    arg['threshold_method'] = 'otsu'

    arg = parseVarargin(varargin, arg)

    NucLabels = np.zeros(nuc.shape, dtype=int)

    for i in range(nuc.shape[2]):
        current_img = nuc[:, :, i]
        nucbw = current_img > filters.threshold_otsu(current_img)
        nucbw = binary_closing(nucbw, disk(2))
        nucbw = binary_fill_holes(nucbw, disk(5))
        nucpeaks = erosion(current_img, arg['nuc_erode'])
        nucpeaks = filters.gaussian(nucpeaks, sigma=arg['nuc_smooth'])
        nucpeaks = np.clip(nucpeaks, np.percentile(nucpeaks, 1),
                           np.percentile(nucpeaks, 99))
        nucpeaks = np.divide(nucpeaks, float(np.amax(nucpeaks)))
        np.place(nucpeaks, ~nucbw, 0)
        dist_img = distance(nucpeaks)
        nucpeaks_max = peak_local_max(
            dist_img, min_distance=10)  #, threshold_abs=arg['nuc_suppress'])
        peak_img = np.zeros(current_img.shape)
        for yx in nucpeaks_max:
            peak_img[yx[0], yx[1]] = 1
        peak_labels = label(peak_img)
        props = regionprops(peak_labels)
        for p in props:
            if p.area == 1:
                continue
            elif p.area == 2:
                peak_img[p.coords[0][0], p.coords[0][1]] = 0
            elif p.area > 2:
                centroid = p.centroid
                pcenter = np.argmin(
                    [np.sum(np.abs(centroid - jj)) for jj in p.coords])
                for idx, xy in enumerate(p.coords):
                    if not idx == pcenter:
                        peak_img[xy[0], xy[1]] = 0
        labels = label(peak_img)
        lbls = watershed(dist_img * -1,
                         labels,
                         connectivity=1,
                         watershed_line=True,
                         mask=nucbw)
        lbls = binary_erosion(lbls, disk(3))
        lbls = binary_dilation(lbls, disk(2))
        lbls = label(lbls)
        lbls = remove_small_objects(lbls, arg['nuc_minarea'])
        NucLabels[:, :, i] = lbls
    return NucLabels
Exemple #52
0
    def run_function(self, function, pixel_data, mask):
        '''Apply the function once to the image, returning the result'''
        count = function.repeat_count
        function_name = function.function.value
        scale = function.scale.value
        custom_repeats = function.custom_repeats.value

        is_binary = pixel_data.dtype.kind == 'b'
        if function.structuring_element == SE_ARBITRARY:
            strel = np.array(function.strel.get_matrix())
        elif function.structuring_element == SE_DISK:
            strel = morph.strel_disk(scale / 2.0)
        elif function.structuring_element == SE_DIAMOND:
            strel = morph.strel_diamond(scale / 2.0)
        elif function.structuring_element == SE_LINE:
            strel = morph.strel_line(scale, function.angle.value)
        elif function.structuring_element == SE_OCTAGON:
            strel = morph.strel_octagon(scale / 2.0)
        elif function.structuring_element == SE_PAIR:
            strel = morph.strel_pair(function.x_offset.value,
                                     function.y_offset.value)
        elif function.structuring_element == SE_PERIODIC_LINE:
            xoff = function.x_offset.value
            yoff = function.y_offset.value
            n = max(scale / 2.0 / np.sqrt(float(xoff * xoff + yoff * yoff)), 1)
            strel = morph.strel_periodicline(xoff, yoff, n)
        elif function.structuring_element == SE_RECTANGLE:
            strel = morph.strel_rectangle(function.width.value,
                                          function.height.value)
        else:
            strel = morph.strel_square(scale)

        if (function_name
                in (F_BRANCHPOINTS, F_BRIDGE, F_CLEAN, F_DIAG, F_CONVEX_HULL,
                    F_DISTANCE, F_ENDPOINTS, F_FILL, F_FILL_SMALL, F_HBREAK,
                    F_LIFE, F_MAJORITY, F_REMOVE, F_SHRINK, F_SKEL, F_SKELPE,
                    F_SPUR, F_THICKEN, F_THIN, F_VBREAK) and not is_binary):
            # Apply a very crude threshold to the image for binary algorithms
            logger.warning("Warning: converting image to binary for %s\n" %
                           function_name)
            pixel_data = pixel_data != 0

        if (function_name
                in (F_BRANCHPOINTS, F_BRIDGE, F_CLEAN, F_DIAG, F_CONVEX_HULL,
                    F_DISTANCE, F_ENDPOINTS, F_FILL, F_FILL_SMALL, F_HBREAK,
                    F_INVERT, F_LIFE, F_MAJORITY, F_REMOVE, F_SHRINK, F_SKEL,
                    F_SKELPE, F_SPUR, F_THICKEN, F_THIN, F_VBREAK, F_OPENLINES)
                or
            (is_binary
             and function_name in (F_CLOSE, F_DILATE, F_ERODE, F_OPEN))):
            # All of these have an iterations argument or it makes no
            # sense to iterate
            if function_name == F_BRANCHPOINTS:
                return morph.branchpoints(pixel_data, mask)
            elif function_name == F_BRIDGE:
                return morph.bridge(pixel_data, mask, count)
            elif function_name == F_CLEAN:
                return morph.clean(pixel_data, mask, count)
            elif function_name == F_CLOSE:
                if mask is None:
                    return scind.binary_closing(pixel_data,
                                                strel,
                                                iterations=count)
                else:
                    return (scind.binary_closing(
                        pixel_data & mask, strel, iterations=count) |
                            (pixel_data & ~mask))
            elif function_name == F_CONVEX_HULL:
                if mask is None:
                    return morph.convex_hull_image(pixel_data)
                else:
                    return morph.convex_hull_image(pixel_data & mask)
            elif function_name == F_DIAG:
                return morph.diag(pixel_data, mask, count)
            elif function_name == F_DILATE:
                return scind.binary_dilation(pixel_data,
                                             strel,
                                             iterations=count,
                                             mask=mask)
            elif function_name == F_DISTANCE:
                image = scind.distance_transform_edt(pixel_data)
                if function.rescale_values.value:
                    image = image / np.max(image)
                return image
            elif function_name == F_ENDPOINTS:
                return morph.endpoints(pixel_data, mask)
            elif function_name == F_ERODE:
                return scind.binary_erosion(pixel_data,
                                            strel,
                                            iterations=count,
                                            mask=mask)
            elif function_name == F_FILL:
                return morph.fill(pixel_data, mask, count)
            elif function_name == F_FILL_SMALL:

                def small_fn(area, foreground):
                    return (not foreground) and (area <= custom_repeats)

                return morph.fill_labeled_holes(pixel_data, mask, small_fn)
            elif function_name == F_HBREAK:
                return morph.hbreak(pixel_data, mask, count)
            elif function_name == F_INVERT:
                if is_binary:
                    if mask is None:
                        return ~pixel_data
                    result = pixel_data.copy()
                    result[mask] = ~result[mask]
                    return result
                elif mask is None:
                    return 1 - pixel_data
                else:
                    result = pixel_data.copy()
                    result[mask] = 1 - result[mask]
                    return result
            elif function_name == F_LIFE:
                return morph.life(pixel_data, count)
            elif function_name == F_MAJORITY:
                return morph.majority(pixel_data, mask, count)
            elif function_name == F_OPEN:
                if mask is None:
                    return scind.binary_opening(pixel_data,
                                                strel,
                                                iterations=count)
                else:
                    return (scind.binary_opening(
                        pixel_data & mask, strel, iterations=count) |
                            (pixel_data & ~mask))
            elif function_name == F_OPENLINES:
                return morph.openlines(pixel_data,
                                       linelength=custom_repeats,
                                       mask=mask)
            elif function_name == F_REMOVE:
                return morph.remove(pixel_data, mask, count)
            elif function_name == F_SHRINK:
                return morph.binary_shrink(pixel_data, count)
            elif function_name == F_SKEL:
                return morph.skeletonize(pixel_data, mask)
            elif function_name == F_SKELPE:
                return morph.skeletonize(
                    pixel_data, mask,
                    scind.distance_transform_edt(pixel_data) *
                    poisson_equation(pixel_data))
            elif function_name == F_SPUR:
                return morph.spur(pixel_data, mask, count)
            elif function_name == F_THICKEN:
                return morph.thicken(pixel_data, mask, count)
            elif function_name == F_THIN:
                return morph.thin(pixel_data, mask, count)
            elif function_name == F_VBREAK:
                return morph.vbreak(pixel_data, mask)
            else:
                raise NotImplementedError(
                    "Unimplemented morphological function: %s" % function_name)
        else:
            for i in range(count):
                if function_name == F_BOTHAT:
                    new_pixel_data = morph.black_tophat(pixel_data,
                                                        mask=mask,
                                                        footprint=strel)
                elif function_name == F_CLOSE:

                    new_pixel_data = morph.closing(pixel_data,
                                                   mask=mask,
                                                   footprint=strel)
                elif function_name == F_DILATE:
                    new_pixel_data = morph.grey_dilation(pixel_data,
                                                         mask=mask,
                                                         footprint=strel)
                elif function_name == F_ERODE:
                    new_pixel_data = morph.grey_erosion(pixel_data,
                                                        mask=mask,
                                                        footprint=strel)
                elif function_name == F_OPEN:
                    new_pixel_data = morph.opening(pixel_data,
                                                   mask=mask,
                                                   footprint=strel)
                elif function_name == F_TOPHAT:
                    new_pixel_data = morph.white_tophat(pixel_data,
                                                        mask=mask,
                                                        footprint=strel)
                else:
                    raise NotImplementedError(
                        "Unimplemented morphological function: %s" %
                        function_name)
                if np.all(new_pixel_data == pixel_data):
                    break
                pixel_data = new_pixel_data
            return pixel_data
Exemple #53
0
def median_otsu(input_volume, vol_idx=None, median_radius=4, numpass=4,
                autocrop=False, dilate=None):
    """Simple brain extraction tool method for images from DWI data.

    It uses a median filter smoothing of the input_volumes `vol_idx` and an
    automatic histogram Otsu thresholding technique, hence the name
    *median_otsu*.

    This function is inspired from Mrtrix's bet which has default values
    ``median_radius=3``, ``numpass=2``. However, from tests on multiple 1.5T
    and 3T data     from GE, Philips, Siemens, the most robust choice is
    ``median_radius=4``, ``numpass=4``.

    Parameters
    ----------
    input_volume : ndarray
        3D or 4D array of the brain volume.
    vol_idx : None or array, optional.
        1D array representing indices of ``axis=3`` of a 4D `input_volume`.
        None is only an acceptable input if ``input_volume`` is 3D.
    median_radius : int
        Radius (in voxels) of the applied median filter (default: 4).
    numpass: int
        Number of pass of the median filter (default: 4).
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the
        bounding box defined by the masked data. Should be on if DWI is
        upsampled to 1x1x1 resolution. (default: False).

    dilate : None or int, optional
        number of iterations for binary dilation

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask

    Notes
    -----
    Copyright (C) 2011, the scikit-image team
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in
        the documentation and/or other materials provided with the
        distribution.
     3. Neither the name of skimage nor the names of its contributors may be
        used to endorse or promote products derived from this software without
        specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
    """
    if len(input_volume.shape) == 4:
        if vol_idx is not None:
            b0vol = np.mean(input_volume[..., tuple(vol_idx)], axis=3)
        else:
            raise ValueError("For 4D images, must provide vol_idx input")
    else:
        b0vol = input_volume.copy()
    # Make a mask using a multiple pass median filter and histogram
    # thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = mask > thresh

    if dilate is not None:
        cross = generate_binary_structure(3, 1)
        mask = binary_dilation(mask, cross, iterations=dilate)

    # Auto crop the volumes using the mask as input_volume for bounding box
    # computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)
    return maskedvolume, mask
Exemple #54
0
    def identify_sources(self):
        """Create a master coordinate list of sources identified in the specified total detection product image
        """
        # read in sci, wht extensions of drizzled product
        image = self.image.data.copy()

        # Estimate FWHM from image sources
        # Background statistics need to be computed prior to subtracting background from image
        bkg_sigma = mad_std(image, ignore_nan=True)
        detect_sources_thresh = self.param_dict["dao"]["bkgsig_sf"] * bkg_sigma

        # Input image will be background subtracted using pre-computed background, unless
        # specified explicitly by the user
        if self.param_dict["dao"]["simple_bkg"]:
            self.bkg_used = np.nanmedian(image)
            image -= self.bkg_used
        else:
            # Estimate background
            self.bkg_used = self.image.bkg.background
            image -= self.bkg_used

        segm = detect_sources(image,
                              detect_sources_thresh,
                              npixels=self.param_dict["sourcex"]["source_box"],
                              filter_kernel=self.image.kernel)
        cat = source_properties(image, segm)
        source_table = cat.to_table()
        smajor_sigma = source_table['semimajor_axis_sigma'].mean().value
        source_fwhm = smajor_sigma * gaussian_sigma_to_fwhm
        if not self.tp_sources:
            # Report configuration values to log
            log.info("{}".format("=" * 80))
            log.info("")
            log.info("Point-source finding settings")
            log.info("Total Detection Product - Input Parameters")
            log.info("INPUT PARAMETERS")
            log.info("{}: {}".format("self.param_dict['dao']['bkgsig_sf']",
                                     self.param_dict["dao"]["bkgsig_sf"]))
            log.info("{}: {}".format(
                "self.param_dict['dao']['kernel_sd_aspect_ratio']",
                self.param_dict['dao']['kernel_sd_aspect_ratio']))
            log.info("{}: {}".format("self.param_dict['dao']['simple_bkg']",
                                     self.param_dict['dao']['simple_bkg']))
            log.info("{}: {}".format("self.image.bkg_rms_mean",
                                     self.image.bkg_rms_mean))
            log.info("{}: {}".format("self.image.bkg_rms_mean",
                                     self.image.bkg_rms_mean))
            log.info("{}: {}".format(
                "self.param_dict['sourcex']['source_box']",
                self.param_dict["sourcex"]["source_box"]))
            log.info("\nDERIVED PARAMETERS")
            log.info("{}: {}".format("bkg_sigma", bkg_sigma))
            log.info("{}: {}".format("detect_sources_thresh",
                                     detect_sources_thresh))
            log.info("{}: {}".format("smajor_sigma", smajor_sigma))
            log.info("{}: {}".format("source_fwhm", source_fwhm))
            log.info("")
            log.info("{}".format("=" * 80))

            # find ALL the sources!!!
            log.info("DAOStarFinder(fwhm={}, threshold={}, ratio={})".format(
                source_fwhm, self.image.bkg_rms_mean,
                self.param_dict['dao']['kernel_sd_aspect_ratio']))
            daofind = DAOStarFinder(
                fwhm=source_fwhm,
                threshold=self.image.bkg_rms_mean,
                ratio=self.param_dict['dao']['kernel_sd_aspect_ratio'])

            # create mask to reject any sources located less than 10 pixels from a image/chip edge
            wht_image = self.image.data.copy()
            binary_inverted_wht = np.where(wht_image == 0, 1, 0)
            exclusion_mask = ndimage.binary_dilation(binary_inverted_wht,
                                                     iterations=10)

            sources = daofind(image, mask=exclusion_mask)

            for col in sources.colnames:
                sources[
                    col].info.format = '%.8g'  # for consistent table output

            self.sources = sources

        # if processing filter product, use sources identified by parent total drizzle product identify_sources() run
        if self.tp_sources:
            self.sources = self.tp_sources['aperture']['sources']
    stellarMask = (stellarMask > 0.01)

    # Recombine the nebular and stellar components
    fgdRegion = np.logical_or(nebularMask, stellarMask)

    # Return the flux-bright pixels to the user
    return fgdRegion


################################################################################

# Read in the Kokopelli Mask
kokopelliMask = ai.reduced.ReducedScience.read('kokopelliMask.fits')

# Dilate the mask in order to be more conservative.
kokopelliMask.data = ndimage.binary_dilation(kokopelliMask.data,
                                             iterations=8).astype(int)

# Construct the 2MASS masks and save to disk
# Read in all the 2MASS images and store them in a dictionary for quick reference
TMASS_Hfiles = np.array(glob.glob(os.path.join(TMASSdir, '*H.fits')))
TMASS_Kfiles = np.array(glob.glob(os.path.join(TMASSdir, '*Ks.fits')))

# Read in the 2MASS images
TMASS_HimgList = [ai.reduced.ReducedScience.read(f) for f in TMASS_Hfiles]
TMASS_KimgList = [ai.reduced.ReducedScience.read(f) for f in TMASS_Kfiles]

# Convert the images to "background masks"
for img in TMASS_HimgList:
    # Construct the output name for this mask
    base = os.path.basename(img.filename)
    targetMask = base.split('.')[0] + '_mask.fits'
Exemple #56
0
def lacosmic(data, contrast, cr_threshold, neighbor_threshold,
             error=None, mask=None, background=None, effective_gain=None,
             readnoise=None, maxiter=4, border_mode='mirror'):
    """
    Remove cosmic rays from an astronomical image using the L.A.Cosmic
    algorithm.

    The `L.A.Cosmic algorithm
    <http://www.astro.yale.edu/dokkum/lacosmic/>`_ is based on Laplacian
    edge detection and is described in `van Dokkum (2001; PASP 113,
    1420)
    <https://ui.adsabs.harvard.edu/abs/2001PASP..113.1420V/abstract>`_.

    Parameters
    ----------
    data : array_like
        The 2D array of the image.

    contrast : float
        Contrast threshold between the Laplacian image and the
        fine-structure image.  If your image is critically sampled, use
        a value around 2.  If your image is undersampled (e.g., HST
        data), a value of 4 or 5 (or more) is more appropriate.  If your
        image is oversampled, use a value between 1 and 2.  For details,
        please see `PASP 113, 1420 (2001)
        <https://ui.adsabs.harvard.edu/abs/2001PASP..113.1420V/abstract>`_,
        which calls this parameter :math:`f_{\\mbox{lim}}`.  In
        particular, Figure 4 shows the approximate relationship between
        the ``contrast`` parameter and the full-width half-maximum (in
        pixels) of stars in your image.

    cr_threshold : float
        The Laplacian signal-to-noise ratio threshold for cosmic-ray
        detection.

    neighbor_threshold : float
        The Laplacian signal-to-noise ratio threshold for detection of
        cosmic rays in pixels neighboring the initially-identified
        cosmic rays.

    error : array_like, optional
        The 1-sigma errors of the input ``data``.  If ``error`` is not
        input, then ``effective_gain`` and ``readnoise`` will be used to
        construct an approximate model of the ``error``.  If ``error``
        is input, it will override the ``effective_gain`` and
        ``readnoise`` parameters.  ``error`` must have the same shape as
        ``data``.

    mask : array_like (bool), optional
        A boolean mask, with the same shape as ``data``, where a `True`
        value indicates the corresponding element of ``data`` is masked.
        Masked pixels are ignored when identifying cosmic rays.  It is
        highly recommended that saturated stars be included in ``mask``.

    background : float or array_like, optional
        The background level previously subtracted from the input
        ``data``.  ``background`` may either be a scalar value or a 2D
        image with the same shape as the input ``data``.  If the input
        ``data`` has not been background subtracted, then set
        ``background=None`` (default).

    effective_gain : float, array-like, optional
        Ratio of counts (e.g., electrons or photons) to the units of
        ``data``.  For example, if your input ``data`` are in units of
        ADU, then ``effective_gain`` should represent electrons/ADU.  If
        your input ``data`` are in units of electrons/s then
        ``effective_gain`` should be the exposure time (or an exposure
        time map).  ``effective_gain`` and ``readnoise`` must be
        specified if ``error`` is not input.

    readnoise : float, optional
        The read noise (in electrons) in the input ``data``.
        ``effective_gain`` and ``readnoise`` must be specified if
        ``error`` is not input.

    maxiter : float, optional
        The maximum number of iterations.  The default is 4.  The
        routine will automatically exit if no additional cosmic rays are
        identified in an interation.  If the routine is still
        identifying cosmic rays after four iterations, then you are
        likely digging into sources (e.g., saturated stars) and/or the
        noise.  In that case, try inputing a ``mask`` or increasing the
        value of ``cr_threshold``.

    border_mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
        The mode in which the array borders are handled during
        convolution and median filtering.  For 'constant', the fill
        value is 0.  The default is 'mirror', which matches the original
        L.A.Cosmic algorithm.

    Returns
    -------
    cleaned_image : `~numpy.ndarray`
        The cosmic-ray cleaned image.

    crmask : `~numpy.ndarray` (bool)
        A mask image of the identified cosmic rays.  Cosmic-ray pixels
        have a value of `True`.
    """

    block_size = 2.0
    kernel = np.array([[0.0, -1.0, 0.0], [-1.0, 4.0, -1.0], [0.0, -1.0, 0.0]])

    clean_data = data.copy()
    if background is not None:
        clean_data += background
    final_crmask = np.zeros(data.shape, dtype=bool)

    if error is not None:
        if data.shape != error.shape:
            raise ValueError('error and data must have the same shape')
    clean_error_image = error

    ncosmics, ncosmics_tot = 0, 0
    for iteration in range(maxiter):
        sampled_img = block_replicate(clean_data, block_size)
        convolved_img = ndimage.convolve(sampled_img, kernel,
                                         mode=border_mode).clip(min=0.0)
        laplacian_img = block_reduce(convolved_img, block_size)

        if clean_error_image is None:
            if effective_gain is None or readnoise is None:
                raise ValueError('effective_gain and readnoise must be '
                                 'input if error is not input')
            med5_img = ndimage.median_filter(clean_data, size=5,
                                             mode=border_mode).clip(min=1.e-5)
            error_image = (np.sqrt(effective_gain*med5_img + readnoise**2) /
                           effective_gain)
        else:
            error_image = clean_error_image

        snr_img = laplacian_img / (block_size * error_image)
        # this is used to remove extended structures (larger than ~5x5)
        snr_img -= ndimage.median_filter(snr_img, size=5, mode=border_mode)

        # used to remove compact bright objects
        med3_img = ndimage.median_filter(clean_data, size=3, mode=border_mode)
        med7_img = ndimage.median_filter(med3_img, size=7, mode=border_mode)
        finestruct_img = ((med3_img - med7_img) / error_image).clip(min=0.01)

        cr_mask1 = snr_img > cr_threshold
        # NOTE: to follow the paper exactly, this condition should be
        # "> contrast * block_size".  "lacos_im.cl" uses simply "> contrast"
        cr_mask2 = (snr_img / finestruct_img) > contrast
        cr_mask = cr_mask1 * cr_mask2
        if mask is not None:
            cr_mask = np.logical_and(cr_mask, ~mask)

        # grow cosmic rays by one pixel and check in snr_img
        selem = np.ones((3, 3))
        neigh_mask = ndimage.binary_dilation(cr_mask, selem)
        cr_mask = cr_mask1 * neigh_mask
        # now grow one more pixel and lower the detection threshold
        neigh_mask = ndimage.binary_dilation(cr_mask, selem)
        cr_mask = (snr_img > neighbor_threshold) * neigh_mask

        # previously unknown cosmic rays found in this iteration
        crmask_new = np.logical_and(~final_crmask, cr_mask)
        ncosmics = np.count_nonzero(crmask_new)

        final_crmask = np.logical_or(final_crmask, cr_mask)
        ncosmics_tot += ncosmics
        log.info('Iteration {0}: Found {1} cosmic-ray pixels, '
                 'Total: {2}'.format(iteration + 1, ncosmics, ncosmics_tot))
        if ncosmics == 0:
            if background is not None:
                clean_data -= background
            return clean_data, final_crmask
        clean_data = _clean_masked_pixels(clean_data, final_crmask, size=5,
                                          exclude_mask=mask)

    if background is not None:
        clean_data -= background
    return clean_data, final_crmask
Exemple #57
0
def predict(args):

    if not Path(args.save_path).exists():
        os.mkdir(args.save_path)

    for id in xrange(70):
        print('-' * 30)
        print('Loading model and preprocessing test data...' + str(id))
        print('-' * 30)
        model = dense_rnn_net(args)
        model.load_weights(args.model_weight)
        sgd = SGD(lr=1e-2, momentum=0.9, nesterov=True)
        model.compile(optimizer=sgd, loss=[weighted_crossentropy])

        #  load data
        img_test, img_test_header = load(args.data + str(id) + '.nii')
        img_test -= args.mean

        #  load liver mask
        mask, mask_header = load(args.liver_path + str(id) + '-ori.nii')
        mask[mask == 2] = 1
        mask = ndimage.binary_dilation(mask, iterations=1).astype(mask.dtype)
        index = np.where(mask == 1)
        mini = np.min(index, axis=-1)
        maxi = np.max(index, axis=-1)

        print('-' * 30)
        print('Predicting masks on test data...' + str(id))
        print('-' * 30)
        score1, score2 = predict_tumor_inwindow(model, img_test, 3, mini, maxi,
                                                args)
        K.clear_session()

        result1 = score1
        result2 = score2
        result1[result1 >= args.thres_liver] = 1
        result1[result1 < args.thres_liver] = 0
        result2[result2 >= args.thres_tumor] = 1
        result2[result2 < args.thres_tumor] = 0
        result1[result2 == 1] = 1

        print('-' * 30)
        print('Postprocessing on mask ...' + str(id))
        print('-' * 30)

        #  preserve the largest liver
        Segmask = result2
        box = []
        [liver_res, num] = measure.label(result1, return_num=True)
        region = measure.regionprops(liver_res)
        for i in range(num):
            box.append(region[i].area)
        label_num = box.index(max(box)) + 1
        liver_res[liver_res != label_num] = 0
        liver_res[liver_res == label_num] = 1

        #  preserve the largest liver
        mask = ndimage.binary_dilation(mask, iterations=1).astype(mask.dtype)
        box = []
        [liver_labels, num] = measure.label(mask, return_num=True)
        region = measure.regionprops(liver_labels)
        for i in range(num):
            box.append(region[i].area)
        label_num = box.index(max(box)) + 1
        liver_labels[liver_labels != label_num] = 0
        liver_labels[liver_labels == label_num] = 1
        liver_labels = ndimage.binary_fill_holes(liver_labels).astype(int)

        #  preserve tumor within ' largest liver' only
        Segmask = Segmask * liver_labels
        Segmask = ndimage.binary_fill_holes(Segmask).astype(int)
        Segmask = np.array(Segmask, dtype='uint8')
        liver_res = np.array(liver_res, dtype='uint8')
        liver_res = ndimage.binary_fill_holes(liver_res).astype(int)
        liver_res[Segmask == 1] = 2
        liver_res = np.array(liver_res, dtype='uint8')
        save(liver_res,
             args.save_path + 'test-segmentation-' + str(id) + '.nii',
             img_test_header)

        del Segmask, liver_labels, mask, region, label_num, liver_res
                out_cut[np.nonzero(out_cut <= threshold)] = 0.
                out_cut[np.nonzero(out_cut > threshold)] = 1.

                out_cut, nr_objects = ndimage.label(out_cut)

                for ii in range(1, nr_objects + 1):
                    if (out_cut[out_cut == ii].sum() /
                            ii) < SMALL_OBJ_THRESHOLD:
                        out_cut[np.nonzero(out_cut == ii)] = 0.

                out_cut[np.nonzero(out_cut != 0)] = 1.

                ## fill
                out_cut = ndimage.binary_fill_holes(out_cut).astype(
                    out_cut.dtype)
                out_cut = ndimage.binary_dilation(
                    out_cut, iterations=2).astype(out_cut.dtype)
                postproc = '_fill_dilation2'

                imsave(model_name + '_out_all/' + image_id + '.png', out_cut)

                rle = mask_to_rle(out_cut, width, height)
                sublist.append([image_id, rle])

            else:
                rle = " -1"
                sublist.append([image_id, rle])
        else:
            rle = " -1"
            sublist.append([image_id, rle])

    submission_df = pd.DataFrame(sublist, columns=sample_df.columns.values)
Exemple #59
0
def generate_mask(hdata, mask_type, cstk, pos, z, new_mask, iteration, md):
    if new_mask == False:
        iteration = 1
    if iteration == 0:
        if mask_type == False:
            mask = cstk[:, :, 0]
            mask = mask == 0
        elif mask_type == 'nuclear':
            img = md.stkread(Position=pos, Zindex=z, Channel='DeepBlue')
            thresh = threshold_local(img[:, :, 0], 325, offset=0)
            binary = img[:, :, 0] > thresh
            erode = ndimage.binary_erosion(binary)
            remove = remove_small_objects(erode, min_size=500)
            fill = ndimage.binary_fill_holes(remove)
            dialate = ndimage.binary_dilation(fill, iterations=50)
            mask = ndimage.binary_fill_holes(dialate)
            hdata.add_and_save_data(mask, pos, z, 'mask')
        elif mask_type == 'spots':
            stk = copy.copy(cstk)
            img = np.max(stk, axis=2)
            blurr = ndimage.gaussian_filter(img, 7)
            thresh = np.percentile(blurr, 90)
            binary = blurr > thresh
            fill = ndimage.binary_dilation(binary, iterations=2)
            remove = remove_small_objects(fill, min_size=10000)
            fill = ndimage.binary_dilation(remove, iterations=20)
            mask = ndimage.binary_fill_holes(fill)
            hdata.add_and_save_data(mask, pos, z, 'mask')
    else:
        if mask_type == False:
            mask = cstk[:, :, 0]
            mask = mask == 0
        elif mask_type == 'nuclear':
            if os.path.exists(
                    os.path.join(
                        hdata.base_path,
                        hdata.generate_fname(pos, z, 'mask', sep="_z_"))):
                mask = hdata.load_data(pos, z, 'mask')
                mask = mask == 1
            else:
                img = md.stkread(Position=pos, Zindex=z, Channel='DeepBlue')
                thresh = threshold_local(img[:, :, 0], 325, offset=0)
                binary = img[:, :, 0] > thresh
                erode = ndimage.binary_erosion(binary)
                remove = remove_small_objects(erode, min_size=500)
                fill = ndimage.binary_fill_holes(remove)
                dialate = ndimage.binary_dilation(fill, iterations=50)
                mask = ndimage.binary_fill_holes(dialate)
                hdata.add_and_save_data(mask, pos, z, 'mask')
        elif mask_type == 'spots':
            if os.path.exists(
                    os.path.join(
                        hdata.base_path,
                        hdata.generate_fname(pos, z, 'mask', sep="_z_"))):
                mask = hdata.load_data(pos, z, 'mask')
                mask = mask == 1
            else:
                stk = copy.copy(cstk)
                img = np.max(stk, axis=2)
                blurr = ndimage.gaussian_filter(img, 7)
                thresh = np.percentile(blurr, 90)
                binary = blurr > thresh
                fill = ndimage.binary_dilation(binary, iterations=2)
                remove = remove_small_objects(fill, min_size=10000)
                fill = ndimage.binary_dilation(remove, iterations=20)
                mask = ndimage.binary_fill_holes(fill)
                hdata.add_and_save_data(mask, pos, z, 'mask')
    return mask
def shapeawewm(mask, sigma):
    diststeps = 10000
    mask = mask.astype('float')
    wc = balancewm(mask)
    binimage = (mask == 1).astype('float')

    cells, cellscount = ndimage.measurements.label(binimage)
    chull = np.zeros_like(mask)
    # convex hull of each object
    for ci in range(1, cellscount + 1):
        I = (cells == ci).astype('float')
        R = convex_hull_image(I) - I
        R = ndimage.binary_opening(R, structure=np.ones(
            (3, 3))).astype('float')
        R = ndimage.binary_dilation(R, structure=np.ones(
            (3, 3))).astype('float')
        chull += R

    # distance transform to object skeleton
    skcells = thin(binimage)
    dtcells = ndimage.distance_transform_edt(skcells != 1)
    border = binimage - ndimage.binary_erosion(
        input=(binimage), structure=np.ones(
            (3, 3)), iterations=1).astype('float')
    tau = np.max(dtcells[border == 1]) + 0.1
    dtcells = np.abs(1 - dtcells * border / tau) * border

    # distance transform to convex hull skeleton
    skchull = thin(chull)
    dtchull = ndimage.distance_transform_edt(skchull != 1)
    border = chull - ndimage.binary_erosion(
        input=(chull), structure=np.ones((3, 3)), iterations=1).astype('float')
    dtchull = np.abs(1 - dtchull * border / tau) * border

    # maximum border
    saw = np.concatenate(
        (dtcells[:, :, np.newaxis], dtchull[:, :, np.newaxis]), 2)
    saw = np.max(saw, 2)
    saw /= np.max(saw)

    # propagate contour values inside the objects
    prop = binimage + chull
    prop[prop > 1] = 1
    prop = ndimage.binary_erosion(input=(prop),
                                  structure=np.ones((3, 3)),
                                  iterations=1).astype('float')
    current_saw = saw

    for i in range(20):
        tprop = ndimage.binary_erosion(input=(prop),
                                       structure=np.ones((3, 3)),
                                       iterations=1).astype('float')
        border = prop - tprop
        prop = tprop

        x1, y1 = np.where(border != 0)
        x2, y2 = np.where(current_saw != 0)

        if x1.size == 0 or x2.size == 0: break

        tsaw = np.zeros_like(saw)
        for a in range(0, x1.size, diststeps):
            minl = np.min(np.array([diststeps + a - 1, x1.size - 1])) + 1
            dis = cdist(
                np.vstack((x2, y2)).transpose(),
                np.vstack((x1[a:minl], y1[a:minl])).transpose())
            ind = np.argmin(dis, axis=0)
            tsaw[x1[a:minl], y1[a:minl]] = current_saw[x2[ind], y2[ind]]

        saw = np.concatenate((saw[:, :, np.newaxis], tsaw[:, :, np.newaxis]),
                             2)
        saw = np.max(saw, 2)
        saw = ndimage.filters.gaussian_filter(saw, sigma)
        saw /= np.max(saw)
        current_saw = saw * (border != 0).astype('float')

    saw = saw + wc + 1
    return saw