- Created a new pixi.toml file to manage project dependencies and tasks. - Defined workspace metadata including authors, channels, name, platforms, and version. - Specified tasks for preprocessing, PSO, DE, and other scripts. - Listed dependencies for Python and various libraries with specific versions. - Configured additional PyPI options for PyTorch installation from a custom index.
80 lines
No EOL
7.4 KiB
Markdown
80 lines
No EOL
7.4 KiB
Markdown
# AGENTS.md
|
||
|
||
本文件提供 AI 編碼代理(Kilo / Claude 等)在 `CBT_project` 內工作時的指引。
|
||
|
||
## 專案概述
|
||
|
||
CBT(Cortical Bone Trajectory,皮質骨軌跡):在腰椎 CT(L1–L5)上自動規劃椎弓根螺絲(pedicle screw)軌跡。將螺絲建模為圓柱體,以 PSO / DE / Nelder-Mead 最佳化在骨頭 mask 上評分(皮質骨接觸、椎體 VBODY 獎勵、tip 處罰、入口端 0.5mm 豁免),取得最佳位置/角度/尺寸後再映回 native CT 空間。
|
||
|
||
## 執行環境
|
||
|
||
- Python 環境:**pixi**(conda env `cbt` 已棄用)。環境在 `.pixi/envs/default/`,python 3.14;`pixi.toml` 定義全部依賴與 tasks。VS Code 已設定 `python.defaultInterpreterPath` 指向 pixi env。
|
||
- `xfr_*.py` 的 shebang 為 `#!/usr/bin/env python`,需先 `pixi shell` / `pixi run`(或 VS Code 選到 pixi interpreter)才有對的 python。
|
||
- 重建環境:`pixi install`(torch 走 `extra-index-urls` 的 pytorch cu126 index,版本 pin 在 `pixi.toml`)。
|
||
- 主要依賴(皆 pypi):`torch`(CUDA,GPU 最佳化)、`SimpleITK`、`scipy`、`scikit-learn`、`numpy`、`nibabel`、`tinydb`、`pyswarm`、`matplotlib`。conda 端只有 python。
|
||
- **無測試、無 lint 設定**。驗證方式:跑小批量 volume、檢查 logs/ 與結果 CSV、以及螺絲柱 in-label 比例(xfr_cbt_native 的 docstring 有驗收標準)。
|
||
|
||
## 資料位置(皆在 repo 之外,勿把大檔 commit 進 repo)
|
||
|
||
| 用途 | 路徑 |
|
||
|---|---|
|
||
| 原始 CT / label(CTSpine1K) | `/mnt/1220/Public/dataset/Spine/CTSpine1K/{data,label}/`(子資料夾:`colon`(=conlon)、`COVID-19`、`HNSCC-3DCT-RT_neck`、`liver`(=Liver)) |
|
||
| 標準化輸出(current) | `/mnt/1248/open2/cyrou/CBT/Seg/Resample/standardized-xfr-3/` |
|
||
| 最終輸出(cbt.nii.gz、X 光投影) | `/mnt/1248/open/cyrou/Output/` |
|
||
| 元資料庫(TinyDB) | repo 根目錄 `xfr_image_metadata.json`(table `images`,key = volume `name`) |
|
||
| 進度 / 日誌 / 結果 | `progress.json`、`logs/`、`results/`(皆已被 gitignore) |
|
||
|
||
`xfr_*.py` 頂部有 hardcode 的資料路徑(`standardized_dir`、`data_root`、`label_root`、`Output_dir`);跑別世代資料時改這些常數,不要假設 CLI 可覆蓋。
|
||
|
||
## 目錄結構
|
||
|
||
```
|
||
core/ 圓柱生成(torch)、中心線相交、評分、objective、optimizer(PSO/DE/NM)
|
||
imaging/ nifti_io、preprocessing、resample、affine、orientation、segmentation、transforms
|
||
visualization/ res_bone_figure(四視角螺絲圖)、res_plot_3d、res_cyl_nifti(存 NIfTI)、res_cyl_to_CT(overlay)
|
||
config/ constant.py(LABEL_MAP、螺絲尺寸、OVERLAP_THRESH、DEFAULT_SPACING)、device.py
|
||
utils/ helpers.py(retry_robust、unique filepath、save_with_unique_name)
|
||
xfr_*.py 現世代管線入口腳本(見下)
|
||
run_*.py 舊世代多 GPU 批次 / benchmark 腳本(base_dir 不同,較少使用)
|
||
references/ 文獻 PDF(唯讀參考,勿改)
|
||
experiment.ipynb 實驗 notebook
|
||
```
|
||
|
||
## 管線流程與入口腳本
|
||
|
||
入口腳本都有對應 pixi task:`pixi run <task> -- <args>`(task 清單在 `pixi.toml [tasks]`:`preprocess`、`pso`、`de`、`check-spinous`、`rerender-spinous`、`cbt-native`、`record-planes`、`plot-level`)。以下直接列腳本名,加 `./` 前缀在 pixi 環境內亦可執行。
|
||
|
||
1. **預處理**:`xfr_preprocess.py [--max-images N] [--output-dir DIR]`
|
||
裁切各 level、重取樣到 0.5mm、方向正規化(best_symmetry_plane / best_upper_endplate_plane),輸出 `<vol>/crop/` 與各 level 的 mask,並把仿射鏈寫進 `<vol>/transform.json`。
|
||
跳過條件:z spacing > 4mm、lumbar label < 2、椎弓根寬度 > 18mm(clip 並標 `_clipped`)。
|
||
2. **最佳化**:`xfr_pso.py [volume_id [level]] [--screw-shape cone|cylinder]`(DE 版:`xfr_de.py`)
|
||
每 level 左/右各跑一支 PSO,輸出螺絲參數與 `render_bone_figure` 四視角圖、CSV。
|
||
3. **驗證**:`xfr_check_spinous.py`、`xfr_rerender_spinous.py`(棘突檢查/重繪)。
|
||
4. **映回 native**:`xfr_cbt_native.py <run_id> [volumes...] [--date D]`
|
||
用 `transform.json` 正向鏈把螺絲映回 native CT,輸出 `cbt.nii.gz`(label 1–10 = L1L…L5R)與 x-ap/x-lat/z-ap/z-lat 投影圖。
|
||
5. **輔助**:`xfr_record_planes.py`(記錄平面入 transform.json)、`xfr_inverse_transform.py`(單一 mask 逆向映射)、`xfr_orig_labels.py`(原始 label 對齊)、`xfr_reprocess_ap.py`(AP 方向修正)、`xfr_plot_level.py`(單 level 圖)、`xfr_migrate_crop.py`(舊佈局遷移到 crop/)。
|
||
|
||
## 程式慣例(重要)
|
||
|
||
- **註解 / docstring 用繁體中文**,識別符號用英文。新增碼保持同風格。
|
||
- **座標系**:numpy 體積為 `(Z, Y, X)`;螺絲參數 `pos = [z, y, x, az°, alt°, d_mm, L_mm]`(xfr 變體為 `[z, x, az°, alt°, d, L]`,y 由 `y_indices` surface 推導,見 `core/optimizer.py::get_first_nonzero_y`)。spacing 為 `[sx, sy, sz]`,預設 0.5 isotropic。
|
||
- **Objective API**:新碼一律用 `core/objective.py` 的 `OptimizationContext` + `make_objective_function[_xfr]`。**禁止依賴 module globals**(`set_global_context` / `objective_function` 是 legacy 兼容路徑,保留勿擴充)。
|
||
- **螺絲尺寸離散化**:`snap_to_discrete_values`(`config.constant.ALLOWED_DIAMETERS/ALLOWED_LENGTHS`);xfr 管線用 `snap_to_discrete_values_xfr`(`core/cylinder.py` 的 `points` 允許 (d, L) 組合表)。xfr 還做 0.9/0.1 混合(`diameter_loss = .9*discrete + .1*raw`)。
|
||
- **transform.json 是 native 映射的單一事實來源**(`imaging.transforms.original_to_source`)。fallback 重算路徑僅供舊世代 volume;改映射邏輯時先讀 `xfr_cbt_native.py` docstring 的驗證紀錄。
|
||
- **元資料庫是 TinyDB**:用 `xfr_preprocess.py::_upsert_by_name` 一類的 upsert 寫入;勿手改 JSON 結構(legacy 遷移邏輯對結構敏感,見 `_migrate_legacy_metadata`)。
|
||
- **NFS 瞬時錯誤**:輸出樹在 NFS 上,`os.makedirs`/寫檔可能短暫 ENOENT/EEXIST。沿用 `utils.helpers.retry_robust` 或 `core/optimizer.py::_makedirs_retry` 的重試模式;勿裸 `os.makedirs` 建輸出目錄。
|
||
- **日誌**:腳本寫 `logs/xfr_<script>_<timestamp>.log`;logger 名稱與腳本一致。
|
||
- **不覆蓋輸出**:存檔用 `utils.helpers.get_unique_filepath` / `save_with_unique_name`(自動 `_1`, `_2` 後綴)。
|
||
- 檔案命名含螺絲參數時,長度進檔名不帶小數(35.0→35)、直徑保留一位小數(`utils.helpers._fmt_length`)。
|
||
|
||
## 多 GPU / 批次
|
||
|
||
`run_all_cases.py --gpu N --total_gpus M`:病人依 index % total_gpus 分配;`run_benchmark.py` / `run_de.py` / `run_pso.py` 為 benchmark 腳本,結果 CSV 在 `optimization_benchmark_results_*.csv`。舊腳本的 `base_dir` 指向 `/home/cyrou/...`(可能已遷移),跑前確認路徑。
|
||
|
||
## 修改注意事項
|
||
|
||
- `references/` 唯讀。
|
||
- `xfr_image_metadata.json`、`progress.json`、`logs/`、`results/`、`.kilo/` 已 gitignore,勿 commit。
|
||
- `core/scoring.py`、`imaging/orientation.py` 有 xfr 版本(`cl_score_torch_xfr`、`segment_spinous_process` 等)與原版並存;改評分邏輯時確認呼叫方用哪個版本(objective 目前用 `_xfr`)。
|
||
- 改 `LABEL_MAP` 或 level 集合時,同步檢查 `xfr_cbt_native.py` 的 label 值定義(L1L=1 … L5R=10)。
|
||
- GPU 不可用時多數 torch 路徑會 fallback CPU,但速度極慢;跑完整最佳化前確認 CUDA 可用。 |