Пример #1
0
def add_features(df, image_in='', origin=[0, 0, 0], dsfacs=[1, 16, 16]):

    if 'centroid-0' in df.columns:

        cens = ['centroid-{}'.format(i) for i in [0, 1, 2]]
        coms = ['com_{}'.format(d) for d in 'zyx']

        df[coms] = df[cens] + origin

        if image_in:

            dt_im = Image(image_in, permission='r')
            dt_im.load(load_data=False)
            data = dt_im.slice_dataset()
            dt_im.close()

            ds_centroid = np.array(df[coms] / dsfacs, dtype='int')
            ds_centroid = [data[p[0], p[1], p[2]] for p in ds_centroid]
            df['dist_to_edge'] = np.array(ds_centroid)

    if 'inertia_tensor_eigvals-0' in df.columns:
        ites = ['inertia_tensor_eigvals-{}'.format(i) for i in [0, 1, 2]]
        eigvals = np.clip(np.array(df[ites]), 0, np.inf)
        df['fractional_anisotropy'] = fractional_anisotropy(eigvals)
        df['major_axis_length'] = get_ellips_axis_lengths(eigvals[:, 0])
        df['minor_axis_length'] = get_ellips_axis_lengths(eigvals[:, -1])

    # TODO: range, variance, ...

    return df
Пример #2
0
def generate_report(image_in, info_dict={}, ioff=True):
    """Generate a QC report of the segmentation process."""

    report_type = 'reseg'

    # Turn interactive plotting on/off.
    if ioff:
        plt.ioff()
    else:
        plt.ion()

    # Get paths from image if info_dict not provided.
    if not info_dict:
        im = Image(image_in)
        info_dict['paths'] = im.split_path()  # FIXME: out_base
        info_dict['paths']['out_base'] = info_dict['paths']['base']
        im.close()
        info_dict['parameters'] = get_parameters(info_dict, report_type)
        # info_dict['centreslices'] = get_centreslices(info_dict, idss=[])
        info_dict['medians'] = {}

    # Create the axes.
    figsize = (18, 9)
    gridsize = (1, 4)
    f = plt.figure(figsize=figsize, constrained_layout=False)
    gs0 = gridspec.GridSpec(gridsize[0], gridsize[1], figure=f)
    # axs = [gen_orthoplot(f, gs0[j, i]) for j in range(0, 2) for i in range(0, 4)]
    axs = [
        gen_orthoplot(f, gs0[j, i]) for j in range(0, gridsize[0])
        for i in range(0, gridsize[1])
    ]

    # Plot the images and graphs. vmaxs = [15000] + [5000] * 7
    info_dict['plotinfo'] = {'vmax': 10000}
    plot_images(axs, info_dict)

    # Add annotations and save as pdf.
    reseg_id = 'axis{:01d}-seam{:02d}-j{:03d}'.format(info_dict['axis'],
                                                      info_dict['seam'],
                                                      info_dict['j'])
    header = 'mLSR-3D Quality Control'
    figtitle = '{}: {} \n {}'.format(
        header,
        report_type,
        reseg_id,
    )
    figpath = '{}_{}_{}-report.pdf'.format(
        info_dict['paths']['out_base'],
        report_type,
        reseg_id,
    )
    print('writing report to {}'.format(figpath))
    f.suptitle(figtitle, fontsize=14, fontweight='bold')
    add_titles(axs, info_dict)
    f.savefig(figpath)
    plt.close(f)
