def __init__(self, img, seed=(0, 0, 0), alpha=1000, sigma=5.48, smoothing=1, threshold=0.31, balloon=5): import morphsnakes self.alpha = alpha self.sigma = sigma self.smoothing = smoothing self.threshold = threshold self.balloon = balloon self.img = img self.seed = seed # self.gI = morphsnakes.gborders(img, alpha=alpha, sigma=sigma) # self.mgac = morphsnakes.MorphGAC(self.gI, smoothing=smoothing, threshold=threshold, balloon=balloon) # self.last_levelset = self.mgac.levelset = circle_levelset(img.shape, seed, balloon) self.macwe = morphsnakes.MorphACWE(img, smoothing=1, lambda1=1, lambda2=2) self.last_levelset = self.macwe.levelset = circle_levelset( img.shape, seed, balloon) self.last_crop_levelset = Crop_arr(self.last_levelset) self.iter_ind = 0 self.max_balloon = balloon * 2
def _autolevelset(self, startPoints="min"): # Convert the startPoints to a list if necessary if not isinstance(startPoints, list): startPoints = [startPoints for i in range(len(self.data))] self.macwes = list() for frame, img in enumerate(self.data): # Set up the image macwe = morphsnakes.MorphACWE(img, smoothing=self.smoothing ,\ lambda1=self.lambda1 ,\ lambda2=self.lambda2 ) macwe.frame = frame if startPoints[frame] == "min": x, y = np.where(img == np.min(img)) elif startPoints[frame] == "max": x, y = np.where(img == np.max(img)) else: raise ValueError( "startPoint %r not understood. It must be either min or max" % startPoints[frame]) macwe.levelset = circle_levelset(img.shape, (x[0], y[0]), 10) self.macwes.append(macwe)
def example_confocal3d(): # Load the image. img = np.load("testimages/confocal.npy") # Morphological ACWE. Initialization of the level-set. macwe = morphsnakes.MorphACWE(img, smoothing=1, lambda1=1, lambda2=2) macwe.levelset = circle_levelset(img.shape, (30, 50, 80), 25)
def test_confocal3d(): # Load the image. img = np.load("testimages/confocal.npy") # Morphological ACWE. Initialization of the level-set. macwe = morphsnakes.MorphACWE(img, smoothing=1, lambda1=1, lambda2=2) macwe.levelset = circle_levelset(img.shape, (30, 50, 80), 25) # Visual evolution. morphsnakes.evolve_visual3d(macwe, num_iters=200)
def step(self, iters=1): balloon = self.balloon img = self.img # self.mgac.step() # self.last_levelset = self.mgac.levelset # self.macwe.step() # self.last_levelset = self.macwe.levelset # return # Coordinates of non-black pixels. coords = np.argwhere(self.last_levelset) # Bounding box of non-black pixels. try: x0, y0, z0 = coords.min(axis=0) x1, y1, z1 = coords.max( axis=0) + 1 # slices are exclusive at the top except: return bounds = [x0, y0, z0, x1, y1, z1] crop_bounds = [] for i, c in enumerate(bounds): c += balloon * (iters + 1) if i > 2 else balloon * (-1) * (iters + 1) if i < 3: c = 0 if c < 0 else c else: s = img.shape[i - 3] c = s if c > s else c crop_bounds.append(c) # print(self.last_crop_levelset.shape) (x0, y0, z0, x1, y1, z1) = crop_bounds = tuple(crop_bounds) # gI = morphsnakes.gborders(img[x0:x1, y0:y1, z0:z1], alpha=self.alpha, sigma=self.sigma) # balloon = self.balloon macwe = morphsnakes.MorphACWE(img[x0:x1, y0:y1, z0:z1], smoothing=1, lambda1=1, lambda2=2) macwe.levelset = self.last_levelset[x0:x1, y0:y1, z0:z1] # balloon = self.balloon * random.uniform(0.5, 1.2) # mgac = morphsnakes.MorphGAC(gI, smoothing=self.smoothing, threshold=self.threshold, balloon=balloon) # mgac.levelset = self.last_levelset[x0:x1, y0:y1, z0:z1] for _ in range(iters): macwe.step() self.last_levelset[x0:x1, y0:y1, z0:z1] = macwe.levelset self.last_crop_levelset = Crop_arr(macwe.levelset, (x0, y0, z0), (x1, y1, z1)) self.iter_ind += iters
def test_lakes(): # Load the image. imgcolor = imread("testimages/lakes3.jpg") / 255.0 img = rgb2gray(imgcolor) # MorphACWE does not need g(I) # Morphological ACWE. Initialization of the level-set. macwe = morphsnakes.MorphACWE(img, smoothing=3, lambda1=1, lambda2=1) macwe.levelset = circle_levelset(img.shape, (80, 170), 25) # Visual evolution. ppl.figure() morphsnakes.evolve_visual(macwe, num_iters=190, background=imgcolor)
def faz_level_set_3d(img, poligono, it): gmin, gmax = 0.0, 1.0 fmin, fmax = img.min(), img.max() nimg = ((gmax - gmin) / (fmax - fmin)) * (img - fmin) + gmin macwe = morphsnakes.MorphACWE(nimg, smoothing=3, lambda1=1, lambda2=1) #macwe= morphsnakes.MorphGAC(nimg,smoothing=1,threshold=0.6, balloon=-2) macwe.levelset = poligono for i in xrange(it): macwe.step() yield macwe.levelset
def morph_snake(img, ROI, radius): #Input: Image to apply snake to as well as a region of interest and radius for the snake to initialize from and extend to #Output: Image of applied snake (including pixel values for mass outline) img1 = img / 255.0 # g(I) gI = morphsnakes.gborders(img1, alpha=1000, sigma=11) mgac = morphsnakes.MorphACWE(img1, smoothing=3, lambda1=1, lambda2=1) mgac.levelset = circle_levelset(img1.shape, ROI, radius) pylab.figure(figsize=(8, 6), dpi=400) return (morphsnakes.evolve_visual(mgac, num_iters=30, background=img1)) #110 pylab.show()
def _segment(image, lambda2, iterations, smoothing=1, sigma=None, threshold=None, init=None): """Segment a region of the image using morphological active contours""" if threshold is not None: image[image < threshold] = 0 if sigma is not None: image = ndif.gaussian_filter(image, sigma=sigma) if init is None: init = np.zeros_like(image, dtype=np.uint8) bounds = np.ceil(np.array(image.shape) * 0.1).astype(int) init[[slice(b, -b) for b in bounds]] = 1 macwe = morphsnakes.MorphACWE(image, smoothing=smoothing, lambda2=lambda2) macwe.levelset = init macwe.run(iterations) return macwe.levelset.astype(np.uint8)
def test_confocal3d(img): if False: macwe = morphsnakes.MorphGAC(img, smoothing=1, threshold=0.3, balloon=-1) else: macwe = morphsnakes.MorphACWE(img, smoothing=1, lambda1=1, lambda2=2) macwe.levelset = circle_levelset(img.shape, (30, 50, 80), 25) if True: # Visual evolution. morphsnakes.evolve_visual3d(macwe, num_iters=200) else: fig = ppl.figure(frameon=False) for i in range(100): macwe.step() fd = macwe.levelset ppl.imshow(np.max(img, axis=2), cmap='gray') ppl.imshow(np.max(fd[:, :, :], axis=2), cmap='jet', alpha=0.3) ppl.show() ppl.pause(.1) ppl.draw()
def snake(img, init_submasks=None, init_contours=None, lambda1=MORPHSNAKE_LAMBDA1, return_masks=True, min_size=MIN_SUBMASK_SIZE, crop_margin=50): """ Args: crop_margin (int): crop the image to fit the extent of all masks plus a margin of `margin`. Set to negative for no cropping. """ if init_contours is None: assert init_submasks is not None, "If no init_contours is given, must provide init_submasks." init_submasks = [ m for m in init_submasks if np.count_nonzero(init_submasks) <= min_size ] assert len( init_submasks ) > 0, "No initial submasks are above the minimal area of %d." % min_size assert all([ (m.shape[0] == img.shape[0]) & (m.shape[1] == img.shape[1]) for m in init_submasks ]), "Not all shapes of initial submasks match the input image." bbox_all_submasks = [bbox_2d(m) for m in init_submasks] xmin, ymin = np.min(bbox_all_submasks[:, [0, 2]]) xmax, ymax = np.max(bbox_all_submasks[:, [1, 3]]) else: init_contours = [c.astype(np.int) for c in init_contours] xmin, ymin = np.min([np.min(c, axis=0) for c in init_contours], axis=0) xmax, ymax = np.max([np.max(c, axis=0) for c in init_contours], axis=0) # Crop to fit the extent. if crop_margin >= 0: crop_xmin = max(0, xmin - crop_margin) crop_ymin = max(0, ymin - crop_margin) crop_xmax = min(img.shape[1] - 1, xmax + crop_margin) crop_ymax = min(img.shape[0] - 1, ymax + crop_margin) cropped_img = img[crop_ymin:crop_ymax + 1, crop_xmin:crop_xmax + 1] else: crop_xmin = 0 crop_ymin = 0 crop_xmax = img.shape[1] - 1 crop_ymax = img.shape[0] - 1 cropped_img = img # Form initial levelsets init_levelsets = [] if init_contours is None: for m in init_submasks: init_levelset = m[crop_ymin:crop_ymax + 1, crop_xmin:crop_xmax + 1] init_levelset[:10, :] = 0 init_levelset[-10:, :] = 0 init_levelset[:, :10] = 0 init_levelset[:, -10:] = 0 init_levelsets.append(init_levelset) else: for cnt in init_contours: init_contours_on_cropped_img = cnt - (crop_xmin, crop_ymin) init_levelset = contours_to_mask([init_contours_on_cropped_img], cropped_img.shape[:2]) init_levelset[:10, :] = 0 init_levelset[-10:, :] = 0 init_levelset[:, :10] = 0 init_levelset[:, -10:] = 0 init_levelsets.append(init_levelset) sys.stderr.write('Found %d levelsets.\n' % len(init_levelsets)) ##################### # Evolve morphsnake # ##################### final_masks = [] for levelset_ind, init_levelset in enumerate(init_levelsets): sys.stderr.write('\nContour %d\n' % levelset_ind) discard = False init_area = np.count_nonzero(init_levelset) t = time.time() msnake = morphsnakes.MorphACWE(cropped_img.astype(np.float), smoothing=int(MORPHSNAKE_SMOOTHING), lambda1=lambda1, lambda2=MORPHSNAKE_LAMBDA2) msnake.levelset = init_levelset.copy() dq = deque([None, None]) for i in range(MORPHSNAKE_MAXITER): # At stable stage, the levelset (thus contour) will oscilate, # so instead of comparing to previous levelset, must compare to the one before the previous oneBefore_levelset = dq.popleft() # If less than 3 pixels are changed, stop. if i > MORPHSNAKE_MINITER: if np.count_nonzero(msnake.levelset - oneBefore_levelset ) < PIXEL_CHANGE_TERMINATE_CRITERIA: break # area = np.count_nonzero(msnake.levelset) # if area < min_size: # discard = True # sys.stderr.write('Too small, stop iteration.\n') # break labeled_mask = label(msnake.levelset.astype(np.bool)) component_sizes = [] for l in np.unique(labeled_mask): if l != 0: m = labeled_mask == l component_area = np.count_nonzero(m) component_sizes.append(component_area) if component_area / float( init_area) > AREA_CHANGE_RATIO_MAX: msnake.levelset[m] = 0 sys.stderr.write( 'Component area expands too much - nullified.\n') elif component_area < min_size: msnake.levelset[m] = 0 sys.stderr.write( 'Component area is too small - nullified.\n') print component_sizes if np.count_nonzero(msnake.levelset) / float( init_area) < AREA_CHANGE_RATIO_MIN: discard = True sys.stderr.write('Area shrinks too much, stop iteration.\n') break dq.append(msnake.levelset) # t = time.time() msnake.step() # sys.stderr.write('Step: %f seconds\n' % (time.time()-t)) # 0.6 second/step, roughly 200 steps takes 120s sys.stderr.write('Snake finished at iteration %d.\n' % i) sys.stderr.write('Snake: %.2f seconds\n' % (time.time() - t)) # 72s if discard: sys.stderr.write('Discarded.\n') continue else: # Handles the case that a single initial contour morphs into multiple contours labeled_mask = label(msnake.levelset.astype(np.bool)) for l in np.unique(labeled_mask): if l != 0: m = labeled_mask == l if np.count_nonzero(m) > min_size: final_masks.append(m) sys.stderr.write('Final masks added.\n') if len(final_masks) == 0: sys.stderr.write('Snake return no valid submasks.\n') return [] if return_masks: final_masks_uncropped = [] for m in final_masks: uncropped_mask = np.zeros(img.shape[:2], np.bool) uncropped_mask[crop_ymin:crop_ymax + 1, crop_xmin:crop_xmax + 1] = m final_masks_uncropped.append(uncropped_mask) return final_masks_uncropped else: final_contours = [] for m in final_masks: cnts = [ cnt_on_cropped + (crop_xmin, crop_ymin) for cnt_on_cropped in find_contour_points(m)[1] ] final_contours += cnts return final_contours
vel = np.zeros((num_vessels, nfrms)) print('coords = ', coords) fig = ppl.figure(num=32, figsize=(16, 16)) fig.clf() ax1 = ppl.subplot(2, 2, 1) ax1.set_xticks([]) ax1.set_yticks([]) ppl.imshow(myimg, cmap=ppl.cm.gray, interpolation='bicubic') masksum = np.zeros((nrows, ncols)) for ptnum, pt in enumerate(coords): # Morphological ACWE. Initialization of the level-set. macwe = morphsnakes.MorphACWE(myimg, smoothing=1, lambda1=1, lambda2=2) macwe.levelset = circle_levelset(myimg.shape, pt, 2) # Visual evolution. numiter = 10 print('Snaking at (%d,%d)...' % (pt)) # finalset = morphsnakes.evolve_visual(macwe, num_iters=numiter, background=myimg) ax1.contour(macwe.levelset, [0.5], colors='r') ax2 = ppl.subplot(2, 2, 2) ax2.set_xticks([]) ax2.set_yticks([]) ax2b = ppl.imshow(macwe.levelset) # Iterate.
# for _ in range(3): # scoremap_thresholded_padded = binary_erosion(scoremap_thresholded_padded, disk(3)) scoremap_thresholded_padded = remove_small_holes( scoremap_thresholded_padded, 1000) # scoremap_thresholded_padded = remove_small_objects(scoremap_thresholded_padded, 100) scoremap_thresholded = scoremap_thresholded_padded[50:-50, 50:-50][:] init_levelset = np.zeros((roi_height, roi_width)) init_levelset[inside_points_inroi[:, 1], inside_points_inroi[:, 0]] = 1. t = time.time() msnake = morphsnakes.MorphACWE(scoremap_thresholded.astype(np.float), smoothing=smoothing, lambda1=1., lambda2=1.) msnake.levelset = init_levelset.copy() # levelset values are either 1.0 or 0.0 dq = deque([None, None]) for i in range(1000): # at stable stage, the levelset (thus contour) will oscilate, # so instead of comparing to previous levelset, must compare to the one before the previous oneBefore_levelset = dq.popleft() if i > 10: # print np.count_nonzero(msnake.levelset - oneBefore_levelset) if np.count_nonzero(msnake.levelset - oneBefore_levelset) < 3:
def generate_mask(fn, tb_fmt='png'): try: submask_dir = create_if_not_exists(os.path.join(output_dir, fn)) execute_command('rm -f %s/*' % submask_dir) img_rgb = imread( os.path.join(input_dir, '%(fn)s.%(tb_fmt)s' % dict(fn=fn, tb_fmt=tb_fmt))) stds = [] images = [] # for c in range(3): for c in [0]: img = img_rgb[..., c].copy() border = np.median(np.r_[img[:10, :].flatten(), img[-10:, :].flatten(), img[:, :10].flatten(), img[:, -10:].flatten()]) if border < 123: # dark background, fluorescent img = img.max( ) - img # invert, make tissue dark on bright background # Stretch contrast img_flattened = img.flatten() vmax_perc = VMAX_PERCENTILE while vmax_perc > 80: vmax = np.percentile(img_flattened, vmax_perc) if vmax < 255: break else: vmax_perc -= 1 vmin_perc = VMIN_PERCENTILE while vmin_perc < 20: vmin = np.percentile(img_flattened, vmin_perc) if vmin > 0: break else: vmin_perc += 1 sys.stderr.write('%d(%d percentile), %d(%d percentile)\n' % (vmin, vmin_perc, vmax, vmax_perc)) img = img_as_ubyte(rescale_intensity(img, in_range=(vmin, vmax))) # img[(img <= vmax) & (img >= vmin)] = 255./(vmax-vmin)*(img[(img <= vmax) & (img >= vmin)]-vmin) # img[img > vmax] = 255 # img[img < vmin] = 0 # img = img.astype(np.uint8) images.append(img) std = np.std(img) stds.append(std) sys.stderr.write('std: %.2f\n' % (std)) best_channel_id = np.argmax(stds) sys.stderr.write('Use channel %s.\n' % ['RED', 'GREEN', 'BLUE'][best_channel_id]) img = images[best_channel_id] ############################# ## Graph cut based method. ## ############################# # Input to slic() must be float slic_labels = slic(img.astype(np.float), sigma=SLIC_SIGMA, compactness=SLIC_COMPACTNESS, n_segments=SLIC_N_SEGMENTS, multichannel=False, max_iter=SLIC_MAXITER) # sim_graph = rag_mean_color(img, slic_labels, mode='similarity', sigma=SUPERPIXEL_SIMILARITY_SIGMA) # Normalized cut - merge superpixels. # for _ in range(3): # try: # t = time.time() # ncut_labels = cut_normalized(slic_labels, sim_graph, in_place=False, thresh=SUPERPIXEL_MERGE_SIMILARITY_THRESH, # num_cuts=GRAPHCUT_NUM_CUTS) # sys.stderr.write('Normalized Cut: %.2f seconds.\n' % (time.time() - t)) # break # except ArpackError as e: # sys.stderr.write('ArpackError encountered.\n') # continue # ncut_boundaries_viz = mark_boundaries(img, label_img=ncut_labels, background_label=-1) # imsave(os.path.join(submask_dir, '%(fn)s_.png' % dict(fn=fn)), ncut_boundaries_viz) ncut_labels = slic_labels # Find background superpixels. background_labels = np.unique( np.concatenate([ ncut_labels[:, 0], ncut_labels[:, -1], ncut_labels[0, :], ncut_labels[-1, :] ])) # Collect training superpixels. border_histos = [] for b in background_labels: histo = np.histogram(img[ncut_labels == b], bins=np.arange(0, 256, 5))[0].astype(np.float) histo = histo / np.sum(histo) border_histos.append(histo) histos = {} for l in np.unique(ncut_labels): histo = np.histogram(img[ncut_labels == l], bins=np.arange(0, 256, 5))[0].astype(np.float) histo = histo / np.sum(histo) histos[l] = histo hist_distances = {} for l, h in histos.iteritems(): hist_distances[l] = np.percentile( [chi2(h, th) for th in border_histos], BORDER_DISSIMILARITY_PERCENTILE) # min is too sensitive if there is a blob at the border if FOREGROUND_DISSIMILARITY_THRESHOLD is None: # Automatically determine this value dist_vals = np.asarray(hist_distances.values()) ticks = np.linspace(0, dist_vals.max(), 100) percentages = [ np.count_nonzero(dist_vals < th) / float(len(dist_vals)) for th in ticks ] def moving_average(interval, window_size): window = np.ones(int(window_size)) / float(window_size) return np.convolve(interval, window, 'same') grad = np.gradient(percentages, 3) # smoothed_grad = moving_average(grad, 1) hessian = np.gradient(grad, 3) # plt.figure(); # plt.plot(ticks, grad, label='grad'); # plt.plot(ticks, smoothed_grad, label='smoothed'); # plt.legend(); # plt.xlabel('Chi2 distance'); # plt.savefig(os.path.join(submask_dir, '%(fn)s_spDissimCumDistGradient.png' % dict(fn=fn))); # plt.close(); # plt.figure(); # plt.plot(ticks, h); # plt.title('Hessian - minima is the plateau point of cum. distr.'); # plt.xlabel('Dissimlarity threshold'); # plt.savefig(os.path.join(submask_dir, '%(fn)s_spDissimCumDistHessian.png' % dict(fn=fn))); # plt.close(); # ticks_sorted = ticks[np.argsort(grad, kind='mergesort')] # ticks_sorted = ticks[np.argsort(smoothed_grad, kind='mergesort')] ticks_sorted = ticks[10:][hessian[10:].argsort()] ticks_sorted_reduced = ticks_sorted[ ticks_sorted < FOREGROUND_DISSIMILARITY_THRESHOLD_MAX] init_contour_percentages = np.asarray([ np.sum([ np.count_nonzero(ncut_labels == l) for l, d in hist_distances.iteritems() if d > th ]) / float(img.size) for th in ticks_sorted_reduced ]) threshold_candidates = ticks_sorted_reduced[(init_contour_percentages < INIT_CONTOUR_COVERAGE_MAX) &\ (init_contour_percentages > 0)] # np.savetxt(os.path.join(submask_dir, '%(fn)s_spThreshCandidates.txt' % dict(fn=fn)), threshold_candidates, fmt='%.3f') print threshold_candidates[:10] foreground_dissimilarity_threshold = threshold_candidates[0] else: foreground_dissimilarity_threshold = FOREGROUND_DISSIMILARITY_THRESHOLD sys.stderr.write('FOREGROUND_DISSIMILARITY_THRESHOLD: %.2f\n' % foreground_dissimilarity_threshold) # Visualize superpixel border distance map superpixel_border_distances = np.zeros_like(img, np.float) for l, s in hist_distances.iteritems(): superpixel_border_distances[ncut_labels == l] = s # plt.figure(); # im = plt.imshow(superpixel_border_distances, vmin=0, vmax=2); # plt.title('Superpixels distance to border'); # plt.colorbar(im, fraction=0.025, pad=0.02); # plt.savefig(os.path.join(submask_dir, '%(fn)s_spBorderDissim.png' % dict(fn=fn))); # plt.close(); # Generate mask for snake's initial contours. superpixel_mask = np.zeros_like(img, np.bool) for l, d in hist_distances.iteritems(): if d > foreground_dissimilarity_threshold: superpixel_mask[ncut_labels == l] = 1 superpixel_mask = remove_small_objects(superpixel_mask, min_size=MIN_SIZE) labelmap, n_submasks = label(superpixel_mask, return_num=True) # superpixel_submasks = [] dilated_superpixel_submasks = [] for i in range(1, n_submasks + 1): m = labelmap == i # superpixel_submasks.append(m) dilated_m = binary_dilation(m, disk(10)) dilated_m = remove_small_objects(dilated_m, min_size=MIN_SIZE) dilated_superpixel_submasks.append(dilated_m) # Visualize # viz = img_as_ubyte(ncut_boundaries_viz) # for submask in superpixel_submasks: # for cnt in find_contour_points(submask)[1]: # cv2.polylines(viz, [cnt.astype(np.int)], True, (255,0,0), 1) # red # for submask in dilated_superpixel_submasks: # for cnt in find_contour_points(submask)[1]: # cv2.polylines(viz, [cnt.astype(np.int)], True, (0,0,255), 1) # blue # imsave(os.path.join(submask_dir, '%(fn)s_ncutSubmasks.png' % dict(fn=fn)), viz) ##################### # Find contours from mask. init_contours = [] for submask in dilated_superpixel_submasks: cnts = find_contour_points(submask.astype(np.int), sample_every=1) if 1 not in cnts or len(cnts[1]) == 0: continue for cnt in cnts[1]: if len(cnt) > INIT_CONTOUR_MINLEN: init_contours.append(cnt) # assert len(init_contours) > 0, 'No contour is detected from entropy mask %s' % fn sys.stderr.write('Extracted %d contours from mask.\n' % len(init_contours)) # Create initial levelset init_levelsets = [] for cnt in init_contours: init_levelset = np.zeros_like(img, np.float) init_levelset[contours_to_mask([cnt], img.shape[:2])] = 1. init_levelset[:10, :] = 0 init_levelset[-10:, :] = 0 init_levelset[:, :10] = 0 init_levelset[:, -10:] = 0 init_levelsets.append(init_levelset) ####################### # Binary Thresholding # ####################### img_enhanced = img ##################### # Evolve morphsnake # ##################### final_masks = [] for init_levelset in init_levelsets: discard = False init_area = np.count_nonzero(init_levelset) t = time.time() msnake = morphsnakes.MorphACWE(img_enhanced.astype(np.float), smoothing=int(MORPHSNAKE_SMOOTHING), lambda1=MORPHSNAKE_LAMBDA1, lambda2=MORPHSNAKE_LAMBDA2) msnake.levelset = init_levelset.copy() dq = deque([None, None]) for i in range(MORPHSNAKE_MAXITER): # At stable stage, the levelset (thus contour) will oscilate, # so instead of comparing to previous levelset, must compare to the one before the previous oneBefore_levelset = dq.popleft() # If less than 3 pixels are changed, stop. if i > MORPHSNAKE_MINITER: if np.count_nonzero(msnake.levelset - oneBefore_levelset ) < PIXEL_CHANGE_TERMINATE_CRITERIA: break area = np.count_nonzero(msnake.levelset) if area < MIN_SIZE: discard = True sys.stderr.write('Too small, stop iteration.\n') break labeled_mask = label(msnake.levelset.astype(np.bool)) for l in np.unique(labeled_mask): if l != 0: m = labeled_mask == l if np.count_nonzero(m) / float( init_area) > AREA_CHANGE_RATIO_MAX: msnake.levelset[m] = 0 sys.stderr.write('Area nullified.\n') if np.count_nonzero(msnake.levelset) / float( init_area) < AREA_CHANGE_RATIO_MIN: discard = True sys.stderr.write( 'Area shrinks too much, stop iteration.\n') break dq.append(msnake.levelset) # t = time.time() msnake.step() # sys.stderr.write('Step: %f seconds\n' % (time.time()-t)) # 0.6 second / step sys.stderr.write('Snake finished at iteration %d.\n' % i) sys.stderr.write('Snake: %.2f seconds\n' % (time.time() - t)) # 72s if discard: sys.stderr.write('Discarded.\n') continue else: # Handles the case that a single initial contour morphs into multiple contours labeled_mask = label(msnake.levelset.astype(np.bool)) for l in np.unique(labeled_mask): if l != 0: m = labeled_mask == l if np.count_nonzero(m) > MIN_SIZE: final_masks.append(m) sys.stderr.write('Final masks added.\n') ############ ## Export ## ############ # submask_viz_dir = create_if_not_exists('/home/yuncong/CSHL_data_processed/%(stack)s/%(stack)s_submask_overlayViz/%(fn)s' % dict(stack=stack, fn=fn)) # execute_command('rm %s/*' % submask_viz_dir) # img_rgb = imread(os.path.join(input_dir, fn + '.' + tb_fmt)) # all_init_cnts = [] # for i, init_levelset in enumerate(init_levelsets): # all_init_cnts += find_contour_points(init_levelset)[1] for i, mask in enumerate(final_masks): imsave( os.path.join(submask_dir, '%(fn)s_submask_%(i)d.png' % { 'fn': fn, 'i': i }), img_as_ubyte(mask)) # viz = img_rgb.copy() # # cnts = find_contour_points(mask) # if len(cnts) == 0: # raise # for cnt in cnts[1]: # cv2.polylines(viz, [cnt.astype(np.int)], True, (255,0,0), 3) # red # # for cnt in all_init_cnts: # cv2.polylines(viz, [cnt.astype(np.int)], True, (0,255,0), 3) # green # viz_fn = os.path.join(submask_dir, '%(fn)s_submask_%(i)d_overlayViz.png' % dict(fn=fn, i=i+1)) # sys.stderr.write(viz_fn + '\n') # imsave(viz_fn, viz) ################################################ # Automatically judge the goodness of each mask ################################################ submasks = final_masks n = len(final_masks) rank1 = np.argsort([np.count_nonzero(m) for m in submasks])[::-1] image_center = np.r_[submasks[0].shape[1] / 2, submasks[0].shape[0] / 2] bbox_to_image_center_distance = [] for m in submasks: xmin, xmax, ymin, ymax = bbox_2d(m) dist = np.sqrt( np.sum((image_center - ((xmin + xmax) / 2, (ymin + ymax) / 2))**2)) bbox_to_image_center_distance.append(dist) rank2 = np.argsort(bbox_to_image_center_distance) r1 = np.asarray( [r for r, i in sorted(enumerate(rank1), key=lambda (r, i): i)]) r2 = np.asarray( [r for r, i in sorted(enumerate(rank2), key=lambda (r, i): i)]) rank = np.argsort( r1 + 1.01 * r2) # weight being close to center a bit more to break tie best_mask_ind = rank[0] decisions = [False for _ in range(n)] decisions[best_mask_ind] = True np.savetxt(os.path.join(submask_dir, '%(fn)s_submasksAlgReview.txt' % dict(fn=fn)), decisions, fmt='%d') except Exception as e: sys.stderr.write('%s\n' % e) sys.stderr.write('Mask error: %s\n' % fn) return