Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4f554c3
Add LEAD-DBS/fMRIPrep input options and default LEAD-DBS template/fcs…
ataha24 May 25, 2025
57d7cd9
Enable registration QC workflow when LEAD-DBS or fMRIPrep inputs are …
ataha24 May 25, 2025
91dedf6
simplify and speed up apply.py by removing second-pass prediction ref…
ataha24 May 25, 2025
6ecf972
Add regqc rule with dynamic support for LEAD-DBS and fMRIPrep inputs
ataha24 May 25, 2025
2cb4097
Add interactive registration QC dashboard with MRI viewer and error p…
ataha24 May 25, 2025
cfd5607
fix path relative to github repo
ataha24 May 25, 2025
5d5a489
add github compatible MNI template and fcsv
ataha24 May 25, 2025
886fb39
Update utils.yaml
ataha24 May 26, 2025
873f784
Update config.yaml
ataha24 May 26, 2025
450cdeb
Merge branch 'main' into regqc-clean
Dhananjhay May 27, 2025
5d26eb7
lint code
mackenziesnyder Jun 2, 2025
25a5a7f
lint snakemake files
mackenziesnyder Jun 2, 2025
9817a47
Merge branch 'main' into regqc-clean
Dhananjhay Jun 18, 2025
ed58338
fix get matrix func to return None if fmriprep is triggered
ataha24 Jun 19, 2025
e0370d8
Merge branch 'main' into regqc-clean
Dhananjhay Jun 27, 2025
f1d27bf
separate regqc conda env from utils
Dhananjhay Jun 27, 2025
a39922c
Merge branch 'main' into regqc-clean
Dhananjhay Aug 15, 2025
fb7343e
add missing packages and ants for testing
Dhananjhay Oct 10, 2025
50cb974
add support for fmriprep
Dhananjhay Nov 28, 2025
960e163
patch path to transforms in fmriprep
Dhananjhay Dec 26, 2025
89899a2
integrate templateflow
Dhananjhay Jan 10, 2026
95abdde
add logic
Dhananjhay Jan 11, 2026
7b0cb7e
debug the logic to synchronize download_template rule with regqc feature
Dhananjhay Jan 13, 2026
1b2feda
add conditional logic to work with different templates
Dhananjhay Jan 13, 2026
355f56c
fix ruff linting error
Dhananjhay Jan 16, 2026
651564d
fix snakefmt linting
Dhananjhay Jan 16, 2026
3b5684e
delete unsupported templates and patch the logic to template path
Dhananjhay Jan 16, 2026
0273fd4
fix ruff lint check
Dhananjhay Jan 19, 2026
3d55482
remove snakemake_timestamps from osf storage and the conditional true…
Dhananjhay Jan 19, 2026
9991175
Merge pull request #97 from afids/djay/integrate-templateflow
Dhananjhay Jan 19, 2026
093ab4f
update dag
Jan 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions autoafids/config/snakebids.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ parse_args:
action: "store_true" # Automatically sets to True when flag is used
default: false # Default to False when not used

--LEAD-DBS-DIR:
help: 'Path to a LEAD-DBS derivatives dataset, for folder(s) that contains multiple derivatives datasets (default: %(default)s) '
default: false
required: false
type: str

--FMRIPREP-DIR:
help: 'Path to a fMRIPrep derivatives dataset, for folder(s) that contains multiple derivatives datasets (default: %(default)s) '
default: false
required: false
type: str

--workdir:
help: |
Expand All @@ -166,10 +177,12 @@ parse_args:

# Nifti template
templatet1w: 'resources/tpl-MNI152NLin2009cAsym_res-01_T1w.nii.gz'
templatet1w_lead: 'resources/tpl-MNI152NLin2009bAsym_res-01_T1w.nii.gz'

# AFIDs fcsv template
fcsv: 'resources/dummy.fcsv'
fcsv_mni: 'resources/tpl-MNI152NLin2009cAsym_res-01_desc-groundtruth_afids.fcsv'
fcsv_mni_lead: 'resources/tpl-MNI152NLin2009bAsym_res-01_desc-groundtruth_afids.fcsv'

