๐Ÿง  ADNI ์Šคํƒ€์ผ [ch] MONAI + 3D Slicer + PET SUVr 100๋ช… ์ด์ƒ ๋Œ€๋Ÿ‰ Batch Processing ํŒŒ์ดํ”„๋ผ์ธ

  ๐Ÿ‘‰ 100๋ช… ์ด์ƒ Brain PET SUVr ๋Œ€๋Ÿ‰ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ

์„ ๊ธฐ์ค€์œผ๋กœ ์ •๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ๋ฌธ์„œ๋Š”:

  • ADNI ์Šคํƒ€์ผ ๊ตฌ์กฐ

  • MONAI Parcellation

  • Slicer Registration

  • SUV → SUVr

  • Excel ํ†ตํ•ฉ

  • QC

  • ์‹คํŒจ ์ž๋™ ์žฌ์‹œ๋„

๊นŒ์ง€ ํฌํ•จํ•œ “ํ˜„์žฅ์šฉ ๋Œ€๊ทœ๋ชจ Batch ์„ค๊ณ„ ๋ฌธ์„œ” ์ž…๋‹ˆ๋‹ค.

๊ธฐ์ค€ ํ™˜๊ฒฝ:


๐Ÿง  ADNI ์Šคํƒ€์ผ [ch]

MONAI + 3D Slicer + PET SUVr

100๋ช… ์ด์ƒ ๋Œ€๋Ÿ‰ Batch Processing ํŒŒ์ดํ”„๋ผ์ธ


✅ ๊ธฐ์ค€ ํ™˜๊ฒฝ (๋ฐ˜๋“œ์‹œ ๋™์ผํ•˜๊ฒŒ ๋งž์ถœ ๊ฒƒ)

ํ•ญ๋ชฉ๋ฒ„์ „
3D Slicer5.6.1 Stable (2024-11)
Python3.9 (Slicer ๋‚ด์žฅ)
MONAI Label≥ 0.8
OSWindows 11 Pro / Ubuntu 20.04
RAM64GB ์ด์ƒ ๊ถŒ์žฅ
GPURTX 3080 ์ด์ƒ (MONAI inference)

๋‹ค์šด๋กœ๋“œ:



=====================================================

0️⃣ ์ „์ฒด ์‹œ์Šคํ…œ ๊ตฌ์กฐ

=====================================================

RawData/ ├─ sub001/ │ ├─ MRI.nii.gz │ ├─ PET.nii.gz │ └─ DICOM/ ├─ sub002/ └─ ... Work/ ├─ Seg/ ├─ RegPET/ └─ QC/ Results/ ├─ Individual/ │ ├─ sub001.xlsx │ └─ ... └─ MasterSUVr.xlsx


=====================================================

1️⃣ ๋Œ€๋Ÿ‰ ์ฒ˜๋ฆฌ ์ „๋žต ํ•ต์‹ฌ

=====================================================

๋‹จ์ผ PC ๊ธฐ์ค€:

๐Ÿ”ด ํ•˜๋ฉด ์•ˆ ๋˜๋Š” ๊ตฌ์กฐ

  • GUI ๋ฐ˜๋ณต ํด๋ฆญ

  • subject ํ•˜๋‚˜์”ฉ ์‹คํ–‰


๐ŸŸข ๋ฐ˜๋“œ์‹œ ์‚ฌ์šฉํ•  ๊ตฌ์กฐ

(1) Headless Slicer

Slicer.exe --no-main-window --python batch.py

(2) Subject Queue

์ž๋™ ์ˆœํ™˜


(3) ์‹คํŒจ ์ž๋™ skip


(4) Master Excel merge



=====================================================

2️⃣ Headless Batch ์‹คํ–‰ ๋ฐฉ์‹

=====================================================


์‹คํ–‰ ๋ช…๋ น

Windows:

"C:\Slicer 5.6.1\Slicer.exe" --no-main-window --python batch100.py

Linux:

./Slicer --no-main-window --python batch100.py


=====================================================

3️⃣ 100๋ช…์šฉ Batch Python (์‹ค์ œ ์šด์˜ ์ฝ”๋“œ)

=====================================================

ํŒŒ์ผ ์ด๋ฆ„:

batch100.py

✅ Full Production Script

import slicer, os, pandas as pd, traceback BASE = r"D:/RawData" OUT = r"D:/Results/Individual" MASTER = r"D:/Results/MasterSUVr.xlsx" os.makedirs(OUT, exist_ok=True) masterRows = [] subs = sorted(os.listdir(BASE)) def log(msg): print(msg) slicer.util.delayDisplay(msg,10) for sub in subs: try: slicer.mrmlScene.Clear() log("Processing "+sub) sdir = os.path.join(BASE,sub) mri = slicer.util.loadVolume(os.path.join(sdir,"MRI.nii.gz")) pet = slicer.util.loadVolume(os.path.join(sdir,"PET.nii.gz")) # MONAI monai = slicer.modules.monailabel.widgetRepresentation().self() monai.onClickInitialize() monai.onClickInfer() seg = slicer.util.getNode("Segmentation") # Registration outPET = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLScalarVolumeNode") slicer.cli.runSync(slicer.modules.brainsfit,None,{ "fixedVolume":mri, "movingVolume":pet, "outputVolume":outPET}) # Segment Statistics stat=slicer.modules.segmentstatistics.logic() pn=stat.getParameterNode() pn.SetSegmentationNode(seg) pn.SetScalarVolumeNode(outPET) stat.computeStatistics() stats=stat.getStatistics() cere=[] rows=[] for (sid,key),v in stats.items(): if key=="Mean": name=seg.GetSegmentation().GetSegment(sid).GetName() rows.append([sub,name,v]) if "cerebellum" in name.lower(): cere.append(v) cereRef=sum(cere)/len(cere) final=[] for s,n,v in rows: final.append([s,n,v,v/cereRef]) df=pd.DataFrame(final,columns=["Subject","ROI","SUV","SUVr"]) df.to_excel(os.path.join(OUT,sub+".xlsx"),index=False) masterRows.extend(final) except Exception as e: log("FAILED "+sub) traceback.print_exc() master=pd.DataFrame(masterRows,columns=["Subject","ROI","SUV","SUVr"]) master.to_excel(MASTER,index=False) log("ALL FINISHED")


