Beispiel #1
0
def test_close_holes_simple():
    img = np.zeros((64,64),bool)
    img[16:48,16:48] = True
    holed =  (img - mahotas.erode(mahotas.erode(img)))
    assert np.all( mahotas.close_holes(holed) == img)
    holed[12,12] = True
    img[12,12] = True
    assert np.all( mahotas.close_holes(holed) == img)
    assert sys.getrefcount(holed) == 2
Beispiel #2
0
def test_close_holes_simple():
    img = np.zeros((64, 64), bool)
    img[16:48, 16:48] = True
    holed = (img - mahotas.erode(mahotas.erode(img)))
    assert np.all(mahotas.close_holes(holed) == img)
    holed[12, 12] = True
    img[12, 12] = True
    assert np.all(mahotas.close_holes(holed) == img)
    assert sys.getrefcount(holed) == 2
def test_close_holes_simple():
    img = np.zeros((64, 64), bool)
    img[16:48, 16:48] = True
    holed = np.logical_xor(img, mahotas.erode(mahotas.erode(img)))
    assert np.all(mahotas.close_holes(holed) == img)
    holed[12, 12] = True
    img[12, 12] = True
    assert np.all(mahotas.close_holes(holed) == img)
    if hasattr(sys, 'getrefcount'):
        assert sys.getrefcount(holed) == 2
Beispiel #4
0
def main(mask, plot=False):
    '''Fills holes in connected pixel components.

    Parameters
    ----------
    mask: numpy.ndarray[numpy.bool]
        binary image that should filled
    plot: bool, optional
        whether a plot should be generated (default: ``False``)

    Returns
    -------
    jtmodules.fill.Output[Union[numpy.ndarray, str]]

    '''
    filled_mask = mh.close_holes(mask, np.ones((3, 3), bool))

    if plot:
        from jtlib import plotting
        plots = [
            plotting.create_mask_image_plot(mask, 'ul'),
            plotting.create_mask_image_plot(filled_mask, 'ur')
        ]
        figure = plotting.create_figure(plots, title='Labeled image')
    else:
        figure = str()

    return Output(filled_mask, figure)
Beispiel #5
0
def optic_disk_detect_3(img):
    '''
    Method that seems to work well with DIARETDB1 database.
    '''

    hsi = rgb_to_hsi(img)
    intensity = hsi[:, :, 2].copy()
    #plt.axis('off'); show_image(intensity)
    #i_sp = add_salt_and_pepper(intensity, 0.005)
    i_med = mh.median_filter(intensity)    # use Wiener filter instead?
    i_clahe = skimage.exposure.equalize_adapthist(i_med)
    #plt.axis('off'); show_image(i_clahe)
    seeds = (i_clahe > 0.85)
    seeds = skimage.morphology.remove_small_objects(seeds, min_size=300, connectivity=2)
    #plt.axis('off'); show_image(seeds)
    optic_disk_map = region_growing_1(i_clahe, radius=3, tol1=0.1, tol2=0.2, tol3=0.2, seeds=seeds)
    optic_disk_map += 1
    #plt.axis('off'); show_image(optic_disk_map)

    _cl_areas = cl_areas(optic_disk_map)
    print _cl_areas
    optic_disk_map = leave_segments_by_mask(optic_disk_map,
                                            (8000 < _cl_areas) & (_cl_areas < 30000))

    #optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=500, connectivity=2)
    optic_disk_map = mh.close_holes(mh.close(optic_disk_map, Bc=np.ones((10, 10))))
    #optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=5000, connectivity=2)
    if np.all(optic_disk_map == 0):
        print 'Disk not found'
    return optic_disk_map
Beispiel #6
0
def main(mask, plot=False):
    '''Fills holes in connected pixel components.

    Parameters
    ----------
    mask: numpy.ndarray[numpy.bool]
        binary image that should filled
    plot: bool, optional
        whether a plot should be generated (default: ``False``)

    Returns
    -------
    jtmodules.fill.Output[Union[numpy.ndarray, str]]

    '''
    filled_mask = mh.close_holes(mask, np.ones((3, 3), bool))

    if plot:
        from jtlib import plotting
        plots = [
            plotting.create_mask_image_plot(mask, 'ul'),
            plotting.create_mask_image_plot(filled_mask, 'ur')
        ]
        figure = plotting.create_figure(plots, title='Labeled image')
    else:
        figure = str()

    return Output(filled_mask, figure)