singularity:
synthstrip: 'docker://freesurfer/synthstrip:1.3'
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Markups fiducial file version = 4.6
# CoordinateSystem = 0
# columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID
vtkMRMLMarkupsFiducialNode_1,-0.204861407692308,2.72288076923077,-4.88105282051282,0,0,0,1,1,1,0,1,AC,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_2,-0.00726026948717949,-25.0450538461538,-2.21068230769231,0,0,0,1,1,1,0,2,PC,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_3,0.025998141025641,-37.691917948718,-11.0111497435897,0,0,0,1,1,1,0,3,infracollicular sulcus,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_4,-0.0892198512820513,-23.1885743589744,-21.5288358974359,0,0,0,1,1,1,0,4,PMJ,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_5,-0.05649251,-13.7676564102564,-10.950028974359,0,0,0,1,1,1,0,5,superior interpeduncular fossa,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_6,13.3113025641026,-25.951058974359,-9.74885435897436,0,0,0,1,1,1,0,6,R superior LMS,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_7,-13.607458974359,-26.4451,-9.7076082051282,0,0,0,1,1,1,0,7,L superior LMS,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_8,10.8321820512821,-30.8104076923077,-21.5949358974359,0,0,0,1,1,1,0,8,R inferior LMS,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_9,-10.9824102564103,-30.8778025641026,-21.4372025641026,0,0,0,1,1,1,0,9,L inferior LMS,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_10,0.0100564897435897,-52.5094615384615,2.14842435897436,0,0,0,1,1,1,0,10,culmen,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_11,-0.0743417574102564,-8.36030051282051,-15.9354820512821,0,0,0,1,1,1,0,11,intermammillary sulcus,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_12,2.02761256410256,-8.15453153846154,-15.0245538461538,0,0,0,1,1,1,0,12,R MB,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_13,-2.19342487179487,-8.21593282051282,-15.0426743589744,0,0,0,1,1,1,0,13,L MB,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_14,0.00940744421052632,-31.5985789473684,0.568596455263158,0,0,0,1,1,1,0,14,pineal gland,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_15,15.1850526315789,5.61940868421053,24.9488552631579,0,0,0,1,1,1,0,15,R LV at AC,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_16,-15.7984342105263,5.47038342105263,25.0905473684211,0,0,0,1,1,1,0,16,L LV at AC,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_17,18.7231289473684,-22.0626210526316,28.0333394736842,0,0,0,1,1,1,0,17,R LV at PC,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_18,-18.4848157894737,-22.2426736842105,28.1745157894737,0,0,0,1,1,1,0,18,L LV at PC,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_19,-0.111086676315789,33.3615236842105,2.12355523157895,0,0,0,1,1,1,0,19,Genu of CC,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_20,0.116840065,-37.6019447368421,6.49650894736842,0,0,0,1,1,1,0,20,Splenium,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_21,34.0034921052632,-4.056905,-27.3505,0,0,0,1,1,1,0,21,R AL temporal horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_22,-34.8327763157895,-6.646575,-25.3468578947368,0,0,0,1,1,1,0,22,L AL temporal horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_23,17.4263131578947,-10.0524047368421,-18.2650921052632,0,0,0,1,1,1,0,23,R superior AM temporal horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_24,-18.1468184210526,-10.9803721052632,-18.3750131578947,0,0,0,1,1,1,0,24,L superior AM temporal horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_25,20.4641447368421,-4.03479921052632,-28.0214973684211,0,0,0,1,1,1,0,25,R inferior AM temporal horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_26,-21.3443842105263,-5.12460973684211,-27.9912052631579,0,0,0,1,1,1,0,26,L inferior AM temporal horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_27,14.6365184210526,-40.7174131578947,4.71004973684211,0,0,0,1,1,1,0,27,R indusium griseum origin,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_28,-14.8907842105263,-43.0901605263158,4.23491921052632,0,0,0,1,1,1,0,28,L indusium griseum origin,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_29,20.8308868421053,-79.2528368421053,4.51120236842105,0,0,0,1,1,1,0,29,R ventral occipital horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_30,-18.9085052631579,-82.82955,3.54751710526316,0,0,0,1,1,1,0,30,L ventral occipital horn,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_31,11.8931421052632,18.5102315789474,-12.3773210526316,0,0,0,1,1,1,0,31,R olfactory sulcal fundus,vtkMRMLScalarVolumeNode1
vtkMRMLMarkupsFiducialNode_32,-13.3650815789474,17.0294973684211,-13.0638105263158,0,0,0,1,1,1,0,32,L olfactory sulcal fundus,vtkMRMLScalarVolumeNode1
14 changes: 14 additions & 0 deletions autoafids/workflow/Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ if config["fidqc"]:

include: "rules/fidqc.smk"

if config["LEAD_DBS_DIR"] or config["FMRIPREP_DIR"]:
print("..... Registration QC Enabled .....")
include: "rules/regqc.smk"

