Skip to content

Commit

Permalink
moved orientation check and reorient if necessary to the wf
Browse files Browse the repository at this point in the history
  • Loading branch information
birajstha committed Sep 17, 2024
1 parent 10eb1d6 commit 829928f
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 138 deletions.
102 changes: 32 additions & 70 deletions CPAC/pipeline/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from CPAC.pipeline.check_outputs import ExpectedOutputs
from CPAC.pipeline.nodeblock import NodeBlockFunction
from CPAC.pipeline.utils import (
check_all_orientations,
check_orientation,
MOVEMENT_FILTER_KEYS,
name_fork,
source_set,
Expand Down Expand Up @@ -68,7 +68,6 @@
read_json,
write_output_json,
)
from nibabel.orientations import OrientationError


class ResourcePool:
Expand Down Expand Up @@ -2409,7 +2408,7 @@ def strip_template(data_label, dir_path, filename):
return data_label, json


def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):
def ingress_pipeconfig_paths(wf, cfg, rpool, unique_id, creds_path=None):
# ingress config file paths
# TODO: may want to change the resource keys for each to include one level up in the YAML as well

Expand All @@ -2418,7 +2417,6 @@ def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):

template_csv = p.resource_filename("CPAC", "resources/cpac_templates.csv")
template_df = pd.read_csv(template_csv, keep_default_na=False)
templates = []
desired_orientation = cfg.pipeline_setup["desired_orientation"]

for row in template_df.itertuples():
Expand Down Expand Up @@ -2489,19 +2487,9 @@ def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):
resampled_template.inputs.template_name = key
resampled_template.inputs.tag = tag

# the set_data below is set up a little differently, because we are
# injecting and also over-writing already-existing entries
# other alternative would have been to ingress into the
# resampled_template node from the already existing entries, but we
# didn't do that here
rpool.set_data(
key,
resampled_template,
"resampled_template",
json_info,
"",
"template_resample",
) # pipe_idx (after the blank json {}) should be the previous strat that you want deleted! because you're not connecting this the regular way, you have to do it manually
node = resampled_template
output = "resampled_template"
node_name = f"{key}_resampled_template"

elif val:
config_ingress = create_general_datasource(f"gather_{key}")
Expand All @@ -2511,27 +2499,31 @@ def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):
creds_path=creds_path,
dl_dir=cfg.pipeline_setup["working_directory"]["path"],
)
rpool.set_data(
key,
config_ingress,
"outputspec.data",
json_info,
"",
f"{key}_config_ingress",
)
# check if val is a nifti file .nii.gz
if val.endswith(".nii.gz"):
templates.append([key, val])

table = check_all_orientations(templates, desired_orientation, reorient=True)
df = pd.DataFrame(table, columns=["Resource", "Path", "Orientation"])

# check if any of the values in Orientation column are not RPI
other_orientation = df[df["Orientation"] != desired_orientation]
if not other_orientation.empty:
msg = f"The following templates are not in RPI orientation: {other_orientation}"
OrientationError(msg)

node = config_ingress
output = "outputspec.data"
node_name = f"{key}_config_ingress"

# check if the output is in desired orientation, if not reorient it
check_orient = pe.Node(
Function(
input_names=["input_file", "desired_orientation", "reorient"],
output_names=["orientation"],
function=check_orientation,
),
name=f"check_orientation_{key}",
)
wf.connect(node, output, check_orient, "input_file")
check_orient.inputs.desired_orientation = desired_orientation
check_orient.inputs.reorient = True

rpool.set_data(
key,
check_orient,
"output_file",
json_info,
"",
f"check_orient-{node_name}-{key}",
)
# templates, resampling from config
"""
template_keys = [
Expand Down Expand Up @@ -2617,7 +2609,7 @@ def _set_nested(attr, keys):
)
cfg.set_nested(cfg, key, node)
"""
return rpool
return wf, rpool


def initiate_rpool(wf, cfg, data_paths=None, part_id=None):
Expand Down Expand Up @@ -2661,38 +2653,8 @@ def initiate_rpool(wf, cfg, data_paths=None, part_id=None):

rpool = ResourcePool(name=unique_id, cfg=cfg)

desired_orientation = cfg.pipeline_setup["desired_orientation"]

if data_paths:
# check all data_paths and convert it to the desired_orientations
# Convert all anat to desired_orientation
if "anat" in data_paths:
anat = []
for key in data_paths["anat"]:
anat.append([key, data_paths["anat"][key]])
if anat:
try:
orientation = check_all_orientations(
anat, desired_orientation, reorient=True
)
except OrientationError as e:
raise e("Anatomical data is not in the desired orientation")

