def seg_to_small_seg(seg, thres=25, rr=2): # rr: z/x-y resolution ratio sz = seg.shape mask = np.zeros(sz, np.uint8) for z in np.where(seg.max(axis=1).max(axis=1) > 0)[0]: tmp = label_cc(seg[z]) ui, uc = np.unique(tmp, return_counts=True) rl = np.zeros(ui[-1] + 1, np.uint8) rl[ui[uc < thres]] = 1 rl[0] = 0 mask[z] += rl[tmp] for y in np.where(seg.max(axis=2).max(axis=0) > 0)[0]: tmp = label_cc(seg[:, y]) ui, uc = np.unique(tmp, return_counts=True) rl = np.zeros(ui[-1] + 1, np.uint8) rl[ui[uc < thres // rr]] = 1 rl[0] = 0 mask[:, y] += rl[tmp] for x in np.where(seg.max(axis=0).max(axis=0) > 0)[0]: tmp = label_cc(seg[:, :, x]) ui, uc = np.unique(tmp, return_counts=True) rl = np.zeros(ui[-1] + 1, np.uint8) rl[ui[uc < thres // rr]] = 1 rl[0] = 0 mask[:, :, x] += rl[tmp] return mask
def distance_transform(label: np.ndarray, bg_value: float = -1.0, relabel: bool = True, padding: bool = False, resolution: Tuple[float] = (1.0, 1.0)): """Euclidean distance transform (DT or EDT) for instance masks. """ eps = 1e-6 pad_size = 2 if relabel: label = label_cc(label) if padding: # The distance_transform_edt function does not treat image border # as background. If image border needs to be considered as background # in distance calculation, set padding to True. label = np.pad(label, pad_size, mode='constant', constant_values=0) label_shape = label.shape all_bg_sample = False distance = np.zeros(label_shape, dtype=np.float32) + bg_value semantic = np.zeros(label_shape, dtype=np.uint8) indices = np.unique(label) if indices[0] == 0: if len(indices) > 1: # exclude background indices = indices[1:] else: # all-background sample all_bg_sample = True if not all_bg_sample: for idx in indices: temp1 = label.copy() == idx temp2 = remove_small_holes(temp1, 16, connectivity=1) semantic += temp2.astype(np.uint8) boundary_edt = distance_transform_edt(temp2, resolution) energy = boundary_edt / (boundary_edt.max() + eps) # normalize distance = np.maximum(distance, energy * temp2.astype(np.float32)) if padding: # Unpad the output array to preserve original shape. distance = array_unpad(distance, get_padsize( pad_size, ndim=distance.ndim)) semantic = array_unpad(semantic, get_padsize( pad_size, ndim=distance.ndim)) return distance, semantic
def syn_sem2inst(label: np.array): # For synaptic polarity, convert semantic annotation to instance # annotation. It assumes the pre- and post-synaptic masks are # closely in touch with their parteners. indices = np.unique(label) assert list(indices) == [0, 1, 2] fg = (label != 0).astype(bool) struct = disk(2, dtype=bool)[np.newaxis, :, :] # only for xy plane fg = binary_dilation(fg, struct) segm = label_cc(fg).astype(int) seg_pos = (label == 1).astype(segm.dtype) seg_neg = (label == 2).astype(segm.dtype) seg_pos = seg_pos * (segm * 2 - 1) seg_neg = seg_neg * (segm * 2) instance_label = np.maximum(seg_pos, seg_neg) # Cast the mask to the best dtype to save storage. max_id = np.amax(np.unique(instance_label)) m_type = getSegType(int(max_id)) return instance_label.astype(m_type)