Why Some Regions in Curved-Surface Pattern Inspection Must Be Intentionally Ignored: ROI Erasure and Local Exclusion Rules

English Abstract
This article explains why some local regions inside a block ROI should be explicitly excluded from detection in a curved-surface pattern inspection system. The point is not to make ROI geometry arbitrarily complex, but to preserve the stability of the rectangular block framework while introducing a lightweight rule layer for local exclusion. The XML-based eraseSet mechanism describes where an exclusion region starts, from which side it enters the ROI, and how far it extends inward. The article also distinguishes this configuration-layer ROI erasure from another type of ambiguity caused by block overlap, which is more effectively handled at runtime by execution order control. In this sense, local exclusion and execution priority belong to different layers of the system, but both serve the same goal: bringing local ambiguity back into a controllable range.

在前面几篇里,我已经讨论了这套系统的问题本体、模板如何组织、配准如何发挥作用、缺陷如何沿测量集被逐点测出来,以及整套系统为什么能够在真实产线上稳定跑起来。

但即便到了这一步,检测区域本身仍然不意味着“框出来就都该检”。

这其实是工业系统里一个很容易被忽略、但又非常现实的问题:

某个 block 的 ROI 一旦确定,并不等于这个 ROI 内的所有局部都适合继续参与检测。

换句话说,问题并不总是出在“算法不会检”;有时恰恰出在:

某些局部区域本来就不该被纳入当前 block 的检测范围。

如果这一点没有被显式处理,那么后面的误判就很容易被一路带出来。而在这套系统里,解决这个问题的办法,并不是推翻原有的矩形 ROI 体系,也不是贸然引入更复杂、更高风险的多边形 block,而是在 xml 层增加了一组非常轻量、但很有力量的局部几何规则:eraseSet

这一篇,我想专门把这件事讲清楚:

  1. 为什么有些 ROI 内部需要“局部禁检”;
  2. eraseSet 到底在描述什么;
  3. 为什么这不是补丁,而是一组显式的局部几何规则;
  4. 为什么 ROI 擦除和 block 相交其实不是同一个问题;
  5. 为什么某些 block 相交带来的歧义,反而更适合由执行顺序去消解。

一、为什么有些 ROI 内部需要“局部禁检”

如果只从表面理解,检测系统似乎只要把一个 block 框出来,然后在这个矩形 ROI 内继续完成配准、测量和缺陷判定即可。

但真实现场里,事情并不总是这么干净。

因为 block 的矩形 ROI,本质上是一种工程上稳定、实现上简单、并行上友好的局部组织方式。它的优点是清楚、稳健、容易实施,也便于和模板、配准、多线程任务拆分一起形成完整系统;但它并不意味着 ROI 里的每一个像素区域都天然适合参与检测。

换句话说,矩形 ROI 是一种检测组织单元,而不是天然精确的语义边界。

这就意味着:在某些具体产品和具体图样里,ROI 内部可能会出现一些局部区域,虽然几何上被框进来了,但从检测逻辑上看,并不应该继续参与当前 block 的缺陷判断。如果不把这些区域显式排除掉,误判就很容易被带出来。

所以,这一层真正要解决的问题并不是“如何更复杂地表达 ROI”,而是:

在保留矩形 block 体系稳定性的前提下,如何把当前 block 中那些本来就不该检的局部区域,从检测链里显式拿掉。

二、eraseSet 到底在描述什么

在前面第三篇讨论模板结构时,已经看到这套系统会把字符模板、全局几何锚点、block 序列和模板入口统一组织进同一份 xml 文件中。eraseSet 正是这份模板 xml 里的另一层标签。它并不负责描述字符骨架或几何锚点,而是专门用来定义:在某个 block 的矩形 ROI 内,哪些局部区域应当被显式排除出当前检测范围。

最直接的形式,就是下面这样的配置:

<eraseSet size="1">
    <erase dock0="right" dock1="begin" enterDist="0" range="0" type="1"/>
</eraseSet>

这段配置看起来很短,但它做的事情并不简单。它并不是在“随便删掉一块区域”,而是在描述:

  • 针对某一类 ROI,从哪一边进入;
  • 在这一边的哪个位置开始;
  • 向内擦除多深;
  • 沿这一边擦除多大范围。

具体来说:

  • dock0:标识从 ROI 的哪一边进入擦除,可取 leftrighttopbottom
  • dock1:标识在该边的哪个位置开始擦除,可取 begincenterend
  • enterDist:标识擦除区域向 ROI 内部伸进的距离
  • range:标识擦除沿该边扩展的范围
  • type:对应当前作用的 block / 模板 类型

也就是说,eraseSet 不是模糊补丁,而是一组显式的局部几何规则。它把“哪些区域不该继续参与当前检测”这件事,从实现层的临时判断,提升成了配置层的正式描述。

三、擦除不是手工补丁,而是一组显式局部几何规则

如果只看参数名,dock0="left"dock1="center" 这样的写法会显得有些抽象。下面这两幅示意图可以更直观地说明:擦除规则并不是随意抹掉一块区域,而是在 ROI 内显式定义“从哪一边进入、从哪个位置开始、向内延伸多深”的局部禁检区。

dock0="left", dock1="center" 的擦除示意图

图 1: dock0="left"dock1="center" 的局部擦除示意。表示从 ROI 左边进入,并在左边的中段位置开始定义擦除区域。

dock0="bottom", dock1="begin" 的擦除示意图

图 2: dock0="bottom"dock1="begin" 的局部擦除示意。表示从 ROI 下边进入,并在该边的起始位置开始定义擦除区域。

