Ejemplo n.º 1
0
def jupyter2pdf(jupyterFile, outputDir=None):
    '''
    convert jupyter2pdf using pdfkit.

    <jupyterFile>: a string or a Path-lib object

    <outputDir>: outputDir, default:cwd

    '''
    from RZutilpy.system import Path, makedirs
    import pdfkit

    jupyterFile = Path(jupyterFile)
    outputDir = Path.cwd() if outputDir is None else Path(outputDir)
    makedirs(outputDir) # create the dir if no exists

    name = jupyterFile.pstem

    !jupyter nbconvert --to html {name}

    htmlFile = Path(jupyterFile.strnosuffix+'.html')
    pdfkit.from_file(htmlFile.str, (outputDir/(name+'.pdf')).str)
    !rm -f {name}.html
Ejemplo n.º 2
0
def t1warp(t1,
           outputDir=None,
           template=None,
           maskvol=None,
           skullstrip_kw=[],
           affine_kw=[],
           affonly=False):
    '''
    Nonlinear (or linear warping) warping t1 file to a template. In afni_proc, they use
    @SSwarper by default. For a standard human T1 file, @SSwarper produce similar warping files
    as this script. But this script might be useful for like unusual cases, for example, Monkey data

    Input:
        <t1>: t1 file, a string or a pathlib object
        <outputDir>: output directory, we first copy t1 file into this outputDir. if None,
            use cwd.
        <template>: the template t1 file,a string or a pathlib object. if None, we use
            afni MNI152_2009_template_SSW.nii.gz file
        <maskvol>: mask volume, a str or a pathlib object. You can supply an maskvol file
            here so the skullstrip step will be skipped. This is useful when you want to
            manually edit the mask volume and supply it to skullstrip
        <skullstrip_kw>, <affine_kw>: lists, extra options supply to '3dSkullstrip' and 'align_epi_anat.py'
            commands. This is useful for like monkey data. Default: [] (empty list)
        <affonly>: boolean (default: False), only need affine transform, no nonlinear warping.

    Output: this will produce several files in <outputDir>, they are generated in order
        **.nii.gz: copy of t1 file
        **_ss.nii.gz: skullstriped(ss) T1
        **_ssmask.nii.gz: skullstriped(ss) brain mask
        **_ssiu.nii.gz: intenstivity unifize(iu) t1 after ss
        **_ssiu_shft: shift to center of mass of the template after iu
        **_ssiu_shft_aff: affine tranformed T1 in the template space
        **_ssiu_shft_aff_mat.aff12.1D: affine transformation matrix
        **_ssui_shft_aff_matINV.aff12.1D: inverse affine transformation
        **_ssiu_shft_aff_nl.nii.gz: nonlinear warp to the template in the template space
        WARP.nii.gz: nonlinear warp file

    Note:
        1. Here we do three transform, shift-affine-nlwarp. The later two can be concatenated but
            it is not recommended to concatenate all three because combining shift into affine and nlwarp
            will make the "3dNwarpapply" take a lot of memory and very long time (and might fail).
            If you want to inversely warp an atlas from template space into native T1 space. You can do like

            # first do inverse (affine+nlwarp)
            cmd = ['3dNwarpApply', '-prefix', f'{template.strnosuffix}_nl2t1.nii.gz', \
               '-nwarp', f'inv({(outputDir/"WARP.nii.gz").str} {t1.strnosuffix}_ssiu_shft_aff2NMT_mat.aff12.1D)', \
               '-source', template.str, '-master', f'{t1.strnosuffix}_ssiu_shft.nii.gz', '-overwrite']
            unix_wrapper(cmd)
            # then inverse the shift
            # Note that here do not use 3dAllineate as it will resample the data one more time
            # Use 3drefit, it will not resample data
            cmd = f'3drefit -duporigin {t1.strnosuffix}_ssiu.nii.gz {template.strnosuffix}_nl2t1.nii.gz}'
            unix_wrapper(cmd)

        2. Be very CAREFUL about the order when concatenating affine and nlwarp!

    To do:
        1. automatically perform inversed warp atlas??

    History:
        20190413 RZ create
    '''

    from RZutilpy.system import Path, unix_wrapper, makedirs

    t1 = Path(t1)
    if template:
        template = Path(template) if ~isinstance(template, Path) else template
    else:  # default template is mni template
        afnipath = unix_wrapper(f'which afni')  # get the afni install Path
        template = Path(afnipath).parent / 'MNI152_2009_template_SSW.nii.gz'

    outputDir = Path.cwd() if outputDir is None else Path(outputDir)
    makedirs(outputDir)  # create outputdir if not exist
    unix_wrapper(f'cp {t1} {outputDir}')  # copy t1 file to outputdir
    t1 = outputDir / f'{t1.name}'  # switch to new t1

    # ======= step 1, skull strip =====================
    if maskvol is None:
        # make brain mask, this step typically is good for a human brain, but tricky for a monkey brain
        cmd = ['3dSkullStrip', \
            '-input', t1.str, \
            '-prefix', f'{t1.strnosuffix}_ssmask.nii.gz', \
            '-mask_vol']
        cmd = cmd + skullstrip_kw
        unix_wrapper(cmd)
        maskvol = Path(f'{t1.strnosuffix}_ssmask.nii.gz')
    # skullstrip-based on mask
    cmd=['3dcalc', '-a', t1.str, '-b', maskvol.str, \
        '-expr', "a*step(b)", \
        '-prefix', f'{t1.strnosuffix}_ss.nii.gz']
    unix_wrapper(cmd)

    # ===== step 2, # intensity unifize ===========
    cmd = f'3dUnifize -prefix {t1.strnosuffix}_ssiu.nii.gz {t1.strnosuffix}_ss.nii.gz'
    unix_wrapper(cmd)

    # ====== step 3, affine transform to NMT template ==================

    # first we can align center of mass
    cmd = f'@Align_Centers -base {template.str} -dset {t1.strnosuffix}_ssiu.nii.gz -cm'
    unix_wrapper(
        cmd)  # this step will generate {t1.strnosuffix}_ssiu_shft.nii.gz
    shftfile = Path.cwd() / f'{t1.pstem}_ssiu_shft.1D'
    unix_wrapper(f'mv {shftfile.str} {outputDir.str}')
    # This step will generate {t1.strnosuffix}_ssiu_shft.nii.gz
    # This step will also generate a 1D transformation file under CWD not OUTPUTDIR
    # we have to copy this 1D file into <outputDir>

    # do affine alignment, note that data will be resampled on NMT grid
    cmd = ['align_epi_anat.py', '-dset1', f'{t1.strnosuffix}_ssiu_shft.nii.gz', \
                  '-dset2', template.str, \
                  '-master_dset1', template.str,\
                  '-suffix', '_aff.nii.gz',\
                  '-dset1to2', '-dset1_strip','None','-dset2_strip','None','-overwrite',\
                  '-output_dir', outputDir.str]
    cmd = cmd + affine_kw
    unix_wrapper(cmd)

    # change transformation file name
    unix_wrapper(
        f'mv {t1.strnosuffix}_ssiu_shft_aff.nii.gz_mat.aff12.1D {t1.strnosuffix}_ssiu_shft_aff_mat.aff12.1D'
    )

    # calc the inverse affine transformation
    cmd = f'cat_matvec -ONELINE {t1.strnosuffix}_ssiu_shft_aff_mat.aff12.1D -I > {t1.strnosuffix}_ssiu_shft_aff_matINV.aff12.1D'
    unix_wrapper(cmd)

    # ================= step 4, nonlinear registration ==============
    # note that this step should be run after completing affine transformation
    # Also here, input dataset is the anat dataset but put on the base grid,
    unix_wrapper(f'rm -rf {(outputDir/"awpy*").str}')
    # use superhard, to get the best alignment, but it take a long time
    cmd = ['auto_warp.py', '-base', template.str, '-skip_affine', 'yes', \
      '-input', f'{t1.strnosuffix}_ssiu_shft_aff.nii.gz', '-overwrite', \
      '-output_dir', (outputDir/'awpy').str, '-qw_opts','-iwarp','-superhard']
    unix_wrapper(cmd)
    # copy and delete redundant files
    unix_wrapper(
        f'cp {(outputDir/"awpy"/"anat.un.qw_WARP.nii").str} {(outputDir/"WARP.nii").str}'
    )
    unix_wrapper(f'gzip -f {(outputDir/"WARP.nii").str}'
                 )  # compress nonlinear warp file
    unix_wrapper(f'rm -rf {(outputDir/"awpy")}')

    # apply transform warp t1 to the template space
    cmd = ['3dNwarpApply', '-prefix', f'{t1.strnosuffix}_ssiu_shft_aff_nl.nii.gz', \
       '-nwarp', f'{(outputDir/"WARP.nii.gz").str} {t1.strnosuffix}_ssiu_shft_aff_mat.aff12.1D', \
       '-source', f'{t1.strnosuffix}_ssiu_shft.nii.gz', '-master', template.str, '-overwrite']
    unix_wrapper(cmd)