# Convert all func to desired_orientation
if "func" in data_paths:
func = []
for key in data_paths["func"]:
func.append([key, data_paths["func"][key]["scan"]])
if func:
try:
orientation = check_all_orientations(
func, desired_orientation, reorient=True
)
except:
raise OrientationError(
"Functional data is not in the desired orientation"
)

# ingress outdir
try:
if (
Expand All @@ -2719,7 +2681,7 @@ def initiate_rpool(wf, cfg, data_paths=None, part_id=None):
)

# grab any file paths from the pipeline config YAML
rpool = ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path)
wf, rpool = ingress_pipeconfig_paths(wf, cfg, rpool, unique_id, creds_path)

# output files with 4 different scans

Expand Down
108 changes: 40 additions & 68 deletions CPAC/pipeline/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,24 @@

from itertools import chain

from nipype import Function, Node

from CPAC.func_preproc.func_motion import motion_estimate_filter
from CPAC.utils.bids_utils import insert_entity
from CPAC.utils.monitoring import IFLOGGER

MOVEMENT_FILTER_KEYS = motion_estimate_filter.outputs


def find_orientation(input_file):
"""Find the orientation of the input file.
def check_orientation(input_file, desired_orientation, reorient=False):
"""Find the orientation of the input file and reorient it if necessary.
Parameters
----------
input_file : str
Input file path
desired_orientation : str
Desired orientation of the input file
reorient : bool
Reorient the input file to the desired orientation
Returns
-------
Expand All @@ -43,11 +46,16 @@ def find_orientation(input_file):

cmd_3dinfo = ["3dinfo", "-orient", input_file]

return (
orientation = (
subprocess.run(cmd_3dinfo, capture_output=True, text=True, check=False)
.stdout.strip()
.upper()
)
if orientation != desired_orientation and reorient:
output_file = reorient_image(input_file, desired_orientation)
else:
output_file = input_file
return output_file


def reorient_image(input_file, orientation):
Expand All @@ -60,73 +68,37 @@ def reorient_image(input_file, orientation):
orientation : str
Desired orientation of the input image
"""
import os
import subprocess

output_file = os.path.join(
os.path.dirname(input_file),
f"reoriented_{os.path.basename(input_file)}",
)
cmd_3drefit = ["3drefit", "-deoblique", input_file]
cmd_3dresample = [
"3dresample",
"-orient",
orientation,
"-prefix",
output_file,
"-inset",
input_file,
]
cmd_mv = ["mv", output_file, input_file]
print(f"""+++
Reorienting : {input_file}
to : {orientation}
+++""")
subprocess.run(cmd_3drefit, check=True)
subprocess.run(cmd_3dresample, check=True)
print(f"""+++Replacing {input_file} with reoriented image
""")
subprocess.run(cmd_mv, check=True)
return


def check_all_orientations(
input_images: list, desired_orientation: str = "RPI", reorient=True
):
"""Check the orientation of all input images.
Parameters
----------
input_images : list
List of input images
desired_orientation : str
Desired orientation of the input images
Returns
-------
orientations : list
List of orientations of the input images
output_file : str
Reoriented image file path
"""
desired_orientation = desired_orientation.upper()
orientations = []
find_orient = Node(
Function(
input_names=["input_file"],
output_names=["orientation"],
function=find_orientation,
),
name="find_orient",
)
try:
import os
import subprocess

output_file = os.path.join(
os.path.dirname(input_file),
f"reoriented_{os.path.basename(input_file)}",
)
cmd_3drefit = ["3drefit", "-deoblique", input_file]
cmd_3dresample = [
"3dresample",
"-orient",
orientation,
"-prefix",
output_file,
"-inset",
input_file,
]

for key, image in input_images:
find_orient.inputs.input_file = image
orientation = find_orient.run().outputs.orientation
if reorient and orientation != desired_orientation:
reorient_image(image, desired_orientation)
orientations.append([key, image, orientation])
return orientations
IFLOGGER.info(f"""+++\nReorienting : {input_file}\nto : {orientation}\n+++""")
subprocess.run(cmd_3drefit, check=True)
subprocess.run(cmd_3dresample, check=True)
return output_file
except Exception as e:
IFLOGGER.error(f"Reorienting failed for {input_file} with error: {e}")
return input_file


def name_fork(resource_idx, cfg, json_info, out_dct):
Expand Down

0 comments on commit 829928f

Please sign in to comment.