SkelHub
SkelHub是一个用于3D骨架化的Python框架。它提供了一个共享的包结构、一个统一的CLI、通用的结果对象和一个与算法无关的评估路径,因此多个骨架化后端可以在一个仓库中运行,而不会将框架核心变成后端特定的粘合剂。
当前状态:
- 支持的算法后端:
mcp,lee94,laplacian,l1_skeleton,palagyi_kuba - 统一CLI入口点:
skelhub run,skelhub evaluate,skelhub graphgen,skelhub graphviz - 评估:用于二进制3D预测/参考骨架体积的基于体素的v1评估套件
- 图生成:Voreen风格骨架NIfTI到原型图GraphML的转换
- 图形可视化:基于PyVista的轻量级GraphML/NIfTI查看器,用于3D血管数据
安装
python -m venv .venv
source .venv/bin/activate
python -m pip install -e .要使用内置的GraphML/NIfTI查看器,请执行以下操作:
# Initialze the viewer
python -m skelhub graphviz
# Initialize the viewer with a GraphML file
python -m skelhub graphviz --input ./test_data/lsys_graph/Lnet_i4_0_tort_centreline.graphml
# Initialize the viewer with a binary NIfTI file
python -m skelhub graphviz --input ./test_outputs/skelhub_mcp_small.nii.gz如果 skelhub 在你的 PATH 来自不同的环境 python/pip 您用于安装时,图形查看器依赖项可能仍然缺失。
您还可以使用安装依赖项 pip install -r requirements.txt,但控制台命令 skelhub 通过软件包安装暴露出来。
仓库结构
SkelHub/
├── docs/
├── skelhub/
│ ├── cli/
│ ├── core/
│ ├── io/
│ ├── algorithms/
│ │ ├── l1_skeleton/
│ │ ├── laplacian/
│ │ ├── lee94/
│ │ └── mcp/
│ ├── evaluation/
│ ├── preprocessing/
│ ├── postprocessing/
│ │ └── graphgen/
│ ├── visualization/
│ └── datasets/
├── tests/
└── test_data/框架说明:
skelhub.core包含共享结果对象、框架接口和后端注册表。skelhub.algorithms.mcp包含当前的MCP实现及其瘦框架适配器。skelhub.algorithms.lee94包含Lee等人1994年提出的精简后端适配器scikit-image.skelhub.algorithms.laplacian包含VascGraph-Lalacian图收缩后端,适用于输出光栅化骨架体积和可选的清理GraphML。skelhub.algorithms.l1_skeleton包含Python原生L1中间骨架v2后端,从点云收缩和分支提取到SkelHub的NIfTI卷合约。skelhub.algorithms.palagyi_kuba包含一个Python原生的Palagyi Kuba 12子项3D细化后端,用于曲线或曲面骨架。skelhub.evaluation包含与算法无关的基于体素的v1评估器,具有单独的验证、几何、形态学和报告助手。skelhub.postprocessing.graphgen包含 沃林-样式骨架到原型GraphML生成。
CLI使用情况
通过框架运行MCP:
skelhub run \
--algorithm mcp \
--input ./test_data/small_test_data/CLIP_MASKED_sub_160um_seg.nii.gz \
--output ./test_outputs/skelhub_mcp_small.nii.gz \
--verbose无需安装即可执行等效的本地模块:
python -m skelhub run --algorithm mcp --input INPUT.nii.gz --output OUTPUT.nii.gz通过相同的框架路径运行Lee94:
skelhub run \
--algorithm lee94 \
--input ./test_data/small_test_data/CLIP_MASKED_sub_160um_seg.nii.gz \
--output ./test_outputs/skelhub_lee94_small.nii.gz \
--verbose运行VascGraph-Lalacian后端:
skelhub run \
--algorithm laplacian \
--input ./test_data/lsys_data/iter_4_8_step_1/Lnet_i4_0_tort.nii.gz \
--output ./test_outputs/skelhub_laplacian.nii.gz \
--verbose可选择添加 --graph_output ./test_outputs/skelhub_laplacian.graphml 导出已清理的图形。添加 --graph_original ./test_outputs/skelhub_laplacian_original.graphml 导出之前的精炼图 post_node_cleaning()(注意:输出图仅适用于此,因为原始作品基于密集图,没有中间光栅化输出可用作骨架。在这里,我添加了一个基于清理后的图构建的光栅化骨架)
运行Python原生L1中间骨架后端:
skelhub run \
--algorithm l1_skeleton \
--input ./test_data/small_test_data/CLIP_MASKED_sub_160um_seg.nii.gz \
--output ./test_outputs/skelhub_l1_skeleton_small.nii.gz \
--verbose运行Palagyi Kuba 12子段落细化后端:
skelhub run \
--algorithm palagyi_kuba \
--input ./test_data/small_test_data/CLIP_MASKED_sub_160um_seg.nii.gz \
--output ./test_outputs/skelhub_palagyi_kuba_small.nii.gz \
--pk-mode curve \
--verbose在框架级别公开的MCP参数:
--root-method {max_fdt,topmost}--threshold-scale FLOAT--dilation-factor FLOAT--max-iterations INT--min-object-size INT--label-objects--verbose
在框架级别公开的Lee94参数:
--binarize-threshold FLOAT
在框架级别公开的拉普拉斯参数:
--graph_output PATH可选的清理GraphML输出路径--graph_original PATH可选的精细预清洁GraphML输出路径--speed_param FLOAT默认0.05--dist_param FLOAT默认0.5--med_param FLOAT默认0.5--degree_threshold FLOAT默认5.0--sampling FLOAT默认1.0--clustering_r FLOAT默认1.0--stop_param FLOAT默认0.001--n_free_iteration INT默认0--area_param FLOAT默认50.0--poly_param INT默认10
在框架级别公开的L1骨架参数:
--l1-sample-count INT默认512--l1-initial-radius FLOAT可选,省略时根据前景点间距自动估计--l1-radius-growth FLOAT默认1.5--l1-max-radius FLOAT可选,省略时从前景范围自动估计--l1-max-iterations INT默认80--l1-stop-error FLOAT默认0.01--l1-repulsion-mu FLOAT默认0.35--l1-repulsion-mu-min FLOAT默认0.15--l1-random-seed INT默认0--l1-output-mode {branches,points}默认branches--l1-use-density-weighting/--no-l1-use-density-weighting默认启用--l1-use-recentering/--no-l1-use-recentering默认启用
在框架级别公开的Palagyi-Kuba参数:
--pk-mode {curve,surface}默认curve--pk-binarize-threshold FLOAT默认0.5--pk-max-cycles INT可选的完整12个子段落循环上限
运行基于体素的评估套件:
skelhub evaluate \
--pred ./test_outputs/skelhub_mcp_small.nii.gz \
--ref ./test_data/lsys_gt/reference_skeleton.nii.gz \
--buffer-radius 1 \
--buffer-radius-unit voxels可选评估标志:
-b, --buffer-radius FLOAT所需缓冲区膨胀半径--buffer-radius-unit {voxels,um}可选半径单位,默认值voxels--json-output PATH可选的结构化JSON报告输出-v, --verbose可选的进度日志和详细的终端报告
从骨架NIfTI生成Voreen风格的原型图GraphML文件:
skelhub graphgen \
--input ./test_data/lsys_gt/iter_4_8_step_1/Lnet_i4_0_tort_centreline_26conn.nii.gz \
--output ./test_outputs/lsys.graphml \
--verbose在交互式PyVista查看器中打开GraphML血管图或二进制NIfTI卷:
skelhub graphviz
skelhub graphviz \
--input ./test_data/lsys_graph/Lnet_i4_0_tort_centreline.graphml \
--edge_thickness 2.5 \
--node_size 7
skelhub graphviz \
--input ./test_outputs/skelhub_mcp_small.nii.gz图形查看器需要每个节点的空间元数据。SkelHub当前的GraphML导出将节点坐标写入为 X, Y,以及 Z,观众直接使用这些字段。 对于NIfTI输入,查看器需要一个3D二进制体积,其值正好在 {0, 1} 并将每个前景体素渲染为体素索引坐标中的一个单位块。
注:
在HPC(例如Bunya)上部署时,需要使用conda环境,然后安装/更新conda C++运行时:
conda activate your_env
conda install -c conda-forge libstdcxx-ng
skelhub graphviz 更安全的选择:
module unload Miniconda3
module load Miniconda3
conda activate your_env
conda install -c conda-forge libstdcxx-ng
export LD_LIBRARY_PATH="$CONDA_PREFIX/lib:$LD_LIBRARY_PATH"
skelhub graphviz Python API
from skelhub.api import (
evaluate_prediction_path,
generate_graphml_from_skeleton_path,
run_algorithm_from_path,
)
from skelhub.algorithms import L1SkeletonConfig, LaplacianConfig, Lee94Config, MCPConfig, PalagyiKubaConfig
result = run_algorithm_from_path(
algorithm="lee94",
input_path="input.nii.gz",
output_path="out.nii.gz",
config=Lee94Config(binarize_threshold=0.5),
)
evaluation = evaluate_prediction_path(
"pred.nii.gz",
"ref.nii.gz",
buffer_radius=1.0,
buffer_radius_unit="voxels",
)
graph = generate_graphml_from_skeleton_path("pred.nii.gz", "pred.graphml")
laplacian = run_algorithm_from_path(
algorithm="laplacian",
input_path="input.nii.gz",
output_path="laplacian.nii.gz",
config=LaplacianConfig(graph_output="laplacian.graphml"),
)
pk = run_algorithm_from_path(
algorithm="palagyi_kuba",
input_path="input.nii.gz",
output_path="pk.nii.gz",
config=PalagyiKubaConfig(mode="curve"),
)
print(result.backend_metadata["config"])
print(evaluation.P)
print(len(graph.nodes), len(graph.edges))输出
SkeletonResult 是所有后端的框架级输出容器。它存储:
algorithm_nameskeleton体素阵列input_metadataruntime_statswarningsbackend_metadata- 可选的
graph
MCP后端将其当前的每对象运行时元数据保存在 result.backend_metadata["mcp"]. Lee94后端将其包装器元数据记录在 result.backend_metadata["lee94"] 并使用 scikit-image的Lee方法实现,而不是仓库细化实现中的自定义方法。 拉普拉斯后端记录下的图收缩元数据 result.backend_metadata["laplacian"],包括清洁的图形节点/边计数和光栅化的骨架体素计数。 L1骨架后端记录v2压缩和分支元数据 result.backend_metadata["l1_skeleton"],包括输出模式、分支计数、密度加权、椭圆重新定中心和最终分割计数。其默认输出光栅化最终的分支曲线;使用 --l1-output-mode points 对于较早的合同点输出。
EvaluationResult 现在显式记录v1评估输出,包括:
TP,FP,FNCp,Cr- 原始、剪切和归一化的形态值
OCC,BCC,以及E - 全球绩效得分
P - 缓冲区半径元数据
- 连接性元数据
- 警告
图形可视化
skelhub graphviz 打开一个轻量级的PyVista查看器,用于GraphML血管图和二进制NIfTI卷。观众:
- 通过现有的加载GraphML
igraph依赖 - 通过现有的加载NIfTI
nibabel依赖 - 使用简单的恒定大小几何体在3D中渲染节点和边
- 将二进制NIfTI前景体素渲染为单位3D块
- 使用PyVista的内置鼠标控件进行相机交互
- 通过以下方式接受GraphML外观控件
--edge_thickness和--node_size - 如果出现以下情况,将打开一个空的PyVista窗口
--input省略 - 可以在一个会话中加载多个GraphML和NIfTI文件,同时一次显示一个活动文件
- 提供了一个右对齐的画布命令行,具有固定大小的按钮背景
Import,Close, `,红色Refresh,和蓝色Reset View` - 预览活动GraphML文件的节点大小和边厚滑块值,然后在以下情况下应用它们
Refresh被按下 - 隐藏活动NIfTI文件的节点大小和边缘厚度滑块,同时保持命令按钮可见
- 使用以下命令恢复活动图的初始相机视图
Reset View无需更改加载的文件或滑块值 - 当鼠标悬停在左上角的紧凑文件标签上时,展开加载的文件列表
- 接受
.graphml,.nii,以及.nii.gz当桌面VTK/PyVista后端向渲染窗口公开文件拖放时的拖放事件
如果GraphML文件不包含可用的节点坐标,则命令会明显失败,而不是猜测布局数据。 如果NIfTI文件不是完全二进制的,查看器将显示警告并拒绝导入。
评估概述
当前的评估子系统是一个真实但有意保守的v1实现。它
- 评估两个二进制三维骨架体积:预测和参考
- 在形状不匹配、间距不匹配或非二进制值上很难失败
- 用缓冲区法计算几何保存
- 根据连通分量和体素端点计算3D形态质量
- 报告全球质量风格评分
P - 保持基于体素和算法无关
v1指标为:
- 几何保存:
TP,FP,FN,完整性Cp,以及正确性Cr - 形态质量:生签
OCC,BCC,以及E,加上剪切和标准化的质量变体 - 全球得分:
P = mean(Cp, Cr, OCC_normalized, BCC_normalized, E_normalized)
当前限制:
- 仅限3D
- 仅限原始二进制骨架输入
- 仅基于体素
- 不基于图形
- 尚未主要通过
SkeletonResult对象,尽管数组级计算器的结构使扩展变得简单明了
