Skip to content

Commit 4a86226

Browse files
adding disambiguation on morphologist aquisition for snapshot generation
1 parent 5ffd7c0 commit 4a86226

File tree

1 file changed

+112
-36
lines changed

1 file changed

+112
-36
lines changed

src/generate_snapshots.py

Lines changed: 112 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,57 @@
3131
)
3232

3333

34-
def find_sulcal_graphs(morphologist_dir):
34+
def list_acquisitions(subject_dir):
35+
"""Return acquisition folder names that contain at least one sulcal graph.
36+
37+
Scans ``<subject_dir>/t1mri/`` and returns all subdirectory names whose
38+
subtree contains a ``.arg`` sulcal/folds graph file. These are the valid
39+
choices for ``--acquisition``.
40+
41+
Args:
42+
subject_dir: Path to a single subject folder.
43+
44+
Returns:
45+
Sorted list of acquisition folder names.
46+
"""
47+
t1mri_dir = osp.join(subject_dir, "t1mri")
48+
if not osp.isdir(t1mri_dir):
49+
return []
50+
candidates = []
51+
for name in os.listdir(t1mri_dir):
52+
acq_dir = osp.join(t1mri_dir, name)
53+
if not osp.isdir(acq_dir):
54+
continue
55+
found = any(
56+
("sulci" in g.lower() or "folds" in g.lower())
57+
for g in glob.glob(osp.join(acq_dir, "**", "*.arg"), recursive=True)
58+
)
59+
if found:
60+
candidates.append(name)
61+
return sorted(candidates)
62+
63+
64+
def find_sulcal_graphs(morphologist_dir, subject=None, acquisition=None):
3565
"""Find sulcal graph files (.arg) in the Morphologist output directory.
3666
3767
Args:
3868
morphologist_dir: Path to derivatives/morphologist-6.0/ directory
69+
subject: Optional subject folder name to restrict the search (e.g.
70+
``"sub_0001"``). When omitted the entire directory is searched.
71+
acquisition: Optional acquisition folder name to restrict the search
72+
(e.g. ``"wk30"``). When omitted all acquisitions are returned.
3973
4074
Returns:
4175
List of paths to .arg files
4276
"""
43-
pattern = osp.join(morphologist_dir, "**", "*.arg")
77+
root = osp.join(morphologist_dir, subject) if subject else morphologist_dir
78+
pattern = osp.join(root, "**", "*.arg")
4479
graphs = glob.glob(pattern, recursive=True)
45-
sulcal_graphs = [g for g in graphs if "sulci" in g.lower() or "folds" in g.lower()]
46-
return sulcal_graphs
80+
graphs = [g for g in graphs if "sulci" in g.lower() or "folds" in g.lower()]
81+
if acquisition:
82+
graphs = [g for g in graphs
83+
if f"/{acquisition}/" in g.replace("\\", "/")]
84+
return graphs
4785

4886