def segment_layer(filename, params):
	'''
	Segment one layer in a stack
	'''
	#extract pixel size in xy and z
	xsize, zsize = extract_zoom(params.folder)

	#load image
	img = tifffile.imread(params.inputfolder + params.folder + filename)

	#normalize image
	img = ndimage.median_filter(img, 3)
	per_low = np.percentile(img, 5)
	img[img < per_low] = per_low
	img = img - img.min()

	per_high = np.percentile(img, 99)
	img[img > per_high] = per_high
	img = img*255./img.max()


	imgf = ndimage.gaussian_filter(img*1., 30./xsize).astype(np.uint8)

	kmask = (imgf > mahotas.otsu(imgf.astype(np.uint8)))*255.

	sizefactor = 10
	small = ndimage.interpolation.zoom(kmask, 1./sizefactor)	#scale the image to a smaller size

	rad = int(300./xsize)

	small_ext = np.zeros([small.shape[0] + 4*rad, small.shape[1] + 4*rad])
	small_ext[2*rad : 2*rad + small.shape[0], 2*rad : 2*rad + small.shape[1]] = small

	small_ext = mahotas.close(small_ext.astype(np.uint8), mahotas.disk(rad))
	small = small_ext[2*rad : 2*rad + small.shape[0], 2*rad : 2*rad + small.shape[1]]
	small = mahotas.close_holes(small)*1.			
	small = small*255./small.max()

	kmask = ndimage.interpolation.zoom(small, sizefactor)	#scale back to normal size
	kmask = normalize(kmask)
	kmask = (kmask > mahotas.otsu(kmask.astype(np.uint8)))*255.	#remove artifacts of interpolation

	if np.median(imgf[np.where(kmask > 0)]) < (np.median(imgf[np.where(kmask == 0)]) + 1)*3:
		kmask = np.zeros_like(kmask)


	#save indices of the kidney mask
#	ind = np.where(kmask > 0)
#	ind = np.array(ind)
#	np.save(params.inputfolder + '../segmented/masks/' + params.folder + filename[:-4] + '.npy', ind)

	#save outlines
	im = np.zeros([img.shape[0], img.shape[1], 3])
	img = tifffile.imread(params.inputfolder + params.folder + filename)
	im[:,:,0] = im[:,:,1] = im[:,:,2] = np.array(img)
	output = overlay(kmask, im, (255,0,0), borders = True)
	tifffile.imsave(params.inputfolder + '../segmented/outlines/' + params.folder + filename[:-4] + '.tif', (output).astype(np.uint8))
Beispiel #8
0
def tissue_region_from_rgb(_img, _min_area=150, _g_th=None):
    """
    TISSUE_REGION_FROM_RGB detects the region(s) of the image containing the
    tissue. The original image is supposed to represent a haematoxylin-eosin
    -stained pathology slide.
    
    The main purpose of this function is to detect the parts of a large image
    which most probably contain tissue material, and to discard the background.
    
    Usage:
        tissue_mask = tissue_from_rgb(img, _min_area=150, _g_th=None)
        
    Args:
        img (numpy.ndarray): the original image in RGB color space
        _min_area (int, default: 150): any object with an area smaller than 
            the indicated value, will be discarded
        _g_th (int, default: None): the processing is done on the GREEN channel
            and all pixels below _g_th are considered candidates for "tissue
            pixels". If no value is given to _g_th, one is computed by K-Means
            clustering (K=2), and is returned.
        
    Returns:
        numpy.ndarray: a binary image containing the mask of the regions
            considered to represent tissue fragments
        int: threshold used for GREEN channel
    """
    
    if _g_th is None:
        # Apply vector quantization to remove the "white" background - work in the
        # green channel:
        vq = MiniBatchKMeans(n_clusters=2)
        _g_th = int(np.round(0.95 * np.max(vq.fit(_G(_img).reshape((-1,1)))
                                           .cluster_centers_.squeeze())))
    
    mask = _G(_img) < _g_th

    skm.binary_closing(mask, skm.disk(3), out=mask)
    mask = img_as_bool(mask)
    mask = skm.remove_small_objects(mask, min_size=_min_area, in_place=True)


    # Some hand-picked rules:
    # -at least 5% H and E
    # -at most 25% background
    # for a region to be considered tissue

    h, e, b = rgb2he2(_img)

    mask &= (h > np.percentile(h, 5)) | (e > np.percentile(e, 5))
    mask &= (b < np.percentile(b, 50))               # at most at 50% of "other components"

    mask = mh.close_holes(mask)

    return img_as_bool(mask), _g_th
