Hi everyone,
I have happily integrated a custom function of mine in a nipype workflow for the first time. Although generally speaking it works fine, in the sense that the input of the previous node get correctly fed to the function and the output of the function get correctly fed to the following node, I am left wondering about what i should do if I wanted to collect the output of my custom function using a datasink.
Below the code that I have up until now:
from nipype.interfaces.dcm2nii import Dcm2niix
from nipype.interfaces.spm.preprocess import Normalize
from nipype.pipeline import Node
from nipype.pipeline import Workflow
from nipype.interfaces.io import DataSink
from nipype.interfaces.utility import Function
from glob import glob
from os import chdir
def center_volumes(to_be_centered_file, out_files = None):
"""
This function center the volume(s) given as input by setting
the offset of the volume so that the center is in the middle of the box.
If no out_files name is given than the "centered_" will be added to the
original name.
:in_files: name of the volume as a string
:out_files (optional): the name of the centered volumes, default
to None
:return: centered image as a nifti file
"""
from nipy import load_image
import nibabel as nib
import os
import numpy as np
img_name = os.path.basename(to_be_centered_file)
img = load_image(to_be_centered_file)
img_centered_header = img.metadata["header"]
img_dim = img_centered_header["dim"][1:4]
img_pixdim = img_centered_header["pixdim"][1:4]
img_centered_header["qoffset_z"] = (img_dim[2]* img_pixdim[2]*
np.sign(img.metadata["header"]["srow_z"][2])*-1)/2
img_centered_header["srow_z"][3] = img_centered_header["qoffset_z"]
img_centered_header["qoffset_y"] = (img_dim[1]* img_pixdim[1]*
np.sign(img.metadata["header"]["srow_y"][1])*-1)/2
img_centered_header["srow_y"][3] = img_centered_header["qoffset_y"]
img_centered_header["qoffset_x"] = (img_dim[0]* img_pixdim[0]*
np.sign(img.metadata["header"]["srow_x"][0])*-1)/2
img_centered_header["srow_x"][3] = img_centered_header["qoffset_x"]
img_original_affine = img.affine
img_centered_affine = img_original_affine[~(img_original_affine==0).all(0)]
img_centered_affine = img_centered_affine[:,~(img_centered_affine==0).all(0)]
img_centered_affine[[0,1,2],3] = np.array([img_centered_header["qoffset_x"],
img_centered_header["qoffset_y"],
img_centered_header["qoffset_z"]])
img_centered = nib.Nifti1Image(img.get_data(), img_centered_affine, header = img_centered_header)
if out_files is None:
centered_filename = "centered_{}".format(img_name)
img_centered.to_filename(centered_filename)
else:
img_centered.to_filename(out_files)
return(os.path.abspath(centered_filename))
dcm2nii = Node(Dcm2niix(compress = "n"), "dcm2nii")
norm = Node(Normalize(template = "/mnt/mydir/TEMPLATE_FDGPET_100.nii"), "norm")
func = Node(Function(input_names=["to_be_centered_file"],
output_names=["centered_filename"],
function=center_volumes), "func")
dsk = Node(DataSink(base_directory="/mnt/mydir/", container="spm_preproc"), "dsk")
app_spm = Workflow(name = "app_spm")
app_spm.base_dir = "/mnt/mydir/"
app_spm.connect([
(dcm2nii, func, [("converted_files", "to_be_centered_file")]),
(func, norm, [("centered_filename", "source")]),
(norm, dsk, [("normalized_source", "norm")]),
])
chdir("/mnt/mydir/")
ss = glob("*")[0:70]
for s in ss:
app_spm.inputs.dcm2nii.source_dir = "/mnt/mydir/" + s
app_spm.run()
My point is that I do not know which output of my custom function use in the connection with datasink, since in this case the output I am interested in is not something that the function return, but a side effect of the function.
Any suggestion or tip will be greatly appreciated