Exemple #1
0
def test_orientations():
    """ Test that the axis string is correctly recovered
    """
    siemens_orientations = {'3': 'Tra', '4': 'Tra', '5': 'Tra', '6': 'Sag',
                            '7': 'Cor', '8': 'Sag', '9': 'Cor', '10': 'Tra>Sag 30.0',
                            '11': 'Tra>Cor 30.0', '12': 'Tra>Cor 30.0 >Sag 15.0',
                            '13': 'Tra>Sag 30.0 >Cor 15.0', '14': 'Tra>Sag -30.0',
                            '15': 'Tra>Cor -30.0', '16': 'Tra>Cor 30.0 >Sag -15.0',
                            '17': 'Tra>Sag 30.0 >Cor -15.0', '18': 'Tra>Sag 30.0',
                            '19': 'Tra>Cor 30.0', '20': 'Tra>Cor 30.0 >Sag 15.0',
                            '21': 'Tra>Sag 30.0 >Cor 15.0'}

    siemens_inplane_orientations = {'3': 0.0, '4': 30.0, '5': -30.0, '6': 0.0,
                                    '7': 0.0, '8': 30.0, '9': 30.0, '10': 0.0,
                                    '11': 0.0, '12': 0.0, '13': 0.0, '14': 0.0,
                                    '15': 0.0, '16': 0.0, '17': 0.0, '18': 20.0,
                                    '19': 20.0, '20': 20.0, '21': 20.0}
    for idx, ori in siemens_orientations.items():
        data = siemens.Siemens('tests/data/siemens/%s' % idx)
        data.calculate_transform()
        calc_ori = data.qform.siemens_orientation()
        # orientation string is correct
        assert ori == calc_ori[0]
        assert abs(siemens_inplane_orientations[idx] - calc_ori[1]) < DIM_TOL
        size = data.qform.get_scale()
        real_size = [20, 25, 30]
        position = data.qform.get_position()
        for i in range(3):
            assert abs(size[i]-real_size[i]) < DIM_TOL
            assert abs(position[i]) < DIM_TOL

        # in plane rotation
        assert approx(np.degrees(data.meta['VoiInPlaneRotation'])) \
            == siemens_inplane_orientations[idx]
Exemple #2
0
def test_read_unaveraged():
    """Test reading a directory of dicoms
    """
    data = siemens.Siemens('tests/data/siemens/eja_svs_press_combined_noave')
    data.get_svsdata()

    assert data.data.shape == (1, 8, 1, 1, 2048)
    for i in range(data.data.shape[0]):
        for j in range(data.data.shape[1]):
            assert data.data[i, j, 0, 0, -1] != 0
Exemple #3
0
def test_read_single():
    """Test reading a single combined DICOM
    """
    test_file = 'tests/data/siemens/3/S8457LTU_2_3_00001_00001_173218510000__1263534865.dcm'
    data_file = siemens.Siemens(test_file)
    svs_file = data_file.get_svsdata()

    data_dir = siemens.Siemens('tests/data/siemens/3')
    svs_dir = data_dir.get_svsdata()

    # is it the right size?
    assert data_file.data.shape == data_dir.data.shape == (1, 1, 1, 1, 2048)

    dcm = dcmwrapper.wrapper_from_file(test_file)
    packed = dcm.get((0x7fe1, 0x1010)).value
    data = struct.unpack("<%df" % (len(packed) / 4), packed)
    cmplx = [data[i]+data[i+1]*1j for i in range(0, len(data), 2)]

    assert (data_file.data == np.conj(cmplx)).all()
    assert (data_file.data == data_dir.data).all()
Exemple #4
0
def test_sidecar():
    """Test creating a BIDS sidecar
    """
    # TODO: Check value consistency
    data = siemens.Siemens('tests/data/siemens/eja_svs_press_uncombined')
    with open('test.json', 'w+') as fp:
        json.dump(data.get_sidecar(), fp, indent=3)

    with open('test.json') as fp:
        bids = json.load(fp)

    # save the transform
    np.savetxt('sub-test_from-Device_to-orig_mode-image_xfm.mat', data.qform.get_matrix())
Exemple #5
0
def test_axis():
    siemens_data = siemens.Siemens('tests/data/siemens/eja_svs_press_combined_noave')
    data = siemens_data.get_svsdata()

    sw = data.sw
    npts = data.fid.shape[-1]

    f = np.arange(-sw/2.0+sw/(2*npts), sw/2, sw/npts)

    # is the frequnecy axis correct?
    orig_f = data.f
    assert approx(f) == orig_f
    assert not (approx(data.f) != orig_f)

    # shift the ppm axis
    ppm_shifted = data.ppm - data._ppmshift
    data.ppm = ppm_shifted
    shifted_f = data.f
    assert approx(shifted_f) != orig_f