Пример #3
0
def downsample_channel(image_in,
                       ch,
                       resolution_level=-1,
                       dsfacs=[1, 4, 4, 1, 1],
                       ismask=False,
                       output='',
                       report={}):
    """Downsample an image."""

    ods = 'data' if not ismask else 'mask'

    # return in case no mask provided
    if not image_in:
        return None, report, ''

    if resolution_level != -1 and not ismask:  # we should have an Imaris pyramid
        image_in = '{}/DataSet/ResolutionLevel {}'.format(
            image_in, resolution_level)

    # load data
    im = Image(image_in, permission='r')
    im.load(load_data=False)
    props = im.get_props()
    if len(im.dims) > 4:
        im.slices[im.axlab.index('t')] = slice(0, 1, 1)
        props = im.squeeze_props(props, dim=4)
    if len(im.dims) > 3:
        im.slices[im.axlab.index('c')] = slice(ch, ch + 1, 1)
        props = im.squeeze_props(props, dim=3)
    data = im.slice_dataset()
    im.close()

    # downsample
    dsfac = tuple(dsfacs[:len(data.shape)])
    if not ismask:
        data = downscale_local_mean(data, dsfac).astype('float32')
    else:
        data = block_reduce(data, dsfac, np.max)

    # generate output
    props['axlab'] = 'zyx'  # FIXME: axlab returns as string-list
    props['shape'] = data.shape
    props['elsize'] = [es * ds for es, ds in zip(im.elsize[:3], dsfac)]
    props['slices'] = None
    mo = write_data(data, props, output, ods)

    # report data
    thr = 1000
    meds_mask = data < thr
    report['medians'][ods] = get_zyx_medians(data, meds_mask)

    c_slcs = {dim: get_centreslice(mo, '', dim) for dim in 'zyx'}
    report['centreslices'][ods] = c_slcs

    return mo, report, meds_mask
Пример #4
0
    def apply_field(image_in, bias_in, outputpath):

        im = Image(image_in, permission='r+')
        im.load(load_data=True)
        bf = Image(bias_in, permission='r+')
        bf.load(load_data=True)

        corr = divide_bias_field(im, bf, outputpath)

        im.close()
        bf.close()
        corr.close()
Пример #5
0
def process_block(image_in, ndim, blockreduce, func, blockoffset, blocksize,
                  margin, fullsize, mo, is_labelimage, relabel, neighbourmerge,
                  save_fwmap, maxlabel, mpi):
    """Write a block of data into a hdf5 file."""

    # open data for reading
    im = Image(image_in, permission='r')
    im.load(mpi.comm, load_data=False)

    # get the indices into the input and output datasets
    # TODO: get indices from attributes
    # TODO: get from mpi.get_blocks
    set_slices_in_and_out(im, mo, blocksize, margin, fullsize)

    # simply copy the data from input to output
    """NOTE:
    it is assumed that the inputs are not 4D labelimages
    """
    if ndim == 4:
        mo.write(im.slice_dataset())
        im.close()
        return
    if ((not is_labelimage)
            or ((not relabel) and (not neighbourmerge) and (not blockreduce))):
        data = im.slice_dataset()
        #datatype = 'uint16'
        #from skimage.util.dtype import convert
        #data = convert(data, np.dtype(datatype), force_copy=False)
        mo.write(data)
        im.close()
        return

    # forward map to relabel the blocks in the output
    if relabel:
        # FIXME: make sure to get all data in the block
        fw, maxlabel = relabel_block(im.ds[:], maxlabel, mpi)
        if save_fwmap:
            comps = im.split_path()
            fpath = '{}_{}.npy'.format(comps['base'], comps['int'][1:])
            np.save(fpath, fw)
        if (not neighbourmerge) and (not blockreduce):
            data = im.slice_dataset()
            mo.write(fw[data])
            im.close()
            return
    else:
        ulabels = np.unique(im.ds[:])
        fw = [l for l in range(0, np.amax(ulabels) + 1)]
        fw = np.array(fw)

    # blockwise reduction of input datasets
    if blockreduce is not None:
        pass
    else:
        data = im.slice_dataset()

    # merge overlapping labels
    fw = merge_overlap(fw, im, mo, data, margin)
    mo.write(fw[data])
    im.close()
Пример #6
0
def get_maxlabels_from_attribute(filelist, ids, maxlabelfile):

    maxlabels = []

    for datafile in filelist:
        image_in = '{}/{}'.format(datafile, ids)
        im = Image(image_in, permission='r')
        im.load(load_data=False)
        maxlabels.append(im.ds.attrs['maxlabel'])
        im.close()

    if maxlabelfile:
        np.savetxt(maxlabelfile, maxlabels, fmt='%d')

    return maxlabels
