コード例 #1
0
def mask(varr, threshold=None, mask_out=False):
    """Create mask on image: set voxel data to 0 where image is below threshold.

    Noise threshold is assumed if set to None

    """
    def _vertical_project(data):

        data = np.mean(data,axis=(0,1))
        return data    

    def _guess_threshold(vertical_projection):

        # TODO account for noise variance in a more normal way...
        thresh = 2 * np.min(vertical_projection)
        return thresh

    # guessing a threshold
    if threshold == None: 
        vprint('Making mask, assuming noise to be in the'+
                'top voxels when determining threshold')
        orig_space = varr.space
        varr.to_anatomical()
        magnitude = vj.core.recon.ssos(varr.data)  # simple combine rcvrs
        # top down is dim2 backwards
        vert_proj = _vertical_project(magnitude)
        vert_min = np.min(vert_proj)
        vert_max = np.max(vert_proj)

        threshold = _guess_threshold(vert_proj)

    # masking
    mask = np.zeros_like(varr.data,dtype='float32')
    mask[magnitude > threshold] = 1.0

    # filling mistakenly masked inner voxels:
    mask = median_filter(mask, size=3)
    # 2nd pass
    mask = median_filter(mask, size=3)

    varr.data = varr.data * mask

    # transform back to original space for consistency
    if orig_space == 'anatomical':
        pass
    elif orig_space == 'local':
        varr.to_local()
    elif orig_space == 'global':  # TODO this is not ready though
        varr.to_global()

    # return results
    if mask_out:
        return varr, mask
    else:
        return varr
コード例 #2
0
def write_nifti(varr,out, save_procpar=True,\
                        save_complex=False,\
                        rcvr_to_timedim=False,\
                        complex_pairs='magn-phase',\
                        combine_rcvrs='ssos',\
                        cut_to_3d=False):
    """Write Nifti1 files from vnmrjpy.varray.
  
    You can specify the data to be saved 
 
    Args:
        varray       -- vnmrjpy.varray object containing the data
        out          -- output path
        save_procpar -- (boolean) saves procpar json in the same directory
        save_complex -- save complex data in real-imag pairs along a dimension
        only4dim     -- compress data into 4 dimensions , if possible
        
    """
    # sanity check for input options

    if combine_rcvrs != None and save_complex == True:
        #TODO
        pass

    # check type of data
    if len(varr.data.shape) < 3:
        raise (Exception('Data dimension error'))
    if not varr.is_kspace_complete:
        raise (Exception('K-space is not completed'))
    #------------------ making the Nifti affine and header-----------------

    # main write
    if '.nii' in out:
        out_name = str(out)
    elif '.nii.gz' in out:
        out_name = str(out[:-3])
    else:
        out_name = str(out) + '.nii'

    data = varr.data

    # OPTION : save_complex----------------------------------------------------

    # to save complex data, real and imaginary parts are added
    # to receiver channel
    if save_complex:
        rch = 4

        if complex_pairs == 'real-imag':
            data = np.concatenate([np.real(data), np.imag(data)], axis=rch)
        elif complex_pairs == 'magn-phase':
            magn = np.absolute(data)
            phase = np.arctan2(np.imag(data), np.real(data))
            data = np.concatenate([magn, phase], axis=rch)
        else:
            raise (Exception('Wrong complex_pairs'))

    # OPTION : rcvr_to_timedim-------------------------------------------------

    if rcvr_to_timedim:
        rch = 4
        timedim = data.shape[rch] * data.shape[3]
        newshape = (data.shape[0], data.shape[1], data.shape[2], timedim)
        data = np.reshape(data, newshape, order='c')

    # OPTION : combine_rcvrs---------------------------------------------------

    if combine_rcvrs == 'ssos':

        data = vj.core.recon.ssos(data, axis=4)
        # cut dimensions more than 3. This is mainly for use with certain FSL calls
        if cut_to_3d:
            if len(data.shape) == 4:
                data = data[..., 0]
            elif len(data.shape) == 5:
                data = data[..., 0, 0]
            else:
                raise (Exception('Not implemented'))
    # set affine as none to use the one in header
    img = nib.Nifti1Image(data, None, varr.nifti_header)
    # create directories if not exists
    basedir = out_name.rsplit('/', 1)[0]
    if not os.path.exists(basedir):
        os.makedirs(basedir)
    nib.save(img, out_name)
    os.system('gzip -f ' + str(out_name))
    vprint('write_nifti : ' + str(out_name) + ' saved ... ')

    if save_procpar:
        new_pp = out_name[:-3] + 'procpar'
        try:
            copyfile(varr.procpar, new_pp)
        except:
            pdname = out_name[:-3] + 'json'
            vj.core.utils.savepd(varr.pd, pdname)