Beispiel #9
0
def tissue_region_from_rgb(_img, _min_area=150, _g_th=None):
    """
    TISSUE_REGION_FROM_RGB detects the region(s) of the image containing the
    tissue. The original image is supposed to represent a haematoxylin-eosin
    -stained pathology slide.
    
    The main purpose of this function is to detect the parts of a large image
    which most probably contain tissue material, and to discard the background.
    
    Usage:
        tissue_mask = tissue_from_rgb(img, _min_area=150, _g_th=None)
        
    Args:
        img (numpy.ndarray): the original image in RGB color space
        _min_area (int, default: 150): any object with an area smaller than 
            the indicated value, will be discarded
        _g_th (int, default: None): the processing is done on the GREEN channel
            and all pixels below _g_th are considered candidates for "tissue
            pixels". If no value is given to _g_th, one is computed by K-Means
            clustering (K=2), and is returned.
        
    Returns:
        numpy.ndarray: a binary image containing the mask of the regions
            considered to represent tissue fragments
        int: threshold used for GREEN channel
    """

    if _g_th is None:
        # Apply vector quantization to remove the "white" background - work in the
        # green channel:
        vq = MiniBatchKMeans(n_clusters=2)
        _g_th = int(
            np.round(0.95 * np.max(
                vq.fit(_G(_img).reshape((-1, 1))).cluster_centers_.squeeze())))

    mask = _G(_img) < _g_th

    skm.binary_closing(mask, skm.disk(3), out=mask)
    mask = img_as_bool(mask)
    mask = skm.remove_small_objects(mask, min_size=_min_area, in_place=True)

    # Some hand-picked rules:
    # -at least 5% H and E
    # -at most 25% background
    # for a region to be considered tissue

    h, e, b = rgb2he2(_img)

    mask &= (h > np.percentile(h, 5)) | (e > np.percentile(e, 5))
    mask &= (b < np.percentile(b, 50))  # at most at 50% of "other components"

    mask = mh.close_holes(mask)

    return img_as_bool(mask), _g_th
Beispiel #10
0
def nuclei_regions(comp_map):
    """
    NUCLEI_REGIONS: extract "support regions" for nuclei. This function
    expects as input a "tissue components map" (as returned, for example,
    by segm.tissue_components) where values of 1 indicate pixels having
    a color corresponding to nuclei.
    It returns a set of compact support regions corresponding to the
    nuclei.


    :param comp_map: numpy.ndarray
       A mask identifying different tissue components, as obtained
       by classification in RGB space. The value 0

       See segm.tissue.tissue_components()

    :return:
    """
    # Deprecated:...
    # img_hem, _ = rgb2he(img0, normalize=True)

    # img_hem = denoise_tv_bregman(img_hem, HE_OPTS['bregm'])

    # Get a mask of nuclei regions by unsupervised clustering:
    # Vector Quantization: background, mid-intensity Hem and high intensity Hem
    # -train the quantizer for 3 levels
    # vq = KMeans(n_clusters=3)
    # vq.fit(img_hem.reshape((-1,1)))
    # -the level of interest is the brightest:
    # k = np.argsort(vq.cluster_centers_.squeeze())[2]
    # mask_hem = (vq.labels_ == k).reshape(img_hem.shape)
    # ...end deprecated

    # Final mask:
    mask = (comp_map == 1)   # use the components classified by color

    # mask = morph.closing(mask, selem=HE_OPTS['strel1'])
    # mask = morph.opening(mask, selem=HE_OPTS['strel1'])
    # morph.remove_small_objects(mask, in_place=True)
    # mask = (mask > 0)

    mask = mahotas.close_holes(mask)
    morph.remove_small_objects(mask, in_place=True)

    dst  = mahotas.stretch(mahotas.distance(mask))
    Bc=np.ones((9,9))
    lmax = mahotas.regmax(dst, Bc=Bc)
    spots, _ = mahotas.label(lmax, Bc=Bc)
    regions = mahotas.cwatershed(lmax.max() - lmax, spots) * mask

    return regions
# end NUCLEI_REGIONS
Beispiel #11
0
def optic_disk_detect_2(img):
    hsi = rgb_to_hsi(img)
    intensity = hsi[:, :, 2].copy()
    i_sp = add_salt_and_pepper(intensity, 0.005)
    i_med = mh.median_filter(i_sp)
    i_clahe = skimage.exposure.equalize_adapthist(i_med)
    optic_disk_map = (i_clahe > 0.6) & (hsi[:, :, 1] < 0.3)
    #show_image(optic_disk_map)
    optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=500, connectivity=2)
    optic_disk_map = mh.close_holes(mh.close(optic_disk_map, Bc=np.ones((30, 30))))
    optic_disk_map = skimage.morphology.remove_small_objects(optic_disk_map, min_size=10000, connectivity=2)
    if np.all(optic_disk_map == 0):
        print 'Disk not found'
    return optic_disk_map
