cbct-bone
cbct-bone is an object-oriented, ready-to-use Python package for extracting binary bone masks from 3D images produced by the target intraoperative CBCT scanner. Its default backend is a v5 2.5D U-Net trained from five reviewed cases, including the interpolated slices between annotation keyframes. Users do not need to train a model, configure a network, or download weights manually.
This version is a research tool, not a medical device. A qualified professional must review every automatic result before it is used for diagnosis, surgical planning, or finite-element analysis.
Features
- Python 3.12 or later is supported, with uv managing the development environment.
- DICOM, NIfTI, and
.ubd.npzreading is delegated exclusively toct_mri_dicom_nii_reader. - The package depends on
med-image-seg==0.1.1from PyPI, so machine-generated annotation JSON can enter the same bilingual GUI and Python annotation workflow. The GUI defaults to English and can switch to Chinese at runtime. - The default v5 ONNX model is downloaded automatically from GitHub Releases on first use; the file is approximately 4.2 MiB.
- Model downloads support
.partresume, retries, an interprocess lock, SHA-256 verification, and atomic installation. - CPU inference uses ONNX Runtime and does not require PyTorch. Other ONNX Runtime execution backends can be selected with the provider option.
- A weight-free 3D adaptive-threshold method remains available as an explicit fallback backend.
- Inputs are normalized to an isotropic LPS grid, and binary masks can be written as NIfTI or
.ubd.npz. MedicalVolumeReader,V5CBCTBoneSegmenter,ModelManager,MedicalMaskWriter,MachineAnnotationWriter, andCBCTBoneExtractorcan be reused or replaced independently.- The annotation GUI lives in the separate
med-image-segproject, so this segmentation package does not carry GUI implementation or training dependencies.
Installation
The project requires Python 3.12 or later.
uv sync --frozen
Install it as a dependency:
uv add cbct-bone
Before a PyPI release is available, install directly from GitHub:
uv add "cbct-bone @ git+https://github.com/GGN-2015/cbct-bone.git"
Command line
The smallest invocation is:
uv run cbct-bone path\to\dicom path\to\bone_mask.nii.gz
The first call downloads and verifies the v5 weights. Later calls use the local cache. The neural models require 0.8 mm isotropic input, which matches the CLI default.
A single DICOM file, .nii, .nii.gz, or .ubd.npz file is also accepted:
uv run cbct-bone scan.nii.gz bone_mask.nii.gz --spacing 0.8
Print diagnostics as JSON:
uv run cbct-bone scan.nii.gz bone_mask.nii.gz --json
Also write per-slice polygon JSON that can be edited by med-image-seg:
uv run cbct-bone scan.nii.gz bone_mask.nii.gz --annotation-json
When --annotation-json has no explicit path, NIfTI and UBD inputs use scan.med-image-seg.json, while DICOM uses .med-image-seg.json in the series directory. A destination can be supplied explicitly:
uv run cbct-bone scan.nii.gz bone_mask.nii.gz `
--annotation-json D:\review\scan.med-image-seg.json
Machine contours are marked as prototype in the JSON. If the target file already exists, the writer replaces old machine contours while preserving manual contours, review state, and forced-empty slices. Machine and manual results on the same slice are combined by union in med-image-seg. Every inferred slice, including an empty slice, is stored as a keyframe, so reviewing a complete model result does not introduce additional interpolation.
Open the generated annotations directly in the standalone review tool:
cd C:\Users\neko\Desktop\github\med-image-seg
uv run med-image-seg --image "D:\images\scan.nii.gz"
Use only an already verified cached model when no network is available:
uv run cbct-bone scan.nii.gz bone_mask.nii.gz --offline
Select a local model, cache directory, or ONNX Runtime provider:
uv run cbct-bone scan.nii.gz bone_mask.nii.gz `
--model D:\models\cbct-bone-intraoperative-v5.onnx `
--provider CPUExecutionProvider
The weight-free adaptive backend can be selected explicitly and permits a different processing resolution:
uv run cbct-bone scan.nii.gz bone_mask.nii.gz `
--backend adaptive --spacing 1.0
The previous published model remains reproducible with --backend v4.
On Windows, the default model cache is %LOCALAPPDATA%\cbct-bone\models; Linux and macOS use their standard user cache directories. Set CBCT_BONE_CACHE_DIR or pass --cache-dir to override it. The registered model size and SHA-256 are fixed in code, and an invalid file never enters the valid cache.
Every model request reads the standard HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables, including their lowercase equivalents. For example:
$env:HTTP_PROXY = "http://127.0.0.1:10808"
$env:HTTPS_PROXY = "http://127.0.0.1:10808"
uv run cbct-bone scan.nii.gz bone_mask.nii.gz
Python's standard library resolves proxy behavior according to the operating system. Proxy addresses and credentials are never written to the model cache.
List all options:
uv run cbct-bone --help
Annotation tool
Polygon annotation, automatic interpolation, immediate JSON persistence, and the GUI have moved to the independent med-image-seg project, which is installed as a runtime dependency of cbct-bone. cbct-bone itself still has no PyTorch or prototype-training dependency.
Python API
The simplest API reads an image, obtains the v5 weights, runs inference, and writes the mask:
from cbct_bone import segment
result = segment(
"path/to/dicom",
"bone_mask.nii.gz",
annotation_path="path/to/dicom/.med-image-seg.json",
)
print(result.mask.shape)
print(result.diagnostics)
print(result.annotation_path)
For composition and dependency injection, use the class interface:
from cbct_bone import (
CBCTBoneExtractor,
MedicalMaskWriter,
MedicalVolumeReader,
ModelManager,
NeuralSegmentationConfig,
V5CBCTBoneSegmenter,
)
reader = MedicalVolumeReader(spacing_mm=0.8)
models = ModelManager() # download + resume + SHA-256 verification
algorithm = V5CBCTBoneSegmenter(
NeuralSegmentationConfig(batch_size=8),
model_manager=models,
offline=False,
)
extractor = CBCTBoneExtractor(
reader=reader,
segmenter=algorithm,
writer=MedicalMaskWriter(),
)
result = extractor.extract(
"path/to/dicom",
"bone_mask.nii.gz",
annotation_path="path/to/dicom/.med-image-seg.json",
)
print(result.mask.shape)
print(result.diagnostics)
Prepare the weights in advance for fully offline inference:
from cbct_bone import ModelManager
model_path = ModelManager().get()
print(model_path)
Reuse only the model class when a NumPy LPS volume is already available:
from cbct_bone import V5CBCTBoneSegmenter
mask, diagnostics = V5CBCTBoneSegmenter().segment(
volume,
spacing_mm=(0.8, 0.8, 0.8),
)
CBCTBoneExtractor uses dependency injection. A custom component only needs methods compatible with the VolumeReader, BoneMaskSegmenter, or MaskWriter protocol to replace that stage.
Algorithm selection
The default v5 model is a compact 2.5D U-Net tuned for the current target intraoperative CBCT scanner. It uses the current axial slice and its two neighbors, applies robust intensity normalization within each volume, and uses the same threshold and 2D connected-component postprocessing as the annotation workflow. Five reviewed studies contributed 1,206 axial training slices after signed-distance interpolation between annotation keyframes. The model must therefore be treated as a scanner-specific annotation aid, not evidence of cross-scanner or whole-body generalization. See MODEL_CARD.md for the full limitations.
The adaptive backend retains a 3D method without anatomical priors:
- Three-class multi-Otsu histogram analysis estimates weak-bone and strong-bone thresholds.
- Local mean and variance in a millimeter-scale 3D neighborhood suppress soft tissue and artifacts that only resemble bone in global intensity.
- 3D hysteresis region growing expands from strong-bone seeds through weak-bone candidates to recover low-density boundaries affected by partial volume.
- Physical-scale closing, enclosed-cavity filling, and minimum-component filtering produce the final binary mask.
This fallback follows the adaptive bone-segmentation approach of Zhang et al., combining initial classification, 3D correlation iteration, and region growing with modern multi-Otsu thresholding and 3D morphology. It requires neither training data nor model weights, but it has no learned anatomical semantics.
For scanners with unusual intensity distributions, thresholds can be overridden explicitly:
uv run cbct-bone scan.nii.gz mask.nii.gz --backend adaptive `
--weak-threshold 180 --strong-threshold 450
The weak threshold must be lower than the strong threshold. Inspect the automatically selected values with --json, then establish scanner-level settings from a small reviewed dataset.
I/O and coordinate conventions
- Input paths are read only through the public loader in
ct_mri_dicom_nii_reader; this project contains no second medical-image reader. - Inputs are resampled to an isotropic
(L, P, S)array before processing. - SimpleITK is used to write NIfTI, but never to read source images.
- NIfTI output retains the resampled grid spacing and LPS origin, with an identity direction matrix.
.ubd.npzdoes not preserve a physical origin. It is useful for fast internal exchange, but not for cross-application workflows that depend on patient coordinates.
Validation status
The v5 model-selection run used 965 slices for fitting and 241 slices in contiguous, spatially distributed validation blocks across five target-scanner studies. Internal Dice was 0.8733, precision was 0.8735, and recall was 0.8731. The release model was then retrained for the selected 58 epochs on all 1,206 keyframe and interpolated slices. These blocks still come from the same patients, and most labels are interpolation-derived, so the values are development metrics rather than an independent patient-level estimate of clinical generalization.
Automated tests cover model caching, resumed downloads, SHA-256 failure, offline mode, ONNX axis restoration, spacing constraints, NIfTI geometry round trips, CLI behavior, and object-oriented dependency injection. Numerical comparison between the ONNX export and the original PyTorch v5 model found a maximum absolute error of 1.49e-5. A same-case full-volume sanity check against the fifth reviewed project measured Dice 0.9280, precision 0.8967, and recall 0.9616; because that case contributed to training, this is not a generalization result. Synthetic tests prevent algorithm and geometry regressions; they are not clinical validation.
Before use on real scanners, build a manually labeled test set stratified by scanner, anatomy, dose protocol, and metal implants. Report Dice, surface Dice, HD95, sensitivity, and false-positive volume.
Multicenter testing on open SynthRAD2023 pelvic CBCT data showed a substantial scanner-domain shift for the pure-threshold method. The v5 model has likewise not been validated on independent patients, other scanners, knees, or whole-body anatomy. The current automatic algorithm is not clinically validated; future evaluation requires a patient-separated independent test set and the same volumetric and surface metrics.
Model release
- Release:
model-v5.0.0 - File:
cbct-bone-intraoperative-v5.onnx - Size:
4,428,425bytes - SHA-256:
e0e5711b856fd22fbb9e0dd31d49c3e73d7b4ea15988029e5acff626304f32f7 - Training grid:
0.8 mmisotropic LPS - Segmentation threshold:
0.8
The runtime accepts a model file only when both its registered size and SHA-256 match.
Run the quality checks:
uv run ruff check .
uv run ruff format --check .
uv run pytest --cov=cbct_bone
uv build
References
- Zhang J, Yan C-H, Chui C-K, Ong S-H. Fast segmentation of bone in CT images using 3D adaptive thresholding. Computers in Biology and Medicine. 2010;40(2):231-236.
- van Eijnatten M, et al. CT image segmentation methods for bone used in medical additive manufacturing. Medical Engineering & Physics. 2018;51:6-16.
- Isensee F, et al. nnU-Net: a self-configuring method for deep learning-based biomedical image segmentation. Nature Methods. 2021;18:203-211.
- Dot G, et al. DentalSegmentator: robust open source deep learning-based CT and CBCT image segmentation. Journal of Dentistry. 2024;147:105130.
License
Metadata
Release files for cbct-bone 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cbct_bone-0.3.0.tar.gz | 125.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cbct_bone-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 154.3 kB
Release files / cbct_bone-0.3.0.tar.gz
| Download URL | cbct_bone-0.3.0.tar.gz |
|---|---|
| Size | 125.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4eeeba16aa189e980e3bc29df8ffce9a82aedc969852a3bcc6e163b8c6219509
|
|
BLAKE2b-256 checksum How to use checksums |
0596fe2319cb18d8511c74280f41a36f1bcdc89ace7ec2422d6391d52ce23f0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.14.6 Windows/11
|
Release files / cbct_bone-0.3.0-py3-none-any.whl
| Download URL | cbct_bone-0.3.0-py3-none-any.whl |
|---|---|
| Size | 29.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9ec6418992dde7b029c1774d6324a3b17d1cf2df37b481672a896ca04d1a7374
|
|
BLAKE2b-256 checksum How to use checksums |
ca12f2180f2675a0bf9539dbb6e240f8bd49a64849e0755bfe4baafd79bcaec6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.14.6 Windows/11
|