## Contents

- Processing Parameters
- Load DICOMs
- Checking Rx
- Regridding data
- ======================= Processing TOF ===========================
- GUI for Defining 3D Vessel Mask from TOF
- Getting skeleton.
- Getting endpoints.
- Get the farthest two endpoints.
- Pruning skeleton.
- Compute distance transforms of voxels to the CCA-ICA skeleton.
- Compute typical radius of vessel, then extract CCA/ICA carotids mask.
- Computing distance along skeleton
- Identify CCA and ICA skeletons and masks.
- Assigning every CCA/ICA voxel a distance
- Saving off TOF processing outputs.
- ===================== Processing OSPCMRI =========================
- Retrieve the OSPCMRI data and OSPCMRI mask for further processing.
- Interpolate missing/outlier timepoints
- Smooth waveforms (Optional)
- Retricting mask to significantly positive OSPCMRI values
- Use the mask to extract voxels
- Update mask by correlation filter (Optional)
- Compute distance values in OSPCMRI mask.
- Averaging at axial locations along vessel
- Creating masks for CCA/ICA along axial locations
- Normalize all waveforms between 0 and 1
- Compute Pulse Wave Velocity (PWV)!
- Compute PI and RI at every location
- Generate waves figure
- Writing results to file

    ===============================================================
    =================== CFMRI OSPCMRI Pipeline ====================
         Pipeline Version: 1.0.0 (2025/09/25).
         For any questions, please contact Conan Chen.
    ===============================================================

## Processing Parameters

Showing the processing flags used.

    ==================== Processing parameters ====================
    tofdir                    = '/Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0007_tof_fl3d_tra_p2_Slabs4_PF66'
    ospcmridir                = '/Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P'
    procdir                   = '/Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/'
    locdir                    = '/Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0002_localizer_64ch/'
    flag_WLS                  = 0
    flag_upsample             = 1
    flag_smooth               = 1
    flag_robust               = 1
    flag_reuseTOFmask         = 0
    flag_publishopen          = 1
    flag_publishcode          = 0
    flag_publish              = 1
    flag_padnslices           = 5
    flag_overwrite            = 1
    flag_manualBP             = 0
    flag_makefigs             = 1
    flag_distbinwidthmm       = 2
    flag_debug                = 0
    flag_corrmaskthresh       = 0.8
    flag_corrmask             = 1
    flag_corritermask         = 0
    flag_checkRx              = 1
    flag_censoriter           = 1
    flag_censor               = 1
    ===============================================================

## Load DICOMs

Loading DICOMs and displaying basic subject information.

    dcm2niix -w 1 -f %s_%d -o /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/ /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P
    dcm2niix -w 1 -f %s_%d -o /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/ /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0007_tof_fl3d_tra_p2_Slabs4_PF66

    Processing Subject SubjectID:

    dataset.patientInfo =
            ID: 'SubjectID'
           age: 100
           sex: 'M/F/O'
        height: 1.7526
        weight: 72.5748

    dataset.scanInfo =
        name: 'OSPCMRI_sag_in-plane_FA10_Venc100_left'
        side: 'left'

## Checking Rx