Beispiel #12
0
def segment_conidia(input_file, output_file):
    img = io.imread(input_file)
    img = img_as_float(img)
    img = filters.gaussian(img, 1)

    thresholded = img_as_ubyte(img > filters.threshold_otsu(img))
    thresholded = mahotas.close_holes(thresholded)

    distance = ndi.distance_transform_edt(thresholded)
    local_maxi = distance == morph.dilation(distance, morph.square(5))
    local_maxi[thresholded == 0] = 0
    markers = ndi.label(local_maxi)[0]

    labels = watershed(-distance, markers, mask=thresholded)
    tifffile.imsave(output_file, img_as_int(labels), compress=5)
Beispiel #13
0
def mahotas_clean_up_seg(input_jacobian,frame_num):
    import mahotas as mh
    dsk = mh.disk(7)
    thresh_r = 0.1
    thresh_g = 1
    size_cutoff = 200
    
    thresholded_jacobian = (np.int32(np.log(1+input_jacobian[frame_num][0])>thresh_r)+\
                            np.int32(np.log(1+input_jacobian[frame_num][1])>thresh_g))>0
    thresholded_jacobian = mh.close_holes(thresholded_jacobian)
    thresholded_jacobian = mh.erode(thresholded_jacobian,dsk)
    labeled = mh.label(thresholded_jacobian)[0]
    sizes = mh.labeled.labeled_size(labeled)
    too_small = np.where(sizes < size_cutoff)
    labeled = mh.labeled.remove_regions(labeled, too_small)
    thresholded_jacobian = labeled>0
    thresholded_jacobian = mh.dilate(thresholded_jacobian,dsk)
    return thresholded_jacobian
Beispiel #14
0
def mahotas_clean_up_seg(input_jacobian, frame_num):
    import mahotas as mh
    dsk = mh.disk(7)
    thresh_r = 0.1
    thresh_g = 1
    size_cutoff = 200

    thresholded_jacobian = (np.int32(np.log(1+input_jacobian[frame_num][0])>thresh_r)+\
                            np.int32(np.log(1+input_jacobian[frame_num][1])>thresh_g))>0
    thresholded_jacobian = mh.close_holes(thresholded_jacobian)
    thresholded_jacobian = mh.erode(thresholded_jacobian, dsk)
    labeled = mh.label(thresholded_jacobian)[0]
    sizes = mh.labeled.labeled_size(labeled)
    too_small = np.where(sizes < size_cutoff)
    labeled = mh.labeled.remove_regions(labeled, too_small)
    thresholded_jacobian = labeled > 0
    thresholded_jacobian = mh.dilate(thresholded_jacobian, dsk)
    return thresholded_jacobian
def segment_tissue2d(input_file, output_file, voxel_xy):
    # load image
    img = io.imread(input_file)

    # normalize image
    img = ndimage.median_filter(img, 3)
    img = img * 255. / img.max()

    ##segment kidney tissue

    sizefactor = 10.
    small = ndimage.interpolation.zoom(
        img, 1. / sizefactor)  # scale the image to a smaller size

    imgf = ndimage.gaussian_filter(small, 3. / voxel_xy)  # Gaussian filter
    median = np.percentile(imgf, 40)  # 40-th percentile for thresholding

    kmask = imgf > median * 1.5  # thresholding
    kmask = mahotas.dilate(kmask, mahotas.disk(5))
    kmask = mahotas.close_holes(kmask)  # closing holes
    kmask = mahotas.erode(kmask, mahotas.disk(5)) * 255

    # remove objects that are darker than 2*percentile
    l, n = ndimage.label(kmask)
    llist = np.unique(l)
    if len(llist) > 2:
        means = ndimage.mean(imgf, l, llist)
        bv = llist[np.where(means < median * 2)]
        ix = np.in1d(l.ravel(), bv).reshape(l.shape)
        kmask[ix] = 0

    kmask = ndimage.interpolation.zoom(kmask,
                                       sizefactor)  # scale back to normal size
    kmask = normalize(kmask)
    kmask = (kmask > mahotas.otsu(kmask.astype(np.uint8))
             )  # remove artifacts of interpolation

    tifffile.imsave(output_file, img_as_ubyte(kmask), compress=5)