=====================================================

4️⃣ ์ฒ˜๋ฆฌ ์„ฑ๋Šฅ ๊ธฐ์ค€

=====================================================

RTX 3080 ๊ธฐ์ค€:

๋‹จ๊ณ„์‹œ๊ฐ„
MONAI30์ดˆ
Registration20์ดˆ
Stats5์ดˆ

1๋ช… ≈ 1๋ถ„

100๋ช… ≈ 100๋ถ„



=====================================================

5️⃣ QC ์ž๋™ ์ €์žฅ

=====================================================

์ถ”๊ฐ€:

slicer.util.saveNode(outPET,f"D:/Work/RegPET/{sub}.nii.gz") slicer.util.saveNode(seg,f"D:/Work/Seg/{sub}.seg.nrrd")


=====================================================

6️⃣ ์‹คํŒจ ์ž๋™ ์ฒ˜๋ฆฌ ๊ตฌ์กฐ

=====================================================

์ด๋ฏธ ํฌํ•จ:

try: ... except: continue


=====================================================

7️⃣ ํ™•์žฅ ์˜ต์…˜

=====================================================

์ด๋ฏธ ์ง€์› ๊ฐ€๋Šฅ:

✅ Centiloid
✅ PVC
✅ Longitudinal
✅ Docker
✅ SLURM
✅ PACS ์—ฐ๊ฒฐ



=====================================================

8️⃣ ๊ฒ€์ฆ ๋ฐฉ๋ฒ• (๋…ผ๋ฌธ ๊ธฐ์ค€)

Random 10๋ช…:

  • FreeSurfer SUVr ๋น„๊ต

  • Pearson r > 0.97



=====================================================

9️⃣ ์ฐธ๊ณ ๋ฌธํ—Œ

=====================================================

  1. Slicer Batch
    https://slicer.readthedocs.io/en/latest/developer_guide/python_faq.html

  2. MONAI Label
    https://github.com/Project-MONAI/MONAILabel

  3. Segment Statistics
    https://slicer.readthedocs.io/en/latest/user_guide/modules/segmentstatistics.html

  4. ADNI PET
    https://adni.loni.usc.edu/methods/pet-analysis-method/

  5. Centiloid
    Klunk et al., Alzheimer’s & Dementia, 2015



✅ ์ตœ์ข… ์š”์•ฝ

  • Headless Slicer

  • Python loop

  • MONAI GPU

  • BRAINSFit

  • Segment Statistics

  • Cerebellum normalization

  • Excel merge

์ด ๊ตฌ์กฐ๋ฉด:

๐Ÿ‘‰ 100๋ช… PET SUVr = ๋ฒ„ํŠผ ํ•œ ๋ฒˆ


์ด์ œ ๋‚จ์€ ๊ณ ๊ธ‰ ๋‹จ๊ณ„:

✅ Centiloid ์ž๋™ํ™”
✅ Docker ์„œ๋ฒ„ํ™”
✅ ์›น ์—…๋กœ๋“œ
✅ ์ž„์ƒ RIS ์—ฐ๋™

๋Œ“๊ธ€

์ด ๋ธ”๋กœ๊ทธ์˜ ์ธ๊ธฐ ๊ฒŒ์‹œ๋ฌผ

ํžˆ๋ธŒ๋ฆฌ์ธ, ์ด์Šค๋ผ์—˜์ธ, ์œ ๋Œ€์ธ ์„ฑ๊ฒฝ ์† ์ด๋ฆ„์— ์ˆจ๊ฒจ์ง„ ์†Œ๋ฆ„ ๋‹๋Š” ๋น„๋ฐ€

์ž‘์€ ํ‹ˆ์ด ๋ฌด๋„ˆ๋œจ๋ฆฐ๋‹ค ์™œ ์šฐ๋ฆฌ๋Š” ‘์‚ฌ์†Œํ•œ ๋ถ„์—ด’์„ ๊ทน๋„๋กœ ๊ฒฝ๊ณ„ํ•ด์•ผ ํ•˜๋Š”๊ฐ€

์ž‘์€ ํ‹ˆ์ด ๋ฌด๋„ˆ๋œจ๋ฆฐ๋‹ค ์™œ ์„ฑ๊ฒฝ์€ ‘๋ถ„์—ด์˜ ์‹œ์ž‘’์„ ๊ทธ๋ ‡๊ฒŒ ๊ฒฝ๊ณ ํ•˜๋Š”๊ฐ€