726:zoffset
2026/7/27 5:41:30 网站建设 项目流程

1

1个像素代表几微米 值越小,放大倍率越大

即:imgResolution (μm/pixel) ↓ → 同物理尺寸对应更多像素 → 放大倍率 ↑ → 细节更精细

2

Zoffset

元件级 zoffset → BaseZ

com_zoffset是每个元件所在 FOV 的真实 Z 高度,跟全局填的ZOffset做差:

差值(mm) ÷ 分辨率(mm/层) = 层偏移量

然后用这个偏移修正算法BaseZ——从基准层往上或往下挪几个像素层,保证搜索起点对准实际位置。

就这么简单。
对,因为板子有翘曲,不同位置的元件实际 Z 高度不一样。

全局 ZOffset = 1.5 ← 用户填的,假设整板是平的 实际: 左边翘起来了 → 左边元件实际 Z = 1.8 → component_zoffset = 1.8 右边塌下去了 → 右边元件实际 Z = 1.2 → component_zoffset = 1.2

如果全用全局 1.5 算 BaseZ,左边元件搜偏低了(找不着基准层),右边元件搜偏高了(也找不着)。

所以路径规划给每个元件算自己的 zoffset,一键配置时逐个换算成各自的 BaseZ,消除翘曲影响。

3


1. Shape(形状)

PCB 上一切可检测的图形元素,是系统的最小操作单元。

Shape = 图形(能画出来) + 检测数据(能算出来)
  • Board:基板,PCB 的物理边界
  • PadCircle:检测窗,划定一个圆形/椭圆形检测区域

2. 坐标

同一位置有两套坐标表达:

坐标类型含义类比
物理坐标(StartX, EndX, mm)PCB 上的真实位置现实世界的位置
像素坐标(PixelStartX, PixelEndX, px)图像上的位置照片上的位置

通过Matrix(变换矩阵)互相转换。


3. Status(状态)

每个 Shape 在检测过程中会经历一系列阶段,用位标志叠加表示:

待检测 → 扫描中 → 扫描完 → 重建中 → 重建完 → 检测中 → 结果(OK/NG)
状态含义
ReadyToExecute准备好了,等待执行
Scaning正在拍照扫描
Reconstructing正在 CT 算法重建 3D 图像
Detecting正在分析检测
ResultOK检测通过 ✅
ResultNG检测不通过 ❌

UI 根据 Status自动变色

4. CT(计算机断层扫描)

用 X 光从不同角度拍摄,重建出物体内部的 3D 图像

三个关键参数:

参数含义单位
imgResolution分辨率,每个像素代表多大mm/pixel
zoffsetZ 轴偏移,焦平面上下移动mm
层数重建多少层切片
imgResolution 越小 → 放大倍率越高 → 看得越精细 zoffset 正 → 焦平面上移;负 → 焦平面下移

6. Drill(钻孔)

PCB 上需要检测的孔位,分两种:

类型说明
通孔(Through Hole)从上面钻穿到下面
背钻(Backdrill)钻到某一层就停,不钻穿

背钻根据方向再分:上钻(从上面钻)、下钻(从下面钻)、上下都钻

DrillStandard= 同一个钻孔规格{ 深度, 半径 },同类钻孔归为一组,共用检测算法。


概念关系总图

Board(基板,PCB 物理边界) │ ├─ Component(元件) │ └─ 一组相关的检测窗 │ ├─ PadCircle(检测窗) │ ├── 坐标(物理 ↔ 像素) │ ├── CT 参数(分辨率 + Z偏移) │ ├── Status(检测生命周期状态 → 驱动颜色) │ ├── AlgorithmViewShapes(子形状) │ └── 检测结果 │ ├─ DrillData(钻孔数据) │ └── 孔类型(通孔/背钻)+ 钻深 + 层厚 │ └─ Template(检测模板) └── 复用配置到同类 Shape

一句话总结

Shape是基本单元,通过CT 重建(分辨率 + Z 偏移)获取内部图像,经历Status 生命周期(扫描→重建→检测→结果),UI 随状态)。

3

三个全局SemaphoreSlim,全部并发数 = 1:

_reconstructLock (1) → 重建:engine.setupResolver → 提交投影 → pollReconDone _extractGlobalLock (1) → 提取:CT 体数据从 C++ 引擎拉到内存 _detectGlobalLock (1) → 检测:ExecuteAlgoProcess 调 C++ 算法

为什么都设成 1?

C++ 重建/提取/算法引擎底层不是线程安全的,多个 Job 同时调会崩。所以每个阶段同一时刻只允许一个 Job 在跑。

实际跑法:

扫图完了之后,10 个 Job 并行跑,但每到重建/提取/检测这仨环节,谁先抢到锁谁先进,剩下的await排队:

Job1 重建 ──┐ Job2 重建 ──┤ → _reconstructLock.WaitAsync() → 抢到的先跑,其他排队 Job3 重建 ──┘ ↓ Job1 提取 → Job2 提取 → Job3 提取 (_extractGlobalLock 排队) ↓ (保存体数据 和 检测 并行) Job1 检测 → Job2 检测 → Job3 检测 (_detectGlobalLock 排队)

保存体数据不依赖 C++ 引擎,所以不和检测抢锁,直接并行跑。

跟同事一句话:C++ 引擎不线程安全,三个全局锁各管一个阶段,保证同一时刻只有一个 Job 在调引擎。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询