Teeth Segmenter (CBCT)(CBCT 牙齿分割与编号)
Teeth Segmenter (CBCT) - User Manual
Dragonfly Prototype Apps · Teeth Segmenter (CBCT)...
版本 Version 1.0 · 2026-09-09
第一部分 中文手册
目录
1. 简介
2. 第 1 步 预处理
3. 第 2 步 深度学习分割
4. 第 3 步 去噪与种子点
5. 第 4 步 分水岭
6. 第 5 步 牙位编号
7. 与原始宏的差别
8. 环境与限制
1. 简介
本插件按一套固定流程对口腔 CBCT 做牙齿分割与 FDI 牙位编号。流程来自客户 2023 年在 Dragonfly 2022.2 中用四个宏实现的方法(灰度预处理 → 深度学习分割 → 手动去噪与确认牙髓种子点 → 分水岭 → 编号),本插件把它整理成五个页签,并把原来纯手工的第三步中能自动完成的部分自动化。
菜单位置:Prototype Apps ▸ Teeth Segmenter (CBCT)...。五个页签始终可用:第 3 步与第 4 步之间需要在 Dragonfly 中手动修正对象,因此每个页签都有自己的对象选择器,并会自动选中上一步刚发布的对象;已有中间结果时可以从任意一步开始。
⚠ 所有参数(包括所选模型)都会自动记住,下次打开面板时恢复。对象选择器(通道、ROI、MultiROI)属于会话状态,不会被记住。
「预处理」页的一键执行全部步骤(按当前设置)会无人值守地跑完整个流程:预处理 → 深度学习分割 → 去噪与种子点 → 分水岭 → 牙位编号 → 发布,每一步都使用你按下按钮那一刻各自页签上显示的设置。按下之前它会明确说明两件事:它会向会话发布六个对象;并且它会跳过第 3 步要求的、对牙齿掩膜与牙髓种子点的人工修正,因此结果必须先核对再使用。所有页签始终可以打开和修改参数,以便在运行之前逐页检查;某一步所需的输入尚不存在时,按下它自己的按钮会给出提示,说明缺的是哪一步。
2. 第 1 步 预处理
选择 CBCT 通道。点击分析直方图可先查看:数据范围、众数所在 bin、由此得到的上限、以及大约有多少体素会被截断。点击预处理并发布则发布一个名为 预处理后 <原名> 的浮点通道。
- 直方图 bin 数(默认 128)与众数 / 比例(默认 0.30):上限 = 众数 bin 的左边界 / 比例。第 0 个 bin(空气)在寻找众数前置零。
- 手动指定上限:直方图不可用时(例如图像含大量负值)自行给出上限。
- 保留源通道的 slope:与原始宏一致,只影响显示,不影响存储的数据。
实测:本插件的 numpy 公式与 Dragonfly 自带的 convertDatasetCreateNew(相同参数)最大相差 3e-8,即 float32 精度。这一步必须与模型训练时完全一致,因此不做任何“改进”。
3. 第 2 步 深度学习分割
选择预处理后的通道和一个模型。模型列表来自 Dragonfly 的 AI 模型库(只列出深度学习模型);点击导入模型…可选择一个模型文件夹、model.ORSModel 文件或导出的 zip,导入后自动选中。所选模型的 ID 会被记住,下次打开时自动选中同一模型。
1. 设置牙齿类别与牙髓类别(客户模型:牙齿 = 1,牙髓 = 5)。
2. 点击运行分割并发布。推理由 Dragonfly 自己的引擎完成,期间 Dragonfly 处于忙碌状态。
3. 查看类别表:每个类别的体素数与占比,以及它被当作牙齿、牙髓还是“其他”。若牙齿或牙髓为空,状态栏会提示检查类别编号。
结果发布为 原始分割 - <通道名>:label 1 = 牙齿,label 2 = 牙髓,label 3 = 其他(可关闭)。勾选同时保留完整的 N 类分割结果可另外保留模型的原始输出。
4. 第 3 步 去噪与种子点
选择原始分割 MultiROI(牙齿/牙髓 label 会根据 label 名称自动填好)。牙齿掩膜:去除小于给定体积的孤岛(默认 20 mm³)、可选开运算、可选只保留最大的 N 个连通区、可选沿 X/Y/Z 的 2D 填洞。牙髓种子点:牙髓连通区(26 邻域)各成一个种子点;小于给定体积(默认 1 mm³)或落在牙齿之外(默认要求 ≥ 50% 在填洞后的牙齿掩膜内)的被丢弃;合并间距小于此值的种子点可把多根牙的髓室与根管碎片合并为一个。
⚠ 多类别分割是互斥的:牙髓体素在牙齿类别里是“洞”。因此“是否在牙齿内”是对填洞后的牙齿掩膜判断的——否则每一个真实的种子点都会被当成噪点丢掉。
结果发布为 牙齿掩膜 - …(ROI)和 牙髓种子点 - …(MultiROI,每个种子点一个 label)。随后请在 Dragonfly 中手动修正:擦掉牙齿掩膜里不是牙齿的部分;确保种子点 MultiROI 中每颗牙恰好一个 label(补画、合并碎片、删除多余 label)。第 4 步会直接使用修改后的对象。
5. 第 4 步 分水岭
选择(修正后的)牙齿掩膜 ROI 与牙髓种子点 MultiROI,两者必须在同一网格上。默认沿 X、Y、Z 三个方向做 2D 填洞(与原始宏一致),地形图取填洞后掩膜距离变换的负值,每个种子点从牙齿内部深处向外生长,两颗相接牙齿的边界落在它们之间最细处。
- 紧致度:0 为经典分水岭;大于 0 时边界更趋向于等距分割。
- 为没有种子点到达的连通区单独分配 label(默认开启,默认下限 20 mm³):模型漏掉牙髓的牙齿不会无声消失,而是以“无种子点 N”为名出现在结果中,并在报告中列出。
结果发布为 牙齿 分割 - …,每颗牙一个 label;表格列出每个 label 的体素数、体积、中心和来源(有种子点 / 无种子点)。完全位于掩膜之外的种子点会被报告。
6. 第 5 步 牙位编号
选择每颗牙一个 label 的 MultiROI,点击计算编号。右侧示意图从咬合面显示每颗牙的质心、FDI 编号(按象限着色)以及每个牙弓的拟合抛物线;点击某颗牙可在“步骤报告”中看到它的详情。
参数 | 含义 | 默认 |
跳过小于此体素数的 label | 原始宏清除小于 50 体素的 label;本插件只跳过并报告,不删除 | 50 |
头顶方向 | +Z 或 -Z 为上方 | +Z |
左 / 右 | 患者右侧位于 -X(放射学惯例,即原始宏的假设)或 +X | -X |
上下颌 | 自动(两颌沿矢状拟合线分开时分开;只有一颌时按牙冠位置投票)/ 强制分开 / 只有上颌 / 只有下颌 | 自动 |
前牙方向 | 自动(由牙弓弯曲方向决定)/ -Y / +Y | 自动 |
上下颌之间的最小间距 | 沿矢状拟合线,两组质心间的最大间隙至少为此值且至少是次大间隙的两倍才算两颌 | 4 mm |
编号规则:上颌右 = 1、上颌左 = 2、下颌左 = 3、下颌右 = 4;每个象限内按到中线顶点的距离排序,得到 11…18 等。一个象限超过 8 颗、某颗牙距中线不到 1 mm、只有一颌、牙弓无法拟合等情况都会在报告中说明。
⚠ 不会检测缺牙:编号只是从中线数起的位置。缺了侧切牙时,尖牙会被编为 12。
发布已编号的 MultiROI:新建一个按 FDI 顺序重排、以 FDI 命名、按象限着色的 MultiROI。直接重命名原 MultiROI 的 label:只写入名称与颜色,不删除、不重排任何 label。
7. 与原始宏的差别
- 原始编号宏对下颌也使用了上颌牙弓的顶点(变量 relVdown 计算后未使用);本插件对每个牙弓使用各自的顶点。
- 原始宏用拟合直线的残差符号分上下颌,只有一颌时会随机分裂;本插件用残差的最大间隙判断是否真有两颌,只有一颌时按牙冠位置投票,并允许强制指定。
- 原始宏假定前牙位于 -Y;本插件由牙弓抛物线的弯曲方向自动判断,并可手动设置。
- 原始分水岭宏会让没有种子点的牙齿消失;本插件报告它们并默认单独分配 label。
- 原始宏直接修改所选 MultiROI;本插件默认发布新对象,只有“直接重命名”按钮会写回原对象。
8. 环境与限制
进程内运行,只依赖 Dragonfly 自带的 numpy、scipy、scikit-image 与 PyQt6;无需 venv、联网或额外安装。第 2 步依赖 Dragonfly 自己的深度学习引擎与授权:在没有 Dragonfly 授权会话的进程中(例如独立的 Python 进程)它会拒绝加载。模型不随插件分发。
Dragonfly 2025.1 与 2027.1 均支持;五个步骤在两个解释器下通过了 102 + 60 + 69 + 8 项自动检查(数学核心、Dragonfly 适配层、离屏面板全流程、翻译目录)。深度学习步骤按 Dragonfly 自带脚本 model_trainer.py 的调用方式实现,尚未在运行中的 Dragonfly 里用客户模型实测。
Part II English Manual
Contents
1. Introduction
2. Step 1 Preprocess
3. Step 2 Deep learning
4. Step 3 Clean & seeds
5. Step 4 Watershed
6. Step 5 Numbering
7. Differences from the original macros
8. Environment and limits
1. Introduction
This plugin performs teeth segmentation and FDI numbering of a dental CBCT following one fixed procedure. The procedure is the customer's 2023 method, written as four Dragonfly 2022.2 macros (grey-value preprocessing, deep-learning segmentation, manual clean-up and pulp-seed confirmation, watershed, numbering); the plugin arranges it as five tabs and automates the automatable half of the formerly manual third step.
Menu: Prototype Apps ▸ Teeth Segmenter (CBCT).... All five tabs are always available: the objects have to be corrected in Dragonfly between steps 3 and 4, so every tab has its own object pickers, pre-selected to what the previous step just published, and a user with an intermediate object can start at any step.
⚠ Every parameter, the chosen model included, is remembered and restored the next time the panel opens. The object pickers (channels, ROIs, MultiROIs) are session state and are not remembered.
Execute All Steps with Current Settings on the Preprocess tab runs the whole workflow unattended - preprocess, deep-learning segmentation, clean and seed, watershed, numbering, publish - each step with whatever its own tab shows at the moment you press it. Two things it says plainly before you press it: it PUBLISHES six objects into the session, and it SKIPS the manual correction of the teeth mask and the pulp seeds that step 3 asks for, so the result has to be checked before it is used. Every tab stays open at all times so the parameters can be read and changed BEFORE the run; a step whose input does not exist yet refuses when you press ITS button and says which step is missing.
2. Step 1 Preprocess
Pick the CBCT channel. Analyse histogram shows the data range, the mode bin, the resulting upper bound and roughly how many voxels will be clipped. Preprocess & publish publishes a float channel named Preprocessed <name>.
- Histogram bins (128) and Mode / ratio (0.30): upper = left edge of the mode bin / ratio. Bin 0 (air) is zeroed before the mode is taken.
- Upper bound by hand: for images where the histogram rule is unusable (many negative values, for instance).
- Keep the source slope: as the original macro did; display only, the stored data are unaffected.
Measured: the plugin's numpy formula and Dragonfly's own convertDatasetCreateNew (same arguments) differ by at most 3e-8, i.e. float32 precision. This step must match the model's training exactly, so nothing about it is 'improved'.
3. Step 2 Deep learning
Pick the preprocessed channel and a model. The list holds the deep models of Dragonfly's AI library; Import model... takes a model folder, a model.ORSModel file or an exported zip and selects the imported model. The model's ID is remembered, so the same model is pre-selected next time.
1. Set the Teeth class and Pulp class (customer model: teeth = 1, pulp = 5).
2. Click Run segmentation & publish. Inference runs in Dragonfly's own engine; Dragonfly is busy meanwhile.
3. Read the class table: voxels and fraction per class, and whether it was taken as teeth, pulp or other. If teeth or pulp came back empty, the status line says to check the class indices.
The result is published as Raw segmentation - <channel>: label 1 = teeth, label 2 = pulp, label 3 = other (optional). Also keep the full N-class result keeps the model's raw output too.
4. Step 3 Clean & seeds
Pick the raw segmentation MultiROI (the teeth / pulp label indices are filled in from the label names). Teeth mask: drop islands below a volume (20 mm³), optional opening, optional keep-the-N-largest, optional 2-D hole filling along X, Y and Z. Pulp seeds: each connected component (26-connectivity) of the pulp becomes a seed; seeds below a volume (1 mm³) or lying outside the teeth (at least 50% inside the hole-filled mask by default) are dropped; Merge seeds closer than merges a multi-rooted tooth's chamber and canal fragments into one.
⚠ A multi-class segmentation is exclusive: pulp voxels are HOLES in the teeth class. 'Inside the teeth' is therefore judged against the hole-filled mask - otherwise every genuine seed is dropped as noise.
Published as Teeth mask - ... (ROI) and Pulp seeds - ... (MultiROI, one label per seed). Then correct them in Dragonfly: erase what is not a tooth from the mask; make sure the seeds MultiROI has exactly one label per tooth (paint, merge fragments, delete stray labels). Step 4 picks up the edited objects.
5. Step 4 Watershed
Pick the (edited) teeth mask ROI and the pulp seeds MultiROI; both must be on the same grid. By default holes are filled in 2-D along X, Y and Z (as the original macro did); the landscape is the negative distance transform of the filled mask, so every seed floods from the deep interior of its tooth and the boundary between touching teeth falls at their thinnest neck.
- Compactness: 0 is the classic watershed; above 0 the boundaries tend towards equidistant cuts.
- Give unreached components labels of their own (on, floor 20 mm³): a tooth whose pulp the model missed does not vanish - it appears as 'Unseeded N' and is listed in the report.
Published as Teeth segmentation - ..., one label per tooth; the table lists voxels, volume, centre and source (seed / no seed) per label. Seeds lying entirely outside the mask are reported.
6. Step 5 Numbering
Pick the one-label-per-tooth MultiROI and click Compute numbering. The schematic on the right shows every centroid from the occlusal side with its FDI number (coloured by quadrant) and each arch's fitted parabola; clicking a tooth puts its details in the step report.
Setting | Meaning | Default |
Skip labels below (voxels) | the original macro cleared labels under 50 voxels; this plugin skips and reports them, never deletes | 50 |
Up direction | +Z or -Z is superior | +Z |
Left / right | the patient's right at -X (radiological convention, the macro's assumption) or +X | -X |
Jaws | auto (split when the jaws separate along the sagittal fit; a single jaw by crown-position vote) / force the split / upper only / lower only | auto |
Anterior | auto (from the arch curvature) / -Y / +Y | auto |
Min. gap between the jaws | the largest gap between the two centroid groups along the sagittal fit must be at least this and at least twice the next gap | 4 mm |
Rule: upper right = 1, upper left = 2, lower left = 3, lower right = 4; within a quadrant the teeth are ordered by distance from the midline vertex, giving 11..18 and so on. More than 8 teeth in a quadrant, a tooth within 1 mm of the midline, a single jaw or an arch that cannot be fitted are all stated in the report.
⚠ Missing teeth are NOT detected: the number is the position counted from the midline. With a missing lateral incisor the canine is numbered 12.
Publish numbered MultiROI creates a new MultiROI relabelled in FDI order, named by FDI number and coloured by quadrant. Rename labels in place writes only names and colours into the source; no label is deleted or renumbered.
7. Differences from the original macros
- The numbering macro used the UPPER arch's vertex for the lower jaw too (relVdown was computed and never used); this plugin uses each arch's own vertex.
- The macro split the jaws by the sign of the line-fit residual, which splits a single jaw at random; this plugin tests the largest residual gap, votes on crown position for a single jaw, and allows forcing.
- The macro assumed the anterior teeth at -Y; this plugin reads the direction from the arch parabola and allows setting it.
- The watershed macro let a tooth without a seed disappear; this plugin reports such components and gives them labels by default.
- The macros modified the selected MultiROI in place; this plugin publishes new objects, and only the 'Rename labels in place' button writes back.
8. Environment and limits
In-process; only Dragonfly's bundled numpy, scipy, scikit-image and PyQt6; no venv, internet or install. Step 2 depends on Dragonfly's own deep-learning engine and licence: in a process without a Dragonfly licence session (a standalone Python, for instance) it refuses to load. The model is not shipped with the plugin.
Dragonfly 2025.1 and 2027.1; the five steps pass 102 + 60 + 69 + 8 automatic checks under both interpreters (maths core, Dragonfly adapter, offscreen end-to-end panel run, translation catalog). The deep-learning step follows the call in Dragonfly's own model_trainer.py and has not yet been exercised with the customer's model inside a running Dragonfly.