Exemple #6
0
def main():
    parser = argparse.ArgumentParser(
        description='Process Siemens SVS data from DICOMs')
    parser.add_argument('dicom', type=str, nargs='+',
                        help="Path to DICOM directory")
    parser.add_argument('--prefix', type=str,
                        help="Output prefix")
    parser.add_argument('--t1', type=str, required=False,
                        help="Path to co-registered T1 NIFTI (saves VOI mask)")
    parser.add_argument('--water', type=str, required=False,
                        help="Path to DICOM directory of unsupressed water data. Will be used for correction.")
    parser.add_argument('--load', dest='load', action='store_true',
                        help="Load FID data from DICOM (required for analysis).")
    parser.add_argument('--no-load', dest='load', action='store_false',
                        help="Do not load FID data")
    parser.add_argument('--fida', dest='fida', action='store_true',
                        help="Run FID-A preprocessing (requires matlab)")
    parser.add_argument('--no-fida', dest='fida', action='store_false',
                        help="Do not run FID-A processing")
    parser.add_argument('--tarquin', dest='tarquin', action='store_true',
                        help="Run Tarquin fit")
    parser.add_argument('--no-tarquin', dest='tarquin', action='store_false',
                        help="Do not run Tarquin fitting")
    parser.add_argument('--no-concat', dest='concat', action='store_false',
                        help="Do not concatenate runs before preprocessing")

    parser.set_defaults(load=True)
    parser.set_defaults(fida=True)
    parser.set_defaults(tarquin=True)

    # args = parser.parse_args(['--prefix', '/Users/roh17004/Downloads/TD919/autotest3',
    #                          '--t1','/Users/roh17004/Downloads/TD919/5/TD919-T1w.nii.gz',
    #                          '/Users/roh17004/Downloads/TD919/39', '/Users/roh17004/Downloads/TD919/42',
    #                          '/Users/roh17004/Downloads/TD919/45'])

    args = parser.parse_args()

    # Parse the DICOMs
    runs = []
    fida_names = []
    for run,fname in enumerate(args.dicom):
        print('Reading metadata from %s...\n' % fname)
        dcm = siemens.Siemens(fname)
        dcm.calculate_transform()
        # save transform
        np.savetxt('%s_run-%02d_from-device_to-orig_mode-image_xfm.mat' % (args.prefix, run+1), dcm.qform.get_matrix())

        # make voxel
        if args.t1 is not None:
            print('Creating VOI mask...\n')
            from autovps import make_voi
            import nibabel as nib
            tform = dcm.calculate_transform()
            t1 = nib.load(args.t1)
            img = make_voi.make_voi(t1, tform)
            nib.save(img, '%s_run-%02d_space-orig_roi.nii.gz' % (args.prefix, run+1))

        # Read data
        if args.load:
            print('Loading data...\n')
            svs = dcm.get_svsdata()

            # Save to FID-A .mat
            fida_fname = '%s_run-%02d_fida.mat' % (args.prefix, run+1)
            svs.save_fida(fida_fname)
            fida_names.append(fida_fname)

            # TODO: save NIFTI, LCM

        runs.append(svs)

    # merge runs

    fids = runs[0].fid
    specs = runs[0].spec

    if len(runs) > 1:
        print('Merging multiple runs...')
        for idx in range(1, len(runs)):
            # check the sequence is the same
            if runs[0].sequence_name != runs[idx].sequence_name:
                raise Exception('Not all runs are the same sequence!')
            if runs[0].te != runs[idx].te:
                raise Exception('Not all runs have the same TE!')
            if runs[0].tr != runs[idx].tr:
                raise Exception('Not all runs have the same TR!')
            if runs[0].sw != runs[idx].sw:
                raise Exception('Not all runs have the same spectral width!')
            # TODO: add equality operator to Transform class
            if not np.all(runs[0].transform.get_matrix() == runs[idx].transform.get_matrix()):
                raise Exception('Not all runs are from the same location!')
            # TODO: check channels match

            fids = np.concatenate((fids, runs[idx].fid), 1)
            specs = np.concatenate((specs, runs[idx].spec), 1)
        svs = runs[0]
        svs.fid = fids
        svs.spec = specs
        fida_fname = '%s_desc-merged_fida.mat' % (args.prefix)
        svs.save_fida(fida_fname)

    # Preprocess using FID-A

    # TODO: Mark STEAM and sLASER
    if args.fida:
        water_arg = '[]'
        # Load water
        if args.water is not None:
            dcm_w = siemens.Siemens(args.water)
            svs_w = dcm_w.get_svsdata()
            fida_w_fname = '%s_water.mat' % args.prefix
            svs_w.save_fida(fida_w_fname)
            water_arg = f"'{fida_w_fname}'"

        print('Preprocessing using FID-A...')

        import subprocess
        from subprocess import Popen
        import platform

        # check for macOS and try to wake up the display
        # so matlab figures will work
        p = None
        if platform.system() == 'Darwin':
            print('macOS might not work!')
            p = Popen(['caffeinate', '-u'])

        if svs.sequence_type == 'PRESS':
            cmd = "preproc_press('%s_report', %s, '%s'); quit" % (args.prefix, water_arg, fida_fname)
            subprocess.run(['matlab', '-nodesktop', '-r', cmd])
            if args.tarquin:
                print('Processing PRESS spectra using Tarquin')
                cmd = """tarquin --input %s_report/spectra_jmrui_ave.txt --format jmrui_txt \
                        --lipid_filter true --auto_phase true --auto_ref true \
                        --crlb_optim false --ref_signals 1h_naa_cr_cho --fs %d \
                        --ft %d --echo %f --pul_seq press \
                        --output_txt %s_report/tarquin.txt \
                        --output_csv %s_report/tarquin.csv \
                        --output_pdf %s_report/tarquin.pdf \
                        --output_image %s_report/tarquin_img.pdf \
                        --ext_pdf true --output_xml %s_report/tarquin.xml --int_basis 1h_brain_glth \
                        --svs_only true --stack_pdf true --te1 .014""" % (args.prefix, svs.sw, svs.larmor, svs.te, args.prefix, args.prefix, args.prefix, args.prefix, args.prefix)
                print(cmd)
                subprocess.run(cmd, shell=True)

        if svs.sequence_type == 'MEGAPRESS':
            
            if not args.concat:
                # preprocess and then align each run separately
                cmd = "preproc_multi_megapress('%s_report', %s, '%s'); quit" % (args.prefix, water_arg,  "','".join(fida_names))   
                print('Preprocessing each run')
            else:
                # preprocess the merged data         
                cmd = "preproc_megapress('%s_report', %s, '%s'); quit" % (args.prefix, water_arg, fida_fname)
                print('Preprocessing merged data')

            subprocess.run(['matlab', '-nodesktop', '-r', cmd])

            if args.tarquin:
                print('Processing MEGA-PRESS difference spectra using Tarquin')
                cmd = """tarquin --input %s_report/spectra_jmrui_diff_ave.txt --format jmrui_txt \
                        --lipid_filter true --auto_phase true --auto_ref true \
                        --crlb_optim false --ref_signals 1h_naa --fs %d \
                        --ft %d --echo %f --pul_seq mega_press \
                        --output_txt %s_report/tarquin.txt \
                        --output_csv %s_report/tarquin.csv \
                        --output_pdf %s_report/tarquin.pdf \
                        --output_image %s_report/tarquin_img.pdf \
                        --ext_pdf true --output_xml %s_report/tarquin.xml --int_basis megapress_gaba \
                        --svs_only true --stack_pdf true --te1 .014""" % (args.prefix, svs.sw, svs.larmor, svs.te, args.prefix, args.prefix, args.prefix, args.prefix, args.prefix)
                print(cmd)
                subprocess.run(cmd, shell=True)

                print('Processing MEGA-PRESS off spectra using Tarquin')
                cmd = """tarquin --input %s_report/spectra_jmrui_off_ave.txt --format jmrui_txt \
                        --lipid_filter true --auto_phase true --auto_ref true \
                        --crlb_optim false --ref_signals 1h_naa --fs %d \
                        --ft %d --echo %f --pul_seq press \
                        --output_txt %s_report/tarquin_off.txt \
                        --output_csv %s_report/tarquin_off.csv \
                        --output_pdf %s_report/tarquin_off.pdf \
                        --output_image %s_report/tarquin_off_img.pdf \
                        --ext_pdf true --output_xml %s_report/tarquin_off.xml --int_basis 1h_brain \
                        --svs_only true --stack_pdf true --te1 .014""" % (args.prefix, svs.sw, svs.larmor, svs.te, args.prefix, args.prefix, args.prefix, args.prefix, args.prefix)
                print(cmd)
                subprocess.run(cmd, shell=True)

        if p is not None:
            p.terminate()
