Skip to content

Commit 26ab059

Browse files
mihmatthew-brett
authored andcommitted
BF: parrec2nii does not fail immediately if one conversions fails. closes gh-30
Instead it keeps processing files and collects errors. At the end it will dump all exceptions and fail with non-zero exit code.
1 parent e62597e commit 26ab059

File tree

1 file changed

+112
-99
lines changed

1 file changed

+112
-99
lines changed

bin/parrec2nii

Lines changed: 112 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,106 @@ def error(msg, exit_code):
8181
print msg
8282
sys.exit(exit_code)
8383

84+
def proc_file(infile, opts):
85+
# load the PAR header
86+
pr_img = pr.load(infile)
87+
pr_hdr = pr_img.get_header()
88+
# get the raw unscaled data form the REC file
89+
raw_data = read_img_data(pr_img, prefer='unscaled')
90+
91+
# compute affine with desired origin
92+
affine = pr_hdr.get_affine(origin=opts.origin)
93+
94+
# create an nifti image instance -- to get a matching header
95+
nimg = nifti1.Nifti1Image(raw_data, affine)
96+
nhdr = nimg.get_header()
97+
98+
if 'parse' in opts.minmax:
99+
# need to get the scaled data
100+
verbose('Load (and scale) the data to determine value range')
101+
if opts.scaling == 'off':
102+
scaled_data = raw_data
103+
else:
104+
slope, intercept = pr_hdr.get_data_scaling(method=opts.scaling)
105+
scaled_data = slope * raw_data
106+
scaled_data += intercept
107+
if opts.minmax[0] == 'parse':
108+
nhdr.structarr['cal_min'] = scaled_data.min()
109+
else:
110+
nhdr.structarr['cal_min'] = float(opts.minmax[0])
111+
if opts.minmax[1] == 'parse':
112+
nhdr.structarr['cal_max'] = scaled_data.max()
113+
else:
114+
nhdr.structarr['cal_max'] = float(opts.minmax[1])
115+
116+
# container for potential NIfTI1 header extensions
117+
exts = nifti1.Nifti1Extensions()
118+
119+
if opts.store_header:
120+
# dump the full PAR header content into an extension
121+
fobj = open(infile, 'r')
122+
hdr_dump = fobj.read()
123+
dump_ext = nifti1.Nifti1Extension('comment', hdr_dump)
124+
fobj.close()
125+
exts.append(dump_ext)
126+
127+
# put any extensions into the image
128+
nimg.extra['extensions'] = exts
129+
130+
# image description
131+
descr = "%s;%s;%s;%s" % (
132+
pr_hdr.general_info['exam_name'],
133+
pr_hdr.general_info['patient_name'],
134+
pr_hdr.general_info['exam_date'].replace(' ',''),
135+
pr_hdr.general_info['protocol_name'])
136+
nhdr.structarr['descrip'] = descr[:80]
137+
138+
if pr_hdr.general_info['max_dynamics'] > 1:
139+
# fMRI
140+
nhdr.structarr['pixdim'][4] = pr_hdr.general_info['repetition_time']
141+
# store units -- always mm and msec
142+
nhdr.set_xyzt_units('mm', 'msec')
143+
else:
144+
# anatomical or DTI
145+
nhdr.set_xyzt_units('mm', 'unknown')
146+
147+
# get original scaling
148+
if opts.scaling == 'off':
149+
slope = 1.0
150+
intercept = 0.0
151+
else:
152+
slope, intercept = pr_hdr.get_data_scaling(method=opts.scaling)
153+
nhdr.set_slope_inter(slope, intercept)
154+
155+
# finalize the header: set proper data offset, pixdims, ...
156+
nimg.update_header()
157+
158+
# figure out the output filename
159+
outfilename = splitext_addext(os.path.basename(infile))[0]
160+
if not opts.outdir is None:
161+
# set output path
162+
outfilename = os.path.join(opts.outdir, outfilename)
163+
164+
# prep a file
165+
if opts.compressed:
166+
verbose('Using gzip compression')
167+
outfilename += '.nii.gz'
168+
outfile = gzip.open(outfilename, 'w')
169+
else:
170+
outfilename += '.nii'
171+
outfile = open(outfilename, 'w')
172+
173+
verbose('Writing %s' % outfilename)
174+
# first write the header
175+
nimg._write_header(outfile, nhdr, slope, intercept)
176+
# now the data itself, but prevent any casting or scaling
177+
nibabel.volumeutils.array_to_file(
178+
raw_data,
179+
outfile,
180+
offset=nhdr.get_data_offset())
181+
# done
182+
outfile.close()
183+
84184