Beispiel #16
0
    def addCell(self, eventTuple):
        if self.maskOn:
            if self.data.ndim == 2:
                self.aveData = self.data.copy()
            else:
                self.aveData = self.data.mean(axis=2)

            x, y = eventTuple
            localValue = self.currentMask[x, y]
            print str(self.mode) + " " + "x: " + str(x) + ", y: " + str(y) + ", mask val: " + str(localValue)

            # ensure mask is uint16
            self.currentMask = self.currentMask.astype("uint16")

            sys.stdout.flush()

            ########## NORMAL MODE
            if self.mode is None:
                if localValue > 0 and localValue != self.currentMaskNumber:
                    print "we are altering mask at at %d, %d" % (x, y)

                    # copy the old mask
                    newMask = self.currentMask.copy()

                    # make a labeled image of the current mask
                    labeledCurrentMask = mahotas.label(newMask)[0]
                    roiNumber = labeledCurrentMask[x, y]

                    # set that ROI to zero
                    newMask[labeledCurrentMask == roiNumber] = self.currentMaskNumber
                    newMask = newMask.astype("uint16")

                    self.listOfMasks.append(newMask)
                    self.currentMask = self.listOfMasks[-1]
                elif localValue > 0 and self.data.ndim == 3:
                    # update info panel
                    labeledCurrentMask = mahotas.label(self.currentMask.copy())[0]
                    roiNumber = labeledCurrentMask[x, y]
                    self.updateInfoPanel(ROI_number=roiNumber)

                elif localValue == 0:

                    xmin = int(x - self.diskSize)
                    xmax = int(x + self.diskSize)
                    ymin = int(y - self.diskSize)
                    ymax = int(y + self.diskSize)

                    sub_region_image = self.aveData[xmin:xmax, ymin:ymax].copy()
                    # threshold = mahotas.otsu(self.data[xmin:xmax, ymin:ymax].astype('uint16'))

                    # do a gaussian_laplacian filter to find the edges and the center

                    g_l = nd.gaussian_laplace(
                        sub_region_image, 1
                    )  # second argument is a free parameter, std of gaussian
                    g_l = mahotas.dilate(mahotas.erode(g_l >= 0))
                    g_l = mahotas.label(g_l)[0]
                    center = g_l == g_l[g_l.shape[0] / 2, g_l.shape[0] / 2]
                    # edges = mahotas.dilate(mahotas.dilate(mahotas.dilate(center))) - center

                    newCell = np.zeros_like(self.currentMask)
                    newCell[xmin:xmax, ymin:ymax] = center
                    newCell = mahotas.dilate(newCell)

                    if self.useNMF:
                        modes, thresh_modes, fit_data, this_cell, is_cell, nmf_limits = self.doLocalNMF(x, y, newCell)

                        for mode, mode_thresh, t, i in zip(modes, thresh_modes, this_cell, is_cell):
                            # need to place it in the right place
                            # have x and y
                            mode_width, mode_height = mode_thresh.shape
                            mode_thresh_fullsize = np.zeros_like(newCell)
                            mode_thresh_fullsize[
                                nmf_limits[0] : nmf_limits[1], nmf_limits[2] : nmf_limits[3]
                            ] = mode_thresh

                            # need to add all modes belonging to this cell first,
                            # then remove the ones nearby.

                            if i:
                                if t:
                                    valid_area = np.logical_and(
                                        mahotas.dilate(
                                            mahotas.dilate(mahotas.dilate(mahotas.dilate(newCell.astype(bool))))
                                        ),
                                        mode_thresh_fullsize,
                                    )
                                    newCell = np.logical_or(newCell.astype(bool), valid_area)
                                else:
                                    newCell = np.logical_and(
                                        newCell.astype(bool), np.logical_not(mahotas.dilate(mode_thresh_fullsize))
                                    )

                        newCell = mahotas.close_holes(newCell.astype(bool))
                        self.excludePixels(newCell, 2)

                    newCell = newCell.astype(self.currentMask.dtype)

                    # remove all pixels in and near current mask and filter for ROI size
                    newCell[mahotas.dilate(self.currentMask > 0)] = 0
                    newCell = self.excludePixels(newCell, 10)

                    newMask = (newCell * self.currentMaskNumber) + self.currentMask
                    newMask = newMask.astype("uint16")

                    self.listOfMasks.append(newMask.copy())
                    self.currentMask = newMask.copy()

            elif self.mode is "OGB":
                # build structuring elements
                se = pymorph.sebox()
                se2 = pymorph.sedisk(self.cellRadius, metric="city-block")
                seJunk = pymorph.sedisk(max(np.floor(self.cellRadius / 4.0), 1), metric="city-block")
                seExpand = pymorph.sedisk(self.diskSize, metric="city-block")

                # add a disk around selected point, non-overlapping with adjacent cells
                dilatedOrignal = mahotas.dilate(self.currentMask.astype(bool), Bc=se)
                safeUnselected = np.logical_not(dilatedOrignal)

                # tempMask is
                tempMask = np.zeros_like(self.currentMask, dtype=bool)
                tempMask[x, y] = True
                tempMask = mahotas.dilate(tempMask, Bc=se2)
                tempMask = np.logical_and(tempMask, safeUnselected)

                # calculate the area we should add to this disk based on % of a threshold
                cellMean = self.aveData[tempMask == 1.0].mean()
                allMeanBw = self.aveData >= (cellMean * float(self.contrastThreshold))

                tempLabel = mahotas.label(np.logical_and(allMeanBw, safeUnselected).astype(np.uint16))[0]
                connMeanBw = tempLabel == tempLabel[x, y]

                connMeanBw = np.logical_and(np.logical_or(connMeanBw, tempMask), safeUnselected).astype(np.bool)
                # erode and then dilate to remove sharp bits and edges

                erodedMean = mahotas.erode(connMeanBw, Bc=seJunk)
                dilateMean = mahotas.dilate(erodedMean, Bc=seJunk)
                dilateMean = mahotas.dilate(dilateMean, Bc=seExpand)

                modes, thresh_modes, fit_data, this_cell, is_cell, limits = self.doLocaNMF(x, y)

                newCell = np.logical_and(dilateMean, safeUnselected)
                newMask = (newCell * self.currentMaskNumber) + self.currentMask
                newMask = newMask.astype("uint16")

                self.listOfMasks.append(newMask.copy())
                self.currentMask = newMask.copy()

            ########## SQUARE MODE
            elif self.mode is "square":
                self.modeData.append((x, y))
                if len(self.modeData) == 2:
                    square_mask = np.zeros_like(self.currentMask)
                    xstart = self.modeData[0][0]
                    ystart = self.modeData[0][1]

                    xend = self.modeData[1][0]
                    yend = self.modeData[1][1]

                    square_mask[xstart:xend, ystart:yend] = 1

                    # check if square_mask interfers with current mask, if so, abort
                    if np.any(np.logical_and(square_mask, self.currentMask)):
                        return None

                    # add square_mask to mask
                    newMask = (square_mask * self.currentMaskNumber) + self.currentMask
                    newMask = newMask.astype("uint16")

                    self.listOfMasks.append(newMask)
                    self.currentMask = self.listOfMasks[-1]

                    # clear current mode data
                    self.clearModeData()

            ########## CIRCLE MODE
            elif self.mode is "circle":
                # make a strel and move it in place to make circle_mask
                if self.diskSize < 1:
                    return None

                if self.diskSize is 1:
                    se = np.ones((1, 1))
                elif self.diskSize is 2:
                    se = pymorph.secross(r=1)
                else:
                    se = pymorph.sedisk(r=(self.diskSize - 1))

                se_extent = int(se.shape[0] / 2)
                circle_mask = np.zeros_like(self.currentMask)
                circle_mask[x - se_extent : x + se_extent + 1, y - se_extent : y + se_extent + 1] = se * 1.0
                circle_mask = circle_mask.astype(bool)

                # check if circle_mask interfers with current mask, if so, abort
                if np.any(np.logical_and(circle_mask, mahotas.dilate(self.currentMask.astype(bool)))):
                    return None

                # add circle_mask to mask
                newMask = (circle_mask * self.currentMaskNumber) + self.currentMask
                newMask = newMask.astype("uint16")

                self.listOfMasks.append(newMask)
                self.currentMask = self.listOfMasks[-1]

            ########## POLY MODE
            elif self.mode is "poly":
                self.modeData.append((x, y))

            sys.stdout.flush()
            self.makeNewMaskAndBackgroundImage()
