Example #1
0
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
Example #2
0
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()
Example #3
0
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()
Example #4
0
def threshold_from_blank(blankimg, perc=99.9, invert=False):
    if invert:
        blankimg = imgz.invert(blankimg)
    return np.percentile(blankimg.ravel(), perc)
Example #5
0
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
Example #6
0
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()
Example #7
0
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()
Example #8
0
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))