Пример #7
0
def generate_report(image_in, info_dict={}, ioff=True):
    """Generate a QC report of the mask creation process."""

    report_type = 'mask'

    # Turn interactive plotting on/off.
    if ioff:
        plt.ioff()
    else:
        plt.ion()

    # Get paths from image if info_dict not provided.
    if not info_dict:
        im = Image(image_in)
        info_dict['paths'] = im.split_path()
        im.close()
        info_dict['parameters'] = get_parameters(info_dict, report_type)
        info_dict['centreslices'] = get_centreslices(info_dict)
        # info_dict['medians'] = get_medians(info_dict)

    # Create the axes.
    figsize = (18, 9)
    gridsize = (1, 4)
    f = plt.figure(figsize=figsize, constrained_layout=False)
    gs0 = gridspec.GridSpec(gridsize[0], gridsize[1], figure=f)
    axs = [gen_orthoplot(f, gs0[0, i]) for i in range(0, 4)]

    # Plot the images and graphs.
    info_dict['plotinfo'] = {'vmax': 10000}
    plot_images(axs, info_dict)

    # Add annotations and save as pdf.
    header = 'mLSR-3D Quality Control'
    figtitle = '{}: {} \n {}'.format(
        header,
        report_type,
        info_dict['paths']['fname']
        )
    figpath = '{}_{}-report.pdf'.format(
        info_dict['paths']['base'],
        report_type
        )
    f.suptitle(figtitle, fontsize=14, fontweight='bold')
    add_titles(axs, info_dict)
    f.savefig(figpath)
Пример #8
0
def get_centreslices(info_dict, idss=[], ch=0):
    """Get the centreslices for all dims and steps."""

    h5_path = info_dict['paths']['file']
    image_in = h5_path + info_dict['paths']['int']
    im = Image(image_in)
    im.load(load_data=False)
    if not idss:
        idss = [k for k in im.file.keys()]
    im.close()

    centreslices = {
        ids: {dim: get_centreslice(h5_path, ids, dim, ch)
              for dim in 'zyx'}
        for ids in idss
    }

    return centreslices
Пример #9
0
def get_info_dict(image_in, info_dict={}, report_type='bfc', channel=0):

    im = Image(image_in)
    im.load(load_data=False)
    info_dict['elsize'] = {dim: im.elsize[i] for i, dim in enumerate(im.axlab)}
    info_dict['paths'] = im.split_path()  # FIXME: out_base
    info_dict['paths']['out_base'] = info_dict['paths']['base']
    im.close()

    ppath = '{}.pickle'.format(info_dict['paths']['base'])
    with open(ppath, 'rb') as f:
        info_dict['parameters'] = pickle.load(f)
    info_dict['centreslices'] = get_centreslices(info_dict)

    # info_dict['medians'] = get_medians(info_dict)
    info_dict['medians'], info_dict['means'], info_dict['stds'], info_dict[
        'n_samples'] = get_means_and_stds(info_dict, ch=channel, thr=1000)

    return info_dict
Пример #10
0
def biasfield_correction(
    image_in,
    parameter_file='',
    outputdir='',
    channels=[],
    mask_in='',
    resolution_level=-1,
    downsample_factors=[1, 1, 1, 1, 1],
    n_iterations=50,
    n_fitlevels=4,
    n_bspline_cps=[5, 5, 5],
):
    """Perform N4 bias field correction."""

    params = get_params(locals(), parameter_file, 'biasfield_correction')

    if not params['channels']:
        im = Image(image_in, permission='r')
        im.load()
        n_channels = im.dims[im.axlab.index('c')]
        params['channels'] = list(range(n_channels))
        im.close()

    n_workers = get_n_workers(len(params['channels']), params)

    arglist = [(
        image_in,
        ch,
        params['mask_in'],
        params['resolution_level'],
        params['downsample_factors'],
        params['n_iterations'],
        params['n_fitlevels'],
        params['n_bspline_cps'],
        outputdir,
    ) for ch in params['channels']]

    with multiprocessing.Pool(processes=n_workers) as pool:
        pool.starmap(estimate_biasfield, arglist)
