This file is indexed.

/usr/bin/parrec2nii is in python-nibabel 1.2.2-1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/usr/bin/python
"""PAR/REC to NIfTI converter
"""

from optparse import OptionParser, Option
import sys
import os
import gzip
import numpy as np
import nibabel
import nibabel.parrec as pr
import nibabel.nifti1 as nifti1
from nibabel.loadsave import read_img_data
from nibabel.filename_parser import splitext_addext

# global verbosity switch
verbose_switch = False


def get_opt_parser():
    # use module docstring for help output
    p = OptionParser(
                usage="%s [OPTIONS] <PAR files>\n\n" % sys.argv[0] + __doc__,
                version="%prog " + nibabel.__version__)

    p.add_option(
        Option("-v", "--verbose", action="store_true",
               dest="verbose", default=False,
               help="Make some noise."))
    p.add_option(
        Option("-o", "--output-dir",
               action="store", type="string", dest="outdir",
               default=None,
               help=\
"""Destination directory for NIfTI files. Default: current directory."""))
    p.add_option(
        Option("-c", "--compressed", action="store_true",
               dest="compressed", default=False,
               help="Whether to write compressed NIfTI files or not."))
    p.add_option(
        Option("--origin", action="store",
               dest="origin", default="scanner",
               help=\
"""Reference point of the q-form transformation of the NIfTI image. If 'scanner'
the (0,0,0) coordinates will refer to the scanner's iso center. If 'fov', this
coordinate will be the center of the recorded volume (field of view). Default:
'scanner'."""))
    p.add_option(
        Option("--minmax", action="store", nargs=2,
               dest="minmax", help=\
"""Mininum and maximum settings to be stored in the NIfTI header. If any of
them is set to 'parse', the scaled data is scanned for the actual minimum and
maximum. To bypass this potentially slow and memory intensive step (the data
has to be scaled and fully loaded into memory), fixed values can be provided as
space-separated pair, e.g. '5.4 120.4'. It is possible to set a fixed minimum
as scan for the actual maximum (and vice versa). Default: 'parse parse'."""))
    p.set_defaults(minmax=('parse', 'parse'))
    p.add_option(
        Option("--store-header", action="store_true",
               dest="store_header", default=False,
               help=\
"""If set, all information from the PAR header is stored in an extension of
the NIfTI file header. Default: off"""))
    p.add_option(
        Option("--scaling", action="store", dest="scaling", default='dv',
               help=\
"""Choose data scaling setting. The PAR header defines two different data
scaling settings: 'dv' (values displayed on console) and 'fp' (floating point
values). Either one can be chosen, or scaling can be disabled completely
('off').  Note that neither method will actually scale the data, but just store
the corresponding settings in the NIfTI header. Default: 'dv'"""))
    return p


def verbose(msg, indent=0):
    if verbose_switch:

        print "%s%s" % (' ' * indent, msg)

def error(msg, exit_code):
    print  >> sys.stderr, msg
    sys.exit(exit_code)

def proc_file(infile, opts):
    # load the PAR header
    pr_img = pr.load(infile)
    pr_hdr = pr_img.get_header()
    # get the raw unscaled data form the REC file
    raw_data = read_img_data(pr_img, prefer='unscaled')

    # compute affine with desired origin
    affine = pr_hdr.get_affine(origin=opts.origin)

    # create an nifti image instance -- to get a matching header
    nimg = nifti1.Nifti1Image(raw_data, affine)
    nhdr = nimg.get_header()

    if 'parse' in opts.minmax:
        # need to get the scaled data
        verbose('Load (and scale) the data to determine value range')
        if opts.scaling == 'off':
            scaled_data = raw_data
        else:
            slope, intercept = pr_hdr.get_data_scaling(method=opts.scaling)
            scaled_data = slope * raw_data
            scaled_data += intercept
    if opts.minmax[0] == 'parse':
        nhdr.structarr['cal_min'] = scaled_data.min()
    else:
        nhdr.structarr['cal_min'] = float(opts.minmax[0])
    if opts.minmax[1] == 'parse':
        nhdr.structarr['cal_max'] = scaled_data.max()
    else:
        nhdr.structarr['cal_max'] = float(opts.minmax[1])

    # container for potential NIfTI1 header extensions
    exts = nifti1.Nifti1Extensions()

    if opts.store_header:
        # dump the full PAR header content into an extension
        fobj = open(infile, 'r')
        hdr_dump = fobj.read()
        dump_ext = nifti1.Nifti1Extension('comment', hdr_dump)
        fobj.close()
        exts.append(dump_ext)

    # put any extensions into the image
    nimg.extra['extensions'] = exts

    # image description
    descr = "%s;%s;%s;%s" % (
                pr_hdr.general_info['exam_name'],
                pr_hdr.general_info['patient_name'],
                pr_hdr.general_info['exam_date'].replace(' ',''),
                pr_hdr.general_info['protocol_name'])
    nhdr.structarr['descrip'] = descr[:80]

    if pr_hdr.general_info['max_dynamics'] > 1:
        # fMRI
        nhdr.structarr['pixdim'][4] = pr_hdr.general_info['repetition_time']
        # store units -- always mm and msec
        nhdr.set_xyzt_units('mm', 'msec')
    else:
        # anatomical or DTI
        nhdr.set_xyzt_units('mm', 'unknown')

    # get original scaling
    if opts.scaling == 'off':
        slope = 1.0
        intercept = 0.0
    else:
        slope, intercept = pr_hdr.get_data_scaling(method=opts.scaling)
        nhdr.set_slope_inter(slope, intercept)

    # finalize the header: set proper data offset, pixdims, ...
    nimg.update_header()

    # figure out the output filename
    outfilename = splitext_addext(os.path.basename(infile))[0]
    if not opts.outdir is None:
        # set output path
        outfilename = os.path.join(opts.outdir, outfilename)

    # prep a file
    if opts.compressed:
        verbose('Using gzip compression')
        outfilename += '.nii.gz'
        outfile = gzip.open(outfilename, 'w')
    else:
        outfilename += '.nii'
        outfile = open(outfilename, 'w')

    verbose('Writing %s' % outfilename)
    # first write the header
    nimg._write_header(outfile, nhdr, slope, intercept)
    # now the data itself, but prevent any casting or scaling
    nibabel.volumeutils.array_to_file(
            raw_data,
            outfile,
            offset=nhdr.get_data_offset())
    # done
    outfile.close()


def main():
    parser = get_opt_parser()
    (opts, infiles) = parser.parse_args()

    global verbose_switch
    verbose_switch = opts.verbose

    if not opts.origin in ['scanner', 'fov']:
        error("Unrecognized value for --origin: '%s'." % opts.origin, 1)

    # store any exceptions
    errs = []
    for infile in infiles:
        verbose('Processing %s' % infile)
        try:
            proc_file(infile, opts)
        except Exception:
            err = sys.exc_info()[1]
            errs.append('%s: %s' % (infile, err))

    if len(errs):
        error('Caught %i exceptions. Dump follows:\n\n %s'
                % (len(errs), '\n'.join(errs)), 1)
    else:
        verbose('Done')


if __name__ == '__main__':
    main()