The figure below provides a low-resolution, sagittal view of the prescriptions for the localizer (grayscale), TOF (blue-green-yellow) and OSPCMRI (red-orange-white) scans. For proper positioning, the top of the TOF Rx should be roughly aligned with the bottom of the cerebellum, and the OSPCMRI Rx up-down (superior-inferior) positioning should track closely with the TOF. Significant deviations may indicate improper scan positioning, and potentially mean the OSPCMRI scans do NOT cover the CCA/ICA segment of interest.

    dcm2niix -w 1 -f %s_%d -o /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/ /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0002_localizer_64ch/

    3dresample -overwrite -input 2_localizer_64ch_i00001.nii -orient RAI -overwrite -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_LocSag_lowres.nii -dxyz 21 5 5
    3dwarp -overwrite -deoblique -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_OSPCMRI_dbq.nii 19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii'[0]'
    ++ 3dWarp: AFNI version=AFNI_23.1.00 (Apr  7 2023) [64-bit]
    ++ Authored by: RW Cox
    ** AFNI converts NIFTI_datatype=4 (INT16) in file /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii to FLOAT32
         Warnings of this type will be muted for this session.
         Set AFNI_NIFTI_TYPE_WARN to YES to see them all, NO to see none.
    # mat44 Obliquity Transformation ::
          0.745690      0.662844      0.067706      64.207626
         -0.666044      0.738774      0.102952     -10.895149
          0.018222     -0.121865      0.992379     -11.268112
    ++ Using minimum spacing of 1.000000 mm for new grid spacing
    3dresample -overwrite -rmode Cu -input /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_OSPCMRI_dbq.nii -dxyz 21 5 5 -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_OSPCMRI_dbq_RAI.nii
    3dZeropad -overwrite -I 23 -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_LocSag_lowres_pad2TOF.nii /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_LocSag_lowres.nii
    ++ 3dZeropad: AFNI version=AFNI_23.1.00 (Apr  7 2023) [64-bit]
    ++ output dataset: /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_LocSag_lowres_pad2TOF.nii
    3dresample -overwrite -input 7_tof_fl3d_tra_p2_Slabs4_PF66.nii -master /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_LocSag_lowres_pad2TOF.nii -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_TOF_resampled.nii
    3dwarp -overwrite -deoblique -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_OSPCMRI_dbq.nii 19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii
    ++ 3dWarp: AFNI version=AFNI_23.1.00 (Apr  7 2023) [64-bit]
    ++ Authored by: RW Cox
    ** AFNI converts NIFTI_datatype=4 (INT16) in file /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii to FLOAT32
         Warnings of this type will be muted for this session.
         Set AFNI_NIFTI_TYPE_WARN to YES to see them all, NO to see none.
    # mat44 Obliquity Transformation ::
          0.745690      0.662844      0.067706      64.207626
         -0.666044      0.738774      0.102952     -10.895149
          0.018222     -0.121865      0.992379     -11.268112
    ++ Using minimum spacing of 1.000000 mm for new grid spacing
    3dresample -overwrite -rmode NN -input /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_OSPCMRI_dbq.nii -master /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_LocSag_lowres_pad2TOF.nii -dxyz 1 5 5 -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//CheckRx_OSPCMRI_dbq_resampled.nii

## Regridding data