85185
def main():
86186
parser = get_opt_parser()
@@ -92,107 +192,20 @@ def main():
92192
if not opts.origin in ['scanner', 'fov']:
93193
error("Unrecognized value for --origin: '%s'." % opts.origin, 1)
94194

195+
# store any exceptions
196+
errs = []
95197
for infile in infiles:
96198
verbose('Processing %s' % infile)
97-
# load the PAR header
98-
pr_img = pr.load(infile)
99-
pr_hdr = pr_img.get_header()
100-
# get the raw unscaled data form the REC file
101-
raw_data = read_img_data(pr_img, prefer='unscaled')
102-
103-
# compute affine with desired origin
104-
affine = pr_hdr.get_affine(origin=opts.origin)
105-
106-
# create an nifti image instance -- to get a matching header
107-
nimg = nifti1.Nifti1Image(raw_data, affine)
108-
nhdr = nimg.get_header()
109-
110-
if 'parse' in opts.minmax:
111-
# need to get the scaled data
112-
verbose('Load (and scale) the data to determine value range')
113-
if opts.scaling == 'off':
114-
scaled_data = raw_data
115-
else:
116-
slope, intercept = pr_hdr.get_data_scaling(method=opts.scaling)
117-
scaled_data = slope * raw_data
118-
scaled_data += intercept
119-
if opts.minmax[0] == 'parse':
120-
nhdr.structarr['cal_min'] = scaled_data.min()
121-
else:
122-
nhdr.structarr['cal_min'] = float(opts.minmax[0])
123-
if opts.minmax[1] == 'parse':
124-
nhdr.structarr['cal_max'] = scaled_data.max()
125-
else:
126-
nhdr.structarr['cal_max'] = float(opts.minmax[1])
127-
128-
# container for potential NIfTI1 header extensions
129-
exts = nifti1.Nifti1Extensions()
130-
131-
if opts.store_header:
132-
# dump the full PAR header content into an extension
133-
fobj = open(infile, 'r')
134-
hdr_dump = fobj.read()
135-
dump_ext = nifti1.Nifti1Extension('comment', hdr_dump)
136-
fobj.close()
137-
exts.append(dump_ext)
138-
139-
# put any extensions into the image
140-
nimg.extra['extensions'] = exts
141-
142-
# image description
143-
descr = "%s;%s;%s;%s" % (
144-
pr_hdr.general_info['exam_name'],
145-
pr_hdr.general_info['patient_name'],
146-
pr_hdr.general_info['exam_date'].replace(' ',''),
147-
pr_hdr.general_info['protocol_name'])
148-
nhdr.structarr['descrip'] = descr[:80]
149-
150-
if pr_hdr.general_info['max_dynamics'] > 1:
151-
# fMRI
152-
nhdr.structarr['pixdim'][4] = pr_hdr.general_info['repetition_time']
153-
# store units -- always mm and msec
154-
nhdr.set_xyzt_units('mm', 'msec')
155-
else:
156-
# anatomical or DTI
157-
nhdr.set_xyzt_units('mm', 'unknown')
158-
159-
# get original scaling
160-
if opts.scaling == 'off':
161-
slope = 1.0
162-
intercept = 0.0
163-
else:
164-
slope, intercept = pr_hdr.get_data_scaling(method=opts.scaling)
165-
nhdr.set_slope_inter(slope, intercept)
166-
167-
# finalize the header: set proper data offset, pixdims, ...
168-
nimg.update_header()
169-
170-
# figure out the output filename
171-
outfilename = splitext_addext(os.path.basename(infile))[0]
172-
if not opts.outdir is None:
173-
# set output path
174-
outfilename = os.path.join(opts.outdir, outfilename)
175-
176-
# prep a file
177-
if opts.compressed:
178-
verbose('Using gzip compression')
179-
outfilename += '.nii.gz'
180-
outfile = gzip.open(outfilename, 'w')
181-
else:
182-
outfilename += '.nii'
183-
outfile = open(outfilename, 'w')
184-
185-
verbose('Writing %s' % outfilename)
186-
# first write the header
187-
nimg._write_header(outfile, nhdr, slope, intercept)
188-
# now the data itself, but prevent any casting or scaling
189-
nibabel.volumeutils.array_to_file(
190-
raw_data,
191-
outfile,
192-
offset=nhdr.get_data_offset())
193-
# done
194-
outfile.close()
195-
199+
try:
200+
proc_file(infile, opts)
201+
except Exception as err:
202+
errs.append('%s: %s' % (infile, err))
203+
204+
if len(errs):
205+
error('Caught %i exceptions. Dump follows:\n\n %s'
206+
% (len(errs), '\n'.join(errs)), 1)
207+
else:
208+
verbose('Done')
196209

197210

198211
if __name__ == '__main__':

0 commit comments

Comments
 (0)