Beispiel #17
0
def test_close_holes_3d():
    'Close holes should raise exception with 3D inputs'
    f = np.random.rand(100,100,3) > .9
    mh.close_holes(f)
Beispiel #18
0
def expand_objects_watershed(seeds_image, background_image, intensity_image):
    '''Expands objects in `seeds_image` using a watershed transform
    on `intensity_image`.

    Parameters
    ----------
    seeds_image: numpy.ndarray[numpy.int32]
        objects that should be expanded
    background_image: numpy.ndarray[numpy.bool]
        regions in the image that should be considered background and should
        not be part of an object after expansion
    intensity_image: numpy.ndarray[Union[numpy.uint8, numpy.uint16]]
        grayscale image; pixel intensities determine how far individual
        objects are expanded

    Returns
    -------
    numpy.ndarray[numpy.int32]
        expanded objects
    '''
    # We compute the watershed transform using the seeds of the primary
    # objects and the additional seeds for the background regions. The
    # background regions will compete with the foreground regions and
    # thereby work as a stop criterion for expansion of primary objects.
    logger.info('apply watershed transform to expand objects')
    labels = seeds_image + background_image
    regions = mh.cwatershed(np.invert(intensity_image), labels)
    # Remove background regions
    n_objects = len(np.unique(seeds_image[seeds_image > 0]))
    regions[regions > n_objects] = 0

    # Ensure objects are separated
    lines = mh.labeled.borders(regions)
    regions[lines] = 0

    # Close holes in objects.
    foreground_mask = regions > 0
    holes = mh.close_holes(foreground_mask) - foreground_mask
    holes = mh.morph.dilate(holes)
    holes_labeled, n_holes = mh.label(holes)
    for i in range(1, n_holes+1):
        fill_value = np.unique(regions[holes_labeled == i])[-1]
        fill_value = fill_value[fill_value > 0][0]
        regions[holes_labeled == i] = fill_value

    # Remove objects that are obviously too small, i.e. smaller than any of
    # the seeds (this could happen when we remove certain parts of objects
    # after the watershed region growing)
    primary_sizes = mh.labeled.labeled_size(seeds_image)
    if len(primary_sizes) > 1:
        min_size = np.min(primary_sizes[1:]) + 1
        regions = mh.labeled.filter_labeled(regions, min_size=min_size)[0]

    # Remove regions that don't overlap with seed objects and assign
    # correct labels to the other regions, i.e. those of the corresponding seeds.
    logger.debug('relabel expanded objects according to their seeds')
    new_label_image, n_new_labels = mh.labeled.relabel(regions)
    lut = np.zeros(np.max(new_label_image)+1, new_label_image.dtype)
    for i in range(1, n_new_labels+1):
        orig_labels = seeds_image[new_label_image == i]
        orig_labels = orig_labels[orig_labels > 0]
        orig_count = np.bincount(orig_labels)
        orig_unique = np.where(orig_count)[0]
        if orig_unique.size == 1:
            lut[i] = orig_unique[0]
        elif orig_unique.size > 1:
            logger.warn(
                'objects overlap after expansion: %s',
                ', '.join(map(str, orig_unique))
            )
            lut[i] = np.where(orig_count == np.max(orig_count))[0][0]
    expanded_image = lut[new_label_image]

    # Ensure that seed objects are fully contained within expanded objects
    index = (seeds_image - expanded_image) > 0
    expanded_image[index] = seeds_image[index]

    return expanded_image