Пример #11
0
def stack_channels(images_in, outputpath=''):

    channels = []
    for image_in in images_in:
        im = Image(image_in, permission='r')
        im.load(load_data=True)
        channels.append(im.ds[:])
    data = np.stack(channels, axis=3)

    mo = Image(outputpath)
    mo.elsize = list(im.elsize) + [1]
    mo.axlab = im.axlab + 'c'
    mo.dims = data.shape
    mo.chunks = list(im.chunks) + [1]
    mo.dtype = im.dtype
    mo.set_slices()
    if outputpath:
        mo.create()
        mo.write(data)
        mo.close()

    return mo
Пример #12
0
def get_paths(image_in,
              resolution_level=-1,
              channel=0,
              outputstem='',
              step='',
              save_steps=False):
    """Get the parameters for the preprocessing step."""

    # get paths from input file
    if resolution_level != -1:  # we should have an Imaris pyramid
        image_in = '{}/DataSet/ResolutionLevel {}'.format(
            image_in, resolution_level)
    im = Image(image_in, permission='r')
    im.load(load_data=False)
    paths = im.split_path()
    im.close()

    # define output basename
    paths['out_base'] = outputstem

    # define h5 output template
    paths['out_h5'] = '{}.h5/{}'.format(paths['out_base'], '{}')

    # define output for main results and intermediate steps
    if not outputstem:
        paths['main'] = paths['steps'] = ''
    else:
        ### FIXME ????????????? what is this?
        if save_steps:
            paths['main'] = paths['steps'] = paths['out_h5']
        else:
            paths['main'] = paths['out_h5']
            paths['steps'] = paths['out_h5']

    # define output for parameters
    paths['params'] = '{}.pickle'.format(paths['out_base'], step)

    return paths
Пример #13
0
def mergeblocks(
    images_in,
    dataslices=None,
    blocksize=[],
    blockmargin=[],
    blockrange=[],
    blockoffset=[0, 0, 0],
    fullsize=[],
    is_labelimage=False,
    relabel=False,
    neighbourmerge=False,
    save_fwmap=False,
    blockreduce=[],
    func='np.amax',
    datatype='',
    usempi=False,
    outputpath='',
    save_steps=False,
    protective=False,
):
    """Merge blocks of data into a single hdf5 file."""

    if blockrange:
        images_in = images_in[blockrange[0]:blockrange[1]]

    mpi = wmeMPI(usempi)

    im = Image(images_in[0], permission='r')
    im.load(mpi.comm, load_data=False)
    props = im.get_props(protective=protective, squeeze=True)
    ndim = im.get_ndim()

    props['dtype'] = datatype or props['dtype']
    props['chunks'] = props['chunks'] or None

    # get the size of the outputfile
    # TODO: option to derive fullsize from dset_names?
    if blockreduce:
        datasize = np.subtract(fullsize, blockoffset)
        outsize = [
            int(np.ceil(d / np.float(b)))
            for d, b in zip(datasize, blockreduce)
        ]
        props['elsize'] = [e * b for e, b in zip(im.elsize, blockreduce)]
    else:  # FIXME: 'zyx(c)' stack assumed
        outsize = np.subtract(fullsize, blockoffset)

    if ndim == 4:
        outsize = list(outsize) + [im.ds.shape[3]]  # TODO: flexible insert

    if outputpath.endswith('.ims'):
        mo = LabelImage(outputpath)
        mo.create(comm=mpi.comm)
    else:
        props['shape'] = outsize
        mo = LabelImage(outputpath, **props)
        mo.create(comm=mpi.comm)

    mpi.blocks = [{'path': image_in} for image_in in images_in]
    mpi.nblocks = len(images_in)
    mpi.scatter_series()

    # merge the datasets
    maxlabel = 0
    for i in mpi.series:

        block = mpi.blocks[i]
        # try:
        maxlabel = process_block(block['path'], ndim, blockreduce, func,
                                 blockoffset, blocksize, blockmargin, fullsize,
                                 mo, is_labelimage, relabel, neighbourmerge,
                                 save_fwmap, maxlabel, mpi)
        print('processed block {:03d}: {}'.format(i, block['path']))
        # except Exception as e:
        #     print('failed block {:03d}: {}'.format(i, block['path']))
        #     print(e)

    im.close()
    mo.close()

    return mo