コード例 #3
0
ファイル: varray.py プロジェクト: hlatkyd/vnmrjpy
    def to_kspace(self, raw=False, zerofill=True,
                    method='vnmrjpy',
                    epiref_type='default',epinav='default'):
        """Build the k-space from the raw fid data and procpar.

        Raw fid_data is numpy.ndarray(blocks, traces * np) format. Should be
        untangled based on 'seqcon' or 'seqfil' parameters.
        seqcon chars refer to (echo, slice, Pe1, Pe2, Pe3)

        For compatibility, an interface to Xrecon is provided. Set 'method' to 
        'xrecon'
        Args:
            raw
            zerofill
            method -- 'xrecon', or 'vnmrjpy'


        note:
        PREVIOUS:
                ([rcvrs, phase, read, slice, echo*time])
        NOW:
                ([phase, read, slice, echo*time, rcvrs])
        """
        # ====================== Child functions, helpers======================
        def _is_interleaved(ppdict):
            res  = (int(ppdict['sliceorder']) == 1)
            return res
        def _is_evenslices(ppdict):
            try:
                res = (int(ppdict['ns']) % 2 == 0)
            except:
                res = (int(ppdict['pss']) % 2 == 0)
            return res
        def make_im2D():
            """Child method of 'make', provides the same as vnmrj im2Drecon"""
            p = self.pd 
            rcvrs = int(p['rcvrs'].count('y'))
            (read, phase, slices) = (int(p['np'])//2,int(p['nv']),int(p['ns']))
            if 'ne' in p.keys():
                echo = int(p['ne'])
            else:
                echo = 1
            time = 1
            # this is the old shape which worked, better to reshape at the end
            finalshape = (rcvrs, phase, read, slices,echo*time*array_length)
            final_kspace = np.zeros(finalshape,dtype='complex64')
           
            for i in range(array_length):
 
                kspace = self.data[i*blocks:(i+1)*blocks,...]

                if p['seqcon'] == 'nccnn':
                    shape = (rcvrs, phase, slices, echo*time, read)
                    kspace = np.reshape(kspace, shape, order='C')
                    kspace = np.moveaxis(kspace, [0,1,4,2,3], [0,1,2,3,4])
                    

                elif p['seqcon'] == 'nscnn':

                    raise(Exception('not implemented'))

                elif p['seqcon'] == 'ncsnn':

                    preshape = (rcvrs, phase, slices*echo*time*read)
                    shape = (rcvrs, phase, slices, echo*time, read)
                    kspace = np.reshape(kspace, preshape, order='F')
                    kspace = np.reshape(kspace, shape, order='C')
                    kspace = np.moveaxis(kspace, [0,1,4,2,3], [0,1,2,3,4])

                elif p['seqcon'] == 'ccsnn':

                    preshape = (rcvrs, phase, slices*echo*time*read)
                    shape = (rcvrs, phase, slices, echo*time, read)
                    kspace = np.reshape(kspace, preshape, order='F')
                    kspace = np.reshape(kspace, shape, order='C')
                    kspace = np.moveaxis(kspace, [0,1,4,2,3], [0,1,2,3,4])
                else:
                    raise(Exception('Not implemented yet'))
                if _is_interleaved(p): # 1 if interleaved slices
                    if _is_evenslices(p):
                        c = np.zeros(kspace.shape, dtype='complex64')
                        c[...,0::2,:] = kspace[...,:slices//2,:]
                        c[...,1::2,:] = kspace[...,slices//2:,:]
                        kspace = c
                    else:
                        c = np.zeros(kspace.shape, dtype='complex64')
                        c[...,0::2,:] = kspace[...,:(slices+1)//2,:]
                        c[...,1::2,:] = kspace[...,(slices-1)//2+1:,:]
                        kspace = c

                final_kspace[...,i*echo*time:(i+1)*echo*time] = kspace

            self.data = final_kspace
            # additional reordering
            self.data = np.moveaxis(self.data,[0,1,2,3,4],[4,1,0,2,3])
            # swap axes 0 and 1 so phase, readout etc is the final order
            self.data = np.swapaxes(self.data,0,1)
            return self

        def make_im2Dcs(**kwargs):
            """
            These (*cs) are compressed sensing variants
            """

            def decode_skipint_2D(skipint):

               pass
 
            raise(Exception('not implemented'))

        def make_im2Depi(**kwargs):

            p = self.pd
            # count navigator echos, also there is a unused one
            if p['navigator'] == 'y':
                pluspe = 1 + int(p['nnav'])  # navigator echo + unused
            else:
                pluspe = 1  # unused only
            
            # init main params
            # -------------------------------------------------------
            comp_seg = p['cseg']
            altread = p['altread']
            nseg = int(p['nseg'])  # number of segments
            etl = int(p['etl'])  # echo train length
            kzero = int(p['kzero'])  
            images = int(p['images'])  # repetitions
            rcvrs = int(p['rcvrs'].count('y'))
            time = len(p['image'])  # total volumes including references
            npe = etl + pluspe  # total phase encode lines per shot
            # getting phase encode scheme
            if p['pescheme'] == 'l':
                pescheme = 'linear'
            elif p['pescheme'] == 'c':
                pescheme = 'centric'
            else:
                pescheme = None
            #TODO make petable?
            if p['petable'] == 'y':
                petab_file = None #TODO
                phase_order = vj.core.epitools.\
                            _get_phaseorder_frompetab(petab_file)
            else:
                phase_order = vj.core.epitools.\
                            _get_phaseorder_frompar(nseg,npe,etl,kzero)

            # init final shape
            if int(p['pro']) != 0:
                (read, phase, slices) = (int(p['nread']), \
                                            int(p['nphase']), \
                                            int(p['ns']))
            else:
                (read, phase, slices) = (int(p['nread'])//2, \
                                            int(p['nphase']), \
                                            int(p['ns']))
            finalshape = (read, phase, slices,time*array_length, rcvrs)
            final_kspace = np.zeros(finalshape,dtype='complex64')
            #navshape = (rcvrs, int(p['nnav']),read,slices,
            #        echo*time*array_length)
            #nav = np.zeros(navshape,dtype='complex64')  #full set of nav echos

            # sanity check
            if int(self.fid_header['np']) != int((etl +pluspe)*read*2):
                raise Exception("np and kspace format doesn't match")

            for i in range(array_length):
 
                # arrange to kspace, but don't do corrections
                kspace = self.data[i*blocks:(i+1)*blocks,...]

                # this case repetitions are in different blocks
                if p['seqcon'] == 'ncnnn':
                
                    #preshape = (rcvrs, time, nseg, slices, npe, read)
                    preshape = (time, rcvrs, nseg, slices, npe, read)
                    kspace = np.reshape(kspace, preshape, order='c')
                    # utility swaps...
                    kspace = np.swapaxes(kspace, 2,3)
                    kspace = np.swapaxes(kspace, 0,1)
                    # dims now: [rcvrs,time,nslices, nseg, phase, read]
                    # reverse odd readout lines
                    kspace = vj.core.epitools._reverse_odd(kspace,\
                                                read_dim=5,phase_dim=4)
                    # correct reversed echos for main ghost corr
                    kspace = vj.core.epitools._navigator_scan_correct(kspace,p)
                    # navigator correct
                    # this is for intersegment, and additional ghost corr
                    kspace = vj.core.epitools.\
                            _navigator_echo_correct(kspace,npe,etl,method='single')
                    # remove navigator echos 
                    kspace = vj.core.epitools._remove_navigator_echos(kspace,etl)
                    kspace = vj.core.epitools._zerofill(kspace, phase, nseg)
                    # start combining segments
                    kspace = vj.core.epitools._combine_segments(kspace,pescheme)
                    # reshape to [read,phase,slice,time,rcvrs]
                    kspace = vj.core.epitools._reshape_stdepi(kspace)
                    # correct for interleaved slices
                    kspace = vj.core.epitools._correct_ilepi(kspace,p)
                    kspace = vj.core.epitools._refcorrect(\
                                        kspace,p,method=epiref_type)

                else:
                    raise(Exception('This seqcon not implemented in epip'))
                # -------------------epi kspace preprocessing------------------
                # TODO check 'image' after array merginf
                final_kspace[...,i*time:(i+1)*time,:] = kspace
            # --------------------- kspace finished----------------------------
            self.data = final_kspace
            return self

        def make_im2Depics():
            raise(Exception('not implemented'))
        def make_im2Dfse(**kwargs):

            p = self.pd
            #petab = vj.util.getpetab(self.procpar,is_procpar=True)
            petab = vj.core.read_petab(self.pd)
            nseg = int(p['nseg'])  # seqgments
            etl = int(p['etl'])  # echo train length
            kzero = int(p['kzero'])  
            images = int(p['images'])  # repetitions
            (read, phase, slices) = (int(p['np'])//2,int(p['nv']),int(p['ns']))

            # setting time params
            echo = 1
            time = images

            phase_sort_order = np.reshape(np.array(petab),petab.size,order='C')
            # shift to positive
            phase_sort_order = phase_sort_order + phase_sort_order.size//2-1

            finalshape = (rcvrs, phase, read, slices,echo*time*array_length)
            final_kspace = np.zeros(finalshape,dtype='complex64')
           
            for i in range(array_length):
 
                kspace = self.data[i*blocks:(i+1)*blocks,...]
                if p['seqcon'] == 'nccnn':

                    #TODO check for images > 1
                    preshape = (rcvrs, phase//etl, slices, echo*time, etl, read)
                    shape = (rcvrs, echo*time, slices, phase, read)
                    kspace = np.reshape(kspace, preshape, order='C')
                    kspace = np.swapaxes(kspace,1,3)
                    kspace = np.reshape(kspace, shape, order='C')
                    # shape is [rcvrs, phase, slices, echo*time, read]
                    kspace = np.swapaxes(kspace,1,3)
                    kspace_fin = np.zeros_like(kspace)
                    kspace_fin[:,phase_sort_order,:,:,:] = kspace
                    kspace_fin = np.moveaxis(kspace_fin, [0,1,4,2,3], [0,1,2,3,4])
                    kspace = kspace_fin
                else:
                    raise(Exception('not implemented'))
                
                if _is_interleaved(p): # 1 if interleaved slices
                    if _is_evenslices(p):
                        c = np.zeros(kspace.shape, dtype='complex64')
                        c[...,0::2,:] = kspace[...,:slices//2,:]
                        c[...,1::2,:] = kspace[...,slices//2:,:]
                        kspace = c
                    else:
                        c = np.zeros(kspace.shape, dtype='complex64')
                        c[...,0::2,:] = kspace[...,:(slices+1)//2,:]
                        c[...,1::2,:] = kspace[...,(slices-1)//2+1:,:]
                        kspace = c
            
                final_kspace[...,i*echo*time:(i+1)*echo*time] = kspace

            self.data = final_kspace
            # additional reordering
            self.data = np.moveaxis(self.data,[0,1,2,3,4],[4,1,0,2,3])
            # swap axes 0 and 1 so phase, readout etc is the final order
            self.data = np.swapaxes(self.data,0,1)
            return self

        def make_im2Dfsecs(**kwargs):
            raise(Exception('not implemented'))
        def make_im3D(**kwargs):
            """Child method of 'make', provides the same as vnmrj im3Drecon"""
            p = self.pd 
            rcvrs = int(p['rcvrs'].count('y'))
            (read, phase, phase2) = (int(p['np'])//2,int(p['nv']),int(p['nv2']))
            if 'ne' in p.keys():
                echo = int(p['ne'])
            else:
                echo = 1
            if 'images' in p.keys():
                time = int(p['images'])
            else:
                time = 1

            finalshape = (rcvrs, phase, read, phase2,echo*time*array_length)
            final_kspace = np.zeros(finalshape,dtype='complex64')
           
            for i in range(array_length):
 
                kspace = self.data[i*blocks:(i+1)*blocks,...]

                if p['seqcon'] == 'nccsn':
                
                    preshape = (rcvrs,phase2,phase*echo*time*read)
                    shape = (rcvrs,phase2,phase,echo*time,read)
                    kspace = np.reshape(kspace,preshape,order='F')
                    kspace = np.reshape(kspace,shape,order='C')
                    kspace = np.moveaxis(kspace, [0,2,4,1,3], [0,1,2,3,4])
                    # what is this??
                    #kspace = np.flip(kspace,axis=3)

                if p['seqcon'] == 'ncccn':
                    preshape = (rcvrs,phase2,phase*echo*time*read)
                    shape = (rcvrs,phase,phase2,echo*time,read)
                    kspace = np.reshape(kspace,preshape,order='F')
                    kspace = np.reshape(kspace,shape,order='C')
                    kspace = np.moveaxis(kspace, [0,2,4,1,3], [0,1,2,3,4])
        
                if p['seqcon'] == 'cccsn':
                
                    preshape = (rcvrs,phase2,phase*echo*time*read)
                    shape = (rcvrs,phase,phase2,echo*time,read)
                    kspace = np.reshape(kspace,preshape,order='F')
                    kspace = np.reshape(kspace,shape,order='C')
                    kspace = np.moveaxis(kspace, [0,2,4,1,3], [0,1,2,3,4])

                if p['seqcon'] == 'ccccn':
                    
                    shape = (rcvrs,phase2,phase,echo*time,read)
                    kspace = np.reshape(kspace,shape,order='C')
                    kspace = np.moveaxis(kspace, [0,2,4,1,3], [0,1,2,3,4])

                final_kspace[...,i*echo*time:(i+1)*echo*time] = kspace

            self.data = final_kspace
            # additional reordering
            self.data = np.moveaxis(self.data,[0,1,2,3,4],[4,1,0,2,3])
            # swap axes 0 and 1 so phase, readout etc is the final order
            self.data = np.swapaxes(self.data,0,1)
            
            return self

        def make_im3Dcs():
            """
            3D compressed sensing
            sequences : ge3d, mge3d, se3d, etc
            """
            # -------------------im3Dcs Make helper functions ---------------------

            def decode_skipint_3D(skipint):
                """
                Takes 'skipint' parameter and returns a 0-1 matrix according to it
                which tells what lines are acquired in the phase1-phase2 plane
                """
                BITS = 32  # Skipint parameter is 32 bit encoded binary, see spinsights
                skip_matrix = np.zeros([int(p['nv']), int(p['nv2'])])
                skipint = [int(x) for x in skipint]
                skipint_bin_vals = [str(np.binary_repr(d, BITS)) for d in skipint]
                skipint_bin_vals = ''.join(skipint_bin_vals)
                skipint_bin_array = np.asarray([int(i) for i in skipint_bin_vals])
                skip_matrix = np.reshape(skipint_bin_array, skip_matrix.shape)

                return skip_matrix

            def fill_kspace_3D(pre_kspace, skip_matrix, shape):
                """
                Fills up reduced kspace with zeros according to skip_matrix
                returns zerofilled kspace in the final shape
                """
                kspace = np.zeros(shape, dtype=complex)
                if self.p['seqcon'] == 'ncccn':

                    n = int(self.p['nv'])
                    count = 0
                    for i in range(skip_matrix.shape[0]):
                        for k in range(skip_matrix.shape[1]):
                            if skip_matrix[i,k] == 1:
                                kspace[:,i,k,:,:] = pre_kspace[:,count,:,:]
                                count = count+1
                self.kspace = kspace
                return kspace

            #------------------------im3Dcs make start -------------------------------

            kspace = self.pre_kspace
            p = self.p
            (read, phase, phase2) = (int(p['np'])//2, \
                                    int(p['nv']), \
                                     int(p['nv2']))

            shiftaxis = (self.config['pe_dim'],\
                        self.config['ro_dim'],\
                        self.config['pe2_dim'])

            if 'ne' in p.keys():
                echo = int(p['ne'])
            else:
                echo = 1

            time = 1

            if p['seqcon'] == 'nccsn':

                pass

            if p['seqcon'] == 'ncccn':
            
                skip_matrix = decode_skipint_3D(p['skipint'])
                pre_phase = int(self.fid_header['ntraces'])    
                shape = (self.rcvrs, phase, phase2, echo*time, read)
                pre_shape = (self.rcvrs, pre_phase, echo*time, read)
                pre_kspace = np.reshape(kspace, pre_shape, order='c')
                kspace = fill_kspace_3D(pre_kspace, skip_matrix, shape)
                kspace = np.moveaxis(kspace, [0,1,4,2,3],[0,1,2,3,4])
                
            self.kspace = kspace
            return kspace

        def make_im3Dute():
            raise(Exception('not implemented')) 

        # ========================== INIT =====================================
        # if data is not from fid, just fft it
        if self.vdtype == 'imagespace':
            raise(Exception('not implemented yet'))        
            #TODO something like this:

            #self.data = vj.core.recon._fft(self.data,dims)
            #self.vdype = 'kspace'                

        #=========================== Xrecon ===================================
        vprint(' making seqfil : {}'.format(self.pd['seqfil']))

        if method == 'xrecon':
            self = vj.xrecon.make_temp_dir(self)
            self = vj.xrecon.mod_procpar(self,output='kspace')
            self = vj.xrecon.call(self)
            self = vj.xrecon.loadfdf(self)
            self = vj.xrecon.clean(self)
            return self

        # ========================= Vnmrjpy recon ============================
        elif method == 'vnmrjpy':

            # check if data is really from fid
            if self.vdtype is not 'fid':
                raise(Exception('varray data is not fid data.'))
            self.data = np.vectorize(complex)(self.data[:,0::2],\
                                                    self.data[:,1::2])
            # check for arrayed parameters, save the length for later 
            array_length = reduce(lambda x,y: x*y, \
                            [i[1] for i in self.arrayed_params])
            blocks = self.data.shape[0] // array_length
            vprint('Making k-space for '+ str(self.apptype)+' '\
                    +str(self.pd['seqfil'])+' seqcon: '+str(self.pd['seqcon']))
            rcvrs = self.pd['rcvrs'].count('y')

            # add epiref
            self.epiref_type = epiref_type
            # ----------------Handle sequence exceptions first---------------------


            if str(self.pd['seqfil']) == 'ge3d_elliptical':
               
                self = make_im3Dcs()

            #--------------------------Handle by apptype---------------------------

            if self.pd['apptype'] == 'im2D':

                self = make_im2D()
                self.is_kspace_complete = True

            elif self.pd['apptype'] == 'im2Dcs':

                self = make_im2Dcs()

            elif self.pd['apptype'] == 'im2Depi':

                self = make_im2Depi()
                self.is_kspace_complete = True

            elif self.pd['apptype'] == 'im2Depics':

                self = make_im2Depics()

            elif self.pd['apptype'] == 'im2Dfse':

                self = make_im2Dfse()
                self.is_kspace_complete = True

            elif self.pd['apptype'] == 'im2Dfsecs':

                self = make_im2Dfsecs()

            elif self.pd['apptype'] == 'im3D':

                self = make_im3D()
                self.is_kspace_complete = True

            elif self.pd['apptype'] == 'im3Dcs':

                self = make_im3Dcs()

            elif self.pd['apptype'] == 'im3Dute':

                self = make_im3Dute()
                self.is_kspace_complete = True

            else:
                raise(Exception('Could not find apptype.'))

        # ===================== Global modifications on Kspace ================

        #TODO if slices are in reversed order, flip them
        
        # in revamp make new axes, mainly for nifti io, and viewers
        # old : [rcvrs, phase, read, slice, time]
        # new : [read, phase, slice, time, rcvrs]

        # TODO moved these to the individual recons
        #self.data = np.moveaxis(self.data,[0,1,2,3,4],[4,1,0,2,3])
        # swap axes 0 and 1 so phase, readout etc is the final order
        #self.data = np.swapaxes(self.data,0,1)
        self.vdtype='kspace'
        self.to_local()

        if vj.config['default_space'] == None:
            pass
        elif vj.config['default_space'] == 'anatomical':
            self.to_anatomical()
        
        return self
コード例 #4
0
def read_fid(fid,procpar=None,load_data=True,
            xrecon=False,xrecon_space='imagespace'):
    """Handles raw data from Varian spectrometer

    Args:
        fid -- path to .fid directory
        procpar -- path to procpar file, specify procpar manually
        load_data -- set false to prevent loading binary data into memory
        xrecon -- Set True for direct reconstruction by Xrecon
        xrecon_space -- either 'kspace' or 'imagespace' for xrecon output

    .fid File structure as per Vnmrj manual:
    ===================================
    struct datafilehead
    Used at the beginning of each data file (fid's, spectra, 2D) 

       int     nblocks;      /* number of blocks in file
       int     ntraces;      /* number of traces per block    
       int     np;           /* number of elements per trace    
       int     ebytes;       /* number of bytes per element            
       int     tbytes;       /* number of bytes per trace        
       int     bbytes;       /* number of bytes per block        
       short   vers_id;      /* software version and file_id status bits
       short   status;       /* status of whole file    
       int       nbheaders;     /* number of block headers            

    struct datablockhead
     Each file block contains the following header 

       short   scale;    /* scaling factor        
       short   status;    /* status of data in block      
       short   index;    /* block index              
       short   mode;    /* mode of data in block     
       int       ctcount;    /* ct value for FID        
       float   lpval;    /* F2 left phase in phasefile    
       float   rpval;    /* F2 right phase in phasefile
       float   lvl;        /* F2 level drift correction       
       float   tlt;        /* F2 tilt drift correction      
    """
    def _decode_header(bheader):
        """Return dictionary of fid header from binary header data"""
        hkey_list = ['nblocks','ntraces','np','ebytes','tbytes','bbytes',\
                 'vers_id','status','nbheaders']
        hval_list = []
        h_dict = {}
        if len(bheader) != 32:
            raise(Exception('Incorrect fid header data: not 32 bytes'))
        else: 
            hval_list.append(int.from_bytes(bheader[0:4],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[4:8],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[8:12],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[12:16],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[16:20],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[20:24],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[24:26],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[26:28],byteorder='big'))
            hval_list.append(int.from_bytes(bheader[28:],byteorder='big'))

            for num, i in enumerate(hkey_list):
                h_dict[i] = hval_list[num]
        
        return h_dict

    def _decode_blockhead(blockheader):
        """Return block header dictionary"""
        bh_dict = {}
        bhk_list = ['scale','status','index','mode','ctcount','lpval'\
                    'rpval','lvl','tlt']
        bhv_list = []
        bhv_list.append(int.from_bytes(blockheader[0:2],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[2:4],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[4:6],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[6:8],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[8:12],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[12:16],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[16:20],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[20:24],byteorder='big'))
        bhv_list.append(int.from_bytes(blockheader[24:28],byteorder='big'))

        for num, i in enumerate(bhk_list):
            bh_dict[i] = bhv_list[num]        
        return bh_dict

    def _chunks(l, n):
        """Generate n long chunks from list l"""
        for i in range(0, len(l), n):
            yield l[i:i + n]

    def _xrecon_read(varr,xrspace):
    
        varr = vj.xrecon.make_temp_dir(varr)
        varr = vj.xrecon.mod_procpar(varr,output=xrspace)
        varr = vj.xrecon.call(varr)
        varr = vj.xrecon.loadfdf(varr,data=xrspace)
        varr = vj.xrecon.clean(varr)
        return varr

    # ============================ INIT =======================================
    # TODO is procpar != None making sense?
    if procpar==None:
    
        if os.path.isdir(fid):
            fid_path = fid
            procpar = str(fid)+'/procpar'
            fid = str(fid)+'/fid'
        else:
            fid_path = fid.rsplit('/',1)[0]
            procpar = fid.rsplit('/')[0]+'/procpar'
    else:
        print('Warning: manual setting of procpar is not fully supported')
    # ============================ XRECON ====================================
    # deal with Xrecon is set True
    if xrecon == True:
        
        pd = read_procpar(procpar)
        arr = _get_arrayed_par_length(pd)
        # TODO ???
        sdim = ['phase', 'read', 'slice', 'time', 'rcvr']

        if xrecon_space == 'kspace':
            vdtype = 'kspace'
        elif xrecon_space == 'imagespace':
            vdtype = 'imagespace'

        varr = vj.varray(data=None,space=None,\
                        pd=pd,fid_header=None,\
                        source='fid',dtype=vj.DTYPE, seqcon=pd['seqcon'],\
                        apptype=pd['apptype'],arrayed_params=arr,\
                        vdtype=None,sdims = sdim, fid_path=fid_path)

        varr = _xrecon_read(varr,xrecon_space)

        varr.vdtype = vdtype
        varr.set_nifti_header()
        varr.to_local()

        return varr


    # ================================ VNMRJPY ================================
    # header data should be 32 bytes
    with open(fid,'rb') as openFid:
        binary_data = openFid.read()
        # binary header data 
        bheader = bytearray(binary_data[:32])
        # binary fid data
        bdata = binary_data[32:]

    header_dict = _decode_header(bheader)
    pd = read_procpar(procpar)

    chunk_size = int(header_dict['bbytes'])
    block_list = list(_chunks(bdata,chunk_size))

    if header_dict['bbytes'] == len(block_list[0]):
        #print('blocksize check OK')
        pass

    vprint('reading fid {}'.format(fid))
    vprint('\nfid header :\n')
    vprint(header_dict)

    #------------main iteration through bytearray -----------------

    if load_data == False:
        fid_data = None  #don't load fid data, useful if xrecon is called next
    elif load_data == True:
        dim = (int(header_dict['nblocks']),\
                int((header_dict['ntraces'])*int(header_dict['np'])))
        fid_data = np.empty(dim)
        if header_dict['ebytes'] == 4:
            dt = '>f'
        if header_dict['ebytes'] == 2:
            dt = '>i2'
        for k,block in enumerate(block_list): # for each block
            block_header = block[:28] # separate block header
            block_data = block[28:]
            fid_data[k,:] = np.frombuffer(bytearray(block_data),dt)

    # fid data ready, now create varray class
    arr = _get_arrayed_par_length(pd)
    sdim = ['phase', 'read', 'slice', 'time', 'rcvr']
    varr = vj.varray(data=fid_data,space=None,pd=pd,fid_header=header_dict,\
                        source='fid',dtype=vj.DTYPE, seqcon=pd['seqcon'],\
                        apptype=pd['apptype'],arrayed_params=arr,vdtype='fid',\
                        sdims = sdim, fid_path=fid_path)
    return varr
コード例 #5
0
    def _parse_header(header):
        keys_to_parse = sorted(['rank','roi','location','spatial_rank',\
                        'matrix','orientation',\
                        'studyid','gap','pe_size','ro_size',\
                        'pe2_size', 'abscissa',\
                        'storage'])
        to_delete = ('char','float','int')
        header = header.decode('ascii').split('\n')
        header_dict = {}    
        for line in header:             # some formatting of header
            vprint(line)
            for item in to_delete:
                if line.startswith(item):
                    line = line.split(item,1)
                    break
            try:
                line = line[1].lstrip()
                line = line.lstrip('*').rstrip(';')
                if '[]' in line:
                    line = line.replace('[]','')
                if '{' in line:
                    line = line.replace('{','(')
                if '}' in line:
                    line = line.replace('}',')')
                if ' ' in line:
                    line = line.replace(' ','')
                line = line.split('=')
                header_dict[line[0]] = line[1]        
            except:
                continue

        for item in keys_to_parse:
            if item in header_dict.keys():            
                if item == 'abscissa':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    tempval = tempval.replace('"','')                
                    header_dict[item] = tuple([k \
                                    for k in tempval.split(',')])
                if item == 'matrix':            
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([int(k) \
                                    for k in tempval.split(',')])
                if item == 'roi':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([float(k)\
                                    for k in tempval.split(',')])
                if item == 'ro_size' or item == 'pe_size' \
                                    or item == 'pe2_size':
                    header_dict[item] = int(header_dict[item])
                if item == 'storage':
                    tempval = header_dict[item];''.join(tempval)
                    tempval = tempval.replace('"','')
                    header_dict[item] = str(tempval)
                if item == 'orientation':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([float(k)\
                                    for k in tempval.split(',')])
                if item == 'location':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([float(k)\
                                    for k in tempval.split(',')])
                if item == 'gap':
                    header_dict[item] = float(header_dict[item])
                if item == 'slices':
                    header_dict[item] = int(header_dict[item])
                if item == 'TR':
                    header_dict[item] = float(header_dict[item])/1000
        return header_dict
コード例 #6
0
def read_fdf(path):
    """Return vnmrjpy.varray from varian .fdf files

    Input can be the whole .img directory (this is preferred) or stand-alone
    .fdf files. Procpar file should be present in directory.

    Args:
        path
    Return:
        varray
    """
    #---------------- auxiliary functions for read method -----------------

    def _preproc_fdf(fdf):

        with open(fdf,'rb') as openFdf:
            fdata = bytearray(openFdf.read())
            nul = fdata.find(b'\x00')
            header = fdata[:nul]
            data = fdata[nul+1:]
        return (header,data)

    # ----------parse fdf header and return into a dictionary --------------

    def _parse_header(header):
        keys_to_parse = sorted(['rank','roi','location','spatial_rank',\
                        'matrix','orientation',\
                        'studyid','gap','pe_size','ro_size',\
                        'pe2_size', 'abscissa',\
                        'storage'])
        to_delete = ('char','float','int')
        header = header.decode('ascii').split('\n')
        header_dict = {}    
        for line in header:             # some formatting of header
            vprint(line)
            for item in to_delete:
                if line.startswith(item):
                    line = line.split(item,1)
                    break
            try:
                line = line[1].lstrip()
                line = line.lstrip('*').rstrip(';')
                if '[]' in line:
                    line = line.replace('[]','')
                if '{' in line:
                    line = line.replace('{','(')
                if '}' in line:
                    line = line.replace('}',')')
                if ' ' in line:
                    line = line.replace(' ','')
                line = line.split('=')
                header_dict[line[0]] = line[1]        
            except:
                continue

        for item in keys_to_parse:
            if item in header_dict.keys():            
                if item == 'abscissa':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    tempval = tempval.replace('"','')                
                    header_dict[item] = tuple([k \
                                    for k in tempval.split(',')])
                if item == 'matrix':            
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([int(k) \
                                    for k in tempval.split(',')])
                if item == 'roi':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([float(k)\
                                    for k in tempval.split(',')])
                if item == 'ro_size' or item == 'pe_size' \
                                    or item == 'pe2_size':
                    header_dict[item] = int(header_dict[item])
                if item == 'storage':
                    tempval = header_dict[item];''.join(tempval)
                    tempval = tempval.replace('"','')
                    header_dict[item] = str(tempval)
                if item == 'orientation':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([float(k)\
                                    for k in tempval.split(',')])
                if item == 'location':
                    tempval = header_dict[item][1:-1];''.join(tempval)
                    header_dict[item] = tuple([float(k)\
                                    for k in tempval.split(',')])
                if item == 'gap':
                    header_dict[item] = float(header_dict[item])
                if item == 'slices':
                    header_dict[item] = int(header_dict[item])
                if item == 'TR':
                    header_dict[item] = float(header_dict[item])/1000
        return header_dict

    #----------process bynary data based on header--------------------

    def _prepare_data(binary_data, header_dict):

        matrix = header_dict['matrix']

        if header_dict['storage'] == 'float' and \
           header_dict['bits'] == '32':
            dt = np.dtype('float32'); dt = dt.newbyteorder('<')

        else:
            raise(Exception('bits may be incorrectly specified in header data'))

        img_data = np.frombuffer(binary_data, dtype=dt)
        img_data = np.reshape(img_data,matrix)
        return img_data
    #---------------------------------------------------------------------
    #                             main read method
    #----------------------------------------------------------------------
    if os.path.isdir(path):
        vprint('\nMaking varray from fdf :  {} \n'.format(path))
        procpar = str(path)+'/procpar'
        fdf_list = sorted(glob.glob(str(path)+'/*.fdf'))
        (header, data) = _preproc_fdf(fdf_list[0])
        pd = read_procpar(procpar)
    else:
        if not path.endswith('.fdf'):
            warnings.warn('Input does not end with .fdf, path might be incorrect')
        vprint('\nMaking varray from fdf :  {} \n'.format(path))
        procpar = path.rsplit('/')[0]+'/procpar'
        pd = read_procpar(procpar)
        fdf_list =[path]
        (header, data) = _preproc_fdf(path)
    
    header_dict = _parse_header(header)
    # ------------------------process if 3d --------------------
    if header_dict['spatial_rank'] == '"3dfov"':

        full_data = []
        time_concat = []
        time = len([1 for i in fdf_list if 'slab001' in i])
        for i in fdf_list: # only 1 item, but there migh be more in future
                            
            (header, data) = _preproc_fdf(i)
            img_data = _prepare_data(data, header_dict)
            # expand to time dim
            img_data = np.expand_dims(img_data,axis=3)
            full_data.append(img_data) # full data in one list

        data_array = np.concatenate(full_data,axis=3)

    #----------------------process if 2d-------------------------
    elif header_dict['spatial_rank'] == '"2dfov"':

        full_data = []
        time_concat = []
        time = len([1 for i in fdf_list if 'slice001' in i])

        for i in fdf_list:                
            (header, data) = _preproc_fdf(i)
            img_data = _prepare_data(data,header_dict)
            # expand 2d to 4d
            img_data = np.expand_dims(np.expand_dims(img_data,2),3)
            full_data.append(img_data) # full data in one list
        # make sublists
        slice_list =[full_data[i:i+time] \
                        for i in range(0,len(full_data),time)]
        for aslice in slice_list:
            time_concat.append(np.concatenate(tuple(aslice),axis=3))
        #slice+time concatenated
        slice_time_concat = np.concatenate(time_concat, axis=2)
        data_array = slice_time_concat
    # --------------------process if 1d------------------------
    elif header_dict['spatial_rank'] == '"1dfov"':
        raise(Exception('Not implemented'))
     
    # making vnmrjpy.varray
    arrayed_params = _get_arrayed_par_length(pd) 
    
    varr = vj.varray(data=data_array, fdf_header=header_dict, pd=pd,\
                    dtype=vj.DTYPE, source='fdf', seqcon=pd['seqcon'],\
                    apptype=pd['apptype'],arrayed_params=arrayed_params,\
                    vdtype='image',space=None)
    
    varr.space = None
    varr.set_nifti_header()
    varr.to_local()
    return varr
コード例 #7
0
def read_procpar(procpar):
    """Return dictionary of varian parameters from procpar file"""

    with open(procpar,'r') as openpp:
        
        name = []
        value = []
        subtype = []
        basictype = []
        maxvalue = []
        minvalue = []
        # possibilities (as of manual): 0 :'line1', 1: 'line2', 2: 'last'
        line_id = 0 
    
        current_name = 0

        for line_num, line in enumerate(openpp.readlines()):

            if line_id == 0:  # parameter name line
                
                fields = line.rsplit('\n')[0].rsplit(' ')
                current_name = fields[0]
                name.append(fields[0])
                subtype.append(int(fields[1]))
                basictype.append(int(fields[2]))

                # can be 0 (undefined), 1 (real), 2 (string)
                current_basictype = int(fields[2])  
                val_list = []  # if parameter value is a multitude of strings
                line_id = 1
                                
            elif line_id == 1:  # parameter value line

                fields = line.rsplit('\n')[0].rsplit(' ')

                # values are real, and all are on this line
                if current_basictype == 1:  
                    val = [fields[i] for i in range(1,len(fields)-1)]
                    if len(val) == 1:  # don't make list if there is only one value
                        val = val[0]
                    value.append(val)
                    line_id = 2
                # values are strings
                elif current_basictype == 2 and int(fields[0]) == 1:
                    
                    value.append(str(fields[1].rsplit('"')[1]))
                    line_id = 2
                # multiple string values
                elif current_basictype == 2 and int(fields[0]) > 1:
                    
                    val_list.append(fields[1])
                    remaining_values = int(fields[0])-1
                    line_id = 3
                
            elif line_id == 2:

                line_id = 0
        
            elif line_id == 3:  # if values are on multiple lines
                if remaining_values > 1:  # count backwards from remaining values
                    val_list.append(fields[0])
                    remaining_values = remaining_values - 1
                elif remaining_values == 1:
                    val_list.append(fields[0])
                    remaining_values = remaining_values - 1
                    value.append(val_list)
                    line_id = 2
                else:
                    raise(Exception('Error reading procpar, problem with line_id'))
            else:
                raise(Exception('Error reading procpar, problem with line_id'))

    vprint('procpar file {} read succesfully'.format(procpar))

    return dict(zip(name, value))