关于 VoxelSieve
VoxelSieve 是用于工业 CT 体数据处理的开源工具,面向检测和材料分析工作流。它可将大型扫描流式处理为稀疏数据集,并提供孔隙分析、表面比较、分割、厚度测量和报告工具。
主要功能
- 01将大型 CT 扫描流式转换为稀疏 VDB 数据集
- 02检测孔隙和疏松区域
- 03将表面与 CAD 模型比较
- 04分割材料并对体数据降噪
- 05测量壁厚
- 06生成检测报告和 DICONDE 序列
适用场景
- 01处理超出可用内存的大型 CT 体数据
- 02检测铸件中的孔隙
- 03将受检零件与 CAD 模型比较
- 04根据扫描分析生成检测报告
MCP 相关
`vs-gui` 浏览器界面可通过 `--mcp` 向 AI 系统提供服务。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
VoxelSieve
面向工业 CT 体数据的开源工具,基于 OpenVDB 构建。
重建后的 CT 体数据是大型、未压缩的原始文件,其中大多数体素都是空气。 VoxelSieve 会将周围的空气与零件分离,保留孔隙等内部空洞,并将结果存储为稀疏分块 VDB 数据集,适用于大于内存容量的扫描数据。在此基础上,它还能查找孔隙和疏松微观结构,并生成检测报告。
| CT 切片 | 孔隙率分析 | 检测报告 |
|---|---|---|
![]() | ![]() | ![]() |
| 钟形壳体合成扫描的剖面:发动机法兰处有疏松区域和缩孔 | vs-porosity:红色表示孔隙,黄色表示疏松区域 | vs-report:按检测区域评估(BDG P 202 方案) |
孔隙率分析的所有图像均来自钟形壳体样件的一次合成扫描,尺寸为 765 × 765 × 380 个体素,体素大小为 0.1 mm(445 MB);扫描中包含位于铸件最后凝固部位的缩孔和疏松区域:vs-synth --part bellhousing --voxel-size 0.1 --hot-spots --lunker 12 --lunker-radius 0.9 --lunker-spread 0.6 --loosening 3 --loosening-radius 1.5 --noise 500 --cupping 0.08 --blur 0.07 --seed 12。每个缩孔体积的测量误差均在真实值的 2% 以内(最小的缩孔为 0.06 mm³,误差在 4% 以内);法兰深处的区域误差在 2% 以内,表面下方的区域误差在 10% 以内;零件体积的误差在 0.02% 以内。
状态:早期开发阶段,最新版本为 0.3.1(参见 CHANGELOG.md)。初次使用? 快速入门指南将通过样例数据,介绍如何从下载开始,借助 AI 助手生成孔隙率报告。工具包括:
| 工具 | 功能 |
|---|---|
vs-sieve | 原始体数据(含厂商标头)或 TIFF 堆栈 → 稀疏分块数据集,流式处理,不受内存限制 |
vs-porosity | 孔隙和疏松区域 → JSON、投影图像、适用于 Blender 或 Houdini 的 VDB |
vs-surface | 数据集 → 表面,形式为紧凑距离掩码、网格或 VDB 等值面 |
vs-segment | 数据集 → 按灰度值或学习模型(--model)划分的材料类别,并根据标签评分 |
vs-denoise | 数据集 → 降噪后的数据集(非局部均值或学习模型);--benchmark 用于比较两者 |
vs-compare | 表面 + CAD 模型(STL)→ 对齐后的理论值与实测值偏差、统计数据、彩色 PLY |
vs-thickness | 数据集 → 每个表面点的壁厚(射线或球体)、薄壁和厚壁区域、彩色 PLY;--volume-map 计算每个材料体素的厚度 |
vs-diconde | 数据集 + 孔隙 + 材料 + 检测顺序 → DICONDE 序列;--info 显示一个序列的信息 |
vs-report | 孔隙率分析 + 验收限值 → 检测报告(HTML,可打印为 PDF) |
vs-battery | 电池单体 → 壳体、电极层、负极超边、颗粒、空隙、报告 |
vs-gui | 带向导、撤销、切片和 3D 视图的浏览器界面;--mcp 可将其提供给 AI 系统 |
vs-synth | STL 网格 → 含缺陷、噪声和伪影的合成 CT 扫描,以及真实值数据 |
vs-phantom | 带解析真实值的简单盒状模体 |
构建
依赖项来自 vcpkg,并在 vcpkg.json 中固定版本。在 Ubuntu 24.04 上:
sudo apt-get install cmake ninja-build g++ git curl zip unzip tar autoconf automake libtool pkg-config
tools/setup-vcpkg.sh && export VCPKG_ROOT=~/vcpkg
cmake --preset release && cmake --build --preset release && ctest --preset release
./build/release/apps/vs-phantom/vs-phantom --out phantom --dims 256
这会写入 phantom.raw(uint16,小端序,x 方向最快)和 phantom.json,其中包含格式说明和解析得到的真实值(孔隙、壁厚、材料体积)。
首次配置会从源代码构建 OpenVDB、Boost 和 TBB,耗时较长;vcpkg 会将构建结果保存在二进制缓存中,供后续构建使用。在切换到 vcpkg 之前配置的构建目录不会采用其工具链;请使用 --fresh 重新配置(cmake --preset release --fresh)。
在 Windows(x64,安装了 C++ 工作负载的 MSVC 2022 构建工具,并在 PATH 中包含 Git Bash 的 Developer PowerShell 中)和 macOS(Apple 芯片,Xcode 命令行工具,以及通过 brew install ninja autoconf autoconf-archive automake libtool pkg-config 安装的工具)上,请改用 windows 或 macos 预设,而不是 release。在 Windows 上,程序会生成到 build/windows/bin。
筛选体数据
VoxelSieve 可写入分块数据集(大小不限,流式处理)或单个 .vdb 网格(适用于小型体数据,载入内存处理)。
用于大型扫描的分块数据集
./build/release/apps/vs-sieve/vs-sieve scan.raw --out scan.vsieve
scan.vsieve/ 包含 index.json、overview.vdb(将整个体数据存储在一个网格中,最多包含 256³ 个体素)以及 level0/、level1/……,其中每个 256³ 分块对应一个 VDB 文件。仅包含外部空气的分块不会写入。输入文件通过内存映射,并分两遍流式处理,因此扫描数据无需全部载入 RAM。--phantom N 会筛选计算生成的 N³ 幻影数据,而不是处理文件。
CT 系统生成的原始文件通常带有专有文件头。VoxelSieve 会跳过它:给定尺寸后,文件中超出体素数据的部分都会被视为文件头,并打印检测到的大小。如果文件还包含尾部数据,请使用 --header <bytes>;对于 8 位数据,请使用 --type uint8;对于大端序 16 位样本,请使用 --big-endian。请检查打印出的文件头大小:如果尺寸设得过小,也会留下多余字节,并被误认为文件头。
| 输入 | 原始大小 | 数据集 | 耗时 | 峰值内存 |
|---|---|---|---|---|
| 1024³ 原始文件(mmap) | 2 GB | 776 MB | 6.1 s | 2.5 GB,其中约 2 GB 是可回收的映射输入页 |
| 1024³ 计算生成的幻影数据 | (2 GB) | 776 MB | 35.5 s | 0.46 GB |
| 2048³ 计算生成的幻影数据 | (16 GB) | 5.8 GB | 345 s | 0.87 GB |
计算生成的幻影数据耗时更长,因为每个体素都会计算两次;其内存数据反映的是筛选器自身的占用,不包括映射输入页。
程序通过 voxelsieve::Dataset 读取数据集,该对象会按需将分块载入带有内存预算的 LRU 缓存:
const auto dataset = voxelsieve::Dataset::open("scan.vsieve", /*cache_bytes=*/4ULL << 30U);
std::optional<float> value = dataset.sample(0, {512, 400, 300}); // nullopt for removed air
std::vector<float> slab(512 * 512 * 16);
dataset.readRegion(0, {{0, 0, 300}, {512, 512, 316}}, slab); // across brick boundaries
dataset.forEachGrid(1, [](const auto& brick, const auto& grid) { /* parallel, uint16/uint8/float */ });
TIFF 堆栈
./build/release/apps/vs-sieve/vs-sieve slices/ --out scan.vsieve --voxel-size 0.05
./build/release/apps/vs-sieve/vs-sieve scan.zip --out scan.vsieve # read without extracting
./build/release/apps/vs-sieve/vs-sieve scan.zip --folder target --threshold 0.5 --out labels.vsieve
./build/release/apps/vs-sieve/vs-sieve recon.zip --value-range -0.05,0.3 --out scan.vsieve # float
./build/release/apps/vs-sieve/vs-sieve pipe.zip --air-from xy --out pipe.vsieve # cut at both ends
切片目录、多页 TIFF 或二者的 ZIP 存档均可直接读取
(voxelsieve::TiffStackSource,ADR 0011)。切片按名称排序,数字按数值排序
(slice2 排在 slice10 前)。支持经典 TIFF 和 BigTIFF、条带和瓦片、未压缩、LZW、Deflate 和 PackBits,以及带或不带水平预测器的格式;支持无符号 8 位或 16
位样本;只要 32 位样本的值不超过 16 位范围(标签体),也可以接受。浮点切片(32 位或 64 位,也包括带浮点预测器的切片)会在给定的值范围内线性映射为 0 到 65535 的灰度值;值范围可通过 --value-range 指定,也可根据 33 张切片估算。映射关系会打印出来并记录在数据集的 index.json 中(value = offset + scale * grey);超出范围的值会被截断并计数(ADR 0015)。不接受彩色图像和有符号图像。如果首尾切片穿过物体(如管道或钻芯),--air-from xy`` 可让外部空气仅从侧面进入,从而保留物体内部(ADR 0003)。如果输入包含多个切片文件夹,则使用灰度值,而非名称类似标签或掩码的文件夹(label*、mask*、 seg*、gt、target);其他文件夹会被打印出来,也可以通过 --folder 选择。体素尺寸取自 OME-XML 图像描述(PhysicalSizeX、Y、Z)、厘米分辨率、非打印默认值(如 72 或 300 dpi)的英寸分辨率,或键值对形式的图像描述(包括切片 spacing);否则假定为 1 mm,并打印出来;可通过 --voxel-size设置。在 GUI 中,此操作为import_tiff。 对于数据集,切片会先在所有核心上解码一次,写入输出目录中的临时原始文件,每个体素占 2 字节(也可通过 --staging-dir 指定其他位置);处理结束后会删除该文件。--no-staging` 会直接读取切片,对于大型堆栈,速度会慢得多。
DICOM 堆栈
./build/release/apps/vs-sieve/vs-sieve dicom/ --out scan.vsieve # a directory of slices
./build/release/apps/vs-sieve/vs-sieve dicom.zip --out scan.vsieve # the same in a ZIP archive
DICOM 切片目录或其 ZIP 存档(无需解压即可读取,并会逐个检查条目的 CRC)由 DCMTK 读取(voxelsieve::DicomStackSource,ADR 0019):支持未压缩或 RLE 格式,无论是否带前导码;切片按其位置沿切片法线排序。
体素尺寸和姿态取自文件。有符号样本会加上 32768,并结合重缩放斜率和截距记录为值映射,因此不会丢失任何值。如果目录中包含多个序列,则读取最大的序列,并打印其他序列。在 GUI 中,此操作为 import_dicom。如果切片厚度小于其间距,或切片间距远大于像素尺寸,导入摘要会发出警告(warnings);interpolate_slices(所有导入)会在测量切片之间插值填充空隙。
DICONDE
./build/release/apps/vs-diconde/vs-diconde scan.vsieve --porosity scan.porosity \
--materials scan.materials --order examples/inspection_order.json --out scan.diconde
./build/release/apps/vs-diconde/vs-diconde --info scan.diconde/volume
DICONDE(ASTM E2339)是用于无损评估的 DICOM(ADR 0024)。VoxelSieve 会将数据集写为一系列 CT 图像,每张切片对应一个文件,并保留精确的灰度值、体素尺寸和物体位置;移除的外部空气会设为气平值。检测顺序会转换为部件信息(零件、序列号、图纸、材料)、检测信息(实验室、客户、报告和订单号、检验员、相对于验收限值的评估)以及扫描设置。孔隙和疏松区域会转换为带有位置、体积和尺寸信息的指示;材料分割则会转换为同一坐标系下的第二个派生标签序列。
DICONDE 文件的读取方式与其他 DICOM 切片相同(vs-sieve、import_dicom),导入时会报告其部件信息和指示。在 GUI 中,此操作为 export_diconde。
首次预览,也适用于网络共享
./build/release/apps/vs-sieve/vs-sieve /mnt/ct-share/part.zip --out part.vsieve --preview first.png
在各轮处理前,导入过程会从整个体积中均匀选取 64 个完整切片并同时显示:沿 z、y 和 x 方向的中央剖面,平面内平均采样至每条边最多 1024 个体素、总计 3200 万个体素;以及这些切片的直方图和估算出的阈值(ADR 0020)。在分阶段导入过程中复制其余数据时,预览会逐渐变清晰:它会由粗到细读取其他预览切片,每轮读取的切片数是上一轮的三倍,并在每轮结束后显示新的预览;最后一轮的直方图涵盖整个体积。每个输入都会将数据按切片存储在一起(例如堆栈文件或原始文件的连续部分),因此每个切片只需请求一次,SMB 上也是如此。导入过程不会再次读取这些数据:网络共享上的堆栈和文件只会按切片复制一次到本地暂存文件,并优先复制预览所用的切片。本地原始文件会直接读取,只显示首次预览;其导入速度取决于各轮处理,而非读取速度。SMB 或 NFS 共享上的原始文件以及映射的网络驱动器也会被检测并暂存,而不是分成小块读取两遍。在 GUI 中,每次导入的进度条都会显示预览,并将其保存在对应步骤中(preview.png);AI 助手可通过 import_preview 获取预览。
也支持读取 gzip 压缩的原始文件(scan.raw.gz 与 scan.json 放在一起),可通过 vs-sieve、import_raw 和 GUI 的文件浏览器读取。gzip 文件只能向前读取,因此此类文件会按切片顺序解压一次并写入暂存文件;预览会在该轮处理结束时生成。如果未压缩数据包含头部,请提供 --header。
单一网格
./build/release/apps/vs-sieve/vs-sieve phantom.raw --out phantom.vdb
尺寸和体素大小从 phantom.json 读取,也可通过 --dims X Y Z 和 --voxel-size MM 指定。体素不必是立方体(ADR 0012):--voxel-size 0.33,0.33,0.6 指定 x、y、z 方向的边长;--slice-thickness 0.4 则用于记录厚度小于间距的切片(切片之间存在间隙)。所有测量、VDB 变换、图像和查看器都会使用各轴的间距。除非设置了 --threshold,否则会根据直方图估算空气与材料之间的阈值:取空气峰值与下一个材料峰值之间的谷值,因此包含多种材料的扫描中,较亮的材料也会被视为材料(只有一种材料时则采用 Otsu 分割);--margin 控制零件周围保留多少空气体素。--dense 会不进行筛选,写入每个体素,作为基准。灰度值保留输入的 16 位或 8 位精度(ADR 0021);使用 --value-type float 时,.vdb 和数据集中的每个数据块都可直接在 Blender 或 Houdini 中打开,因为它们只读取 OpenVDB 的标准网格类型。
Phantom 基准测试(中空盒体,孔隙约占总体积的四分之一,噪声 σ = 500,4 个核心):
| 体积 | 原始文件 | 密集 VDB | 筛选后 VDB | 活跃体素 | 筛选时间 |
|---|---|---|---|---|---|
| 256³ | 32 MB | 43.6 MB | 11.8 MB | 27 % | 0.03 s |
| 512³ | 256 MB | 348.9 MB | 85.9 MB | 26 % | 0.23 s |
该表的测量结果使用 32 位浮点数存储灰度值(ADR 0002),因此密集基准文件比原始文件大。根据 ADR 0021,网格会保留输入的 16 位精度:256³ phantom 的密集 VDB 占原始文件的 115%,而非 140%。
设计决策记录在 docs/adr 中。
从 STL 合成扫描
vs-synth 会将一个封闭的 STL 网格(单位为 mm)转换为原始 CT 体积,加入人工缺陷、噪声和伪影,并生成包含真值的 JSON 伴随文件。这是用于测试缺陷分析的环境。
./build/release/apps/vs-synth/vs-synth part.stl --out part --voxel-size 0.05 \
--lunker 5 --loosening 2 --noise 500 --cupping 0.1 --rings 8
./build/release/apps/vs-sieve/vs-sieve part.raw --out part.vsieve
--lunker N:缩孔,形状不规则,由相互重叠的球体组成。--loosening N:组织疏松区域(Gefügeauflockerung),包含许多接近或小于体素尺寸的小孔,孔隙率最高为--loosening-porosity(默认值为 5 %)。--noise、--cupping(束硬化)、--rings(围绕 z 轴的环形伪影)。--blur MM:成像链的模糊度,使用 sigma 为该值的高斯点扩散函数。--hot-spots会将缩孔和疏松区域放置在最厚的截面中,也就是铸件最后凝固的位置,而不是任意有空间的位置;--lunker-spread F会将缩孔尺寸调整到--lunker-radius的 (1 - F) 倍。--box X Y Z使用长方体代替 STL 文件;--part housing|bracket|hub|bellhousing使用包含壁、筋、凸台、孔和圆角的示例铸件(--scale、--stl会写出其网格)。

part.json 会列出每个缺陷的位置、尺寸和空洞体积,以及总孔隙率。灰度值会精确表示空洞体积,即使孔隙远小于一个体素也一样(参见 docs/adr/0005-synthetic-scans-from-meshes.md)。扫描会按需计算并流式写入磁盘:1040 × 840 × 640 个体素(1.1 GB),包含 15 个缺陷,在 4 个核心上耗时 41 s。
表面
vs-surface 会定位零件的表面(默认采用 ISO 50 %),并将其存储为体素掩码;每个体素占 4 位,用于编码 ±1 个体素范围内以 1/7 体素为步长的有符号表面距离;距离更远的部分只标记为“材料”或“空气”。仅存储与表面相交的 8³ 区块,并按砖块进行 zstd 压缩,因此文件大小随表面积增长,而非随扫描数据增长:
./build/release/apps/vs-synth/vs-synth --part housing --voxel-size 0.1 --blur 0.05 --out housing
./build/release/apps/vs-sieve/vs-sieve housing.raw --out housing.vsieve
./build/release/apps/vs-surface/vs-surface housing.vsieve --out housing.vss --stl housing.stl
上方的壳体(520 × 400 × 220 个体素)生成的文件大小为 156 kB,相比 16 位原始体积压缩了 588 : 1,其三角剖分表面与解析表面的距离为 0.033 个体素(RMS)。voxelsieve::SurfaceMask 可读取单个体素或区域的编码和距离,并将其转换为 VDB level set 或网格;--vdb 会导出供 Blender 或 Houdini 使用的 level set。GUI 会将其作为“Surface”操作运行,并显示掩码的中间切片。格式和测量结果见:docs/adr/0009-surface-distance-mask.md。

名义值与实测值对比
vs-compare 将扫描表面与零件的 CAD 模型(STL,单位为 mm)进行对比。它会将 CAD 模型与扫描结果对齐,并测量每个表面点的有符号偏差:零件材料多于名义值时为正,缺少材料时为负。
./build/release/apps/vs-compare/vs-compare housing.vss housing-cad.stl --out housing.compare \
--tolerance 0.1
- **对齐:**默认情况下,两个表面的主轴用于粗略对齐,再通过稳健的最佳拟合(点到平面 ICP)进行优化。CAD 模型可以处于任意位置和方向。
--align refine从--initial开始进行最佳拟合;--align none则按原样使用--initial,例如 CAD 模型已经处于扫描坐标系中时。 - 输出:
compare.json:变换、拟合结果、均值、RMS、极值和百分位数、公差内外的面积,以及直方图。deviation.ply:带有偏差值和逐顶点颜色的扫描表面。deviation_view_1.png、deviation_view_2.png:分别从上方和下方观察的着色视图。- 使用
--aligned-stl时生成的cad_aligned.stl:转换到扫描坐标系中的 CAD 模型。
- **内部空洞:**默认排除封闭内部空洞(气孔)的表面;这些属于孔隙率分析的范围。
- **柔性零件:**对于在扫描仪中无法保持名义形状的零件(薄板金属、塑料、橡胶),
--non-rigid会在刚性对齐后将扫描表面弯曲,使其贴合 CAD 模型。弯曲具有弹性且平滑:薄的部分容易弯曲,厚的部分和零件整体几乎不弯曲;小于控制点间距(--non-rigid-spacing)的特征不会被弯曲,因此凹痕、凸起和错误的壁厚仍会保留为偏差。随后在弯曲后的表面上测量偏差;deviation.ply和displacement_view_[12].png显示每个点的移动距离,而compare.json保留仅经过刚性对齐的结果数据以供对比 (docs/adr/0022-non-rigid-registration.md)。
在合成铸件上,拟合可将 CAD 模型的位姿确定到 0.15 个体素的精度,并以 0.02 mm 的精度测量 0.4 mm 的凹痕。GUI 会以“名义值与实测值对比”这一操作运行比较,并在 3D 视图中将彩色表面显示为“名义值与实测值偏差”。方法与决策详见:docs/adr/0010-nominal-actual-comparison.md。

壁厚
vs-thickness 无需 CAD 模型,即可测量零件表面各点的壁厚,并找出厚度超出图纸允许范围的区域:
./build/release/apps/vs-thickness/vs-thickness housing.vsieve --out housing.thickness \
--min-wall 2.5 --max-wall 8
- 方法:
--method ray(默认)沿灰度值穿过内法线,到达壁的另一侧表面,精度可达一个体素的分数,如同使用卡尺测量。如果射线从边缘离开壁,或沿着加强筋穿过,而到达的表面不在搜索角度范围(--search-angle,默认 30°)内,则该点不测量,而不会报告一个并非壁厚的长度。--method sphere则取材料内部与该点接触的最大球体直径:这种方法可在所有位置测量,包括加强筋和拐角,但根据定义,在凸边处测得的值较小。 - 气孔: 气孔会使所在处的壁变薄:其表面会限制射线和球体,但只有外层表面会获得数值(使用
--all-surfaces也会测量气孔表面)。 - 输出:
wall_thickness.json:按面积加权的统计数据(最小值、平均值、百分位数、直方图)、已测量表面的占比,以及薄壁和厚壁区域的面积、极值和位置。thickness.ply:以 mm 为单位的表面网格,每个顶点包含壁厚值和颜色。thickness_view_1.png、thickness_view_2.png:从上方和下方查看的图像;薄壁以红色表示,依次经过黄色和绿色到蓝色表示厚壁;低于最小值的区域为洋红色,高于最大值的区域为紫色,而未找到厚度不超过--max-thickness的壁时显示为灰色。
- 大型扫描: 内存中只保留表面网格(
--max-triangles);灰度值通过砖块缓存沿射线读取。 - 与 CAD 模型对比:
--nominal part.compare(vs-compare的输出)还会使用相同的方法测量对齐后的 CAD 模型在各点的名义壁厚,并计算实际壁厚与名义值的偏差:例如,芯部偏移导致两侧壁厚都偏离设计值。thickness.ply会为每个顶点添加nominal和deviation,thickness_deviation_view_[12].png会显示这些偏差。 - 零件内部:
--volume-map还会将每个材料体素的局部厚度(包含该体素的材料内部最大球体直径)写入数据集thickness_map/,并附带统计数据、超出限值的区域,以及最厚处的切片。它能找到表面无法显示的材料堆积,例如壁与法兰交接处的热点。厚度超过--map-max-thickness(默认值:零件最小尺寸,最多 64 个体素)的材料会记为该值。凸边归入其界定的壁。
GUI 会将其作为“壁厚”操作运行,并在 3D 视图中以“壁厚”显示彩色表面(进行名义值与实际值对比后,也会显示名义壁厚),并在切片视图中叠加显示厚度图;报告会新增壁厚部分(见下文)。方法和决策详见:
docs/adr/0030-wall-thickness.md。

孔隙率分析
vs-porosity 可在筛选后的数据集中查找内部孔隙和微观结构疏松区域:
./build/release/apps/vs-porosity/vs-porosity part.vsieve --out part.porosity
porosity.json:零件体积、孔隙率,以及每个孔隙和区域的中心、边界和空洞体积。projection_x.png、projection_y.png、projection_z.png:零件的灰度厚度图,孔隙以红色显示,区域以黄色显示。porosity.vdb:数据集世界坐标空间中的pores和zones网格,可在 Blender 或 Houdini 中与零件一同查看。
孔隙体积根据灰度值计算,因此边缘处部分填充的体素会按其占比计入。区域由 8³ 个体素组成的块构成,其灰度值明显低于表面下相同深度处的材料灰度值,因此不会将束硬化造成的碗形效应报告为孔隙率(参见 docs/adr/0006-porosity-analysis.md)。在一个 830 MB 的合成扫描数据集上(1025 × 775 × 525 个体素,含 6 个缩孔、3 个疏松区域、噪声和 10 % 的碗形效应),每个缩孔的体积与真实值相差不超过 2 %,每个区域相差不超过 2 %,总孔隙率相差不超过 1 %;在 4 个核心上,分析耗时约 30 秒。距外部空气不超过 3 个体素的体素会从区域检测中排除,因此不会将斜面、圆角和孔等部分体积边缘穿过体素块的结构误判为疏松材料。
PorosityOptions 以及 --min-pore、--zone-sigma 和 --zone-min 选项用于设置检测阈值。
检测报告
vs-report 会运行孔隙率分析,将分析结果与检测订单的验收限值进行评估,并将检测报告写入一个独立的 HTML 文件(可在浏览器中打印为 PDF):
./build/release/apps/vs-report/vs-report part.vsieve --order examples/inspection_order.json \
--out part.report
报告结构参照 ISO/IEC 17025(7.8)的报告内容和 ISO 15708-3 的 CT 检测报告:订单、零件、方法、扫描设置、分析参数和检测限、含投影图像和孔隙列表的结果、评估及批准。检测订单(examples/inspection_order.json)提供扫描无法获知的信息,例如客户、零件编号或管电压;缺失的必填字段会在报告中标记为“未提供”,并以警告形式打印。
验收遵循 BDG P 202 的方案:每个检测区域(数据集坐标中的一个框,或整个零件)可选设置最大孔隙尺寸、超过某个尺寸的孔隙数量、孔隙率,以及是否允许疏松组织的限值。限值由图纸或客户提供。
使用 --surface part.vss(来自 vs-surface)时,报告会以 3D 形式展示零件及其孔隙:零件呈玻璃质感,孔隙为红色,疏松区域为琥珀色,并按真实比例显示。使用 --comparison part.compare(来自 vs-compare)时,报告会加入名义值与实测值的对比:关键数值、从上方和下方观察的彩色偏差图,以及偏差直方图。使用 --wall-thickness part.thickness(来自 vs-thickness)时,报告会加入壁厚信息:统计数据、彩色视图、直方图,以及薄壁和厚壁区域。订单中的 wall_thickness 部分用于设置限值,max_area_below_min_mm2 可容许锐边等位置的小面积薄壁区域,而不是仅依据最薄点进行判定。分析生成壁厚图(--volume-map)后,报告也会显示该图;max_mm 还会评估零件内部最厚的位置。提供 CAD 模型(--nominal)时,nominal_tolerance_mm 用于评估与名义壁厚的偏差,max_area_outside_nominal_mm2 可容许少量区域超出该范围:
"wall_thickness": { "min_mm": 2.5, "max_mm": 8.0, "max_area_below_min_mm2": 5.0,
"nominal_tolerance_mm": 0.4, "max_area_outside_nominal_mm2": 5.0 }
在 GUI 中,如果项目已有最新的表面、对比和壁厚结果,报告步骤会采用这些结果。视图由 CPU 渲染(voxelsieve/render.hpp),无需 GPU。
对于纤维复合材料及其他由多种材料构成的零件,GUI 中的报告步骤还会采用材料分割结果(含灰度值、体积和占比的材料信息,以及按材料着色的切片)和纤维取向结果(含方向、占比和离散度的纤维族信息,以及按方向着色的切片)。订单中的 fibres 部分用于设置各纤维族的要求,并分别与名义方向最接近的实测纤维族进行比较:
"fibres": { "families": [
{ "name": "Warp", "direction": [0, 0, 1], "tolerance_deg": 5,
"min_share_percent": 40, "max_share_percent": 60 } ] }


报告布局使用模板:vs-report --print-template > my_template.html 会输出内置模板,--template my_template.html 则使用自定义模板。模板采用 Mustache 子集语法({{name}}、{{#list}}...{{/list}}、{{^name}}...{{/name}});输出中的 report.json 展示所有可用数据。详见 docs/adr/0007-inspection-report.md。
尺寸测量和首件报告
measure_dimensions 操作会测量扫描表面上图纸所标注的特征,其中 CAD 模型通过名义值与实测值对比(compare_cad 或 compare_objects)进行定位。以 CAD 模型坐标为基准的检验计划(examples/first_article_plan.json)通过特征上的点来指定特征:在 CAD 模型上查找平面、圆柱、球体和点,使用最小二乘法将其拟合到扫描表面,并将零件基准对齐(3-2-1、RPS)或保持最佳拟合状态。特征包括尺寸(直径、半径、距离、角度、坐标)、形状(平面度、圆柱度、球度)、方向(平行度、垂直度)、位置、轮廓和点偏差,每项都包含其气泡编号、名义值和公差。GUI 方法 cad_features 会以图片形式列出 CAD 模型的常规几何特征,因此无需 CAD 系统即可编写计划。
first_article_report 会生成首件检验报告:封面(供应商、客户、零件、图纸和修订版本、提交原因,来自 examples/first_article_order.json)、判定结果、包含名义值、公差、实测值和结果的特征列表、以红色和绿色气泡标注特征编号的 CAD 模型视图、测量特征,以及在项目包含这些内容时的名义值与实测值对比和带有验收限值的孔隙率。与测试报告一样,它会生成一个 HTML 文件,使用可替换模板(vs-report --print-first-article-template),并附带 report.json 和 characteristics.csv。拟合采用最小二乘法,而非最小区域法;有关方法及其局限,请参见 docs/adr/0027-dimensional-measurement.md。

电池单体
vs-battery(操作 battery_inspection)可检验圆柱形(罐体内卷绕电极)或叠片式(软包、方形)锂离子电池单体:测量每个截面上的外壳直径、圆度误差、凹痕和壁厚,检测芯部、电极层数和层间距、电极堆叠中每层各边的阳极超出量、电极边缘不平整度,以及层间金属颗粒和气体空隙。通过 --order examples/battery_order.json(操作 battery_report),可生成测试报告,根据订单要求评估电池单体的超出量、层数、尺寸、圆度、壁厚、间隙、颗粒和空隙。
vs-battery --cell cylindrical --out cell --extension 3 1 0.35 40 100 # synthetic cell, defect
vs-sieve cell.raw --out cell.vsieve
vs-battery cell.vsieve --out cell_result --order examples/battery_order.json
合成电池单体的第四圈正极在顶部 60° 范围内突出;报告会在该层和角度处检测到它:

也可以检验以截面图像而非体积形式提供的圆柱形电池单体:输入文件夹或 ZIP 存档,其中每个电池单体各有一个文件夹,内含 axial_images/<angle>.png(沿轴向的纵向截面,角度对应的右半部,以及其对侧的左半部,顶部一行位于高端)和 radial_images/<position mm>.png(横截面)。外壳和层来自横截面,超出量来自每个纵向截面的两个半部,颗粒和空隙则来自所有图像(操作 battery_images)。如果不使用 --image-cell,则会检验所有电池单体,并由 cells.csv 汇总结果:
vs-battery --images scans.zip --list-cells
vs-battery --images scans.zip --out results --order examples/battery_order.json
除非通过 --pixel-size 指定像素尺寸,否则会根据纵向截面高度范围内各横截面的位置推算像素尺寸。
电池单体轴线或叠片法线必须沿体积的某一轴向。有关方法及其局限,请参见 docs/adr/0029-battery-cell-inspection.md。
项目、操作和插件
该库将工作记录为一个项目:其中包含 project.json 和每个步骤各自目录的文件夹。
每个步骤都会存储其操作、参数、输入、输出和消息;撤销和重做会移动步骤游标,而撤销后创建新步骤会丢弃已撤销的步骤。操作不会更改其输入。
voxelsieve::OperationRegistry registry;
voxelsieve::registerBuiltinOperations(registry); // open_dataset, import_raw, import_tiff, porosity, …
registry.loadPlugins("plugins"); // every *.so (*.dll) in the directory
auto project = voxelsieve::Project::create("casting.vsproj", "Casting 4711");
project.run(registry, "import_raw", {{"path", "scan.raw"}});
project.run(registry, "porosity"); // input: the latest dataset
project.run(registry, "report", {{"order_path", "examples/inspection_order.json"}});
project.undo();
插件是一个共享库,它导出 voxelsieve_plugin_api_version() 和
voxelsieve_register_operations();examples/plugins/histogram 是一个完整示例。请参阅
docs/adr/0008-gui-projects-operations-ui.md。
GUI
vs-gui 会启动 GUI 并打印其地址,默认地址为 http://localhost:8410。浏览器
界面会引导你完成三个步骤:选择数据集(或导入原始文件)、运行孔隙率分析等操作,以及创建检测报告。每个步骤都会连同其
参数和结果显示在操作记录中,并且可以撤销(Ctrl+Z)和重做;项目会在每个步骤后保存。插件会显示在内置操作旁边。

视图显示沿 x、y 或 z 轴的切片。它只会从与缩放级别相匹配的分辨率层级加载屏幕上的分块,因此处理数百 GB 的扫描数据时仍能保持快速。滚轮可缩放, 拖动可平移;方向键(或 Shift 加滚轮)可切换切片;孔隙会以红色着色,疏松区域会以黄色着色,点击列表中的孔隙即可跳转到该处。

3D 视图会在浏览器中对数据集的粗略层级进行光线投射(每个轴最多 256 个体素):
“表面”会根据在直方图中拖动调整的阈值为零件表面着色;“传递函数”
会按灰度值合成颜色和不透明度;“最大强度投影”会显示每条射线上的最密集值。可在直方图上编辑传递函数:点击可添加控制点,
拖动可移动控制点,双击可移除控制点;每个控制点都有自己的颜色;颜色映射(Steel、
Viridis、Ember、Copper、Grey)可重新为所有控制点着色,预设则从典型设置开始。孔隙
和区域各有自己的颜色,光照会跟随灰度渐变,沿 x 轴切开可剖开零件。背景可以是柔和的浅色、渐变或纯色。拖动可旋转零件,
右键拖动或按住 Shift 拖动可移动零件,滚轮可缩放。拉近后,视图会再次加载相机附近的零件,并使用该处像素所需的层级(/api/volume 搭配 region),
再将其渐显于粗略体积之上,因此你观察的位置会获得更高分辨率。
“提取的表面”仅显示运行“Surface”操作后得到的表面,以完整分辨率的三角网格呈现,而非粗略层级。平坦区域会使用更大的三角形;
若表面超过三角形预算(GET /api/surface?max_triangles=,默认
150 万个),则会以两倍体素尺寸重新采样,直到符合预算。沿 x 轴切开也可以剖开它。

加载体积数据后,视图会根据其直方图推荐两到三种渲染方式,每种都配有一张小图:显示材料的密度分布、低于材料密度的区域(孔隙、 疏松结构)以及更高的峰值(例如夹杂物),或者显示作为实体的零件。

项目会记住显示方式:再次打开时,阶段、切片、缩放和窗口、相机、传递函数、
颜色和背景都会恢复。“保存视图”会在项目中以名称和图片保存当前
视图(views/<id>.png);点击该视图即可再次显示,“导出图像”则会下载图片。视图用于展示,而非处理,因此它们不是步骤,撤销不会影响视图。
一个项目可以包含多个对象:处于同一全局坐标系中的扫描件和 CAD 模型(STL),每个对象都有自己的位姿(ADR 0018)。「Objects」视图会按对象的实际位置显示它们,并使用各自的颜色。对象通过按顺序应用的步骤进行对齐:「Move」手动移动、「Align by point pairs」通过在两个对象上分别点击选取点,以及「Best fit of the surfaces」(从对象当前所在位置开始,或从彼此相距较远的对象的主轴开始)。随后,「Nominal-actual comparison」会在两个对象各自所在的位置,将扫描件与 CAD 模型或另一个扫描件进行测量比较;结果会显示在 3D 视图和报告中,形式与 compare_cad 的报告类似。通过 MCP,view_objects 会将场景渲染为图片,materials 则会把分割体积中的每种材料渲染为具有相应颜色的表面。切片视图会显示所示体积切片中的其他对象:其他扫描件会以各自颜色融合显示,或以棋盘格显示;CAD 模型则显示为切割线。
当扫描件包含零件之外的内容(例如支撑零件的夹具)时,「Isolate part」(isolate_part)会生成一个数据集,其中不包含区域(以体素表示的方框)之外的体素,也不包含最大对象之外的其他对象,以便只对零件进行分割、孔隙率和体积分析(ADR 0026)。彼此接触的对象会通过先腐蚀分开、再生长复原的方式分离(separate_voxels);切割平面和圆柱则可以切除方框无法处理的部分。材料分割会使用 materials 0 自动确定材料数量:每个直方图峰值各算一种材料,或根据高斯混合模型识别出的每个肩部和尾部各算一种材料。histogram 方法会显示分割结果建议以及类别边界处的体素占比;使用 preview_thresholds 的 view_slice 可预览各类别。「Material meshes」(material_meshes)会将每种材料的表面导出为 STL,并以该材料的颜色将其添加为对象。「Measure objects」(measure_objects)会测量每种材料中的各个连通对象,或其包围的空气(材料 0,例如鱼类的鳔或空腔):体积、表面积、质心、包围盒、沿主轴的长度以及沿指定轴的长度,并以表格形式输出(objects.csv)。


vs-gui --project /data/casting.vsproj --plugins build/release/plugins
服务仅监听 127.0.0.1,且没有身份验证;请勿将其暴露到网络上。
AI 系统:MCP
vs-gui --mcp 会通过 Model Context Protocol(stdio)提供 GUI 服务,使 AI 助手能够操作 VoxelSieve:创建或打开项目、运行操作、撤销和重做,以及读取结果。它在你的计算机上运行:扫描件仍保留在原处,助手只会收到孔隙列表、测量结果、切片图像和报告等结果。
安装。 每个版本都提供适用于 Linux(x64)、Windows(x64)和 macOS(Apple silicon)的软件包,均由相同源代码构建:
voxelsieve-<version>-<platform>.mcpb:MCP 软件包。使用 Claude Desktop 打开(双击,或拖到设置中的 Extensions 页面),然后选择存放扫描件的目录。voxelsieve-<version>-<platform>.tar.gz/.zip:包含所有工具及其库。解压到任意位置即可,无需安装其他内容。voxelsieve-<version>-samples.zip:铸造外壳的合成扫描件,包含其 CAD 模型、检验顺序和缺陷真实数据,可用于快速入门。ghcr.io/yoshi5534/voxelsieve:使用packaging/Dockerfile通过 Linux 软件包构建的 Docker 镜像:默认提供浏览器 UI;使用--mcp启动 MCP(参见 快速入门)。
这些软件包目前尚未签名。在 macOS 上,使用 xattr -dr com.apple.quarantine voxelsieve-* 清除一次下载标记;在 Windows 上,SmartScreen 可能会要求确认。Linux 构建需要 glibc 2.39 或更高版本(Ubuntu 24.04、Debian 13、Fedora 40)。
注册解压后的服务,并将其作为 stdio 服务添加到任意 MCP 客户端。选项后面的目录是 VoxelSieve 读取数据和存放项目的唯一位置:
claude mcp add voxelsieve -- /opt/voxelsieve/bin/vs-gui --mcp /data/scans # Claude Code
{"mcpServers": {"voxelsieve": {"command": "/opt/voxelsieve/bin/vs-gui",
"args": ["--mcp", "/data/scans"]}}}
服务会保留上次使用的项目,并在下次启动时重新打开该项目(除非 --project 指定了其他项目,或使用了 --no-reopen),因此,每次对话都启动新服务的客户端也能找到已打开的项目。
然后可以这样提问:“导入 /data/scans/housing.raw,分析孔隙率,并按照示例订单编写一份检验报告”,或“显示最新数据集的第 400 层切片,并标出孔隙”。客户端可以取消正在运行的导入或分析;操作会在下一次报告进度时停止。大型扫描的导入和分析可能耗时较长,超出客户端等待单次调用的时间:使用 background: true 时,run_<operation> 工具会立即返回;wait 会持续跟踪操作(每次调用最多 50 s),并在操作完成时返回其步骤;cancel 会停止操作。pipeline 可在一次调用中依次运行多个操作,例如导入、isolate_part、segment_materials 和 material_meshes。
工具:project_create、project_open、project_status、project_save_as、undo、redo、objects、results、object_select、dataset_info、histogram(灰度值、阈值和建议的材料数量)、cad_features(CAD 模型的平面、圆柱和球体,并附带图片,供检验计划使用)、view_slice(带有孔隙和区域标注的切片图像)、view_objects(也会显示材料颜色)、import_preview、step_telemetry、list_files、read_file(文本文件,以及作为图像显示的 PNG 图片)、browse、wait、cancel、pipeline,以及每个操作对应的一个 run_<operation> 工具,包括插件(--plugins <dir> 或 VOXELSIEVE_PLUGIN_PATH)。为减少模型可选的工具,除非指定 --tools all,否则不提供用于保存浏览器 UI 视图的工具(view_set、view_save、view_list、view_image、view_rename、view_delete)、list_operations(tools/list 已会描述每个操作)和 object_add(与 run_open_dataset 和 run_add_mesh 相同)。工具带有注解,因此客户端可以知道哪些工具只读取数据(readOnlyHint),哪些工具会删除内容(destructiveHint)。参数架构来自各项操作;错误会作为工具错误返回,并附上原因;长时间运行的操作会报告进度。
资源:项目各步骤生成的结果文件(report.html、report.json、porosity.json、投影图片、比较结果和测量结果)会以 voxelsieve://step/<id>/<output>/<file> 的形式列出,以便客户端将其附加到对话中。数据集不会通过协议发送,只会发送其元数据和这些结果。
提示词:porosity_check(根据检验订单检查孔隙率,并生成报告)、compare_with_cad(比较名义值与实际值)、wall_thickness_check(检查壁厚是否达到图纸规定的最小值)、first_article_inspection(在扫描图上测量图纸中的特征,并生成首件检验报告)和 first_look(尺寸、体素尺寸、三个切片),可引导模型完成常规检验。
贡献
参见 CONTRIBUTING.md。提交须按照 Developer Certificate of Origin 签署。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。


