Exemplo n.º 1
0
def find_series_nuclei(self, i, **kwargs):
    """Function for parallelized nuclear segmentation.

    Args:
      i (int): series index.
      **kwargs: ncores.
    
    Returns:
      pygpseq.wraps.Series: updated i-th series instance.
    """

    # Set series verbosity
    if kwargs['ncores'] != 1:
        self.series[i].verbose = False

    # Get starting time
    start_time = time.time()

    # Find nuclei
    self.series[i], log = self.series[i].find_nuclei(**kwargs)

    # Print log all at once
    time_msg = 'Took %s s.\n' % (round(time.time() - start_time, 3))
    if not 1 == kwargs['ncores']:
        log += iot.printout(time_msg, 1, False)
        self.printout(log, 0)
    else:
        self.printout(time_msg, 1)

    # Output
    return (self.series[i])
Exemplo n.º 2
0
def get_series_nuclear_data(self, summary, sidx, **kwargs):
    """Function for parallelized single-pixel nuclear data retrieval.

    Args:
      summary (list): list of summaries.
      sidx (int): series index.
      **kwargs: ncores.
    
    Returns:
      np.array: series nuclear data.
    """

    # Set series verbosity
    if kwargs['ncores'] != 1:
        self.series[sidx - 1].verbose = False
    else:
        self.series[sidx - 1].verbose = True

    # Get starting time
    start_time = time.time()

    # Setup starting message
    msg = 'Retrieving nuclear data from series #' + str(sidx) + '...'
    msg = iot.printout(msg, 1, verbose=False)

    # Get nuclei ids for current series
    ns = [i for i in range(summary.shape[0]) if summary['s'][i] == sidx]
    ns = summary['n'][ns]

    # Retrieve nuclear data
    data, dp, vp, log = self.series[sidx - 1].get_nuclei_data(ns, **kwargs)

    # Print log all at once
    time_msg = 'Took %s s.' % (round(time.time() - start_time, 3))
    if not 1 == kwargs['ncores']:
        log = msg + log
        log += iot.printout(time_msg, 2, False)
        self.printout(log, 0)
    else:
        self.printout(time_msg, 2)

    # Output
    return ({'spx_data': data, 'density': dp, 'volume': vp})
Exemplo n.º 3
0
def read_tiff(impath, k=None, noSelection=False, rescale=1):
    '''Read tiff image.

    Args:
      impath (str): path to tiff image.
      k (int): number of dimensions in output image for re-slicing.
      noSelection (bool): whether to discard empty dimensions.
      rescale (float): scaling factor.
    
    Returns:
      np.ndarray: image.
      None: file is possibly corrupt.
    '''

    assert os.path.isfile(impath), "trying to read missing file"

    # Read TIFF (capture any parsing issues)
    try:
        with warnings.catch_warnings(record=True) as wlist:
            im = imread(impath)
            if 0 != len(wlist):
                if "axes do not match shape" in str(wlist[0]):
                    printout(
                        "image axes do not match metadata in '%s'. %s" %
                        (impath, "Using the image axes."), -1)
    except (ValueError, TypeError) as e:
        msg = "Something went wrong while trynig to read a file"
        printout("%s (possibly corrupt):\n%s\n" % (msg, impath),
                 -2,
                 canAbort=False)
        return (None)

    # Reshape and re-slice
    while 0 == im.shape[0] and not noSelection:
        im = im[0]
    if type(0) == type(k): im = slice_k_d_img(im, k)

    # Rescale
    if 1 != rescale: im = (im / rescale).astype('float')

    return (im)