Beispiel #19
0
def segment_layer(filename, params):
    '''
	Segment one layer in a stack
	'''
    start = time.time()
    #extract pixel size in xy and z
    xsize, zsize = extract_zoom(params.folder)

    #load image
    img = tifffile.imread(params.inputfolder + params.folder + filename)

    #normalize image
    img = ndimage.median_filter(img, 3)
    img = img * 255. / img.max()

    ##segment kidney tissue

    sizefactor = 10.
    small = ndimage.interpolation.zoom(
        img, 1. / sizefactor)  #scale the image to a smaller size

    imgf = ndimage.gaussian_filter(small, 3. / xsize)  #Gaussian filter
    median = np.percentile(imgf, 40)  #40-th percentile for thresholding

    kmask = imgf > median * 1.5  #thresholding
    kmask = mahotas.dilate(kmask, mahotas.disk(5))
    kmask = mahotas.close_holes(kmask)  #closing holes
    kmask = mahotas.erode(kmask, mahotas.disk(5)) * 255

    #remove objects that are darker than 2*percentile
    l, n = ndimage.label(kmask)
    llist = np.unique(l)
    if len(llist) > 2:
        means = ndimage.mean(imgf, l, llist)
        bv = llist[np.where(means < median * 2)]
        ix = np.in1d(l.ravel(), bv).reshape(l.shape)
        kmask[ix] = 0

    kmask = ndimage.interpolation.zoom(kmask,
                                       sizefactor)  #scale back to normal size
    kmask = normalize(kmask)
    kmask = (kmask > mahotas.otsu(kmask.astype(
        np.uint8))) * 255.  #remove artifacts of interpolation

    #save indices of the kidney mask
    ind = np.where(kmask > 0)
    ind = np.array(ind)
    np.save(
        params.inputfolder + '../segmented/masks/kidney/' + params.folder +
        filename[:-4] + '.npy', ind)

    #segment glomeruli, if there is a kidney tissue
    if kmask.max() > 0:
        #remove all intensity variations larger than maximum radius of a glomerulus
        d = mahotas.disk(int(float(params.maxrad) / xsize))
        img = img - mahotas.open(img.astype(np.uint8), d)
        img = img * 255. / img.max()
        ch = img[np.where(kmask > 0)]

        #segment glomeruli by otsu thresholding	only if this threshold is higher than the 75-th percentile in the kidney mask
        t = mahotas.otsu(img.astype(np.uint8))

        if t > np.percentile(ch, 75) * 1.5:
            cells = img > t
            cells[np.where(kmask == 0)] = 0
            cells = mahotas.open(
                cells, mahotas.disk(int(float(params.minrad) / 2. / xsize)))

        else:
            cells = np.zeros_like(img)

    else:
        cells = np.zeros_like(img)

    #save indices of the glomeruli mask
    ind = np.where(cells > 0)
    ind = np.array(ind)
    np.save(
        params.inputfolder + '../segmented/masks/glomeruli/' + params.folder +
        filename[:-4] + '.npy', ind)