4987
def find_white_mesh(graph_path):
@@ -367,6 +405,14 @@ def generate_umap_snapshot(embeddings_dir, reference_data_dir, output_path,
367405
return snapshots
368406

369407

408+
def _detect_hemi(graph_path):
409+
"""Return 'right' or 'left' based on graph filename."""
410+
fname = osp.basename(graph_path).lower()
411+
if fname.startswith("r") or "_r" in fname or "right" in fname:
412+
return "right"
413+
return "left"
414+
415+
370416
class GenerateSnapshots(ScriptBuilder):
371417
"""Script for generating visualization snapshots."""
372418

@@ -377,6 +423,12 @@ def __init__(self):
377423
)
378424
(self
379425
.add_optional_argument("--morphologist_dir", "Path to Morphologist output directory")
426+
.add_optional_argument("--subject",
427+
"Subject folder name to visualize (e.g. sub_0001). "
428+
"When omitted the first subject found is used.")
429+
.add_optional_argument("--acquisition",
430+
"Acquisition folder name to use (e.g. wk30, wk40). "
431+
"Required when a subject has multiple segmentations.")
380432
.add_optional_argument("--embeddings_dir", "Path to embeddings output directory")
381433
.add_optional_argument("--cortical_tiles_dir", "Path to cortical tiles crops directory")
382434
.add_argument("--output_dir", type=str, required=True, help="Directory to save snapshot images")
@@ -433,39 +485,63 @@ def run(self) -> int:
433485
def _run_sulcal(self, size):
434486
"""Generate sulcal graph snapshots."""
435487
snapshots = []
436-
if self.args.morphologist_dir and osp.exists(self.args.morphologist_dir):
437-
print("\nGenerating sulcal graph snapshots...")
438-
graphs = find_sulcal_graphs(self.args.morphologist_dir)
439-
print(f" Found {len(graphs)} sulcal graph(s)")
440-
441-
QUAT_LEFT = (0.5, 0.5, 0.5, 0.5)
442-
QUAT_RIGHT = (0.5, -0.5, -0.5, 0.5)
443-
444-
for graph_path in graphs[:2]:
445-
fname = osp.basename(graph_path).lower()
446-
if fname.startswith("r") or "_r" in fname or "right" in fname:
447-
hemi = "right"
448-
quat = QUAT_RIGHT
449-
else:
450-
hemi = "left"
451-
quat = QUAT_LEFT
452-
453-
white_mesh = find_white_mesh(graph_path)
454-
if white_mesh:
455-
print(f" White mesh: {white_mesh}")
456-
457-
out = osp.join(self.args.output_dir, f"sulcal_graph_{hemi}.png")
458-
try:
459-
snap = generate_sulcal_graph_snapshot(
460-
graph_path, out, size,
461-
view_quaternion=quat,
462-
mesh_path=white_mesh,
488+
morphologist_dir = self.args.morphologist_dir
489+
if not morphologist_dir or not osp.exists(morphologist_dir):
490+
if morphologist_dir:
491+
print(f"Morphologist directory not found: {morphologist_dir}")
492+
return snapshots
493+
494+
print("\nGenerating sulcal graph snapshots...")
495+
subject = getattr(self.args, "subject", None)
496+
acquisition = getattr(self.args, "acquisition", None)
497+
498+
graphs = find_sulcal_graphs(morphologist_dir, subject=subject,
499+
acquisition=acquisition)
500+
501+
# Group by hemisphere — keep one graph per side
502+
by_hemi = {"left": [], "right": []}
503+
for g in graphs:
504+
by_hemi[_detect_hemi(g)].append(g)
505+
506+
# Warn if multiple acquisitions exist and user hasn't disambiguated
507+
if not acquisition:
508+
for hemi, hemi_graphs in by_hemi.items():
509+
if len(hemi_graphs) > 1:
510+
subject_dir = (osp.join(morphologist_dir, subject)
511+
if subject else morphologist_dir)
512+
acqs = list_acquisitions(subject_dir)
513+
acq_list = ", ".join(acqs) if acqs else "unknown"
514+
print(
515+
f" Warning: {len(hemi_graphs)} {hemi} graphs found "
516+
f"(acquisitions: {acq_list}). "
517+
f"Using the first one. Re-run with --acquisition <name> "
518+
f"to select a specific one."
463519
)
464-
snapshots.append(snap)
465-
except Exception as e:
466-
print(f" Error processing {graph_path}: {e}")
467-
elif self.args.morphologist_dir:
468-
print(f"Morphologist directory not found: {self.args.morphologist_dir}")
520+
break
521+
522+
QUAT = {"left": (0.5, 0.5, 0.5, 0.5), "right": (0.5, -0.5, -0.5, 0.5)}
523+
524+
total = sum(len(v) for v in by_hemi.values())
525+
print(f" Found {total} sulcal graph(s)")
526+
527+
for hemi, hemi_graphs in by_hemi.items():
528+
if not hemi_graphs:
529+
continue
530+
graph_path = hemi_graphs[0]
531+
white_mesh = find_white_mesh(graph_path)
532+
if white_mesh:
533+
print(f" White mesh: {white_mesh}")
534+
out = osp.join(self.args.output_dir, f"sulcal_graph_{hemi}.png")
535+
try:
536+
snap = generate_sulcal_graph_snapshot(
537+
graph_path, out, size,
538+
view_quaternion=QUAT[hemi],
539+
mesh_path=white_mesh,
540+
)
541+
snapshots.append(snap)
542+
except Exception as e:
543+
print(f" Error processing {graph_path}: {e}")
544+
469545
return snapshots
470546

471547
def _run_tiles(self, size):

0 commit comments

Comments
 (0)