Exemplo n.º 4
0
def analyze_field_of_view(
        sid,
        data,
        im2fov,
        dilate_factor,
        istruct,
        aspect,
        mask_dir,
        mask_prefix,
        plotCompartments,
        pole_fraction,
        outdir,
        noplot,
        labeled,
        compressed,
        dist_type,
        nbins,
        discard_dilation_mode,
        an_type,
        seg_type,  # Required by the Binarize class
        mask2d_dir=None,
        verbose=False,
        debug=False,
        debug_dir=""):
    '''Given a table with FISH data, add information on:
        - lamin/center absolute/normalized distance
        - angle between homogue pairs
        - compartment assignment
        - dots coordinates in normalized ellipsoid

    Args:
        sid (int): series ID.
        data (pd.DataFrame): FISH data table.
        im2fov (dict): sid-to-absPath dictionary.
        dilate_factor (int): number of pixels for dilation
        istruct (tuple): 3D isotropic structuring element for dilation.
        aspect (tuple): ZYX voxel aspect.
        mask_dir (string): path to folder for TIFF masks import/export.
        mask_prefix (string): prefix for TIFF masks.
        plotCompartments (bool): generate compartment plots.
        pole_fraction (float):.
        outdir (str): path to analysis output folder.
        noplot (bool): turn plotting off.
        labeled (bool): import/export masks as labeled.
        compressed (bool): export masks as compressed TIFFs.
        dist_type (str): nuclear distance calculation mode.
        nbins (int): number of bins for density profile.
        an_type
        seg_type
        verbose (bool): display action log.
        debug (bool): debugging mode.
    '''

    # ASSERT ===================================================================

    reqcols = ['File']
    for c in reqcols:
        assert c in data.columns, "missing '%s' column." % c

    # INPUT ====================================================================

    v = verbose
    msg = printout("Job '%s'..." % (im2fov[sid], ), 1, v)
    subt = data.loc[np.where(data['File'] == sid)[0], :]

    # Get DNA scaling factor and rescale
    sf = imt.get_rescaling_factor(im2fov[sid])
    msg += printout("Re-scaling factor: %f" % sf, 2, v)

    # Read image
    msg += printout("Reading image ...", 2, v)
    im = imt.read_tiff(im2fov[sid], k=3, rescale=sf)
    if type(None) == type(im):
        return (None)

    # SEGMENTATION =============================================================

    Segmenter = Binarize(an_type=an_type, seg_type=seg_type, verbose=verbose)

    # Check if already segmented
    already_segmented = False
    if not type(None) == type(mask_dir):
        mpath = os.path.join(mask_dir,
                             mask_prefix + os.path.basename(im2fov[sid]))
        already_segmented = os.path.isfile(mpath)

    # Skip or binarize
    if already_segmented:
        msg += printout("Skipped binarization, using provided mask.", 3, v)
        imbin = imt.read_tiff(mpath, k=3)

        # Check input mask for shape match
        if imbin.shape != im.shape:
            errmsg = "Inconsistent shape of provided mask and image: "
            errmsg += "%s and %s\n" % (str(im.shape), str(imbin.shape))
            msg += printout(errmsg, -2, v, False)

            msg += printout("Reverting to binarization.", 2, v)
            imbin = None
            already_segmented = False
        else:
            if not labeled: imbin = imbin != 0  # Binarize
            thr = 0
            already_segmented = type(None) != type(imbin)

    if not already_segmented:
        msg += printout("Binarizing...", 2, v)
        (imbin, thr, log) = Segmenter.run(im)
        msg += log

        # Filter based on object size
        imbin, tmp = Segmenter.filter_obj_XY_size(imbin)
        imbin, tmp = Segmenter.filter_obj_Z_size(imbin)

        if not type(None) == type(mask2d_dir):
            mask2d_path = os.path.join(mask2d_dir,
                                       os.path.basename(im2fov[sid]))
            if os.path.isfile(mask2d_path):
                mask2d = imt.read_tiff(mask2d_path, k=2)
                # If labeled, inherit nuclei labels
                imbin = Segmenter.combine_2d_mask(imbin,
                                                  mask2d,
                                                  labeled2d=labeled)

    # Estimate background
    dna_bg = imt.estimate_background(im, imbin, seg_type)
    msg += printout("Estimated background: %.2f a.u." % (dna_bg, ), 3, v)

    # NUCLEI ===================================================================

    msg += printout("Retrieving nuclei...", 2, v)
    if 1 == np.max(imbin):
        L = label(imbin)
    else:
        L = imbin

    # Save mask ----------------------------------------------------------------

    # Export binary mask as TIF
    if not type(None) == type(mask_dir) and not already_segmented:
        msg += printout("Exporting mask as tif...", 4, v)
        if not os.path.isdir(mask_dir): os.mkdir(mask_dir)

        # Export labeled mask
        if labeled: plot.save_tif(mpath, L, 'uint8', compressed)
        else:  # Export binary mask (min/max)
            L[np.nonzero(L)] = 255
            plot.save_tif(mpath, L, 'uint8', compressed)
            L = label(imbin)

    # Export mask as PNG
    if not noplot:
        # Create png masks output directory
        maskdir = os.path.join(outdir, 'masks/')
        if not os.path.isdir(maskdir): os.mkdir(maskdir)
        imbname = os.path.splitext(os.path.basename(im2fov[sid]))[0]

        # Save default mask
        msg += printout("Saving default binary mask...", 3, v)
        plot.export_mask_png("%smask.%s.default.png" % (maskdir, imbname),
                             imbin, "Default mask.")

        # Export dilated mask
        if 0 != dilate_factor:
            msg += printout("Saving dilated mask...", 3, v)
            plot.export_mask_png(
                "%smask.%s.dilated%d.png" % (maskdir, imbname, dilate_factor),
                dilation(imbin, istruct),
                "Dilated mask, %d factor." % (dilate_factor, ))

        # Export labeled mask
        msg += printout("Saving nuclear ID mask...", 3, v)
        plot.export_mask_png(
            "%smask.%s.nuclei.png" % (maskdir, imbname), L,
            'Nuclei in "%s" [%d objects]' %
            (os.path.basename(im2fov[sid]), L.max()))

    # Store nuclei -------------------------------------------------------------
    msg += printout("Building nuclei...", 3, v)
    msg, curnuclei, dp, nv = nucleus.build_nuclei(
        msg,
        L,
        dilate_factor,
        series_id=sid,
        thr=thr,
        dna_bg=dna_bg,
        sig_bg=0,
        aspect=aspect,
        offset=(1, 1, 1),
        logpath=IOinterface().logpath,
        dist_type=dist_type,
        discard_dilation_mode=discard_dilation_mode,
        i=im,
        istruct=istruct,
        nbins=nbins,
        debug=debug,
        debug_dir=debug_dir)

    # ANALYSIS =================================================================

    msg += printout("Analyzing...", 2, v)

    # Assign dots to cells -----------------------------------------------------

    msg += printout("Assigning dots to cells...", 3, v)
    subt = dot.dots2cells(subt, curnuclei, dilate_factor)

    # Distances ----------------------------------------------------------------

    msg += printout("Calculating lamina distance...", 3, v)
    subt, msg = dot.calc_dot_distances(
        msg,
        subt,
        curnuclei,
        aspect,
        dist_type,
        discard_dilation_mode=discard_dilation_mode)

    # Compartments -------------------------------------------------------------

    msg += printout("Annotating compartments...", 3, v)

    # Setup condition for compartment plotting
    compdir = None
    aggdir = None
    if plotCompartments and not noplot:
        compdir = os.path.join(outdir, 'compartments/')
        if not os.path.isdir(compdir): os.mkdir(compdir)
        aggdir = os.path.join(outdir, 'agg_vis/')
        if not os.path.isdir(aggdir): os.mkdir(aggdir)

    # Perform annotation
    subt, tvcomp, msg = nucleus.annotate_compartments(msg, subt, curnuclei,
                                                      compdir, pole_fraction,
                                                      aspect)

    # Plot aggregated visualization
    nucleus.plot_nuclei_aggregated(subt, tvcomp, aspect, aggdir)

    # CONCLUDE =================================================================

    # Remove masks from curnuclei to free some memory
    for k in curnuclei.keys():
        del curnuclei[k].mask

    # Output
    msg += printout("< Finished job.", 0, v)
    return ((curnuclei, subt, tvcomp, dp, nv, msg))
Exemplo n.º 5
0
if 3 == len(img.shape):
    print("3D stack found: %s" % str(img.shape))
    if args.force2D:
        print("Enforcing 2D split (extracting 1st slice only).")
        status = "2D"
        umes = "pixel"
        img = img[0, :, :].copy()
    else:
        status = "3D"
        umes = "voxel"
elif 2 == len(img.shape):
    print("2D image found: %s" % str(img.shape))
    status = "2D"
    umes = "pixel"
else:
    printout("Cannot split a 1D image. File: %s" % args.input, -2)

# Enlarge or calculate pixel loss ----------------------------------------------

if args.enlarge:
    img = tiff_enlarge(img, x_side, y_side)
    print("Image enlarged to %s" % str(img.shape))
else:
    loss = calc_split_loss(img, x_side, y_side)
    print("%d %ss lost (%.2f%%). Use -e to avoid loss." % (
        loss, umes, loss / np.prod(img.shape) * 100))

# Split image ------------------------------------------------------------------

if "2D" == status:
    tiff_split_2d(img, x_side, y_side, args.outdir, args.input, args.inverted)