Skip to content

Commit 791ec85

Browse files
committed
rebase update_multiorient_name
1 parent 383525d commit 791ec85

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

heudiconv/convert.py

+39
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,34 @@ def update_uncombined_name(
523523
return filename
524524

525525

526+
def update_multiorient_name(
527+
metadata: dict[str, Any],
528+
filename: str,
529+
) -> str:
530+
if "acq-" in filename:
531+
lgr.warning(
532+
"Not embedding multi-orientation information as prefix already uses acq- parameter."
533+
)
534+
return filename
535+
iop = metadata.get("ImageOrientationPatientDICOM")
536+
iop = [round(x) for x in iop]
537+
cross_prod = [
538+
iop[1] * iop[5] - iop[2] * iop[4],
539+
iop[2] * iop[3] - iop[0] * iop[5],
540+
iop[0] * iop[4] - iop[1] * iop[3],
541+
]
542+
cross_prod = [abs(x) for x in cross_prod]
543+
slice_orient = ["sagittal", "coronal", "axial"][cross_prod.index(1)]
544+
bids_pairs = filename.split("_")
545+
# acq needs to be inserted right after sub- or ses-
546+
ses_or_sub_idx = sum(
547+
[bids_pair.split("-")[0] in ["sub", "ses"] for bids_pair in bids_pairs]
548+
)
549+
bids_pairs.insert(ses_or_sub_idx, "acq-%s" % slice_orient)
550+
filename = "_".join(bids_pairs)
551+
return filename
552+
553+
526554
def convert(
527555
items: list[tuple[str, tuple[str, ...], list[str]]],
528556
converter: str,
@@ -953,6 +981,7 @@ def save_converted_files(
953981
echo_times: set[float] = set()
954982
channel_names: set[str] = set()
955983
image_types: set[str] = set()
984+
iops: set[str] = set()
956985
for metadata in bids_metas:
957986
if not metadata:
958987
continue
@@ -968,6 +997,10 @@ def save_converted_files(
968997
image_types.update(metadata["ImageType"])
969998
except KeyError:
970999
pass
1000+
try:
1001+
iops.update(str(metadata["ImageOrientationPatientDICOM"]))
1002+
except KeyError:
1003+
pass
9711004

9721005
is_multiecho = (
9731006
len(set(filter(bool, echo_times))) > 1
@@ -978,6 +1011,7 @@ def save_converted_files(
9781011
is_complex = (
9791012
"M" in image_types and "P" in image_types
9801013
) # Determine if data are complex (magnitude + phase)
1014+
is_multiorient = len(iops) > 1
9811015
echo_times_lst = sorted(echo_times) # also converts to list
9821016
channel_names_lst = sorted(channel_names) # also converts to list
9831017

@@ -1008,6 +1042,11 @@ def save_converted_files(
10081042
bids_meta, this_prefix_basename, channel_names_lst
10091043
)
10101044

1045+
if is_multiorient:
1046+
this_prefix_basename = update_multiorient_name(
1047+
bids_meta, this_prefix_basename
1048+
)
1049+
10111050
# Fallback option:
10121051
# If we have failed to modify this_prefix_basename, because it didn't fall
10131052
# into any of the options above, just add the suffix at the end:

heudiconv/tests/test_convert.py

+13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
bvals_are_zero,
1818
update_complex_name,
1919
update_multiecho_name,
20+
update_multiorient_name,
2021
update_uncombined_name,
2122
)
2223
from heudiconv.utils import load_heuristic
@@ -143,6 +144,18 @@ def test_update_uncombined_name() -> None:
143144
update_uncombined_name(metadata, base_fn, set(channel_names)) # type: ignore[arg-type]
144145

145146

147+
def test_update_multiorient_name() -> None:
148+
"""Unit testing for heudiconv.convert.update_multiorient_name(), which updates
149+
filenames with the acq field if appropriate.
150+
"""
151+
# Standard name update
152+
base_fn = "sub-X_ses-Y_task-Z_run-01_bold"
153+
metadata = {"ImageOrientationPatientDICOM": [0, 1, 0, 0, 0, -1]}
154+
out_fn_true = "sub-X_ses-Y_acq-sagittal_task-Z_run-01_bold"
155+
out_fn_test = update_multiorient_name(metadata, base_fn)
156+
assert out_fn_test == out_fn_true
157+
158+
146159
def test_b0dwi_for_fmap(tmp_path: Path, caplog: pytest.LogCaptureFixture) -> None:
147160
"""Make sure we raise a warning when .bvec and .bval files
148161
are present but the modality is not dwi.

0 commit comments

Comments
 (0)