14 几何基元检测
把一个零件放到相机下,工业视觉要回答的第一类问题往往朴素得出奇:这条边在哪里?这个孔的圆心在哪里?对位贴装靠边缘位置做运动闭环,尺寸检测靠两条边的距离,机械手抓取靠孔心坐标——它们最终都归结为同一件事:以亚像素(subpixel)精度找到图像中的点、直线、圆等几何基元(geometric primitive)。“亚像素”三个字不是噱头:一套 10 μm/像素的成像系统,若定位只能精确到整像素,测量分辨率就被钉死在 10 μm;而恰当的亚像素定位可以稳定做到 1/10 像素甚至更高——相当于不换任何硬件,把系统精度提高了一个数量级。
本章用一幅真实的工业样图贯穿所有实验(图 14.1):暗背景上放着一块跑道形(oblong)金属连接器件(2448×2048 单通道灰度,取自 Smart3 的”找点·找直线·找圆”标准方案)。零件外轮廓的上沿是一条近似水平的直边,中段平直、两端收成圆角;件内有两个左右对称的镗孔,每孔中央是镗穿后露出暗背景的圆形孔口,外圈包着一道亮起的环形台阶。我们将先沿上沿直边提取一串边缘点并拟合直线,再用圆形 ROI 分别罩住两个孔拟合圆——直边两端的圆角肩部会扮演”捣乱者”,把稳健拟合的全部价值逼出来。
14.1 边缘点提取
要定位一条边,并不需要对整幅图像做边缘检测(那是 章节 13 的主题)。工业上的做法直接得多:在一个大致框住目标边缘的 ROI 内布设 \(N\) 条相互平行的搜索线(search line),把二维定位问题拆成 \(N\) 个一维问题。每条搜索线上的处理流程完全相同:
- 取灰度剖面(gray profile):沿搜索线方向逐点读取灰度,得到一条一维曲线。
- 投影平均:在垂直于搜索线的方向上取若干像素求平均(称为投影宽度内的投影),用平均压制单像素噪声——这与 章节 6 的道理一脉相承:独立的零均值噪声靠平均抵消。
- 一阶导数定位:对平均后的剖面求一阶导数,边缘对应导数幅值的极值;幅值低于阈值的极值视为噪声,不予报告。
- 亚像素插值:设导数幅值的离散极值点及其左右邻的幅值分别为 \(g_0\)、\(g_{-1}\)、\(g_{+1}\),对这三点做抛物线插值,顶点相对极值点的偏移为
\[ \delta = \frac{g_{-1}-g_{+1}}{2\,(g_{-1}-2g_0+g_{+1})}, \]
\(\delta\) 落在 \(\pm 1/2\) 像素以内,边缘的亚像素位置即”整像素极值位置 \(+\ \delta\)“。三个采样值确定一条抛物线,顶点公式是封闭的,计算量可以忽略——亚像素精度几乎是免费的。
这套机制有一组必须理解原理才能配好的参数。边缘强度阈值(如 strengthThresh)是一阶导数幅值的准入门槛:设得太低,噪声起伏会被当成边缘;太高,对比度弱的真实边缘会漏报。极性(polarity)规定接受哪种灰度跳变——黑→白(上升沿)、白→黑(下降沿)或全部:本例从上向下扫描,从暗背景跨入亮工件,是典型的黑→白边缘;锁定极性能直接滤掉一半假边缘。边缘宽度是预期的灰度过渡带宽度,决定求导时的差分跨度:取得太小对噪声敏感,太大会把相邻的两条边糊成一条。投影宽度是抑噪与模糊的权衡:投影越宽,平均掉的噪声越多、边缘强度估计越稳,但如果边缘与搜索线不严格垂直,过宽的投影会把倾斜的边缘”抹斜”,定位反而偏移——经验上取 3~7 像素居多。边缘类型决定一条搜索线上找到多个候选边缘时报告哪一个:第一条、最后一条还是强度最佳的一条;“最佳”对油污、反光造成的弱假边缘最稳健。
图 14.2 展示了在上沿 ROI 内布设 60 条搜索线的提取结果:ROI 故意略微越过平直段、探入两端的圆角肩部,于是 60 个白十字中——中段的点沿真实直边整齐排列,而两端肩部的点随圆角明显向下偏出。搜索线忠实地报告了它”看到”的边缘位置,肩部点就这样混进了点集(按到拟合直线 \(|d|>5\) px 计,共 18 个)。如何不被它们带偏,是下一节的主题。
14.2 直线拟合:最小二乘与稳健方法
有了一串边缘点,下一步是从中估计一条直线。最小二乘(least squares,LSQ)拟合最小化所有点到直线的垂直距离平方和
\[ \min_{L} \sum_{i} r_i^2, \qquad r_i = \operatorname{dist}(\mathbf p_i,\, L), \]
解有闭式(过点集质心、方向取散布矩阵的主特征向量),快且无超参数。在所有点都”大致正确”时它是最优的——这与高斯噪声下平均最优是同一个统计事实。但它对离群点(outlier)极其敏感,原因就藏在那个平方里:残差先平方再求和,一个偏离 30 px 的肩部点对目标函数的贡献是一个偏离 0.5 px 正常点的 3600 倍。为了安抚极少数大残差点,拟合直线宁可整体偏转,让大多数好点各自多错一点——平方惩罚被大残差支配,是 LSQ 失稳的根源。
稳健估计(robust estimation)的思路是把平方惩罚换成对大残差更宽容的惩罚。Huber (Huber 1964) 的方案等价于给每个点一个随残差变化的权重:
\[ w(r)=\begin{cases}1 & |r|\le \kappa\\[2pt] \kappa/|r| & |r|>\kappa\end{cases} \]
残差不超过调节常数 \(\kappa\) 的点享受完整话语权,超过的点权重按 \(\kappa/|r|\) 衰减——残差越大,发言权越小,但不会一票否决。由于权重依赖残差、残差又依赖拟合结果,求解采用迭代重加权最小二乘(iteratively reweighted least squares,IRLS):
输入:边缘点集 {p_i},调节常数 κ
1. 用普通最小二乘拟合初始直线,所有权重 w_i ← 1
2. 重复直至收敛(直线参数变化足够小,或达到最大迭代次数):
a. 计算各点到当前直线的距离 r_i
b. 按 Huber 规则更新权重:|r_i| ≤ κ 则 w_i ← 1,否则 w_i ← κ/|r_i|
c. 以权重 w_i 做加权最小二乘,更新直线
3. 输出直线及各点最终残差
每一轮迭代里,离群点的权重被进一步压低,直线一步步向”多数好点”靠拢,通常三五轮即收敛。
另一条著名的稳健路线是 RANSAC(随机抽样共识)(Fischler 和 Bolles 1981):反复随机抽取最小样本(直线只需 2 点)拟合,统计落入容差带的”共识”点数,取共识最大的模型。IRLS 从全体点出发靠加权收敛,RANSAC 靠随机抽样撞出不含离群点的样本。离群比例很高(接近甚至超过一半)时 RANSAC 更可靠;离群点少而正常点带连续噪声时,IRLS 更精、更快,且结果可重复(无随机性)——工业边缘拟合多属后一种情形。
口说无凭,用上一节的 60 个边缘点做一组对照实验。ROI 两端各越入一段圆角肩部,落入其中的搜索线给出一小撮整体下偏的离群点(共 18 个,占 60 点的三成)。LSQ 一侧故意关掉离群点剔除(rejectRatio=1、rejectDist=20——剔除门槛 20 px 让肩部离群点全部参与拟合),Huber 一侧取 rejectRatio=10、rejectDist=5。以统一规则评估两条拟合线——只统计到各自拟合线距离 \(|d|\le 5\) px 的内点的均方根误差(RMSE):LSQ 为 2.793 px,Huber 为 1.456 px,相差近一倍;从几何上看,LSQ 的拟合线被两端肩部拉得整体下沉、并随两侧不对称的离群分布发生偏转,而 Huber 的拟合线稳稳贴住中段真实直边。
一个常见的评估陷阱:SDK 的拟合接口返回的 RMSE 是全点 RMSE——本实验 LSQ 一侧为 5.908 px,其中大头是肩部离群点自身的残差。这个数不适合用来对比两种拟合的精度:离群点对任何一条”正确”的直线都有大残差,全点 RMSE 惩罚的是数据,不是拟合。公平的对比必须用统一的内点规则(如本例的 \(|d|\le 5\) px)。
14.3 圆与椭圆拟合
定位圆孔时,搜索线从平行布设换成径向布设:用圆形 ROI 罩住孔,沿角度均匀布设搜索线,每条线沿半径方向(由里到外)扫描,其余流程——投影平均、一阶导数、亚像素插值——与直线情形完全相同。径向布设多了两个关键参数:期望半径 expectRadius 与半径容差 radiusRange,它们把搜索约束在 \([\,\text{expectRadius}-\text{radiusRange},\ \text{expectRadius}+\text{radiusRange}\,]\) 的环形搜索带内。本例 expectRadius=45、radiusRange=30,搜索带为 15~75 px。约束搜索带一举两得:孔内的孔口与孔外的环形台阶都被排除在外,假边缘大幅减少;每条搜索线的扫描长度也随之缩短,节省时间。
圆拟合分代数拟合(algebraic fitting)与几何拟合(geometric fitting)两类:前者最小化圆方程的代数残差,有闭式解、速度极快,但加权方式隐含偏差;后者最小化点到圆的真实欧氏距离,需要迭代但无偏。工业库的常见做法是用代数解作初值、几何迭代收尾,兼得速度与精度。
实验对两个孔各跑一次找圆:48 条径向搜索线全部命中孔缘,每孔得到 48 个边缘点(图 14.3 两幅子图中的白十字),黑十字标出拟合得到的孔心。左孔拟合结果为圆心 (1143.83, 1085.32)、半径 44.60 px,右孔为圆心 (1586.00, 1077.59)、半径 44.93 px,两孔孔心距(pitch)为 442.06 px。两孔的 48 个边缘点全部为有效点、剔除点为 0——这块零件孔缘完好,没有任何点偏离基准圆超过剔除门槛。孔心坐标与孔距正是连接器配合与机械手抓取所需的核心量:插针孔位定下抓取目标,孔距锁定配合方向。
稳健拟合在这里还藏着一份”副产品”值得点明:它在交付基准圆的同时,也交出了一份”哪些点不服从基准”的剔除清单。本例零件孔缘完好,剔除清单为空;可一旦孔缘出现凸起毛刺、崩缺或镗刀振纹,对应的边缘点就会偏离基准圆、被剔除门槛筛出,剔除点的位置与聚集程度直接成为缺陷的标记。换言之,以拟合圆为标称轮廓、检查各边缘点的径向偏差或剔除点的分布,即可在同一次拟合里同时完成测量与缺陷判定。章节 26 会把这一思路系统展开。
14.4 SciVision 实现
边缘点提取与直线拟合由 SCIMV::SciSvLineLocator 提供:
SCIMV::SciSvLineLocator lineLoc;
SciPointArray edgePts;
long rc = lineLoc.LinePointsLocator(src, lineROI, emptyRegion,
/*strengthThresh*/ 25, /*direction 上->下*/ 0, /*polarity 黑->白*/ 0,
/*edgeWidth*/ 3, /*projectWidth*/ 5, /*edgeType 最佳*/ 2,
/*searchLineCount*/ 60, /*findPointType 一阶导*/ 1, &edgePts);
rc = lineLoc.FitLine(edgePts, /*fitMethod Huber*/ 1, 10, 5, 0, 0, &lineHuber, &rmseHuber, &distHuber);LinePointsLocator 的参数与 小节 14.1 的原理一一对应:strengthThresh=25 是一阶导数幅值门槛;direction=0 指定从上向下扫描;polarity=0 只接受黑→白跳变(本例从暗背景进入亮工件);edgeWidth=3 与 projectWidth=5 分别是差分跨度与投影平均宽度;edgeType=2 在多个候选中取强度最佳者;searchLineCount=60 条搜索线;findPointType=1 用一阶导数极值定位。输出 edgePts 即 60 个亚像素边缘点。FitLine 的 fitMethod 取 0 为最小二乘、1 为 Huber,随后的 rejectRatio 与 rejectDist 控制拟合中的离群点剔除(剔除轮数与距离门槛)——小节 14.2 实验中 LSQ 一侧正是用 1, 20 这对取值把剔除实际关掉的。
找圆由 SCIMV::SciSvEllipseLocator 一步完成(搜索 + 拟合),对左右两孔各调用一次,孔心与半径从输出图形 circleShape 中读取:
SCIMV::SciSvEllipseLocator circleLoc;
SciROI circleROI; SciPoint center(holeCx, holeCy);
circleROI.GenCircle(center, 80); // 圆形 ROI 罩住孔缘搜索带
SciOverlay circleShape;
SciPointArray circlePts, circleEffect, circleReject;
rc = circleLoc.EllipseLocator(src, circleROI, emptyRegion, /*isEllipse*/ false,
/*strengthThresh*/ 25, /*direction 由里到外*/ 0, /*polarity 黑->白*/ 0,
/*edgeWidth*/ 3, /*projectWidth*/ 5, /*edgeType 最佳*/ 2, /*fitMethod LSQ*/ 0,
/*searchLineCount*/ 48, /*rejectRatio*/ 10, /*rejectDist*/ 5,
/*expectRadius*/ 45, /*radiusRange*/ 30,
&circleShape, &circlePts, &circleEffect, &circleReject);
SciPoint fc; double fr = 0; circleShape.GetCircle(&fc, &fr); // 取孔心与半径isEllipse=false 表示拟合圆而非椭圆;direction=0 指定搜索线由孔心向外扫描;polarity=0 只接受黑→白跳变(由暗孔口跨入亮台阶);fitMethod=0 为最小二乘拟合,rejectRatio=10 控制其离群点剔除轮数;expectRadius=45 与 radiusRange=30 划定 15~75 px 的环形搜索带(本例的圆形 ROI 半径相应取 80)。四个输出依次是拟合圆图形 circleShape、全部边缘点 circlePts、参与拟合的有效点 circleEffect 与被剔除的点 circleReject——图 14.3 两幅子图画的就是两孔各自的 circlePts 与拟合孔心。GetCircle 从 circleShape 取出孔心坐标与半径。
一个诚实的提醒:当前版本 SDK 在 fitMethod=1(Huber)时,FitLine 的 RMSE 输出参数返回的是无效值(NaN)。示例工程因此统一改用各点到拟合线的距离数组(FitLine 的最后一个输出参数)自行计算内点 RMSE——这正是 小节 14.2 中 2.793/1.456 两个数字的来源。商用 SDK 偶有这类瑕疵,工程上的对策是:关键指标尽量从原始输出(点、距离)自行复算,而不是无条件信任汇总值。生成本章全部实验图像与数字的完整可运行工程位于 code/geometric_primitives/,所用样图自包含于 code/geometric_primitives/sample/connector.jpg。
工业案例:电池极片边缘定位
锂电池卷绕工序要求阴、阳极片与隔膜对齐到 0.1 mm 量级,对齐闭环依赖对极片边缘的实时定位。难点在于极片分切后边缘普遍存在毛边:若用普通最小二乘拟合,毛边点会把边缘线拉偏,卷绕对齐随之产生系统性偏差——必须使用 Huber 等稳健拟合(或分段局部拟合后取中位)才能压住。搜索线数量是精度与节拍的直接权衡:线越多,拟合的统计精度越高,耗时也线性增长,产线上常用 30~100 条,按节拍余量取上限。另一个实战要点是 edgeType 选”最佳边缘”:极片表面的油污与辊面反光会制造强度较弱的假边缘,选”第一条”容易锁错目标,选强度最佳者则基本免疫。
14.5 小结
- 工业定位的标准流水线是”搜索线采样 → 一维边缘定位 → 亚像素插值 → 几何拟合”:把二维问题拆成 \(N\) 个一维问题,每条搜索线上投影平均抑噪、一阶导数极值定边、抛物线顶点插值出亚像素位置。
- 亚像素几乎是免费的,但有前提:抛物线插值只在剖面足够干净时才兑现精度,投影宽度(抑噪 vs 模糊)、边缘强度阈值、极性与边缘类型都要按场景配置,而不是用默认值。
- 最小二乘对离群点敏感的根源是平方惩罚:大残差支配目标函数,少数肩部离群点足以拉偏整条直线。Huber 加权 + IRLS 给大残差点按 \(\kappa/|r|\) 降权,本章实验中内点 RMSE 从 2.793 px 改善到 1.456 px。
- 对比拟合精度要用统一的内点规则:全点 RMSE 把离群点自身的残差也记在拟合头上,是常见的评估陷阱。
- 稳健圆拟合一次交付测量与缺陷线索:本章对两个镗孔各拟合出孔心与半径(孔距 442.06 px,可直接用于配合与抓取),完好孔缘的剔除点为 0;一旦孔缘出现缺陷,剔除清单即成为缺陷的位置标记——基准几何用于测量,离群清单用于缺陷判定。
圆与椭圆若需更精确的直接拟合,可参考其代数解法的两篇经典:Taubin 的隐式曲线与曲面估计 (Taubin 1991),以及 Fitzgibbon 等人的椭圆专用直接最小二乘法 (Fitzgibbon, Pilu, 和 Fisher 1999)。关于亚像素边缘提取与几何基元拟合更系统的论述(包括椭圆、圆弧及不确定度分析),可进一步阅读 Steger 等人的著作 (Steger, Ulrich, 和 Wiedemann 2018)。



