def binarize_image(img, blank_bbox, threshold="otsu", threshold_perc=99.9, opening=None, min_hole=25, min_object=25, invert=False, autoexpose=False): if invert: img = imgz.invert(img) if autoexpose: img = imgz.equalize_adaptive(img) if opening is not None: img = morphology.opening(img, selem=morphology.disk(opening)) threshold_dict = { "otsu": filters.threshold_otsu, "li": filters.threshold_li, "isodata": filters.threshold_isodata } if threshold in ["otsu", "li", "isodata"]: threshold = threshold_dict[threshold](img) else: threshold = threshold_from_blank_bbox(img, blank_bbox, perc=threshold_perc) binary_img = pipe(img > threshold, imgz.remove_small_holes(min_hole), imgz.remove_small_objects(min_object)) return binary_img
def main(imgfile, outfile, rows, cols, threshold="otsu", elemsize=None, min_gap=None, min_n=None, display=False, invert=False, autoexpose=False): """Infer the coordinates of a gridded set of objects in an image. Grid finding involves three key steps: 1. Image thresholding to define foreground vs background and generate a binary image 2. Morphological opening of the binary image 3. Inference of the grid coordinates from foreground objects in the binary image. User can optionally choose to invert and apply exposure equalization to the input image. Inversion is required when the objects of interest are dark objects on a light background (e.g. transparency scanning). """ img = io.imread(imgfile) if invert: img = imgz.invert(img) if autoexpose: img = imgz.equalize_adaptive(img) threshold_dict = { "otsu": imgz.threshold_otsu, "li": imgz.threshold_li, "isodata": imgz.threshold_isodata } threshold_func = threshold_dict[threshold] binary_img, selem_size = threshold_and_open(img, threshold_func) try: results = find_grid(binary_img, rows, cols, min_gap, min_n) s = json.dumps(results, indent=1) outfile.write(s) except RuntimeError: if display: fig, ax = plot.subplots() ax.imshow(img) plt.show() if display: fig, ax = plt.subplots() ax.imshow( spotzplot.colorize_grayscale(img, binary_img, clr=[1, 0, 0, 0.25])) spotzplot.draw_bboxes(results["bboxes"], ax) plt.show()
def main(imgfiles, outdir, rows, cols, prefix = "grid", threshold = "otsu", elemsize = None, min_gap = None, min_n = None, display = False, invert = False, autoexpose = False): """Infer the coordinates of a gridded set of objects in an image. Grid finding involves three key steps: 1. Image thresholding to define foreground vs background and generate a binary image 2. Morphological opening of the binary image 3. Inference of the grid coordinates from foreground objects in the binary image. User can optionally choose to invert and apply exposure equalization to the input image. Inversion is required when the objects of interest are dark objects on a light background (e.g. transparency scanning). """ threshold_dict = {"otsu":imgz.threshold_otsu, "li":imgz.threshold_li, "isodata":imgz.threshold_isodata} threshold_func = threshold_dict[threshold] for imgfile in imgfiles: img = np.squeeze(io.imread(imgfile)) oimg = np.copy(img) if invert: img = imgz.invert(img) if autoexpose: img = imgz.equalize_adaptive(img) binary_img, selem_size = threshold_and_open(img, threshold_func) try: grid_data = find_grid(binary_img, rows, cols, min_gap, min_n) except RuntimeError: print("No grid found in {}".format(imgfile)) if display: fig, ax = plt.subplots() ax.imshow(oimg, cmap = "gray") ax.imshow(binary_img, cmap = "Reds", alpha = 0.45) plt.show() sys.exit(1) s = json.dumps(grid_data, indent = 1) root, _ = os.path.splitext(os.path.basename(imgfile)) outfile = os.path.join(outdir, "{}-{}.json".format(prefix, root)) with open(outfile, "w") as f: f.write(s) if display: fig, ax = plt.subplots() ax.imshow(oimg, cmap = "gray") ax.imshow(binary_img, cmap = "Reds", alpha = 0.45) spotzplot.draw_bboxes(grid_data["bboxes"], ax) plt.show()
def threshold_from_blank(blankimg, perc=99.9, invert=False): if invert: blankimg = imgz.invert(blankimg) return np.percentile(blankimg.ravel(), perc)
def segment_image(img, grid_data, threshold="local", blocksize=None, sigma=None, elemsize=None, min_hole=None, min_object=None, max_eccentricity=0.75, clear_border=False, invert=False, autoexpose=False): min_dim, max_dim = min(img.shape), max(img.shape) if invert: img = imgz.invert(img) if autoexpose: img = imgz.equalize_adaptive(img) # Thresholding # threshold_dict = { "local": imgz.threshold_gaussian, "otsu": imgz.threshold_otsu, "li": imgz.threshold_li, "isodata": imgz.threshold_isodata } threshold_func = threshold_dict[threshold] if threshold == "local": if blocksize is None: blocksize = 3 if sigma is None: sigma = 4 threshold_func = threshold_func(blocksize, sigma) binary_img = threshold_func(img) # Morphological opening # if elemsize is None: elemsize = int(round(min(3, min_dim / 100. + 1))) binary_img = imgz.disk_opening(elemsize, binary_img) # Filter holes, small objects, border # if min_hole is None: min_hole = int(max(1, min_dim * 0.02)**2) if min_object is None: min_object = int(max(1, min_dim * 0.005)**2) binary_img = pipe(binary_img, imgz.remove_small_objects(min_object), imgz.remove_small_holes(min_hole)) if clear_border: binary_img = imgz.clear_border(binary_img) # Filter and relabel based on grid # labeled_img = filter_objects_by_grid(grid_data, binary_img) return labeled_img
def main(imgfiles, gridfile, outdir, prefix, opensize=3, closesize=3, minhole=25, minobject=25, border=10, maxdist=30, seedwidth=5, globalthresh=False, userthresh=0, threshold="li", localthresh=0.5, invert=True, autoexpose=False, display=False, saveimage=False, withgrid=False): """Segment microbial colonies in an image of a pinned plate. Input is one or more image files, a JSON "grid file" created by the gridder program, and the name of the directory to write the segmentation mask to. Segmentation involves: - Inversion (required if dark colonies on light) and auto exposure (optional) - Thresholding based on grid (unless globalthresh or userthresh specified) - Filtering of small objects and holes - Morphological closing - Watershed determination of objects within grid """ threshold_dict = { "otsu": filters.threshold_otsu, "li": filters.threshold_li, "triangle": filters.threshold_triangle, "mean": filters.threshold_mean, "yen": filters.threshold_yen } threshold_func = threshold_dict[threshold] grid_data = json.load(open(gridfile, "r")) grid_centers = np.array(grid_data["centers"]) grid_bboxes = grid_data["bboxes"] for imgfile in imgfiles: img = np.squeeze(io.imread(imgfile)) if invert: iimg = imgz.invert(img) else: iimg = img if autoexpose: iimg = imgz.equalize_adaptive(iimg) # threshold if userthresh > 0: thresh_img = iimg > userthresh elif globalthresh: thresh_img = iimg > threshold_func(iimg) else: thresh_img = threshold_bboxes(grid_bboxes, iimg, threshold_func=threshold_func, min_local_threshold=localthresh, border=border) thresh_img = pipe(thresh_img, imgz.remove_small_objects(minobject), imgz.remove_small_holes(minhole), imgz.disk_closing(closesize), imgz.disk_opening(opensize), imgz.clear_border) filtered_img, filtered_regions = assign_objects_to_grid( grid_centers, thresh_img, maxdist=maxdist) filtered_bboxes = [r.bbox if r else None for r in filtered_regions] watershed_img = watershed_segment_bboxes(grid_centers, filtered_bboxes, iimg, thresh_img, seed_width=seedwidth) root, _ = os.path.splitext(os.path.basename(imgfile)) outfile = os.path.join(outdir, "{}-{}.npz".format(prefix, root)) sp.sparse.save_npz(outfile, sp.sparse.coo_matrix(watershed_img)) if saveimage: fig, ax = spotzplot.draw_image_and_labels(img, watershed_img, mask_cmap="Reds", alpha=0.35, fontsize=4, textcolor="orange") if withgrid: spotzplot.draw_bboxes(grid_bboxes, ax=ax) imagefile = os.path.join(outdir, "{}-{}.png".format(prefix, root)) nrows, ncols = img.shape if nrows > ncols: FIG_SIZE = (9, 6) else: FIG_SIZE = (6, 9) fig.set_size_inches(FIG_SIZE) fig.savefig(imagefile, dpi=300) if display: fig, ax = plt.subplots(1, 1) ax.imshow(color.label2rgb(watershed_img, img, bg_label=0)) if withgrid: spotzplot.draw_bboxes(grid_bboxes, ax=ax) plt.show()
def main(imgfiles, outdir, rows, cols, prefix = "grid", threshold = "otsu", userthresh=0, opensize = 3, pkthresh = 0.1, pkdist = None, display = False, invert = False, autoexpose = False, rotate = True): """Infer the coordinates of a gridded set of objects in an image. Grid finding involves three key steps: 1. Image thresholding to define foreground vs background and generate a binary image 2. Morphological opening of the binary image 3. Inference of the grid coordinates from foreground objects in the binary image. User can optionally choose to invert and apply exposure equalization to the input image. Inversion is required when the objects of interest are dark objects on a light background (e.g. transparency scanning). """ threshold_dict = {"otsu" : imgz.threshold_otsu, "li" : imgz.threshold_li, "triangle" : imgz.threshold_triangle, "mean" : imgz.threshold_mean, "yen" : imgz.threshold_yen} threshold_func = threshold_dict[threshold] for imgfile in imgfiles: img = np.squeeze(io.imread(imgfile)) # invert and autoexpose if invert: iimg = imgz.invert(img) else: iimg = img if autoexpose: iimg = imgz.equalize_adaptive(iimg) # initial thresholding and rotation correction if userthresh > 0: rbimg = iimg > userthresh else: rbimg = pipe(iimg, threshold_func) rbimg = pipe(rbimg, imgz.disk_opening(opensize), imgz.clear_border) angle = 0 if rotate: _, angle = find_rotation_angle(rbimg) rbimg = fix_rotation(rbimg) img = transform.rotate(img, -angle, resize = False, preserve_range = True, mode = "constant") try: # find the grid grid = find_grid(rows, cols, rbimg, pkthresh, pkdist) except RuntimeError: print("No grid found in {}".format(imgfile)) if display: fig, ax = plt.subplots() ax.imshow(img, cmap = "gray") ax.imshow(rbimg, cmap = "Reds", alpha = 0.45) plt.show() sys.exit(1) grid_data = dict(bboxes = grid.bboxes, centers = grid.centers.tolist(), row_width = grid.row_width, col_width = grid.col_width, rotation_angle = angle) s = json.dumps(grid_data, indent = 1) root, _ = os.path.splitext(os.path.basename(imgfile)) outfile = os.path.join(outdir, "{}-{}.json".format(prefix, root)) with open(outfile, "w") as f: f.write(s) if display: fig, ax = plt.subplots() ax.imshow(img, cmap = "gray") ax.imshow(rbimg, cmap = "Reds", alpha = 0.45) spotzplot.draw_bboxes(grid.bboxes, ax) plt.show()
def main(imgfile, gridfile, outfile, threshold = "local", blocksize = None, sigma = None, elemsize = None, min_hole = None, min_object = None, clear_border = False, invert = False, autoexpose = False, display = False): """Segment microbial colonies in an image of a pinned plate. Segmentation involves: """ img = io.imread(imgfile) min_dim, max_dim = min(img.shape), max(img.shape) grid_data = json.load(open(gridfile, "r")) if invert: img = imgz.invert(img) if autoexpose: img = imgz.equalize_adaptive(img) # # Thresholding # threshold_dict = {"local":imgz.threshold_gaussian, "otsu":imgz.threshold_otsu, "li":imgz.threshold_li, "isodata":imgz.threshold_isodata} threshold_func = threshold_dict[threshold] if threshold == "local": if blocksize is None: blocksize = (2 * max_dim//200) + 1 if sigma is None: sigma = 2 * blocksize threshold_func = threshold_func(blocksize, sigma) binary_img = threshold_func(img) # # Morphological opening # if elemsize is None: elemsize = int(round(min(7, min_dim/100. + 1))) binary_img = imgz.disk_opening(elemsize, binary_img) # # Filter holes, small objects, border # if min_hole is None: min_hole = max(1, min_dim * 0.01)**2 if min_object is None: min_object = max(1, min_dim * 0.01)**2 binary_img = pipe(binary_img, imgz.remove_small_holes(min_hole), imgz.remove_small_objects(min_object)) if clear_border: binary_img = imgz.clear_border(binary_img) # # Filter and relabel based on grid # labeled_img = filter_objects_by_grid(binary_img, grid_data["centers"]) regions = measure.regionprops(labeled_img) if display: fig, ax = plt.subplots() ax.imshow(img, cmap = "gray") ax.imshow(labeled_img > 0, cmap = "Reds", alpha = 0.35) spotzplot.draw_region_labels(regions, ax, color = "Tan") plt.show() if outfile is None: root, _ = os.path.splitext(os.path.basename(imgfile)) outfile = "mask-" + root + ".npz" sp.sparse.save_npz(outfile, sp.sparse.coo_matrix(labeled_img))