Sgtm ======================================================= .. py:class:: petpal.preproc.symmetric_geometric_transfer_matrix.Sgtm(input_image_path: str, segmentation_image_path: str, fwhm: float | tuple[float, float, float], label_map_option: str | None = None, zeroth_roi: bool = False) Handle sGTM partial volume correction on provided PET images. Initialize running sGTM :param input_image_path: Path to input parametric image on which sGTM will be run. :type input_image_path: str :param segmentation_image_path: Path to segmentation image to which parametric image is aligned which is used to delineate regions for PVC. :type segmentation_image_path: str :param fwhm: Full width at half maximum of the Gaussian blurring kernel for each dimension in mm. If only one number is provided, it is used for all dimensions. :type fwhm: float | tuple[float, float, float] :param label_map_option: Path to segmentation label map table, to be read by :func:`~.read_label_map_tsv`, for segmentation labeling ROIs in the outputs. Defaults to None. :type label_map_option: Optional, str :param zeroth_roi: If False, ignores the zeroth ``0`` label in calculations, often used to exclude background or non-ROI regions. Defaults to False. :type zeroth_roi: bool .. rubric:: Example .. code-block:: python import numpy as np from petpal.preproc.symmetric_geometric_transfer_matrix import Sgtm # Get 3D imaging and set FWHM parameter input_3d_image_path = "sub-001_ses-01_space-mpr_desc-SUV_pet.nii.gz" segmentation_image_path = "sub-001_ses-01_space-mpr_seg.nii.gz" fwhm = (5.,5.,5.) # initiate Sgtm class, run analysis, and save to an output TSV file. sgtm_analysis = Sgtm(input_image_path=input_3d_image_path, segmentation_image_path=segmentation_image_path, fwhm=fwhm, zeroth_roi = False) sgtm_analysis(output_path="sub-001_ses-01_pvc-sGTM_desc-SUV_pet.tsv") # Do the same with a time series 4D image. This results in a TAC for each region in # the segmentation file, that has been partial volume corrected with the sGTM # method. input_4d_image_path = "sub-001_ses-01_space-mpr_pet.nii.gz" sgtm_4d_analysis = Sgtm(input_image_path=input_4d_image_path, segmentation_image_path=segmentation_image_path, fwhm=fwhm, label_map_option=label_map_option, zeroth_roi = False) sgtm_4d_analysis(output_path="/path/to/output/directory/", out_tac_prefix='sub-001_ses-001_desc-sGTM') .. py:method:: run() Determine whether input image is 3D or 4D and run the correct sGTM method. If input image is 3D, implied usage is getting the average sGTM value for each region in the volume. If input image is 4D, implied usage is getting a time series average value for each frame in image within each region. .. py:method:: save(output_path: str, out_tac_prefix: str | None = None, one_tsv_per_region: bool = False) Save sGTM results by writing the resulting array to one or more files. The behavior depends on the input image provided. If input image is 3D, saves the average sGTM value for each region in a TSV with one row per region. If input image is 4D, saves time series average values for each frame within each region. 4D operation saves a single file unless `one_tsv_per_region` is set to True. :param output_path: Path to save sGTM results. For 3D images, this should typically be the full path to a .tsv file. For 4D images, this is the directory where the sGTM TACs will be saved. :type output_path: str :param out_tac_prefix: Prefix of the TAC files. Typically, something like ``'sub-001_ses-001_desc-sGTM'``. Defaults to None. :type out_tac_prefix: Optional, str :param one_tsv_per_region: If True, saves one tsv file for each unique region, as opposed to one file containing all TACs if False. Default False. :type one_tsv_per_region: bool .. py:method:: __call__(output_path: str, out_tac_prefix: str | None = None) Run sGTM and save results. Applies :meth:`run_sgtm` for 3D images and :meth:`run_sgtm_4d` for 4D images. :param output_path: Path to save sGTM results. For 3D images, this is a .tsv file. For 4D images, this is a directory. :type output_path: str .. py:property:: sigma :type: list[float] Blurring kernal sigma for sGTM based on the input FWHM. :returns: *sigma (list[float])* -- List of sigma blurring radii for Gaussian kernel. Each sigma value corresponds to an axis: x, y, and z. Values are determined based on the FWHM input to the object and the voxel dimension in the input image. .. py:property:: unique_labels :type: tuple[numpy.ndarray, list[str]] Get unique ROI indices and corresponding labels. If a segmentation label map was provided at instantiation, the table will be used to determine the unique ROI indices and labels. If a segmentation label map was not provided at instantiation, the segmentation image will be used to determine the unique ROI indices, and labels will be inferred in numerical order of indices. :returns: *unique_segmentation_labels (tuple[np.ndarray, list[str]])* -- Tuple containing the unique ROI indices (mapping) and inferred segmentation labels. .. py:method:: get_omega_matrix(voxel_by_roi_matrix: numpy.ndarray) -> numpy.ndarray :staticmethod: Get the Omega matrix for sGTM. See :meth:`run_sgtm` for details. :param voxel_by_roi_matrix: The ``V`` matrix described in :meth:`run_sgtm` obtained by applying a Gaussian filter to each ROI. :type voxel_by_roi_matrix: np.ndarray :returns: *omega (np.ndarray)* -- ``\Omega`` matrix as described in :meth:`run_sgtm`. .. py:method:: solve_sgtm(omega: numpy.ndarray, voxel_by_roi_matrix: numpy.ndarray, input_numpy: numpy.ndarray) -> tuple :staticmethod: Set up and solve linear equation for sGTM. :param omega: The Omega matrix for sGTM. See :meth:`run_sgtm` for details. :type omega: np.ndarray :param voxel_by_roi_matrix: The ``V`` matrix for sGTM. See :meth:`run_sgtm` for more details. :type voxel_by_roi_matrix: np.ndarray :param input_numpy: The input 3D PET image converted to numpy array. :type input_numpy: np.ndarray .. py:method:: get_voxel_by_roi_matrix(unique_labels: numpy.ndarray, segmentation_arr: numpy.ndarray, sigma: list[float]) -> numpy.ndarray :staticmethod: Get the ``V`` matrix for sGTM by blurring each ROI and converting into vectors. See :meth:`run_sgtm` for more details. :param unique_labels: Array containing unique values in the discrete segmentation image. :type unique_labels: np.ndarray :param segmentation_arr: Array containing discrete segmentation image converted to a numpy array. :type segmentation_arr: np.ndarray :param sigma: List of sigma blurring radii on x, y, z axes respectively. :type sigma: list[float] :returns: *voxel_by_roi_matrix (np.ndarray)* -- The blurred ROI matrix for sGTM. .. py:method:: run_sgtm_3d() -> tuple[numpy.ndarray, numpy.ndarray, float] Apply Symmetric Geometric Transfer Matrix (SGTM) method for Partial Volume Correction (PVC) to PET images based on ROI labels. This method involves using a matrix-based approach to adjust the PET signal intensities for the effects of partial volume averaging. :returns: *Tuple[np.ndarray, np.ndarray, float]* -- - np.ndarray: Array of unique ROI labels. - np.ndarray: Corrected PET values after applying PVC. - float: Condition number of the omega matrix, indicating the numerical stability of the inversion. :raises AssertionError: If `self.input_image` and `self.segmentation_image` do not have the same dimensions. .. rubric:: Notes The SGTM method uses the matrix :math:`\Omega` (omega), defined as: .. math:: \Omega = V^T V where :math:`V` is the matrix obtained by applying Gaussian filtering to each ROI, converting each ROI into a vector. The element :math:`\Omega_{ij}` of the matrix :math:`\Omega` is the dot product of vectors corresponding to the i-th and j-th ROIs, representing the spatial overlap between these ROIs after blurring. The vector :math:`t` is calculated as: .. math:: t = V^T p where :math:`p` is the vectorized PET image. The corrected values, :math:`t_{corrected}`, are then obtained by solving the linear system: .. math:: \Omega t_{corrected} = t This provides the estimated activity concentrations corrected for partial volume effects in each ROI. .. py:method:: run_sgtm_4d() -> numpy.ndarray Calculated partial volume corrected TACs on a 4D image by running sGTM on each frame in the 4D image. This results in a time series of average activity for each region specified in the segmentation image. This can then be used for kinetic modeling. :returns: *frame_results (np.ndarray)* -- Average activity in each region calculated with sGTM for each frame. .. py:method:: save_results_3d(sgtm_result: tuple, out_tsv_path: str) Saves the result of an sGTM calculation. Result is saved as one value for each of the unique regions found in the segmentation image. :param sgtm_result: Output of :meth:`run_sgtm_3d` :type sgtm_result: tuple :param out_tsv_path: File path to which results are saved. :type out_tsv_path: str .. py:method:: save_results_4d_tacs(sgtm_result: numpy.ndarray, out_tac_dir: str, out_tac_prefix: str) Saves the result of an sGTM calculation on a 4D PET series. Result is saved as a TAC for each of the unique regions found in the segmentation image. :param sgtm_result: Array of results from :meth:`run_sgtm_4d` :type sgtm_result: np.ndarray :param out_tac_dir: Path to folder where regional TACs will be saved. :type out_tac_dir: str :param out_tac_prefix: Prefix of the TAC files. :type out_tac_prefix: str .. py:method:: save_results_4d_multitacs(sgtm_result: numpy.ndarray, out_tac_dir: str, out_tac_prefix: str) Like :meth:`save_results_4d_tacs`, but saves all TACs to a single file. :param sgtm_result: Array of results from :meth:`run_sgtm_4d` :type sgtm_result: np.ndarray :param out_tac_dir: Path to folder where regional TACs will be saved. :type out_tac_dir: str :param out_tac_prefix: Prefix of the TAC files. :type out_tac_prefix: str