rule all:
input:
Expand All @@ -369,6 +372,17 @@ rule all:
)
if config["fidqc"]
else [],
regqc=inputs[config["modality"]].expand(
bids(
root=root,
datatype="regqc",
desc="reg",
suffix="qc.html",
**inputs[config["modality"]].wildcards
)
)
if config["LEAD_DBS_DIR"] or config["FMRIPREP_DIR"]
else [],
afidspred=inputs[config["modality"]].expand(
bids(
root=root,
Expand Down
2 changes: 1 addition & 1 deletion autoafids/workflow/envs/utils.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
name: utils
channels: [conda-forge, defaults]
dependencies: [python=3.9, nibabel, pandas, matplotlib, joblib]
dependencies: [python=3.9, nibabel, pandas, matplotlib, joblib, plotly, simpleitk, scipy]
2 changes: 1 addition & 1 deletion autoafids/workflow/profiles/default/config.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
use-conda: True
conda-frontend: conda
conda-frontend: conda
129 changes: 129 additions & 0 deletions autoafids/workflow/rules/regqc.smk
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from pathlib import Path
import glob

lead_dbs_dir = config.get("LEAD_DBS_DIR", False)
fmriprep_dir = config.get("FMRIPREP_DIR", False)

def get_warp_path(subject):
if lead_dbs_dir:
trans_dir = (
Path(lead_dbs_dir)
/ f"sub-{subject}"
/ "normalization"
/ "transformations"
)
pattern = f"sub-{subject}*_from-MNI*_to-anchorNative_desc-ants.nii.gz"
matches = list(trans_dir.glob(pattern))
if matches:
return str(matches[0])
return None

elif fmriprep_dir:
trans_dir = (
Path(fmriprep_dir)
/ f"sub-{subject}"
/ "anat"
)
pattern = f"sub-{subject}*from-T1w_to-MNI*_mode-image_xfm.h5"
matches = list(trans_dir.glob(pattern))
if matches:
return str(matches[0])
return None

else:
raise ValueError("No LEAD-DBS or fMRIPrep directory provided for warp.")

def get_optional_matrix_path(subject):
trans_dir = (
Path(lead_dbs_dir)
/ f"sub-{subject}"
/ "coregistration"
/ "transformations"
)
pattern = f"sub-{subject}_desc-precoreg_*T1w.mat"
matches = list(trans_dir.glob(pattern))
if matches:
return str(matches[0])
return []

def get_resampled_im(subject):
if lead_dbs_dir:
pattern = str(
Path(lead_dbs_dir)
/ f"sub-{subject}"
/ "normalization"
/ "anat"
/ f"sub-{subject}_ses-preop_space-*_desc-preproc_acq-*_T1w.nii*"
)
matches = glob.glob(pattern)
if matches:
return matches[0]
else:
raise FileNotFoundError(f"No resampled image found for subject {subject} in LEAD-DBS")

elif fmriprep_dir:
pattern = str(
Path(fmriprep_dir)
/ f"sub-{subject}"
/ "anat"
/ f"sub-{subject}*_space-MNI*_desc-preproc_T1w.nii.gz"
)
matches = glob.glob(pattern)
if matches:
return matches[0]
else:
raise FileNotFoundError(f"No resampled image found for subject {subject} in fMRIPrep")

else:
raise ValueError("No LEAD-DBS or fMRIPrep directory provided for resampled image.")

def get_ref_paths():
if lead_dbs_dir:
refimage = str(Path(workflow.basedir).parent / config["templatet1w_lead"])
refcoordinate = str(Path(workflow.basedir).parent / config["fcsv_mni_lead"])
else:
refimage = str(Path(workflow.basedir).parent / config["templatet1w"])
refcoordinate = str(Path(workflow.basedir).parent / config["fcsv_mni"])
return refimage, refcoordinate

rule regqc:
input:
afidfcsv=bids(
root=root,
datatype="afids-cnn",
desc="afidscnn",
suffix="afids.fcsv",
**inputs[config["modality"]].wildcards
),
im=lambda wildcards: get_resampled_im(wildcards.subject),
warp=lambda wildcards: get_warp_path(wildcards.subject),
optional_matrix=lambda wildcards: get_optional_matrix_path(wildcards.subject),
output:
html=bids(
root=root,
datatype="regqc",
desc="reg",
suffix="qc.html",
**inputs[config["modality"]].wildcards
),
csv=bids(
root=root,
datatype="regqc",
desc="reg",
suffix="qc.csv",
**inputs[config["modality"]].wildcards
),
fcsv=bids(
root=root,
datatype="regqc",
desc="reg",
suffix="afids.fcsv",
**inputs[config["modality"]].wildcards
),
params:
refim=lambda wildcards: get_ref_paths()[0],
refcoord=lambda wildcards: get_ref_paths()[1],
conda:
"../envs/utils.yaml"
script:
"../scripts/regqc.py"
16 changes: 1 addition & 15 deletions autoafids/workflow/scripts/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,21 +377,7 @@ def apply_model(
mni_fid_resampled,
radius,
)
# do it again to improve prediction
fid_pred = np.rint(fid_resampled).astype(int)
distances2 = predict_distances(
radius,
model,
fid_pred,
img_data,
)
fid_resampled2 = process_distances(
distances2,
img_data,
fid_pred,
radius,
)
return fid_voxel2world(fid_resampled2, img.affine)
return fid_voxel2world(fid_resampled, img.affine)


def apply_all(
Expand Down
Loading
Loading