Пример #14
0
def apply_bias_field_full(image_in,
                          bias_in,
                          dsfacs=[1, 64, 64, 1],
                          in_place=False,
                          write_to_single_file=False,
                          blocksize_xy=1280,
                          outputpath='',
                          channel=None):
    """single-core in ~200 blocks"""

    perm = 'r+' if in_place else 'r'
    im = Image(image_in, permission=perm)
    im.load(load_data=False)

    bf = Image(bias_in, permission='r')
    bf.load(load_data=False)

    if channel is not None:
        im.slices[3] = slice(channel, channel + 1)
    if write_to_single_file:  # assuming single-channel copied file here
        mo = Image(outputpath)
        mo.load()
        mo.slices[3] = slice(0, 1, 1)

    mpi = wmeMPI(usempi=False)
    mpi_nm = wmeMPI(usempi=False)
    if blocksize_xy:
        blocksize = [im.dims[0], blocksize_xy, blocksize_xy, 1, 1]
        blockmargin = [0, im.chunks[1], im.chunks[2], 0, 0]
    else:
        blocksize = im.dims[:3] + [1, 1]
        blockmargin = [0] * len(im.dims)
    mpi.set_blocks(im, blocksize, blockmargin)
    mpi_nm.set_blocks(im, blocksize)
    mpi.scatter_series()

    for i in mpi.series:
        print(i)
        block = mpi.blocks[i]
        data_shape = list(im.slices2shape(block['slices']))
        block_nm = mpi_nm.blocks[i]
        it = zip(block['slices'], block_nm['slices'], blocksize, data_shape)
        data_shape = list(im.slices2shape(block_nm['slices']))
        data_slices = []
        for b_slc, n_slc, bs, ds in it:
            m_start = n_slc.start - b_slc.start
            m_stop = m_start + bs
            m_stop = min(m_stop, ds)
            data_slices.append(slice(m_start, m_stop, None))
        data_slices[3] = block['slices'][3]
        data_shape = list(im.slices2shape(data_slices))

        # get the fullres image block
        im.slices = block['slices']
        data = im.slice_dataset().astype('float')

        # get the upsampled bias field
        bias = get_bias_field_block(bf, im.slices, data.shape)
        data /= bias
        data = np.nan_to_num(data, copy=False)

        if in_place:
            im.slices = block_nm['slices']
            data = data[tuple(data_slices[:3])].astype(im.dtype)
            im.write(data)
        elif write_to_single_file:
            mo.slices = block_nm['slices']
            mo.slices[3] = slice(0, 1, 1)
            data = data[tuple(data_slices[:3])].astype(mo.dtype)
            mo.write(data)
        else:
            props = im.get_props()
            if len(im.dims) > 4:
                props = im.squeeze_props(props, dim=4)
            if len(im.dims) > 3:
                props = im.squeeze_props(props, dim=3)
            props['axlab'] = 'zyx'  # FIXME: axlab return as string-list
            props['shape'] = bias.shape
            props['slices'] = None
            props['dtype'] = bias.dtype
            mo = Image(block['path'], **props)  # FIXME: needs channel
            mo.create(comm=mpi.comm)
            mo.slices = None
            mo.set_slices()
            mo.write(data=bias)
            mo.close()

    im.close()
    bf.close()
