def test_call_op(self): dir_ops = dir(operations) dir_ops = [i for i in dir_ops if not i.startswith('__')] for d in dir_ops: if hasattr(getattr(operations, d), '__module__'): module = getattr(getattr(operations, d), '__module__') if 'tracking_operations' in module: container = Container(self.img.shape) container.curr_cells = CellListMaker( self.img, self.label, 1).make_list() container.prev_cells = CellListMaker( self.img, self.label, 0).make_list() func = getattr(operations, d) con = func(self.img.copy(), self.label.copy(), container, self.holder) self.assertTrue(isinstance(con, Container))
def watershed_distance(img, label, container, holder, ERODI=5, DEBRISAREA=50, DISPLACEMENT=50, MASSTHRES=0.2): '''watershed existing label, meaning make a cut at the deflection. After the cuts, objects will be linked if they are within DISPLACEMENT and MASSTHRES. If two candidates are found, it will pick a closer one. Args: ERODI (int): Erosion size element for generating watershed seeds. Smaller ERODI will allow more cuts. DISPLACEMENT (int): The maximum distance (in pixel) MASSTHRES (float): The maximum difference of total intensity changes. 0.2 means it allows for 20% total intensity changes. ''' untr_prev, untr_curr = container.unlinked mask_untracked = container._label_untracked.astype(bool) wshed_label = watershed(mask_untracked, ERODI) wshed_label = skilabel(sizefilterandopen(wshed_label, DEBRISAREA, np.Inf, 0)) newcells = CellListMaker(img, wshed_label, holder, holder.frame).make_list() distanceUntracked = _distance_diff(untr_prev, newcells) masschangeUntracked = _totalintensity_difference(untr_prev, newcells) withinarea = distanceUntracked < DISPLACEMENT withinmass = abs(masschangeUntracked) < MASSTHRES withinareaMass = withinarea * withinmass withinareaMass = pick_closer_binarycostmat(withinareaMass, distanceUntracked) good_curr_idx, good_prev_idx = find_one_to_one_assign(withinareaMass) # update the link for ci, pi in zip(good_curr_idx, good_prev_idx): untr_prev[pi].next = newcells[ci] # Get all linear coordinates from good newly segmented cells good_curr_coords = [newcells[n].prop.coords for n in good_curr_idx] lin_curr_coords = [convert_coords_to_linear(i, holder.img_shape) for i in flatlist(good_curr_coords)] # find cells in old mask (in current) that overlaps with good new cells old_cells_to_remove, lin_old_coords_remove = find_coords_overlap_coords(untr_curr, lin_curr_coords, holder.img_shape) # find cells in new mask which overlaps with the cells in old mask newcells_to_update = find_cells_overlap_linear_coords(newcells, lin_old_coords_remove, holder.img_shape) # remove old cells for old_cell in old_cells_to_remove: container.curr_cells.remove(old_cell) # add new cells container.curr_cells.extend(newcells_to_update) return container
def test_cell_list_CellListMaker(self): clm = CellListMaker(self.img, self.label, self.param, self.frame) celllist = clm.make_list() self.assertTrue(isinstance(celllist, list)) self.assertTrue(isinstance(celllist[0], Cell))
def track_neck_cut(img, label, container, holder, ERODI=5, DEBRISAREA=50, DISPLACEMENT=50, MASSTHRES=0.2, LIM=10, EDGELEN=5, THRES_ANGLE=180, STEPLIM=10): """ Adaptive segmentation by using tracking informaiton. Separate two objects by making a cut at the deflection. For each points on the outline, it will make a triangle separated by EDGELEN and calculates the angle facing inside of concave. EDGELEN (int): A length of edges of triangle on the nuclear perimeter. THRES_ANGLE (int): Define the neck points if a triangle has more than this angle. STEPLIM (int): points of neck needs to be separated by at least STEPLIM in parimeters. """ untr_prev, untr_curr = container.unlinked label_untracked = container._label_untracked unique_labels = np.unique(label_untracked) unique_labels = unique_labels[unique_labels > 0] newcells = [] all_new_cells = [] for label_id in unique_labels: mask = label_untracked == label_id cl_label = clear_border(mask) outlines = labels2outlines(cl_label).astype(np.uint16) rps = regionprops(outlines) rps = [i for i in rps if i.perimeter > STEPLIM] for cell in rps: score, coords = calc_neck_score_thres_filtered(cell.coords, edgelen=EDGELEN, thres=THRES_ANGLE, steplim=STEPLIM) if len(score) > 1: r0, c0 = coords[0, :] if coords.shape[0] > LIM: coords = coords[:LIM, :] for cand in coords[1:, :]: untr_prev = container.unlinked[0] cut_label = skilabel(cut_neck(cl_label, r0, c0, cand[0], cand[1]), conn=1) new_cells_temp = CellListMaker(img, cut_label, holder, holder.frame).make_list() if len(new_cells_temp) > 1: distanceUntracked = _distance_diff( untr_prev, new_cells_temp) masschangeUntracked = _totalintensity_difference( untr_prev, new_cells_temp) withinarea = distanceUntracked < DISPLACEMENT withinmass = abs(masschangeUntracked) < MASSTHRES withinareaMass = withinarea * withinmass withinareaMass = pick_closer_binarycostmat( withinareaMass, distanceUntracked) good_curr_idx, good_prev_idx = find_one_to_one_assign( withinareaMass) if len(good_curr_idx) > 0: # update the link all_new_cells.append(new_cells_temp) for ci, pi in zip(good_curr_idx, good_prev_idx): newcells.append(new_cells_temp[ci]) untr_prev[pi].next = new_cells_temp[ci] break good_curr_coords = [n.prop.coords for n in newcells] lin_curr_coords = [ convert_coords_to_linear(i, holder.img_shape) for i in flatlist(good_curr_coords) ] # find cells in old mask (in current) that overlaps with good new cells old_cells_to_remove, lin_old_coords_remove = find_coords_overlap_coords( untr_curr, lin_curr_coords, holder.img_shape) # find cells in new mask which overlaps with the cells in old mask all_new_cells = [i for j in all_new_cells for i in j] newcells_to_update = find_cells_overlap_linear_coords( all_new_cells, lin_old_coords_remove, holder.img_shape) # remove old cells for old_cell in old_cells_to_remove: container.curr_cells.remove(old_cell) # add new cells container.curr_cells.extend(newcells_to_update) return container
def prepare_curr_cells(self): self.container.curr_cells = CellListMaker(self.img, self.label, self.holder.frame).make_list()