Python scipy.ndimage.binary_closing() Examples
The following are 26
code examples of scipy.ndimage.binary_closing().
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example.
You may also want to check out all available functions/classes of the module
scipy.ndimage
, or try the search function
.
Example #1
Source File: test_ndimage.py From Computable with MIT License | 6 votes |
def test_binary_closing01(self): expected = [[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]] for type in self.types: data = numpy.array([[0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 1, 1, 0, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], type) out = ndimage.binary_closing(data) assert_array_almost_equal(out, expected)
Example #2
Source File: test_ndimage.py From Computable with MIT License | 6 votes |
def test_binary_closing02(self): struct = ndimage.generate_binary_structure(2, 2) expected = [[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]] for type in self.types: data = numpy.array([[1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 0, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]], type) out = ndimage.binary_closing(data, struct) assert_array_almost_equal(out, expected)
Example #3
Source File: volume.py From luna16 with BSD 2-Clause "Simplified" License | 6 votes |
def process_failure(name): name = name.replace("mask","truth") name2 = name.replace("truth","") image,_,_ = image_read_write.load_itk_image(name2) #image_cropped = image[:,120:420,60:460] image_mask = np.zeros(image.shape) center = 256 cc,rr = circle(center+20,center,160) image_mask[:,cc,rr] = 1 image[image>threshold]=0 image[image!=0]=1 image = image*image_mask #image_cropped[image_cropped>threshold]=0 #image_cropped[image_cropped!=0]=1 kernel20 = np.zeros((15,15)) cc,rr = circle(7,7,8) kernel20[cc,rr]=1 image = binary_closing(image, [kernel20],1) #image[:,:,:]=0 #image[:,120:420,60:460]=image_cropped truth,_,_ = image_read_write.load_itk_image(name) print evaluator.calculate_dice(image,truth,name) image = np.array(image,dtype=np.int8) #LoadImages.save_itk(image,name)
Example #4
Source File: test_ndimage.py From GraphicDesignPatternByPython with MIT License | 6 votes |
def test_binary_closing01(self): expected = [[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]] for type_ in self.types: data = numpy.array([[0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 1, 1, 0, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], type_) out = ndimage.binary_closing(data) assert_array_almost_equal(out, expected)
Example #5
Source File: test_ndimage.py From GraphicDesignPatternByPython with MIT License | 6 votes |
def test_binary_closing02(self): struct = ndimage.generate_binary_structure(2, 2) expected = [[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]] for type_ in self.types: data = numpy.array([[1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 0, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]], type_) out = ndimage.binary_closing(data, struct) assert_array_almost_equal(out, expected)
Example #6
Source File: line_seperate.py From chamanti_ocr with Apache License 2.0 | 6 votes |
def calc_hist(self, ): hist_ = np.sum(self.imgarr, axis=1).astype('float') hist_mean = np.mean(hist_) self.fft = abs(np.fft.rfft(hist_ - hist_mean)) max_harm = int(np.argmax(self.fft)) self.best_harmonic = self.ht // (1 + max_harm) assert max_harm > 0 self.closed = nd.binary_closing(self.imgarr, structure=np.ones((1, self.best_harmonic // 4))) self.hist = np.sum(self.closed, axis=1).astype("float") self.gauss_hist = nd.filters.gaussian_filter1d( self.hist, self.best_harmonic / 16, mode='constant', cval=0, truncate=2.0) self.d_gauss_hist = nd.filters.convolve(self.gauss_hist, [-1, 0, 1])
Example #7
Source File: utils.py From lungmask with GNU General Public License v3.0 | 6 votes |
def simple_bodymask(img): maskthreshold = -500 oshape = img.shape img = ndimage.zoom(img, 128/np.asarray(img.shape), order=0) bodymask = img > maskthreshold bodymask = ndimage.binary_closing(bodymask) bodymask = ndimage.binary_fill_holes(bodymask, structure=np.ones((3, 3))).astype(int) bodymask = ndimage.binary_erosion(bodymask, iterations=2) bodymask = skimage.measure.label(bodymask.astype(int), connectivity=1) regions = skimage.measure.regionprops(bodymask.astype(int)) if len(regions) > 0: max_region = np.argmax(list(map(lambda x: x.area, regions))) + 1 bodymask = bodymask == max_region bodymask = ndimage.binary_dilation(bodymask, iterations=2) real_scaling = np.asarray(oshape)/128 return ndimage.zoom(bodymask, real_scaling, order=0)
Example #8
Source File: render_app.py From centerpose with MIT License | 5 votes |
def get_uv_mask(vertices_vis, triangles, uv_coords, h, w, resolution): triangles = triangles.T vertices_vis = vertices_vis.astype(np.float32) uv_mask = render_texture(uv_coords.T, vertices_vis[np.newaxis, :], triangles, resolution, resolution, 1) uv_mask = np.squeeze(uv_mask > 0) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = uv_mask.astype(np.float32) return np.squeeze(uv_mask)
Example #9
Source File: segmentation_labelling.py From kaggle-heart with MIT License | 5 votes |
def breakup_region(component): distance = ndi.distance_transform_edt(component) skel = skeletonize(component) skeldist = distance*skel local_maxi = peak_local_max(skeldist, indices=False, footprint=disk(10)) local_maxi=ndi.binary_closing(local_maxi,structure = disk(4),iterations = 2) markers = ndi.label(local_maxi)[0] labels = watershed(-distance, markers, mask=component) return(labels)
Example #10
Source File: img_utils.py From TractSeg with Apache License 2.0 | 5 votes |
def bundle_specific_postprocessing(data, bundles): """ For certain bundles checks if bundle contains two big blobs. Then it reduces the threshold for conversion to binary and applies hole closing. """ bundles_thresholds = { "CA": 0.3, "FX_left": 0.4, "FX_right": 0.4, } data_new = [] for idx, bundle in enumerate(bundles): data_single = data[:, :, :, idx] if bundle in list(bundles_thresholds.keys()): if has_two_big_blobs(data_single > 0.5, bundle, debug=False): print("INFO: Using bundle specific postprocessing for {} because bundle incomplete.".format(bundle)) thr = bundles_thresholds[bundle] else: thr = 0.5 data_single = data_single > thr size = 6 data_single = ndimage.binary_closing(data_single, structure=np.ones((size, size, size))) # returns bool else: data_single = data_single > 0.5 data_new.append(data_single) return np.array(data_new).transpose(1, 2, 3, 0).astype(np.uint8)
Example #11
Source File: img_utils.py From TractSeg with Apache License 2.0 | 5 votes |
def postprocess_segmentations(data, bundles, blob_thr=50, hole_closing=None): """ Postprocessing of segmentations. Fill holes and remove small blobs. hole_closing is deactivated per default because it incorrectly fills up the gyri (e.g. in AF). """ skip_hole_closing = ["CST_right", "CST_left", "MCP"] increased_hole_closing = [] # not needed anymore because already done in bundle-specific postprocessing data_new = [] for idx, bundle in enumerate(bundles): data_single = data[:,:,:,idx] #Fill holes if hole_closing is not None and bundle not in skip_hole_closing: size = hole_closing # Working as expected (size 2-3 good value) if bundle in increased_hole_closing: size *= 2 data_single = ndimage.binary_closing(data_single, structure=np.ones((size, size, size))).astype(data_single.dtype) # Remove small blobs if blob_thr is not None: data_single = remove_small_blobs(data_single, threshold=blob_thr, debug=False) data_new.append(data_single) data_new = np.array(data_new).transpose(1, 2, 3, 0) return data_new
Example #12
Source File: test_filters.py From porespy with MIT License | 5 votes |
def test_morphology_fft_closing_3D(self): im = self.im truth = spim.binary_closing(im, structure=ball(3)) test = ps.tools.fftmorphology(im, strel=ball(3), mode='closing') assert np.all(truth == test)
Example #13
Source File: test_filters.py From porespy with MIT License | 5 votes |
def test_morphology_fft_closing_2D(self): im = self.im[:, :, 50] truth = spim.binary_closing(im, structure=disk(3)) test = ps.tools.fftmorphology(im, strel=disk(3), mode='closing') assert np.all(truth == test)
Example #14
Source File: render_app.py From MaskInsightface with Apache License 2.0 | 5 votes |
def get_uv_mask(vertices_vis, triangles, uv_coords, h, w, resolution): triangles = triangles.T vertices_vis = vertices_vis.astype(np.float32) uv_mask = render_texture(uv_coords.T, vertices_vis[np.newaxis, :], triangles, resolution, resolution, 1) uv_mask = np.squeeze(uv_mask > 0) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) uv_mask = uv_mask.astype(np.float32) return np.squeeze(uv_mask)
Example #15
Source File: render_app.py From PRNet with MIT License | 5 votes |
def get_uv_mask(vertices_vis, triangles, uv_coords, h, w, resolution): triangles = triangles.T vertices_vis = vertices_vis.astype(np.float32) uv_mask = render_texture(uv_coords.T, vertices_vis[np.newaxis, :], triangles, resolution, resolution, 1) uv_mask = np.squeeze(uv_mask > 0) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = uv_mask.astype(np.float32) return np.squeeze(uv_mask)
Example #16
Source File: mask.py From pyem with GNU General Public License v3.0 | 5 votes |
def main(args): if args.threshold is None: print("Please provide a binarization threshold") return 1 data, hdr = read(args.input, inc_header=True) mask = binarize_volume(data, args.threshold, minvol=args.minvol, fill=args.fill) if args.base_map is not None: base_map = read(args.base_map, inc_header=False) base_mask = binarize_volume(base_map, args.threshold, minvol=args.minvol, fill=args.fill) total_width = args.extend + args.edge_width excl_mask = binary_dilate(mask, total_width, strel=args.relion) base_mask = binary_dilate(base_mask, args.extend, strel=args.relion) base_mask = base_mask &~ excl_mask if args.overlap > 0: incl_mask = binary_dilate(base_mask, args.overlap, strel=args.relion) & excl_mask base_mask = base_mask | incl_mask mask = base_mask elif args.extend > 0: mask = binary_dilate(mask, args.extend, strel=args.relion) if args.close: se = binary_sphere(args.extend, False) mask = binary_closing(mask, structure=se, iterations=1) final = mask.astype(np.single) if args.edge_width != 0: dt = distance_transform_edt(~mask) # Compute *outward* distance transform of mask. idx = (dt <= args.edge_width) & (dt > 0) # Identify edge points by distance from mask. x = np.arange(1, args.edge_width + 1) # Domain of the edge profile. if "sin" in args.edge_profile: y = np.sin(np.linspace(np.pi/2, 0, args.edge_width + 1)) # Range of the edge profile. f = interp1d(x, y[1:]) final[idx] = f(dt[idx]) # Insert edge heights interpolated at distance transform values. write(args.output, final, psz=hdr["xlen"] / hdr["nx"]) return 0
Example #17
Source File: utils.py From lungmask with GNU General Public License v3.0 | 5 votes |
def crop_and_resize(img, mask=None, width=192, height=192): bmask = simple_bodymask(img) # img[bmask==0] = -1024 # this line removes background outside of the lung. # However, it has been shown problematic with narrow circular field of views that touch the lung. # Possibly doing more harm than help reg = skimage.measure.regionprops(skimage.measure.label(bmask)) if len(reg) > 0: bbox = np.asarray(reg[0].bbox) else: bbox = (0, 0, bmask.shape[0], bmask.shape[1]) img = img[bbox[0]:bbox[2], bbox[1]:bbox[3]] img = ndimage.zoom(img, np.asarray([width, height]) / np.asarray(img.shape), order=1) if not mask is None: mask = mask[bbox[0]:bbox[2], bbox[1]:bbox[3]] mask = ndimage.zoom(mask, np.asarray([width, height]) / np.asarray(mask.shape), order=0) # mask = ndimage.binary_closing(mask,iterations=5) return img, mask, bbox ## For some reasons skimage.transform leads to edgy mask borders compared to ndimage.zoom # def reshape_mask(mask, tbox, origsize): # res = np.ones(origsize) * 0 # resize = [tbox[2] - tbox[0], tbox[3] - tbox[1]] # imgres = skimage.transform.resize(mask, resize, order=0, mode='constant', cval=0, anti_aliasing=False, preserve_range=True) # res[tbox[0]:tbox[2], tbox[1]:tbox[3]] = imgres # return res
Example #18
Source File: image_utils.py From visualqc with Apache License 2.0 | 5 votes |
def background_mask(mri, thresh_perc=1): """Creates the background mask from an MRI""" grad_magnitude = gradient_magnitude(mri) nonzero_grad_mag = grad_magnitude[grad_magnitude > 0] thresh_val = np.percentile(nonzero_grad_mag.flatten(), thresh_perc) background_mask = grad_magnitude < thresh_val se36 = ndimage.generate_binary_structure(3, 6) closed = ndimage.binary_closing(background_mask, se36, iterations=6) final_mask = ndimage.binary_erosion(closed, se36, iterations=5) return final_mask
Example #19
Source File: megafacade.py From facade-segmentation with MIT License | 5 votes |
def find_facade_cuts(facade_sig, dilation_amount=60): edges = facade_sig > facade_sig.mean() + facade_sig.std() edges = binary_closing(edges, structure=np.ones(dilation_amount)) run, start, val = run_length_encode(edges) result = [] for s, e in zip(start[val], start[val] + run[val]): result.append(s + facade_sig[s:e].argmax()) result = [0] + result + [len(facade_sig) - 1] result = np.unique(result) return np.array(result)
Example #20
Source File: test_ndimage.py From GraphicDesignPatternByPython with MIT License | 5 votes |
def test_closing_new_arguments(self): closed_new = ndimage.binary_closing(self.array, self.sq3x3, 1, None, 0, None, 0, False) assert_array_equal(closed_new, self.closed_old)
Example #21
Source File: test_ndimage.py From GraphicDesignPatternByPython with MIT License | 5 votes |
def setup_method(self): a = numpy.zeros((5,5), dtype=bool) a[1:4, 1:4] = True a[4,4] = True self.array = a self.sq3x3 = numpy.ones((3,3)) self.opened_old = ndimage.binary_opening(self.array, self.sq3x3, 1, None, 0) self.closed_old = ndimage.binary_closing(self.array, self.sq3x3, 1, None, 0)
Example #22
Source File: evaluate_segmentation.py From luna16 with BSD 2-Clause "Simplified" License | 5 votes |
def process_image(name, do_closing, closing_structure): image_train,_,_ = image_read_write.load_itk_image(name) name = name.replace("mask","truth") image_truth,_,_ = image_read_write.load_itk_image(name) truth = np.zeros(image_truth.shape, dtype=np.uint8) truth[image_truth >0]=1 if do_closing: image_train = binary_closing(image_train, closing_structure,1) image_train = binary_closing(image_train, [[[1]],[[1]],[[1]],[[1]],[[1]]],1) score = calculate_dice(image_train,truth, name) return score
Example #23
Source File: render_app.py From LipReading with MIT License | 5 votes |
def get_uv_mask(vertices_vis, triangles, uv_coords, h, w, resolution): triangles = triangles.T vertices_vis = vertices_vis.astype(np.float32) uv_mask = render_texture(uv_coords.T, vertices_vis[np.newaxis, :], triangles, resolution, resolution, 1) uv_mask = np.squeeze(uv_mask > 0) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_closing(uv_mask) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = ndimage.binary_erosion(uv_mask, structure = np.ones((4,4))) uv_mask = uv_mask.astype(np.float32) return np.squeeze(uv_mask)
Example #24
Source File: image_utils.py From visualqc with Apache License 2.0 | 4 votes |
def mask_image(input_img, update_factor=0.5, init_percentile=2, iterations_closing=5, return_inverse=False, out_dtype=None): """ Estimates the foreground mask for a given image. Similar to 3dAutoMask from AFNI. iterations_closing : int Number of iterations of binary_closing to apply at the end. """ prev_clip_level = np.percentile(input_img, init_percentile) while True: mask_img = input_img >= prev_clip_level cur_clip_level = update_factor * np.median(input_img[mask_img]) if np.isclose(cur_clip_level, prev_clip_level, rtol=0.05): break else: prev_clip_level = cur_clip_level if len(input_img.shape) == 3: se = ndimage.generate_binary_structure(3, 6) elif len(input_img.shape) == 2: se = ndimage.generate_binary_structure(2, 4) else: raise ValueError('Image must be 2D or 3D') mask_img = binary_closing(mask_img, se, iterations=iterations_closing) mask_img = binary_fill_holes(mask_img, se) if return_inverse: mask_img = np.logical_not(mask_img) if out_dtype is not None: mask_img = mask_img.astype(out_dtype) return mask_img # alias
Example #25
Source File: anatomical.py From mriqc with BSD 3-Clause "New" or "Revised" License | 4 votes |
def gradient_threshold(in_file, in_segm, thresh=1.0, out_file=None): """ Compute a threshold from the histogram of the magnitude gradient image """ import os.path as op import numpy as np import nibabel as nb from scipy import ndimage as sim struc = sim.iterate_structure(sim.generate_binary_structure(3, 2), 2) 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(f'{fname}_gradmask{ext}') imnii = nb.load(in_file) hdr = imnii.header.copy() hdr.set_data_dtype(np.uint8) # pylint: disable=no-member data = imnii.get_data().astype(np.float32) mask = np.zeros_like(data, dtype=np.uint8) # pylint: disable=no-member mask[data > 15.] = 1 segdata = nb.load(in_segm).get_data().astype(np.uint8) segdata[segdata > 0] = 1 segdata = sim.binary_dilation( segdata, struc, iterations=2, border_value=1).astype(np.uint8) mask[segdata > 0] = 1 mask = sim.binary_closing(mask, struc, iterations=2).astype(np.uint8) # Remove small objects label_im, nb_labels = sim.label(mask) artmsk = np.zeros_like(mask) if nb_labels > 2: sizes = sim.sum(mask, label_im, list(range(nb_labels + 1))) ordered = list(reversed(sorted(zip(sizes, list(range(nb_labels + 1)))))) for _, label in ordered[2:]: mask[label_im == label] = 0 artmsk[label_im == label] = 1 mask = sim.binary_fill_holes(mask, struc).astype(np.uint8) # pylint: disable=no-member nb.Nifti1Image(mask, imnii.affine, hdr).to_filename(out_file) return out_file
Example #26
Source File: ca1pc.py From sima with GNU General Public License v2.0 | 4 votes |
def apply(self, rois, dataset): channel = sima.misc.resolve_channels(self._channel, dataset.channel_names) processed_im = _processed_image_ca1pc( dataset, channel, self._x_diameter, self._y_diameter)[0] shape = processed_im.shape[:2] ROIs = ROIList([]) for roi in rois: roi_indices = np.nonzero(roi.mask[0]) roi_indices = np.ravel_multi_index(roi_indices, shape) # pixel values in the cut vals = processed_im.flat[roi_indices] # indices of those values below the otsu threshold # if all values are identical, continue without adding an ROI try: roi_indices = roi_indices[vals < threshold_otsu(vals)] except ValueError: continue # apply binary opening and closing to the surviving pixels # expand the shape by 1 in all directions to correct for edge # effects of binary opening/closing twoD_indices = [np.unravel_index(x, shape) for x in roi_indices] mask = np.zeros([x + 2 for x in shape]) for indices in twoD_indices: mask[indices[0] + 1, indices[1] + 1] = 1 mask = ndimage.binary_closing(ndimage.binary_opening(mask)) mask = mask[1:-1, 1:-1] roi_indices = np.where(mask.flat)[0] # label blobs in each cut labeled_array, num_features = measurements.label(mask) for feat in range(num_features): blob_inds = np.where(labeled_array.flat == feat + 1)[0] twoD_indices = [np.unravel_index(x, shape) for x in blob_inds] mask = np.zeros(shape) for x in twoD_indices: mask[x] = 1 ROIs.append(ROI(mask=mask)) return ROIs