Пример #15
0
def generate_report(image_in, info_dict={}, ioff=True):
    """Generate a QC report of the segmentation process."""

    report_type = 'seg'

    # Turn interactive plotting on/off.
    if ioff:
        plt.ioff()
    else:
        plt.ion()

    # Get paths from image if info_dict not provided.
    if not info_dict:
        im = Image(image_in)
        info_dict['paths'] = im.split_path()  # FIXME: out_base
        info_dict['paths']['out_base'] = info_dict['paths']['base']
        im.close()
        info_dict['parameters'] = load_parameters(
            info_dict['paths']['out_base'])
        info_dict['centreslices'] = get_centreslices(
            info_dict,
            idss=[
                'mean_mask',
                'memb/planarity_mask',
                'memb/mean',
                'memb/mean_smooth',
                'chan/ch00',
                'nucl/dapi_mask',
                'nucl/dapi_preprocess',
                'segm/labels_edt',
                'segm/labels_memb',
                'segm/labels_memb_del',
                'segm/seeds_edt',
                'segm/seeds_mask',
                'segm/seeds_peaks_dil',
            ])
        info_dict['medians'] = {}

    # Create the axes.
    figsize = (18, 9)
    gridsize = (2, 4)
    f = plt.figure(figsize=figsize, constrained_layout=False)
    gs0 = gridspec.GridSpec(gridsize[0], gridsize[1], figure=f)
    axs = [
        gen_orthoplot(f, gs0[j, i]) for j in range(0, 2) for i in range(0, 4)
    ]

    # Plot the images and graphs. vmaxs = [15000] + [5000] * 7
    info_dict['plotinfo'] = {'vmax': 10000}
    plot_images(axs, info_dict)

    # Add annotations and save as pdf.
    header = 'mLSR-3D Quality Control'
    figtitle = '{}: {} \n {}'.format(header, report_type,
                                     info_dict['paths']['fname'])
    figpath = '{}_{}-report.pdf'.format(info_dict['paths']['out_base'],
                                        report_type)
    f.suptitle(figtitle, fontsize=14, fontweight='bold')
    add_titles(axs, info_dict)
    f.savefig(figpath)

    info_dict.clear()
Пример #16
0
def csv_to_im(
    image_in,
    csv_path,
    labelkey='label',
    key='dapi',
    name='',
    maxlabel=0,
    normalize=False,
    scale_uint16=False,
    replace_nan=False,
    channel=-1,
    outpath='',
):
    """Write segment backprojection."""

    if isinstance(image_in, Image):
        labels = image_in
    else:
        labels = LabelImage(image_in)
        labels.load(load_data=False)

    if not maxlabel:
        labels.set_maxlabel()
        maxlabel = labels.maxlabel

    if csv_path.endswith('.csv'):
        df = pd.read_csv(csv_path)
        df = df.astype({labelkey: int})
    elif csv_path.endswith('.h5ad'):
        import scanpy as sc
        adata = sc.read(csv_path)
        if not csv_path.endswith('_nofilter.h5ad'):
            adata.X = adata.raw.X
        df = adata.obs[labelkey].astype(int)
        df = pd.concat([df, adata[:, key].to_df()], axis=1)

    # for key in keys:  # TODO
    fw = np.zeros(maxlabel + 1, dtype='float')
    for index, row in df.iterrows():
        fw[int(row[labelkey])] = row[key]

    if replace_nan:
        fw = np.nan_to_num(fw)
    if normalize:

        def normalize_data(data):
            """Normalize data between 0 and 1."""
            data = data.astype('float64')
            datamin = np.amin(data)
            datamax = np.amax(data)
            data -= datamin
            data *= 1 / (datamax - datamin)
            return data, [datamin, datamax]

        fw_n, fw_minmax = normalize_data(fw)
        fw_n *= 65535
        fw = fw_n
    elif scale_uint16:  # for e.g. pseudotime / FA / etc / any [0, 1] vars
        fw *= 65535

    out = labels.forward_map(list(fw))

    if outpath.endswith('.ims'):
        mo = Image(outpath, permission='r+')
        mo.load(load_data=False)
        if channel >= 0 and channel < mo.dims[3]:
            ch = channel
        else:
            mo.create()
            ch = mo.dims[3] - 1
        mo.slices[3] = slice(ch, ch + 1, 1)
        mo.write(out.astype(mo.dtype))  # FIXME: >65535 wraps around
        cpath = 'DataSetInfo/Channel {}'.format(ch)
        name = name or key
        mo.file[cpath].attrs['Name'] = np.array([c for c in name], dtype='|S1')
        mo.close()
    elif outpath.endswith('.nii.gz'):
        props = labels.get_props()
        if not labels.path.endswith('.nii.gz'):
            props = transpose_props(props, outlayout='xyz')
            out = out.transpose()
        mo = write_output(outpath, out, props)
    else:
        outpath = outpath or gen_outpath(labels, key)
        mo = write_output(outpath, out, labels.get_props())

    return mo