Ejemplo n.º 3
0
def makeimagestack3dfiles(m, outputprefix=None, skips=(5, 5, 5), k=(0, 0, 0), \
    cmap='gray', returnstack=False, **stack_kw):
    '''
    makeimagestack3dfiles(m, outputprefix=None, skips=[5, 5, 5], k=[0, 0, 0], \
        cmap='gray', **kwargs):

    Input:
        <m>: is a 3D matrix or a nibabel image object
        <outputprefix>: is a output prefix,if it is NONE, then do not write images
        <skips> (optional) is a sequence of numbers of slices to skip in each of the 3 dimensions.
          Default: [5, 5, 5].
        <k> (optional) is a sequence with numbers containing the times to CCW rotate matrix
            rotation info. See np.rot90. Default: [0, 0, 0]. <k[i]> indicates
            rotate the image when writing image stack along ith dimension
        <cmap> is the colormap to use. Default: gray(256), any matplotlib colormap input is fine
        <returnstack>: boolean, whether to return the 3 imagestack. Useful to visualize
            and can help adjust <skips> and <k>. Default:False
        <stack_kw>: kwargs for makeimagestack, include <wantnorm>, <addborder>
            <csize>,<bordersize>
    Output:
        <imglist>: a 1x3 list containing the image matrix for 2,1,0 dimensions.
            note here the order is not from 0-2 dimensions. Each image is within
            range 0~1 float 64.

    We take <m> and write out three .png files, one for each slicing:
      <outputprefix>_view0.png
      <outputprefix>_view1.png
      <outputprefix>_view2.png

    The first slicing is through the first dimension with ordering [0 1 2].
    The second slicing is through the second dimension with ordering [1 3 2].
    The third slicing is through the third dimension with ordering [2 3 1].
    Note that this is different from KK's makeimagestack3dfiles.m

    After slicing, rotation (if supplied) is applied within the first
    two dimensions using np.rot90

    Example:
        vol = makegaussian3d([100 100 100],[.7 .3 .5],[.1 .4 .1]);
        makeimagestack3dfiles(vol,'test',(10, 10, 10),k=(5,5,5),wantnorm=(0, 1))

    To do:
        1. Fix the filepath problem

    History
        20180621 RZ added <returnstack> input
        20180502 RZ fixed the k rotdaion bug, now should be more clear.
        20180412 RZ changed the default cmap to 'gray'
        20180419 RZ changed the functionality of outputprefix, not saving images if None..

    '''
    from matplotlib.pyplot import imsave
    from nibabel.nifti1 import Nifti1Image as nifti
    from RZutilpy.imageprocess import makeimagestack
    from RZutilpy.system import Path, makedirs
    import numpy as np
    import os


    if isinstance(m, nifti):
        m = m.get_data()

    _is_writeimage = True
    if outputprefix is None:
        outputprefix = Path.cwd()
        _is_writeimage = False

    # create the folder if not exist.
    assert makedirs(Path(outputprefix).parent)

    # define permutes
    imglist = []
    # we make the dimension to slice to the last one
    permutes = np.array([[1, 2, 0], [0, 2, 1], [0, 1, 2]])
    for dim in range(3):
        temp = m
        if dim == 0:
            # note that the first element in the output image is along 1st dimension
            temp = temp[::skips[dim], :, :].transpose(permutes[dim, :])
        elif dim == 1:
            temp = temp[:, ::skips[dim], :].transpose(permutes[dim, :])
        elif dim == 2:
            temp = temp[:, :, ::skips[dim]].transpose(permutes[dim, :])
        # rotate image
        if k[dim]:  # note
            temp = np.rot90(temp, k=k[dim], axes=(0, 1))  # CCW rotate

        f = makeimagestack(temp, **stack_kw)
        imglist.append(f)
        # write the image
        fname = Path(outputprefix).parent / f'{Path(outputprefix).pstem}_view{dim}.png'
        # note that plt.imsave can automatically recognize the vmin and vmax, no
        # need to convert it to uint8 like in matlab
        if _is_writeimage:  # if not, only return the images of three views
            imsave(fname.str, f, cmap=cmap)

    # return the imagestacks for visualization and debugging
    if returnstack:
        return imglist  # reverse list to keep compatible the original axis