Zero-pads the OSPCMRI data in the slice direction, i.e. increasing the width of the OSPCMRI Rx slab. Then, warps the TOF data (cardinal) to the zero-padded OSPCMRI grid (oblique), and resampled both TOF and OSPCMRI to a 1mm isotropic resolution. This yields a modified TOF dataset in the same grid/resolution as the OSPCMRI. In subsequent steps, the user (with automated help from the script for some aspects) will act on this modified TOF dataset to define the vessel mask for subsequent OSPCMRI processing.

    sending incremental file list

    sent 104 bytes  received 12 bytes  232.00 bytes/sec
    total size is 3,492,192  speedup is 30,105.10
    sending incremental file list

    sent 86 bytes  received 12 bytes  196.00 bytes/sec
    total size is 8,008,032  speedup is 81,714.61
    ** AFNI converts NIFTI_datatype=4 (INT16) in file /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii to FLOAT32
         Warnings of this type will be muted for this session.
         Set AFNI_NIFTI_TYPE_WARN to YES to see them all, NO to see none.
     [7m*+ WARNING: [0m   If you are performing spatial transformations on an oblique dset,
      such as /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii,
      or viewing/combining it with volumes of differing obliquity,
      you should consider running:
         3dWarp -deoblique
      on this and  other oblique datasets in the same session.
     See 3dWarp -help for details.
    ++ Oblique dataset:/Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii is 42.372952 degrees from plumb.
    ++ 3dinfo: AFNI version=AFNI_23.1.00 (Apr  7 2023) [64-bit]

    Dataset File:    /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph_RAI.nii
    Identifier Code: AFN_3OJ_wmZgAVKXnvKjEcun0A  Creation Date: Tue Sep 23 16:02:19 2025
    Template Space:  ORIG
    Dataset Type:    Echo Planar (-epan)
    Byte Order:      LSB_FIRST {assumed} [this CPU native = LSB_FIRST]
    Storage Mode:    NIFTI
    Storage Space:   6,983,680 (7.0 million) bytes
    Geometry String: "MATRIX(4,0,0,-19.24884,0,1,0,-81.27656,0,0,1,-224.9308):1,124,176"
    Data Axes Tilt:  Plumb
    Data Axes Orientation:
      first  (x) = Right-to-Left
      second (y) = Anterior-to-Posterior
      third  (z) = Inferior-to-Superior   [-orient RAI]
    R-to-L extent:   -19.249 [R] -to-   -19.249 [R] -step-     4.000 mm [  1 voxels]
    A-to-P extent:   -81.277 [A] -to-    41.723 [P] -step-     1.000 mm [124 voxels]
    I-to-S extent:  -224.931 [I] -to-   -49.931 [I] -step-     1.000 mm [176 voxels]
    Number of time steps = 80  Time step = 0.01406s  Origin = 0.00000s
      -- At sub-brick #0 '?' datum type is float:        -4096 to          4088
      -- At sub-brick #1 '?' datum type is float:        -4094 to          4092
      -- At sub-brick #2 '?' datum type is float:        -4096 to          4088
    ** For info on all 80 sub-bricks, use '3dinfo -verb' **

    ----- HISTORY -----
    [username@cfmriconan.ucsd.edu: Tue Sep 23 16:02:19 2025] {AFNI_23.1.00:macos_10.12_local} 3dresample -orient RAI -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph_RAI.nii -input /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii

    Dimension: R-to-L    Thickness: 4 mm
    Dimension: A-to-P    Thickness: 1 mm
    Dimension: I-to-S    Thickness: 1 mm
    3dZeropad -R 5 -L 5 -prefix /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph_RAI_pad.nii /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph_RAI.nii'[0]'++ 3dZeropad: AFNI version=AFNI_23.1.00 (Apr  7 2023) [64-bit]
    ++ output dataset: /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed//19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph_RAI_pad.nii
    ++ 3dWarp: AFNI version=AFNI_23.1.00 (Apr  7 2023) [64-bit]
    ++ Authored by: RW Cox
    ** AFNI converts NIFTI_datatype=4 (INT16) in file /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/19_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_ph.nii to FLOAT32
         Warnings of this type will be muted for this session.
         Set AFNI_NIFTI_TYPE_WARN to YES to see them all, NO to see none.
    # mat44 Obliquity Transformation ::
          0.745690     -0.666044      0.018222     -54.930298
          0.662844      0.738774     -0.121865     -35.883797
          0.067706      0.102952      0.992379       7.956694
    ++ Using minimum spacing of 0.781250 mm for new grid spacing

## ======================= Processing TOF ===========================

The 'hidden' flag also closes figures with hidden handles, such as volshow windows.

## GUI for Defining 3D Vessel Mask from TOF

This section generates a GUI that allows the user to set a TOF intensity threshold to binarize the TOF, and automatically and/or manually refine the binarized mask to produce a 3D binary dataset representing a vessel mask.

## Getting skeleton.

Skeletonizing the 3D vessel mask.

## Getting endpoints.

Detecting the endpoints of the 3D vessel mask.

## Get the farthest two endpoints.

The skeleton connecting the farthest two endpoints is assumed to represent the CCA/ICA segment of interest. Intermediate endpoints are assumed to be the ECA or potentially spurious branches arising from minor imperfections of the binarized TOF data.

## Pruning skeleton.

Prune all minor skeleton voxels/branches until we are left with only the skeleton component that connects the two farthest endpoints (the main CCA/ICA branch). The longest pruned branch is assumed to be the ECA, and this will be considered when automatically identifying the carotids branch point. All other pruned branches are assumed to be spurious branches.

## Compute distance transforms of voxels to the CCA-ICA skeleton.

Compute distance transform to the CCA-ICA skeleton. Also compute the distance transform to non-CCA-ICA skeleton voxels. These distance maps help define which voxels we attribute to the CCA-ICA mask.

## Compute typical radius of vessel, then extract CCA/ICA carotids mask.

Compute the typical radius of the vessel, which helps assign voxels in the carotids branching area to either the CCA/ICA segments of interest, or to the ECA segment that will be pruned.

## Computing distance along skeleton

Starting from the lower endpoint (the CCA), compute the distance along the CCA/ICA sketlon up to the upper endpoint (the ICA).

## Identify CCA and ICA skeletons and masks.

The largest pruned branch is assumed to be the ECA. The point where the ECA connects to the rest of the skeleton is the carotids branchpoint, i.e. where CCA branches into ICA and ECA.

## Assigning every CCA/ICA voxel a distance

Starting from the lower endpoint (the CCA), computing the distance along the CCA/ICA sketlon.

## Saving off TOF processing outputs.

Saving off TOF processing outputs into the dataset.TOFproc field.

## ===================== Processing OSPCMRI =========================

Cleaning up workspace and loading saved outputs from TOF processing.

## Retrieve the OSPCMRI data and OSPCMRI mask for further processing.

Retrieving OSPCMRI data and mask for further processing. The initial OPSCMRI mask is simply the MIP (in the slice-direction) of the TOF-derived CCA-ICA mask! This mask gives a good estimate of where the vessel voxels are located in the OSPCMRI data, and will be refined through subsequent processing steps.

## Interpolate missing/outlier timepoints

Interpolate any missing cardiac phases (e.g. if we expect 80 cardiac phases but the scanner only outputted 78 DICOM images), or non-physiological outlier cardiac phases (which come from dcm2niix trying to do some undisclosed estimation of missing cardiac phases - only seems to do so for certain dcm2niix versions).

    Warning: Ignoring extra legend entries.

## Smooth waveforms (Optional)

Applies a third-order Savitsky-Golay filter of frame-length 17 to smooth the waveforms in the cardiac phase dimension.

## Retricting mask to significantly positive OSPCMRI values

Only keeps OSPCMRI voxels that pass a right-tail Signed-Rank test with a threshold of p < 0.01. Excluded voxels will generally represent noise or venous voxels.

## Use the mask to extract voxels

Use the current OSPCMRI mask to extract OSPCMRI voxel waveforms.

## Update mask by correlation filter (Optional)

Within the OSPCMRI mask resulting from the sign-rank step, further exclude any voxels that are poorly correlated with the mean waveform. This tends to remove any remaining voxels that are noisy and/or exhibit a non-physiological waveform.

## Compute distance values in OSPCMRI mask.

Using the path-length distance information from the 3D (TOF-derived) vessel mask, flatten that distance information into the 2D OSPCMRI plane. This effectively assigns each OSPCMRI voxel a value for distance along the vessel.

## Averaging at axial locations along vessel

Bin OSPCMRI voxels by their along-path distance. This produces voxel waveforms at the newly-averaged axial locations.

## Creating masks for CCA/ICA along axial locations

For each axial location (i.e. location along the vessel), assign it to either the CCA or ICA. This is used for computing PI and RI for the CCA and ICA later.

## Normalize all waveforms between 0 and 1

Normalize all axially-averaged OSPCMRI waveforms to span a range (min-to-max) of 0 to 1. See Figure 1D of OSPCMRI paper.

## Compute Pulse Wave Velocity (PWV)!

Compute Pulse Wave Velocity using Middle UpStroke Area (MUSA), Time-To-Foot (TTF), and Circular Cross-Correlation (CXCORR) methods to estimate the time delays of each waveform relative to the reference waveform. By then considering the distance along the vessel, PWV can be computed.

## Compute PI and RI at every location

Compute PI and RI for each axially-averaged waveform.

## Generate waves figure

Generate a waveforms figure, just for visual quality assurance purposes.

## Writing results to file

Writing results to results.txt, results.json, and results.mat.

    Processing complete!
    Results saved to: /Users/username/Documents/20220706_2DVSASL_Pulsatility/20221209__SubjectFolder/0019_OSPCMRI_sag_in-plane_FA10_Venc100_left_P_processed/results.mat

    results_struct =

      struct with fields:

                patient_ID: {'SubjectID'}
             patient_age_Y: 100
               patient_sex: 'M/F/O'
          patient_height_m: 1.7526
        patient_weight_lbs: 72.5748
                RR_mean_ms: 993
                RR_stdv_ms: 23
              PWV_MUSA_mps: 12.0659
              PWVpval_MUSA: 1.3762e-06
               PWV_TTF_mps: 15.3053
               PWVpval_TTF: 2.2419e-06
            PWV_CXCORR_mps: 5.9050
            PWVpval_CXCORR: 4.9664e-15
                    PI_CCA: 2.3947
                    PI_ICA: 1.2404
                    RI_CCA: 7.4043
                    RI_ICA: 2.2867
                 scan_name: {'OSPCMRI_sag_in-plane_FA10_Venc100_left'}
                 scan_side: {'left'}