Beispiel #20
0
def test_close_holes_3d():
    'Close holes should raise exception with 3D inputs'
    f = np.random.rand(100, 100, 3) > .9
    with pytest.raises(ValueError):
        mh.close_holes(f)
Beispiel #21
0
def expand_objects_watershed(seeds_image, background_image, intensity_image):
    '''Expands objects in `seeds_image` using a watershed transform
    on `intensity_image`.

    Parameters
    ----------
    seeds_image: numpy.ndarray[numpy.int32]
        objects that should be expanded
    background_image: numpy.ndarray[numpy.bool]
        regions in the image that should be considered background and should
        not be part of an object after expansion
    intensity_image: numpy.ndarray[Union[numpy.uint8, numpy.uint16]]
        grayscale image; pixel intensities determine how far individual
        objects are expanded

    Returns
    -------
    numpy.ndarray[numpy.int32]
        expanded objects
    '''
    # We compute the watershed transform using the seeds of the primary
    # objects and the additional seeds for the background regions. The
    # background regions will compete with the foreground regions and
    # thereby work as a stop criterion for expansion of primary objects.
    logger.info('apply watershed transform to expand objects')
    labels = seeds_image + background_image
    regions = mh.cwatershed(np.invert(intensity_image), labels)
    # Remove background regions
    n_objects = len(np.unique(seeds_image[seeds_image > 0]))
    regions[regions > n_objects] = 0

    # Ensure objects are separated
    lines = mh.labeled.borders(regions)
    regions[lines] = 0

    # Close holes in objects.
    foreground_mask = regions > 0
    holes = mh.close_holes(foreground_mask) - foreground_mask
    holes = mh.morph.dilate(holes)
    holes_labeled, n_holes = mh.label(holes)
    for i in range(1, n_holes+1):
        fill_value = np.unique(regions[holes_labeled == i])[-1]
        fill_value = fill_value[fill_value > 0][0]
        regions[holes_labeled == i] = fill_value

    # Remove objects that are obviously too small, i.e. smaller than any of
    # the seeds (this could happen when we remove certain parts of objects
    # after the watershed region growing)
    primary_sizes = mh.labeled.labeled_size(seeds_image)
    if len(primary_sizes) > 1:
        min_size = np.min(primary_sizes[1:]) + 1
        regions = mh.labeled.filter_labeled(regions, min_size=min_size)[0]

    # Remove regions that don't overlap with seed objects and assign
    # correct labels to the other regions, i.e. those of the corresponding seeds.
    logger.debug('relabel expanded objects according to their seeds')
    new_label_image, n_new_labels = mh.labeled.relabel(regions)
    lut = np.zeros(np.max(new_label_image)+1, new_label_image.dtype)
    for i in range(1, n_new_labels+1):
        orig_labels = seeds_image[new_label_image == i]
        orig_labels = orig_labels[orig_labels > 0]
        orig_count = np.bincount(orig_labels)
        orig_unique = np.where(orig_count)[0]
        if orig_unique.size == 1:
            lut[i] = orig_unique[0]
        elif orig_unique.size > 1:
            logger.warn(
                'objects overlap after expansion: %s',
                ', '.join(map(str, orig_unique))
            )
            lut[i] = np.where(orig_count == np.max(orig_count))[0][0]
    expanded_image = lut[new_label_image]

    # Ensure that seed objects are fully contained within expanded objects
    index = (seeds_image - expanded_image) > 0
    expanded_image[index] = seeds_image[index]

    return expanded_image
Beispiel #22
0
def test_close_holes_3d():
    'Close holes should raise exception with 3D inputs'
    f = np.random.rand(100,100,3) > .9
    mh.close_holes(f)