一旦结合这两幅图再看 eraseSet,它的工程意义就会很清楚:这不是一种“现场看着不顺眼就手工抹掉”的做法,而是在矩形 ROI 体系内部,增加一层可配置、可解释、可复查的局部禁检规则。

这也是为什么我会觉得它非常“工业”。因为它并没有推翻原有 block 体系,也没有把问题升级成更大、更复杂的几何表达问题,而是:

  • 保留矩形 ROI
  • 保留原有模板与配准链;
  • 保留原有实施方式与并行组织;
  • 只对局部确实不该参与检测的区域做最小修正。

从这个角度看,擦除功能的真正意义不在于“删掉一块区域”,而在于:

把局部不该检的地方,从系统层面明确写出来。

四、为什么没有直接把 block 改成多边形

从纯几何表达角度看,如果 block 的目标区域本来就不是矩形,那么一个看起来很自然的想法就是:

既然矩形 ROI 会把一些不该检测的区域一起框进来,那为什么不干脆把 block 设计成多边形?

这个想法在几何上当然成立。多边形 ROI 理论上更自由,也更容易贴合对象边界。

但在工业检测系统里,“表达更自由”并不天然等于“系统更好”。

因为一旦从矩形 ROI 改成多边形 ROI,复杂度会立刻沿着整条链扩散:

  • 模板创建复杂化;
  • 实施工程师标注难度上升;
  • ROI 提取与内存组织复杂化;
  • 后续 mask、裁切和边界处理复杂化;
  • 配准误差与边界误差的容忍度变低;
  • 多线程任务拆分和现场调试风险一起上升。

更重要的是,多边形 ROI 虽然在表达上更灵活,但在真实现场里往往更“脆”。因为它贴得越紧,对局部定位误差、局部形变和成像扰动就越敏感。于是原本为了“更精确”而引入的复杂表达,最后反而可能把系统带向更高的误判风险和更低的可实施性。

所以,从工程角度看,多边形 block 并不是一个“更先进”的自然升级,而更像是把一个局部问题,推向了整条系统链的高风险复杂化。

也正因为如此,eraseSet 这种做法才显得非常成熟:它不追求几何表达的最大自由度,而是在保留矩形 block 体系稳定性的前提下,用最小改动去消除局部歧义。

五、为什么 ROI 擦除和 block 相交其实不是同一个问题

这里需要特别澄清一件事:

ROI 擦除并不等于 block 相交问题的主解法。

这两件事在表面上都像“局部区域不该继续参与检测”,但它们其实属于两个不同层次的问题。

1. ROI 擦除解决的是单个 block 内部的局部禁检

也就是说,当前这个 block 已经确定,ROI 也已经确定。问题在于:这个 ROI 里有一小块区域,本来就不该继续参与当前 block 的检测。这时,eraseSet 的作用就是把这块区域显式擦掉。

2. block 相交解决的是不同 block 之间的局部歧义

而另一个问题——两个矩形 block 几何上发生交集,容易引起多镭误判——本质上并不是“当前 ROI 内有块地方不该检”,而是:

同一局部区域同时进入了两个 block 的检测视野。

这是另一层问题。它的核心不是“当前 block 自己该不该看这块区域”,而是“两个 block 谁该先看、谁该后看,以及谁的结果应该在这个局部优先成立”。

也正因为如此,它最漂亮的处理方式,并不是继续往 eraseSet 里堆规则,而是运行层的执行顺序控制。

六、为什么某些 block 相交,反而更适合靠执行顺序解决

对于少数存在几何交集的 block,现场上效果最好的办法,并不是强行再去增加一层显式擦除,而是:

  1. 先运行那个“插入别人区域”的 block
  2. 它运行完以后清理自身影响;
  3. 再运行另一个受影响的 block
  4. 后者就不会再受到相交区域的污染。

这个思路本质上并不是 ROI 擦除,而是一种执行层的局部消歧策略

我更愿意把它理解成:

通过 block 执行优先级,先处理局部歧义的主动一方,再让后续 block 在更干净的局部区域上继续检测。

这件事之所以重要,不只是因为它“现场效果很好”,而是因为它说明这套系统在遇到复杂局部歧义时,并不是执着于用同一类几何规则去解决所有问题,而是:

  • 配置层的问题,用配置层规则解决;
  • 执行层的问题,用执行层调度解决。

这其实是一种非常成熟的系统判断。

当然,这里也要说清楚:这种顺序控制更接近实现层的工程经验,而不是像 eraseSet 那样的显式几何规则。它可以作为少数特殊局部歧义的漂亮解法,但不应取代 ROI 擦除,去承担“哪些区域本来就不该检”这种更基础的配置层职责。

七、所以,这一层体现的不是补丁思维,而是工程判断

把这一篇讲到这里,其实就能看清一件事:这套系统面对局部歧义时,并没有简单地走向“更复杂的几何表达”,也没有把所有问题都压成同一种补丁,而是很清楚地区分了两类事情:

  • 哪些地方本来就不该检:用 eraseSet 这样的显式局部几何规则解决;
  • 哪些地方是不同 block 之间的局部相交歧义:用执行顺序这样的运行层策略去消解。

这两者分别属于配置层和执行层。真正体现成熟度的,并不是“功能越多越好”,而是:

在什么层次的问题上,用什么层次的规则去解决。

所以,如果要把这一篇压缩成一句话,我更愿意这样说:

显式 ROI 擦除解决的是“哪些地方本来就不该检”,而执行优先级解决的是“局部相交时谁先看、谁后看”。这两者分别属于配置层和运行层,共同把局部歧义收回到了可控范围。

下一讲,我更愿意继续沿着这一点往下写:当模板、ROI、局部测量与运行层调度都已经建立起来之后,这套系统是如何在现场不断吸收新增需求、同时又努力维持主干稳定的。