diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/data_flow/__init__.py b/src/data_flow/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/data_flow/dicom_operations.py b/src/data_flow/dicom_operations.py
new file mode 100755
index 0000000000000000000000000000000000000000..e373a8bf580ea0c25b3e6b312797fe465bfc50d3
--- /dev/null
+++ b/src/data_flow/dicom_operations.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""Module provides functionality to deal with DICOM files."""
+
+import datetime as dt
+from pathlib import Path
+from typing import Tuple
+
+import pydicom
+
+
+def read_subjects_age_gender(dcm_path: Path) -> Tuple[int, str]:
+    """
+    Read age and gender for a subject from a DCM file.
+
+    Parameters
+    ----------
+    dcm_path : Path
+        Path to a DCM file.
+
+    Returns
+    -------
+    Tuple[int, str]
+        (age, gender).
+
+    """
+    ds = pydicom.dcmread(dcm_path)
+
+    try:
+        age = int(ds["PatientAge"].value)
+    except AssertionError:
+        birth_date = ds["PatientBirthDate"].value
+        birth_date = dt.date(year=birth_date[:4],
+                             month=birth_date[4:6],
+                             day=birth_date[6:8])
+        acq_date = ds["AcquisitionDate"].value
+        acq_date = dt.date(year=acq_date[:4],
+                           month=acq_date[4:6],
+                           day=acq_date[6:8])
+        age = acq_date.year - birth_date.year
+        if acq_date.month < birth_date.month:
+            age -= 1
+        elif (
+                acq_date.month == birth_date.month
+        ) and (acq_date.day < birth_date.day):
+            age -= 1
+
+    gender = ds["PatientSex"].value
+
+    return age, gender
diff --git a/src/data_flow/itk_operations.py b/src/data_flow/itk_operations.py
new file mode 100755
index 0000000000000000000000000000000000000000..70752c0f24b13df301eccf30d8f5d1a8b467ef47
--- /dev/null
+++ b/src/data_flow/itk_operations.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This module provides functionality for handling ITK images.
+
+Mainly, there are conversions to and from them.
+"""
+
+from typing import List, Tuple
+
+import itk
+import numpy as np
+
+ITK_COORD_LPI: np.ndarray = np.array([-1, -1, 1], dtype=float)
+
+
+def convert_affine_to_itk_params(
+        affine: np.ndarray,
+) -> Tuple[List, List, itk.Matrix]:
+    """
+    Get itk conform information from affine matrix.
+
+    Parameters
+    ----------
+    affine : np.ndarray
+        Affine matrix.
+
+    Raises
+    ------
+    ValueError
+        If affine spatial dimensionality is not 3.
+
+    Returns
+    -------
+    Tuple[List, List, itk.Matrix]
+        Affine space with itk conform values: spacing, origin, direction.
+
+    """
+    if affine.shape[0] != 4:
+        raise ValueError(
+            f'Spatial dimensionality is not 3, but {affine.shape[0] - 1}.'
+        )
+
+    # Extract affine informations
+    affine_direction = affine[:3, :3]
+    affine_spacing: np.ndarray = np.linalg.norm(affine_direction, axis=0)
+    affine_origin = affine[:3, 3]
+
+    # Convert affine informations
+    affine_origin = affine_origin * ITK_COORD_LPI
+    affine_direction = affine_direction / affine_spacing
+    affine_direction = (affine_direction.T * ITK_COORD_LPI).T
+
+    # Return itk conform values
+    return (
+        affine_spacing.tolist(),
+        affine_origin.tolist(),
+        itk.matrix_from_array(affine_direction),
+    )
+
+
+def convert_itk_params_to_affine(itk_img: itk.Image) -> np.ndarray:
+    """
+    Extract an affine matrix from itk image.
+
+    Parameters
+    ----------
+    itk_img : itk.Image
+        ITK image.
+
+    Raises
+    ------
+    ValueError
+        If image dimensionality does not match.
+
+    Returns
+    -------
+    affine : np.ndarray
+        Affine matrix.
+
+    """
+    if itk_img.GetImageDimension() != 3:
+        raise ValueError(
+            f'Image dimensionality isnot 3, but {itk_img.GetImageDimension()}.'
+        )
+
+    # Extract image information
+    affine_origin = itk_img.GetOrigin()
+    affine_spacing = itk_img.GetSpacing()
+    affine_direction = itk.array_from_matrix(itk_img.GetDirection())
+
+    # Convert affine information
+    affine_origin = affine_origin * ITK_COORD_LPI
+    affine_direction = affine_direction * affine_spacing
+    affine_direction = (affine_direction.T * ITK_COORD_LPI).T
+
+    # Conclude affine information
+    affine = np.eye(4, dtype=float)
+    affine[:3, :3] = affine_direction
+    affine[:3, 3] = affine_origin
+
+    return affine
+
+
+def convert_nifti_array_to_itk(
+        img: np.ndarray,
+        affine: np.ndarray,
+        voxel_type: itk.itkCType = itk.F,
+) -> itk.Image:
+    """
+    Convert a physical 3D-image to an ITK Image.
+
+    Parameters
+    ----------
+    img : np.ndarray
+        Input image effectivly in F ordering.
+    affine : np.ndarray
+        Affine matrix defining the physical cartesian space of image grid.
+    voxel_type : itk.itkCType, optional
+        Data type of voxels. The default is itk.F.
+
+    Raises
+    ------
+    ValueError
+        If image dimensionality is not 3.
+        If affine spatial dimensionality is not 3.
+
+    Returns
+    -------
+    itk_img :  itk.Image
+        Converted ITK image.
+
+    """
+    if len(img.shape) != 3:
+        raise ValueError(
+            f'Image dimensionality is not 3, but {len(img.shape)}.')
+
+    if img.flags['C_CONTIGUOUS']:
+        # Is set to F-Odering so that shapes of np and ITK image match.
+        # Note, that NIfTI1 images are effectivly in F-Ordering.
+        img = np.asfortranarray(img)
+
+    affine_spacing, affine_origin, affine_direction = \
+        convert_affine_to_itk_params(affine=affine)
+
+    # Convert to ITK, data is copied
+    itk_img = itk.image_from_array(img)
+    itk_img = itk_img.astype(voxel_type)
+
+    # Set image informations
+    itk_img.SetOrigin(affine_origin)
+    itk_img.SetSpacing(affine_spacing)
+    itk_img.SetDirection(affine_direction)
+
+    return itk_img
+
+
+def convert_itk_img_to_nifti_array(
+        itk_img: itk.Image,
+        dtype: np.dtype = float,
+) -> Tuple[np.ndarray, np.ndarray]:
+    """
+    Convert an ITK image to a Numpy array with a defined physical space.
+
+    Parameters
+    ----------
+    itk_img : itk.Image
+        Image in ITK format.
+    dtype : np.dtype, optional
+        Voxel dtype. The default is float.
+
+    Returns
+    -------
+    img : TYPE
+        Image arrage in F-ordering.
+    affine : TYPE
+        Corresponding affine matrix.
+
+    """
+    affine = convert_itk_params_to_affine(itk_img)
+
+    # Convert to array, data is copied.
+    # This will always be a C ordered array.
+    # Has to be transposed to match NIfTI1 convention of F-Ordering.
+    img = itk.array_from_image(itk_img).T
+    img = img.astype(dtype)
+
+    return img, affine
diff --git a/src/data_flow/itk_transform_operations.py b/src/data_flow/itk_transform_operations.py
new file mode 100644
index 0000000000000000000000000000000000000000..b89eb4cf8954e7530274dfc021b9093ec3613c30
--- /dev/null
+++ b/src/data_flow/itk_transform_operations.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Dec 19 11:44:28 2024
+
+@author: jsteiglechner
+"""
+
+from typing import Tuple
+
+import itk
+import numpy as np
+
+
+def extract_elastix_parameters(
+        transform_parameters: itk.ParameterObject,
+) -> Tuple[np.ndarray, np.ndarray]:
+    """
+    Extract parameters of elastix object to affine parameters.
+
+    Parameters
+    ----------
+    transform_parameters : itk.ParameterObject
+        Parameters of operation.
+
+    Returns
+    -------
+    center : TYPE
+        center of rotation point.
+    elx_parameters : TYPE
+        transform parameters.
+
+    """
+    parameter_map = transform_parameters.GetParameterMap(0)
+
+    center = np.array(
+        [float(p) for p in parameter_map['CenterOfRotationPoint']]
+    )
+    elx_parameters = np.array(
+        [float(p) for p in parameter_map['TransformParameters']]
+    )
+
+    return center, elx_parameters
+
+
+def get_transformation_matrix(
+        itk_transform: itk.Transform,
+) -> np.ndarray:
+    """
+    Extract relevant a linear itk transform to generate the affine matrix.
+
+    Parameters
+    ----------
+    itk_transform : itk.Transform
+        Linear transform.
+
+    Returns
+    -------
+    transformation_matrix : TYPE
+        Affine transformation matrix.
+
+    """
+    affine_direction = itk.array_from_matrix(itk_transform.GetMatrix())
+    affine_origin = np.asarray(itk_transform.GetTranslation())
+
+    # Conclude affine information
+    transformation_matrix = np.eye(4, dtype=float)
+    transformation_matrix[:3, :3] = affine_direction
+    transformation_matrix[:3, 3] = affine_origin
+
+    return transformation_matrix
+
+
+def build_euler_transformation(
+        center: np.ndarray,
+        transform: np.ndarray,
+) -> itk.Euler3DTransform:
+    """
+    Build an Euler transformation from elastix parameters.
+
+    Parameters
+    ----------
+    center : np.ndarray
+        Center of rotation point in shape (dim, ).
+    transform : np.ndarray
+        Transform parameters in shape (dim * (dim+1), ).
+
+    Returns
+    -------
+    euler_transform : TYPE
+        Applicable Euler transform.
+
+    """
+    euler_transform = itk.Euler3DTransform[itk.D].New()
+
+    fixed_parameters = itk.OptimizerParameters[itk.D](len(center))
+    for i, p in enumerate(center):
+        fixed_parameters[i] = p
+    euler_transform.SetFixedParameters(fixed_parameters)
+
+    itk_parameters = itk.OptimizerParameters[itk.D](len(transform))
+    for i, p in enumerate(transform):
+        itk_parameters[i] = p
+    euler_transform.SetParameters(itk_parameters)
+
+    return euler_transform
+
+
+def build_affine_transformation(
+        center: np.ndarray,
+        transform: np.ndarray,
+) -> itk.AffineTransform:
+    """
+    Build an Affine transformation from elastix parameters.
+
+    Parameters
+    ----------
+    center : np.ndarray
+        Center of rotation point in shape (dim, ).
+    transform : np.ndarray
+        Transform parameters in shape (dim * (dim+1), ).
+
+    Returns
+    -------
+    affine_transform : TYPE
+        Applicable affine transform.
+
+    """
+    affine_transform = itk.AffineTransform[itk.D, len(center)].New()
+
+    fixed_parameters = itk.OptimizerParameters[itk.D](len(center))
+    for i, p in enumerate(center):
+        fixed_parameters[i] = p
+    affine_transform.SetFixedParameters(fixed_parameters)
+
+    itk_parameters = itk.OptimizerParameters[itk.D](len(transform))
+    for i, p in enumerate(transform):
+        itk_parameters[i] = p
+    affine_transform.SetParameters(itk_parameters)
+
+    return affine_transform
diff --git a/src/data_flow/nifti_operations.py b/src/data_flow/nifti_operations.py
new file mode 100644
index 0000000000000000000000000000000000000000..066f969a777843f420a63d0781f4cc48a9f0c1ec
--- /dev/null
+++ b/src/data_flow/nifti_operations.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+This module provides functionality for handling NIfTI images with nibabel.
+
+Created on Fri Aug  4 14:19:10 2023
+
+@author: jsteiglechner
+"""
+
+from pathlib import Path
+from typing import Tuple, Union
+
+import nibabel as nib
+import numpy as np
+
+
+def read_nii(filepath: Union[str, Path]) -> Tuple[np.ndarray, np.ndarray]:
+    """
+    Read brain MRI and corresponding affine from .nii file.
+
+    Note that nibabel generates a fortran ordered array.
+
+    Parameters
+    ----------
+    filepath : Union[str, Path]
+        Path to MRI.
+
+    Returns
+    -------
+    image : TYPE
+        Image data.
+    affine_matrix : TYPE
+        Corresponsing affine matrix.
+
+    """
+    nifti = nib.load(filepath)
+    image = nifti.dataobj[:]
+    affine_matrix = nifti.affine
+
+    return image, affine_matrix
+
+
+def save_nii(
+        image: np.ndarray,
+        affine_matrix: np.ndarray,
+        filepath: Union[str, Path],
+        dtype: np.dtype = float,
+) -> None:
+    """
+    Save brain MRI with affine matrix in NIfTI file format.
+
+    Parameters
+    ----------
+    image : np.ndarray
+        Image data.
+    affine_matrix : np.ndarray
+        Corresponding affine matrix.
+    filepath : Union[str, Path]
+        Path where MRI should be saved.
+    dtype : np.dtype, optional
+        The type of the saved array. The default is float.
+
+    Returns
+    -------
+    None
+        DESCRIPTION.
+
+    """
+    nifti = nib.Nifti1Image(image, affine_matrix, dtype=dtype)
+    nib.save(nifti, filepath)
+
+
+def get_datatype(image: np.ndarray) -> np.dtype:
+    """
+    Get datatype of image data.
+
+    Parameters
+    ----------
+    image : np.ndarray
+        NIfTI image dataobj.
+
+    Returns
+    -------
+    datatype : np.dtype
+        numpy datatype.
+
+    """
+    if np.all(np.equal(np.mod(image, 1), 0)):
+        if np.min(image) >= 0:
+            if np.max(image) <= (2**8 - 1):
+                datatype = np.uint8
+            elif np.max(image) <= (2**16 - 1):
+                datatype = np.uint16
+            else:
+                datatype = np.uint32
+        elif (np.min(image) > -2**15) and (np.max(image) < 2**15):
+            datatype = np.int16
+        else:
+            datatype = np.int32
+    else:
+        datatype = np.dtype('float')
+
+    return datatype
+
+
+def convert_to_original_datatype(
+        image: np.ndarray,
+        datatype: np.dtype,
+) -> np.ndarray:
+    """
+    Convert an image to a certain original datatype.
+
+    Parameters
+    ----------
+    image : np.ndarray
+        Image dataobject.
+    datatype : np.dtye
+        original datatype.
+
+    Returns
+    -------
+    image : TYPE
+        Converted image.
+
+    """
+    if datatype == np.dtype('float'):
+        image = image.astype(float)
+    elif datatype == np.uint8:
+        image = nib.casting.float_to_int(image, 'uint8')
+    elif datatype == np.uint16:
+        image = nib.casting.float_to_int(image, 'uint16')
+    elif datatype == np.uint32:
+        image = nib.casting.float_to_int(image, 'uint32')
+    elif datatype == np.int16:
+        image = nib.casting.float_to_int(image, 'int16')
+    else:
+        image = nib.casting.float_to_int(image, 'int32')
+
+    return image