def lap_waterhsed_intensity(img, holder, DEBRISAREA=50, BLUR=2, MAXSIZE=5000, OPENING=0, THRES=0.01, SEPARATE=3, FILTERINGSIZE=20, RATIO=1, MIN_SIGMA=8, MAX_SIGMA=12, CIRC_THRES=0.8): ''' Approximate sigma is given by sigma=radius/sqrt(2). MIN_SIGMA, MAX_SIGMA, SEPARATE are important to deal with oversegmentation... ''' img = gaussian_filter(img, BLUR) foreground = extract_foreground_adaptive(img, RATIO, FILTERINGSIZE) sigma_list = range(int(MIN_SIGMA), int(MAX_SIGMA)) local_maxima = lap_local_max(img, sigma_list, THRES) local_maxima[-foreground] = 0 local_maxima = skilabel(peak_local_max_edge(local_maxima, SEPARATE)) label = sitk_watershed_intensity(img, local_maxima) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = circularity_thresh(label, CIRC_THRES) label = skilabel(clear_border(label, buffer_size=2)) return label
def label_high_pass(img, slen=3, SIGMA=0.5, THRES=50, CLOSE=3): """For Salmonella""" cc = calc_high_pass(img, slen, SIGMA) cc[cc < 0] = 0 la = skilabel(cc > THRES, conn=1) la = closing(la, disk(CLOSE)) return la
def logglobal(img, holder, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, NUCRAD=10, magnitude=2, SHRINK=0, REGWSHED=10, HPASS=2.5, GLAP=3, CIRC_THRESH=0.8): logimg = np.log(img) highpassImg = highpassfilter(logimg, NUCRAD * HPASS) sharpLogimg = logimg + magnitude * highpassImg lapSharpLogimg = gaussian_laplace(sharpLogimg, NUCRAD / GLAP) lapSharpLogimg = lapSharpLogimg - lapSharpLogimg.min() lapSharpLogimg = lapSharpLogimg.max() - lapSharpLogimg img = lapSharpLogimg global_thresh = skifilter.threshold_otsu(img) bw = img > global_thresh bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = circularity_thresh(label, CIRC_THRES) label = skilabel(clear_border(label, buffer_size=2)) return label
def lapgauss_constant(img, holder, SIGMA=2.5, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, SHRINK=0, REGWSHED=10, THRES=0.3, COPEN=1, THINERODE=4, CIRC_THRES=0.8): cimg = calc_lapgauss(img, SIGMA) bw = cimg > THRES bw = binary_fill_holes(bw) bw = skimorph.remove_small_objects(bw, DEBRISAREA, connectivity=4) bw = binary_opening(bw, np.ones((COPEN, COPEN))) bw = remove_thin_objects(bw, THINERODE) bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = circularity_thresh(label, CIRC_THRES) label = skilabel(clear_border(label, buffer_size=2)) return label
def constant_lap_edge(img, holder, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, NUCRAD=6, MAGNITUDE=2, SHRINK=0, REGWSHED=10, FILTERSIZE=1, THRES=4, HPASS=8, CIRC_THRES=0.8): img = gaussian_filter(img, FILTERSIZE) edge = enhance_edges(img, HPASS, NUCRAD) logimg = np.log(img) - edge * MAGNITUDE bw = logimg > THRES bw = binary_fill_holes(bw) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) if OPENING != 0: # added by KL bw = binary_opening(bw, np.ones((OPENING, OPENING)), iterations=1) #added by KL label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = circularity_thresh(label, CIRC_THRES) label = skilabel(clear_border(label, buffer_size=2)) return label
def logadaptivegauss(img, holder, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, magnitude=2, NUCRAD=10, FILTERINGSIZE=100, T=10, SHRINK=0, REGWSHED=10, GLAP=3, HPASS=2.5): logimg = np.log(img) highpassImg = highpassfilter(logimg, NUCRAD * HPASS) sharpLogimg = logimg + magnitude * highpassImg lapSharpLogimg = gaussian_laplace(sharpLogimg, NUCRAD / GLAP) lapSharpLogimg = lapSharpLogimg - lapSharpLogimg.min() lapSharpLogimg = lapSharpLogimg.max() - lapSharpLogimg img = lapSharpLogimg fim = gaussian_filter(img, FILTERINGSIZE) bw = img > fim * (1. + T / 100.) bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = skilabel(clear_border(label, buffer_size=2)) return label
def lapgauss_adaptive(img, holder, RATIO=3.0, FILTERINGSIZE=50, SIGMA=2.5, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, SHRINK=0, REGWSHED=10, COPEN=1, THINERODE=4, CIRC_THRES=0.8): bw = extract_foreground_adaptive(img, RATIO, FILTERINGSIZE) cimg = calc_lapgauss(img, SIGMA) bw[cimg > 0] = 0 bw = binary_fill_holes(bw) bw = skimorph.remove_small_objects(bw, DEBRISAREA, connectivity=4) bw = binary_opening(bw, np.ones((int(COPEN), int(COPEN)))) bw = remove_thin_objects(bw, THINERODE) bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = circularity_thresh(label, CIRC_THRES) label = skilabel(clear_border(label, buffer_size=2)) return label
def remove_thin_objects(bw, THINERODE): label = skilabel(bw) erod_label = grey_erosion(label, THINERODE) unq_label = np.unique(label) unq_erod_label = np.unique(erod_label) thinobj_id = [i for i in unq_label if i not in unq_erod_label] for i in thinobj_id: bw[label == i] = 0 return bw
def example_thres(img, holder, THRES=100): """take pixel above THRES as a foreground. Examples: >>> img = np.zeros((3, 3)) >>> img[0, 0] = 10 >>> img[2, 2] = 10 >>> example_thres(img, None, THRES=5) array([[1, 0, 0], [0, 0, 0], [0, 0, 2]]) """ return skilabel(img > THRES)
def lap_local_max(img, sigma_list, THRES): img = np.uint16(img) lapimages = [] for sig in sigma_list: simg = sitk.GetImageFromArray(img) nimg = sitk.LaplacianRecursiveGaussian(image1=simg, sigma=sig) lapimages.append(-sitk.GetArrayFromImage(nimg)) image_cube = np.dstack(lapimages) local_maxima = peak_local_max(image_cube, threshold_abs=THRES, footprint=np.ones((3, 3, 3)),threshold_rel=0.0,exclude_border=False, indices=False) local_maxima = local_maxima.sum(axis=2) local_maxima = skilabel(local_maxima) return local_maxima
def lap_local_max(img, sigma_list, MIN_DIST, REL_THRES): img = np.uint16(img) lapimages = [] for sig in sigma_list: simg = sitk.GetImageFromArray(img) nimg = sitk.LaplacianRecursiveGaussian(image1=simg, sigma=sig) lapimages.append(-sitk.GetArrayFromImage(nimg)) image_cube = np.dstack(lapimages) local_maxima = peak_local_max(image_cube, min_distance=MIN_DIST, threshold_rel=REL_THRES, exclude_border=False, indices=False) local_maxima = local_maxima.sum(axis=2) local_maxima = skilabel(local_maxima) return local_maxima
def adaptivethreshwithglobal_neckcut(img, holder, ADAPTIVEBLOCK=21, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, FILTERSIZE=1, THRESHRELATIVE=1, SHRINK=0, REGWSHED=10, THRES_ANGLE=181, EDGELEN=5): img = gaussian_filter(img, FILTERSIZE) global_thresh = skifilter.threshold_otsu(img) bw = skifilter.threshold_adaptive(img, ADAPTIVEBLOCK, 'gaussian') bw = bw * img > global_thresh * THRESHRELATIVE bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) cl_label = clear_border(label) outlines = labels2outlines(cl_label) rps = regionprops(outlines) good_coords = [] for cell in rps: score, coords = calc_neck_score_thres(cell.coords, edgelen=EDGELEN, thres=THRES_ANGLE) if len(score) > 1: r0, c0 = coords[0, :] # Find candidates for cand in coords[1:, :]: cut_label = cut_neck(cl_label == cell.label, r0, c0, cand[0], cand[1]) cand_label = skilabel(cut_label) cand_rps = regionprops(cand_label) cand_rps = [i for i in cand_rps if i.area > DEBRISAREA] if len(cand_rps) > 1: good_coords.append([r0, c0, cand[0], cand[1]]) break # Reflect cut in the label for gc in good_coords: cut_neck(label, *gc) return label
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 global_otsu(img, holder, FILTERSIZE=1, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, SHRINK=0, REGWSHED=10): img = gaussian_filter(img, FILTERSIZE) global_thresh = skifilter.threshold_otsu(img) bw = img > global_thresh bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = skilabel(clear_border(label, buffer_size=2)) return label
def repair_sal(img, pimg, comb, pcomb, label, nuc_prop, nuc_loc, THRESCHANGE=1000): # repair prev = regionprops(pcomb, pimg, cache=False) prev_label = [i.label for i in prev] curr = regionprops(comb, img, cache=False) curr_label = [i.label for i in curr] store = [] for cell in curr: curr_sig = cell.mean_intensity * cell.area if cell.label in prev_label: p_cell = prev[prev_label.index(cell.label)] prev_sig = p_cell.mean_intensity * p_cell.area else: break if np.any(label == cell.label): store.append(curr_sig - prev_sig) if judge_bad(curr_sig, prev_sig, THRESCHANGE): # or diff ratio? for rp in regionprops(skilabel(label == cell.label), img, cache=False): dist = pairwise_distance((rp.centroid, ), nuc_loc)[0] for num in range(1, 4): neighbor_nuc = nuc_prop[np.argsort(dist)[num]] neiid = neighbor_nuc.label nei_curr = curr[curr_label.index(neiid)] if neiid not in prev_label: break nei_prev = prev[prev_label.index(neiid)] nei_curr_sig = nei_curr.mean_intensity * nei_curr.area nei_prev_sig = nei_prev.mean_intensity * nei_prev.area if judge_bad(nei_curr_sig, nei_prev_sig, THRESCHANGE): label[rp.coords[:, 0], rp.coords[:, 1]] = neiid break else: pass return label
def adaptivethresh2blocks(img, holder, ADAPTIVEBLOCK=21, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, FILTERSIZE=1, SHRINK=0, REGWSHED=10): img = gaussian_filter(img, FILTERSIZE) bw = skifilter.threshold_adaptive(img, ADAPTIVEBLOCK, 'gaussian') bw2 = skifilter.threshold_adaptive(img, img.shape[0] / 4, 'gaussian') bw = bw * bw2 bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = skilabel(clear_border(label, buffer_size=2)) return label
def adaptivethreshwithglobal(img, holder, ADAPTIVEBLOCK=21, DEBRISAREA=50, MAXSIZE=1000, OPENING=2, FILTERSIZE=1, THRESHRELATIVE=1, SHRINK=0, REGWSHED=10): img = gaussian_filter(img, FILTERSIZE) global_thresh = skifilter.threshold_otsu(img) bw = skifilter.threshold_adaptive(img, ADAPTIVEBLOCK, 'gaussian') bw = bw * img > global_thresh * THRESHRELATIVE bw = sizefilterandopen(bw, DEBRISAREA, MAXSIZE, OPENING) if SHRINK > 0: bw = binary_erosion(bw, np.ones((SHRINK, SHRINK))) label = devide_and_label_objects(bw, REGWSHED) label = sizefilter_for_label(label, DEBRISAREA, MAXSIZE, OPENING) label = skilabel(clear_border(label, buffer_size=2)) return label
def devide_and_label_objects(bw, REGWSHED): label = skilabel(bw).astype(np.int64) if REGWSHED > 0: label = watershed(label, REGWSHED) return label
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