def test_return_N(connectivity): labels = np.zeros((10, 10, 10), dtype=np.uint8) cc3d_labels, N = cc3d.connected_components(labels, connectivity=connectivity, return_N=True) assert N == 0 assert np.max(cc3d_labels) == 0 labels = np.ones((10, 10, 10), dtype=np.uint8) + 2 cc3d_labels, N = cc3d.connected_components(labels, connectivity=connectivity, return_N=True) assert N == 1 assert np.max(cc3d_labels) == 1 labels = np.ones((512, 512, 512), dtype=np.uint8, order='F') labels[256:, :256, :256] = 2 labels[256:, 256:, :256] = 3 labels[:256, 256:, :256] = 4 labels[256:, 256:, 256:] = 5 labels[:256, 256:, 256:] = 6 labels[256:, :256, 256:] = 7 labels[:256, :256, 256:] = 8 labels[128, 128, 128] = 9 cc3d_labels, N = cc3d.connected_components(labels, connectivity=connectivity, return_N=True) assert N == 9 assert np.max(cc3d_labels) == 9 labels = np.random.randint(0, 2, (128, 128, 128), dtype=bool) cc3d_labels, N = cc3d.connected_components(labels, connectivity=connectivity, return_N=True) assert N == np.max(cc3d_labels)
def test_epl_special_case(connectivity): sx = 256 sy = 257 sz = 252 img = np.zeros((sx, sy, sz), dtype=np.uint8, order="F") y = np.random.randint(0, sy) z = np.random.randint(0, sz) img[:, y, z] = 6 out = cc3d.connected_components(img, connectivity=connectivity) epl, start, end = cc3d.estimate_provisional_labels(img) assert epl == 1 assert start == y + sy * z assert end == start assert out.dtype == np.uint16 gt = np.zeros(img.shape, dtype=np.uint8, order="F") gt[:, y, z] = 1 assert np.all(out == gt) img[:100, y, z] = 3 gt[100:, y, z] = 2 epl, start, end = cc3d.estimate_provisional_labels(img) out = cc3d.connected_components(img, connectivity=connectivity) assert epl == 2 assert start == end print(gt[:, y, z]) print(out[:, y, z]) assert np.all(out == gt)
def CCL(labels_in_main, layers=1): labels_out_main = cc3d.connected_components(labels_in_main) # 26-connected N = np.max(labels_out_main) # Dealing with boundary condition indices = np.arange(-layers, layers) labels_in = [ np.take(labels_in_main, indices, axis=idir) for idir in range(3) ] for idir in range(3): labels_out = cc3d.connected_components(labels_in[idir]) # 26-connected # if no labels at boundary, skip if labels_out.sum() == 0: continue # if there are labels at boundary labels = np.unique(labels_out)[1:] for label in labels: ends = labels_out == label end1 = np.take(ends, range(0, layers), axis=idir) end2 = np.take(ends, range(-layers, 0), axis=idir) domain_end1 = np.take(labels_out_main, range(-layers, 0), axis=idir) domain_end2 = np.take(labels_out_main, range(0, layers), axis=idir) domain_label1 = np.unique(domain_end1[end1]) domain_label2 = np.unique(domain_end2[end2]) labels_out_main[np.isin(labels_out_main, domain_label1)] = N + label labels_out_main[np.isin(labels_out_main, domain_label2)] = N + label N = np.max(labels_out_main) return labels_out_main
def test_max_labels_nonsensical(): input_labels = np.arange(0, 64 ** 3).astype(np.uint64).reshape((64,64,64)) real_labels = cc3d.connected_components(input_labels, max_labels=64*64*64) zero_labels = cc3d.connected_components(input_labels, max_labels=0) negative_labels = cc3d.connected_components(input_labels, max_labels=-50) assert np.all(real_labels == zero_labels) assert np.all(real_labels == negative_labels)
def _run(delta): print(f"Delta {delta}...") times = [] for i in range(10): s = time.time() cc3d.connected_components(labels, connectivity=connectivity, delta=delta) e = time.time() dt = e-s times.append(dt) summary(times, voxels)
def test_single_pixel_2d(order, connectivity): binary_img = np.zeros((3, 3), dtype=np.uint8, order=order) binary_img[1, 1] = 1 labels = cc3d.connected_components(binary_img, connectivity=connectivity) assert np.all(labels == binary_img) binary_img = np.zeros((5, 5), dtype=np.uint8, order=order) binary_img[1, 1] = 1 labels = cc3d.connected_components(binary_img, connectivity=connectivity) assert np.all(labels == binary_img)
def test_stress_upper_bound_for_binary_8(size): labels = np.zeros((size, size), dtype=bool) labels[0::2, 0::2] = True out = cc3d.connected_components(labels, connectivity=8) assert np.max(out) + 1 <= (256**2) // 4 + 1 for _ in range(10): labels = np.random.randint(0, 2, (256, 256), dtype=bool) out = cc3d.connected_components(labels, connectivity=8) assert np.max(out) + 1 <= (256**2) // 4 + 1
def test_stress_upper_bound_for_binary_26(size, zeroth_pass): labels = np.zeros((size,size,size), dtype=np.bool) labels[::2,::2,::2] = True out = cc3d.connected_components(labels, connectivity=26, zeroth_pass=zeroth_pass) assert np.max(out) + 1 <= (256**3) // 8 + 1 for _ in range(10): labels = np.random.randint(0,2, (256,256,256), dtype=np.bool) out = cc3d.connected_components(labels, connectivity=26, zeroth_pass=zeroth_pass) assert np.max(out) + 1 <= (256**3) // 8 + 1
def test_multilabel_speed(labels, connectivity=26): voxels = labels.size times = [] for i in range(10): s = time.time() cc3d.connected_components(labels, connectivity=connectivity) e = time.time() dt = e-s times.append(dt) prettyprint(dt, voxels) summary(times, voxels)
def test_continuous_ccl_diagonal(order, dtype, connectivity): labels = np.zeros((2, 2), dtype=dtype, order=order) labels[0, 0] = 1 labels[1, 0] = 2 labels[0, 1] = 3 labels[1, 1] = 4 out = cc3d.connected_components(labels, delta=0, connectivity=connectivity) assert np.all(np.unique(labels) == [1, 2, 3, 4]) out = cc3d.connected_components(labels, delta=1, connectivity=connectivity) assert np.all(out == 1)
def test_binary_image_processing(labels, connectivity=26): voxels = labels.size times = [] for label, img in tqdm(cc3d.each(labels, binary=True, in_place=True)): s = time.time() cc3d.connected_components(img) # scipy.ndimage.measurements.label(labels, structure=structures[connectivity]) e = time.time() dt = e-s times.append(dt) prettyprint(dt, voxels) summary(times, voxels)
def measure_CM_dist_real_size(struct1, struct2, pixdim=1, dtype=np.uint8, max_classes=2): """ :param struct1: ndarray of 3D image 1 (the result of nib.get_data()) :param struct2: ndarray of 3D image 2 (the result of nib.get_data()) :param pixdim - should be a list, even of one element (if isotropic resolution): :param max_classes - Should be 2: corresponds to left and right :return: Euclidan distance between center of mass of the structures (in mm) """ import cc3d # pip install connected-components-3d --no-binary :all: (https://pypi.org/project/connected-components-3d/) if len(pixdim) > 1: voxel_size = [pixdim[2], pixdim[1], pixdim[3]] # OS: This looks strange... else: voxel_size = [pixdim[0], pixdim[0], pixdim[0]] # Construct labels - connected components #lbl1 = ndimage.label(struct1.astype(dtype))[0]# Looks like there's a bug here... #lbl2 = ndimage.label(struct2.astype(dtype))[0] lbl1 = cc3d.connected_components( struct1.astype(dtype)) # 26-connected (default) lbl2 = cc3d.connected_components( struct2.astype(dtype)) # 26-connected (default) # cc3d might output a pixel as a nex class - observed in PD55.nii.gz for DISTAL 2017 - single pixel=3 lbl1[lbl1 > max_classes] = max_classes lbl2[lbl2 > max_classes] = max_classes lbl1 = check_cc_of_same_object(lbl1, lbl2) lbl_index = [f for f in range(1, np.max(lbl1) + 1)] struct1_cm = np.array( ndimage.measurements.center_of_mass(struct1, lbl1, lbl_index)) struct2_cm = np.array( ndimage.measurements.center_of_mass(struct2, lbl2, lbl_index)) cm_diff = [] cm_dist = [] for ii in range(len(struct1_cm)): cm_diff_tmp = (struct1_cm[ii] - struct2_cm[ii]) * voxel_size cm_dist_tmp = np.linalg.norm(cm_diff_tmp) cm_diff.append(cm_diff_tmp) cm_dist.append(cm_dist_tmp) return cm_dist, cm_diff
def test(order, ground_truth): print(order) input_labels = np.zeros((7, 7, 8), dtype=dtype, order=order) input_labels[:] = 1 input_labels[:, 3, :] = 0 input_labels[:, :, 3] = 0 output_labels = cc3d.connected_components(input_labels).astype(dtype) print(output_labels) assert np.all(output_labels == ground_truth) input_labels[:, 4:, 4:] = 2 output_labels = cc3d.connected_components(input_labels).astype(dtype) assert np.all(output_labels == ground_truth)
def test(order, ground_truth): input_labels = np.zeros( (17,17), dtype=dtype, order=order) input_labels[:] = 1 input_labels[:,8] = 0 input_labels[8,:] = 0 output_labels = cc3d.connected_components(input_labels, connectivity=connectivity).astype(dtype) print(output_labels) assert np.all(output_labels == ground_truth) input_labels[9:,9:] = 2 output_labels = cc3d.connected_components(input_labels, connectivity=connectivity).astype(dtype) output_labels = output_labels[:,:] assert np.all(output_labels == ground_truth)
def test_largest_k(k): threshold = 20 labels = np.random.randint(0, 5, size=(100, 100, 100), dtype=np.uint8) cc_labels = cc3d.connected_components(labels) uniq, cts = np.unique(cc_labels, return_counts=True) k_cc_labels = cc3d.largest_k(labels, k=k) uniq_k, cts_k = np.unique(k_cc_labels, return_counts=True) assert len(uniq_k) <= k + 1 retained_labels = np.unique(cc_labels * (k_cc_labels > 0)) lbls = [] if k > 0: lbls = sorted([(u, c) for u, c in zip(uniq, cts) if u != 0], key=lambda x: x[1]) lbls = [x[0] for x in lbls[-k:]] lbls.sort() retained_labels.sort() if retained_labels[0] == 0: retained_labels = retained_labels[1:] assert np.all(lbls == retained_labels)
def test_2d_diagonals_4_connected(connectivity): input_labels = np.array([ [0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], ], dtype=np.uint32) ground_truth_sauf = np.array([ [0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3, 0, 0, 4, 0, 0, 5, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0], [0, 7, 0, 0, 8, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0], [9, 0, 10, 0, 0, 0, 11, 11, 0, 0, 12, 12, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 11, 11, 0, 0, 12, 12, 0, 0, 0, 0, 0], [0, 0, 13, 0, 14, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0], [0, 16, 0, 0, 0, 17, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0], ], dtype=np.uint32) ground_truth_bbdt = np.array([ [0, 0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 3, 0, 0, 5, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0], [0, 8, 0, 0, 10, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0], [7, 0, 9, 0, 0, 0, 11, 11, 0, 0, 12, 12, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 11, 11, 0, 0, 12, 12, 0, 0, 0, 0, 0], [0, 0, 13, 0, 14, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0], [0, 16, 0, 0, 0, 17, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0], ], dtype=np.uint32) output_labels = cc3d.connected_components(input_labels, connectivity=connectivity) print(output_labels) assert np.all(output_labels == ground_truth_sauf) or np.all(output_labels == ground_truth_bbdt)
def connected_objects(data_array, connectivity_values=26): """ function creating a list of objects that are connected and satisfy certain conditions. This aims at replacing Mathworks bwconncomp.m function https://www.mathworks.com/help/images/ref/bwconncomp.html""" import cc3d labels_out = cc3d.connected_components(np.array(data_array), connectivity=connectivity_values) return labels_out
def play(args): # fgbg = cv2.bgsegm.createBackgroundSubtractorMOG() fgbg = cv2.createBackgroundSubtractorMOG2() kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) reader = select_reader(args.input_type) generator = reader(args.input, reverse=args.reverse) detect_imgs = np.array([ cv2.morphologyEx(fgbg.apply(frame), cv2.MORPH_OPEN, kernel) for frame_i, frame in enumerate(generator) ]) cc = cc3d.connected_components(detect_imgs, connectivity=26, delta=0) if args.reverse: cc = cc[::-1] components = extract_components_faster(cc, args) components = comp_sort(components) with open(args.pkl, 'wb') as f: pickle.dump(components, f) cc = np.logical_not(np.logical_not(cc)).astype(np.uint8) * 255 with open(args.cc, 'wb') as f: pickle.dump(cc, f) print(f'\nFound {len(components)} events, save to {args.pkl}')
def process_item(item): global general_size_dict, path_patches, overlap count = 0 beg = datetime.datetime.now() direct_path = os.path.join(path_patches, item) patch = read_nifti(direct_path).astype(np.uint8) patch = patch[:-overlap, :-overlap, :-overlap] labels_out = cc3d.connected_components(patch) size_dict = {} max_v = int(np.amax(labels_out)) for i in range(max_v + 1): if i == 0: size = np.sum(labels_out[labels_out == i]) / 1 else: size = np.sum(labels_out[labels_out == i]) / i size_dict[i] = size general_size_dict[f"{item}"] = size_dict progress_bar(len(general_size_dict.keys()), total_length, "Counting cells ") diff = datetime.datetime.now() - beg proc_time = diff.microseconds count += max_v return (count, proc_time)
def pre_processing1(data): # original data (512,512,z) labels_out = cc3d.connected_components(data.astype('int32')) skull_label = skull_id1(labels_out) skull = (labels_out == skull_label) skull = skull + 1 - 1 return skull
def postprocessing(l,S): import cc3d import fastremap """ This function forces conectivity. Keyword arguments: L : numpy.ndarray Labelled image S : int Spacing Returns ------- final: numpy.ndarray Segmentation result """ for smooth in range(2): #Remove spourious regions generated during segmentation cc = cc3d.connected_components(raster.astype(dtype=np.uint16), connectivity=6, out_dtype=np.uint32) #print('Num of shapes: %d' % len(list(rasterio.features.shapes(relabeled.astype(dtype=np.uint16))))) T = int((S**2)/2) #Use Connectivity as 4 to avoid undesired connections raster = rasterio.features.sieve(cc.astype(dtype=np.int32),T,connectivity = 4) return raster
def _fix_to_permissive_connectivity(self, labeld_state_map, cc_outoput, permissivness=4): new_id = 0 new_labeld_state_map = np.zeros(labeld_state_map.shape) # for each id that has degeneracy print("StateCalculator: Aplying permissive connectivity algorithm") for id in tqdm(np.unique(labeld_state_map)): # create 3d binary map deg_map = np.where(labeld_state_map == id, 1, 0) sample_index = tuple(np.argwhere(deg_map == 1)[0]) if np.count_nonzero(deg_map) == np.count_nonzero( cc_outoput == cc_outoput[sample_index]): # non degenerate state new_labeld_state_map = np.where(deg_map, new_id, new_labeld_state_map) new_id += 1 continue # degenerate case dilated_map = binary_dilation(deg_map, iterations=permissivness) # run cc again new_cc = cc3d.connected_components(dilated_map, connectivity=26) for id in np.unique(new_cc): new_labeld_state_map = np.where((new_cc == id) & deg_map, new_id, new_labeld_state_map) new_id += 1 return new_labeld_state_map
def get_main_struct(img_file, write_file): """ For a voxel representation of vascular network, return the main structure of the vessels using connected component analysis. """ with open(img_file, 'rb') as f: model = read_as_3d_array(f) import cc3d labels_in = np.array(model.data) labels_out = cc3d.connected_components(labels_in) # 26-connected N = np.max(labels_out) main = np.zeros(labels_in.shape, dtype=int) count = 1 for segid in range(1, N+1): extracted_image = labels_out * (labels_out == segid) extracted_image = np.array(np.array(extracted_image, dtype=bool), dtype=int) if np.count_nonzero(extracted_image != 0) > 10: main = main + extracted_image print("%d: %d" %(segid, np.count_nonzero(extracted_image != 0))) count += 1 main = np.array(np.array(main, dtype=bool), dtype=int) new_f = open(write_file, "xb") new_model = VoxelModel(main, model.dims, model.translate, model.scale, model.axis_order) write_binvox(new_model, new_f)
def get_edges(img_file, pt_file, write_file): """ Analyze the vessels and the points sampled from the vessels, give the connection information. """ with open(img_file, 'rb') as f, open(pt_file, 'rb') as p1: model = read_as_3d_array(f) pts = read_as_3d_array(p1).data pts_coords = np.transpose(dense_to_sparse(pts), (1, 0)) import cc3d labels_in = np.array(model.data) labels_out = cc3d.connected_components(labels_in) N = np.max(labels_out) edge_list = [] for segid in range(1, N+1): extracted_image = labels_out == segid skel = Skeleton(extracted_image) for i in range(skel.n_paths): coords = skel.path_coordinates(i) prev = None for c in coords: c = np.array(c, dtype=int) for j in range(len(pts_coords)): if (c == pts_coords[j]).all(): if prev == None: prev = j else: cur = j edge_list.append([prev, cur]) prev = cur break np.save(write_file, edge_list)
def apply_3d_connected_componetns(volume_3d): ## REMOVE THE 3D CONNECTED COMPONENTS THAT ARE NOT CONNECTED TO THE LUNGS labels_out = cc3d.connected_components(volume_3d, out_dtype=np.uint16) labels = np.unique(labels_out) areas = np.zeros_like(labels) for con_component in range(np.max(labels)): areas[con_component + 1] = np.sum(1 * (labels_out == (con_component + 1))) print(areas[np.argsort(areas)]) rank_components = labels[np.argsort(areas)] rank_areas = areas[np.argsort(areas)] # here we will select only the blobs tat belong to the lungs, sometimes, during # the inhalation the lung blobs are together, thus only 1 blob is to be selected. n_blobs = 4 if rank_areas[-2] / rank_areas[-1] < 0.2: n_blobs = 4 lungs_labels = rank_components[-n_blobs:] segmentation = np.zeros_like(volume_3d) for mark in lungs_labels: segmentation[labels_out == mark] = 1 plt.subplot(1, 2, 1) plt.imshow(labels_out[60, :, :]) plt.subplot(1, 2, 2) plt.imshow(segmentation[60, :, :]) plt.show() return segmentation, labels_out
def test_out_dtype_too_small(): labels = np.arange(0, 41**3).astype(np.uint32) + 1 try: out = cc3d.connected_components(labels, out_dtype=np.uint16) assert False except ValueError: pass
def remove_islands_gp(seg_vol, max_islands_to_keep=2, dtype=np.uint8): import cc3d # pip install connected-components-3d --no-binary :all: (https://pypi.org/project/connected-components-3d/) from copy import deepcopy seg_vol_orig = deepcopy(seg_vol).astype(dtype) # Create components seg_vol[seg_vol != 0] = 1 labels_out = cc3d.connected_components( seg_vol.astype(dtype)) # 26-connected (default) # Extract individual components vox_count = [] extracted_image_buffer = [] N = np.max(labels_out) for segid in range(1, N + 1): extracted_image = labels_out * (labels_out == segid) #extracted_image[extracted_image != 0] = 1 extracted_image_buffer.append(extracted_image.astype(dtype)) # Calculate number of voxels vox_count_tmp = np.sum(extracted_image[extracted_image != 0]) vox_count.append(vox_count_tmp) # For GP (i+e) keep only the two largest islands smallest_indices = sorted(range(len(vox_count)), key=lambda x: vox_count[x])[0:len(vox_count) - max_islands_to_keep] for ii in range(len(smallest_indices)): mask = extracted_image_buffer[smallest_indices[ii]] mask[mask != 0] = 1 mask = 1 - mask seg_vol_orig = seg_vol_orig * mask return seg_vol_orig
def test_2d_diagonals(): input_labels = np.array([ [0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], ], dtype=np.uint32) ground_truth = np.array([ [0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 0, 0, 1, 0, 0, 3, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0], [0, 2, 0, 0, 1, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0], [2, 0, 2, 0, 0, 0, 4, 4, 0, 0, 4, 4, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 4, 0, 0, 0, 0, 0], [0, 0, 5, 0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0], [0, 5, 0, 0, 0, 6, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0], ], dtype=np.uint32) output_labels = cc3d.connected_components(input_labels) print(output_labels) assert np.all(output_labels == ground_truth)
def test_out_dtype_invalid(): labels = np.zeros((512, 512, 512), dtype=np.uint8) try: out = cc3d.connected_components(labels, out_dtype=np.uint8) assert False except ValueError: pass
def find_center(raw, patch): """Isolate the single cc in labels, cut out in raw, set the brightest point as center point """ labels = cc3d.connected_components(patch) #XXX labels = patch result = np.zeros_like(raw) max_l = np.amax(labels) for i in range(1, max_l): sub_label = np.copy(labels) sub_label[sub_label != i] = 0 if (np.count_nonzero(sub_label > 0)) > 1: bb = _get_bb(sub_label) sub_label = sub_label[bb[0][0]:bb[1][0] + 1, bb[0][1]:bb[1][1] + 1, bb[0][2]:bb[1][2] + 1] sub_raw = raw[bb[0][0]:bb[1][0] + 1, bb[0][1]:bb[1][1] + 1, bb[0][2]:bb[1][2] + 1] sub_label[sub_label > 0] = 1 sub_raw *= sub_label center_value = np.amax(sub_raw) center_coords = np.where(sub_raw == center_value) result[bb[0][0] + center_coords[0], bb[0][1] + center_coords[1], bb[0][2] + center_coords[2]] = i else: result += sub_label return result