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 = (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
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 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
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))
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
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
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
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
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)
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 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)
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()
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)
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
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)
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)