Exemple #7
0
def test_nifti():
    with warns(UserWarning, match='Assuming channels are combined'):
        siemens_data = siemens.Siemens(
            'tests/data/siemens/eja_svs_press_combined_noave')
        data = siemens_data.get_svsdata()
        data.save_nifti('test.nii')
Exemple #8
0
%load_ext autoreload
%autoreload 2

import autovps.dataset.siemens as siemens
from autovps.dataset import svsdata
from autovps import make_voi
import nibabel as nib

base_path = '/Users/roh17004/Downloads/104DI'
#press
data = siemens.Siemens(base_path + '/12')
svs = data.get_svsdata()
svs.save_fida(base_path + '/press.mat')

data = siemens.Siemens(base_path + '/15')
svs = data.get_svsdata()
svs.save_fida(base_path + '/MEGA1.mat')

data = siemens.Siemens(base_path + '/18')
svs = data.get_svsdata()
svs.save_fida(base_path + '/MEGA2.mat')

data = siemens.Siemens(base_path + '/21')
svs = data.get_svsdata()
svs.save_fida(base_path + '/MEGA3.mat')

tform= data.calculate_transform()
t1=nib.load(base_path + '/3/104DI-T1w_MPR.nii.gz')

img = make_voi.make_voi(t1, tform)
nib.save(img, base_path+'/roi.nii.gz')