|
24 | 24 | save_scans_key,
|
25 | 25 | tuneup_bids_json_files,
|
26 | 26 | add_participant_record,
|
| 27 | + BIDSError |
27 | 28 | )
|
28 | 29 | from .dicoms import (
|
29 | 30 | group_dicoms_into_seqinfos,
|
@@ -243,7 +244,7 @@ def convert(items, converter, scaninfo_suffix, custom_callable, with_prov,
|
243 | 244 | if not isinstance(outtypes, (list, tuple)):
|
244 | 245 | outtypes = (outtypes,)
|
245 | 246 |
|
246 |
| - prefix_dirname = op.dirname(prefix + '.ext') |
| 247 | + prefix_dirname = op.dirname(prefix) |
247 | 248 | outname_bids = prefix + '.json'
|
248 | 249 | bids_outfiles = []
|
249 | 250 | lgr.info('Converting %s (%d DICOMs) -> %s . '
|
@@ -462,6 +463,8 @@ def save_converted_files(res, item_dicoms, bids, outtype, prefix, outname_bids,
|
462 | 463 | """
|
463 | 464 | from nipype.interfaces.base import isdefined
|
464 | 465 |
|
| 466 | + prefix_dirname, prefix_basename = op.split(prefix) |
| 467 | + |
465 | 468 | bids_outfiles = []
|
466 | 469 | res_files = res.outputs.converted_files
|
467 | 470 |
|
@@ -492,16 +495,112 @@ def save_converted_files(res, item_dicoms, bids, outtype, prefix, outname_bids,
|
492 | 495 | # Also copy BIDS files although they might need to
|
493 | 496 | # be merged/postprocessed later
|
494 | 497 | bids_files = sorted(res.outputs.bids
|
495 |
| - if len(res.outputs.bids) == len(res_files) |
496 |
| - else [None] * len(res_files)) |
| 498 | + if len(res.outputs.bids) == len(res_files) |
| 499 | + else [None] * len(res_files)) |
| 500 | + |
| 501 | + ### Do we have a multi-echo series? ### |
| 502 | + # Some Siemens sequences (e.g. CMRR's MB-EPI) set the label 'TE1', |
| 503 | + # 'TE2', etc. in the 'ImageType' field. However, other seqs do not |
| 504 | + # (e.g. MGH ME-MPRAGE). They do set a 'EchoNumber', but not for the |
| 505 | + # first echo. To compound the problem, the echoes are NOT in order, |
| 506 | + # so the first NIfTI file does not correspond to echo-1, etc. So, we |
| 507 | + # need to know, beforehand, whether we are dealing with a multi-echo |
| 508 | + # series. To do that, the most straightforward way is to read the |
| 509 | + # echo times for all bids_files and see if they are all the same or not. |
| 510 | + |
| 511 | + # Check for echotime information |
| 512 | + echo_times = set() |
| 513 | + |
| 514 | + for bids_file in bids_files: |
| 515 | + if bids_file: |
| 516 | + # check for varying EchoTimes |
| 517 | + echot = load_json(bids_file).get('EchoTime', None) |
| 518 | + if echot is not None: |
| 519 | + echo_times.add(echot) |
497 | 520 |
|
| 521 | + # To see if the echo times are the same, convert it to a set and see if |
| 522 | + # only one remains: |
| 523 | + is_multiecho = len(echo_times) >= 1 if echo_times else False |
| 524 | + |
| 525 | + ### Loop through the bids_files, set the output name and save files |
498 | 526 | for fl, suffix, bids_file in zip(res_files, suffixes, bids_files):
|
499 |
| - outname = "%s%s.%s" % (prefix, suffix, outtype) |
500 |
| - safe_copyfile(fl, outname, overwrite) |
| 527 | + |
| 528 | + # TODO: monitor conversion duration |
501 | 529 | if bids_file:
|
502 |
| - outname_bids_file = "%s%s.json" % (prefix, suffix) |
| 530 | + fileinfo = load_json(bids_file) |
| 531 | + |
| 532 | + # set the prefix basename for this specific file (we'll modify it, |
| 533 | + # and we don't want to modify it for all the bids_files): |
| 534 | + this_prefix_basename = prefix_basename |
| 535 | + |
| 536 | + # _sbref sequences reconstructing magnitude and phase generate |
| 537 | + # two NIfTI files IN THE SAME SERIES, so we cannot just add |
| 538 | + # the suffix, if we want to be bids compliant: |
| 539 | + if bids_file and this_prefix_basename.endswith('_sbref'): |
| 540 | + # Check to see if it is magnitude or phase reconstruction: |
| 541 | + if 'M' in fileinfo.get('ImageType'): |
| 542 | + mag_or_phase = 'magnitude' |
| 543 | + elif 'P' in fileinfo.get('ImageType'): |
| 544 | + mag_or_phase = 'phase' |
| 545 | + else: |
| 546 | + mag_or_phase = suffix |
| 547 | + |
| 548 | + # Insert reconstruction label |
| 549 | + if not ("_rec-%s" % mag_or_phase) in this_prefix_basename: |
| 550 | + |
| 551 | + # If "_rec-" is specified, prepend the 'mag_or_phase' value. |
| 552 | + if ('_rec-' in this_prefix_basename): |
| 553 | + raise BIDSError( |
| 554 | + "Reconstruction label for multi-echo single-band" |
| 555 | + " reference images will be automatically set, remove" |
| 556 | + " from heuristic" |
| 557 | + ) |
| 558 | + |
| 559 | + # If not, insert "_rec-" + 'mag_or_phase' into the prefix_basename |
| 560 | + # **before** "_run", "_echo" or "_sbref", whichever appears first: |
| 561 | + for label in ['_run', '_echo', '_sbref']: |
| 562 | + if (label in this_prefix_basename): |
| 563 | + this_prefix_basename = this_prefix_basename.replace( |
| 564 | + label, "_rec-%s%s" % (mag_or_phase, label) |
| 565 | + ) |
| 566 | + break |
| 567 | + |
| 568 | + # Now check if this run is multi-echo |
| 569 | + # (Note: it can be _sbref and multiecho, so don't use "elif"): |
| 570 | + # For multi-echo sequences, we have to specify the echo number in |
| 571 | + # the file name: |
| 572 | + if bids_file and is_multiecho: |
| 573 | + # Get the EchoNumber from json file info. If not present, it's echo-1 |
| 574 | + echo_number = fileinfo.get('EchoNumber', 1) |
| 575 | + |
| 576 | + |
| 577 | + supported_multiecho = ['_bold', '_epi', '_sbref', '_T1w'] |
| 578 | + # Now, decide where to insert it. |
| 579 | + # Insert it **before** the following string(s), whichever appears first. |
| 580 | + for imgtype in supported_multiecho: |
| 581 | + if (imgtype in this_prefix_basename): |
| 582 | + this_prefix_basename = this_prefix_basename.replace( |
| 583 | + imgtype, "_echo-%d%s" % (echo_number, imgtype) |
| 584 | + ) |
| 585 | + break |
| 586 | + |
| 587 | + # Fallback option: |
| 588 | + # If we have failed to modify this_prefix_basename, because it didn't fall |
| 589 | + # into any of the options above, just add the suffix at the end: |
| 590 | + if this_prefix_basename == prefix_basename: |
| 591 | + this_prefix_basename += suffix |
| 592 | + |
| 593 | + # Finally, form the outname by stitching the directory and outtype: |
| 594 | + outname = op.join(prefix_dirname, this_prefix_basename) |
| 595 | + outfile = outname + '.' + outtype |
| 596 | + |
| 597 | + # Write the files needed: |
| 598 | + safe_copyfile(fl, outfile, overwrite) |
| 599 | + if bids_file: |
| 600 | + outname_bids_file = "%s.json" % (outname) |
503 | 601 | safe_copyfile(bids_file, outname_bids_file, overwrite)
|
504 | 602 | bids_outfiles.append(outname_bids_file)
|
| 603 | + |
505 | 604 | # res_files is not a list
|
506 | 605 | else:
|
507 | 606 | outname = "{}.{}".format(prefix, outtype)
|
|
0 commit comments