条件
工业相机拍摄的蜂窝微孔芯片,绝大多数孔没有可用亮度,分辨率 4080×3072,孔按六角(蜂窝)排列,孔距大约 27 像素。画面主体很暗,能看见的亮孔成团出现在右侧和下方,中央一大片几乎是空的。左侧还有一条很亮的芯片边缘,不参与孔的周期。
微孔芯片、微孔板读数里,这种图很常见:阴性孔曝光后接近相机黑电平,阳性孔只占一小部分。要做的不是把亮点圈出来,而是给出整张行列对齐的矩阵,包括那些看不见的孔该落在哪里。

图 1 原始图像,全局。青框、黄框是后面一直使用的两个固定放大区域。文件:01-全局.jpg

图 2 同一张原图的细局部。中央这一个窗口里,孔只是零星几个绿点。文件:01-细局部.jpg
测量结果
| 项目 | 数值 |
|---|---|
| 网格类型 | 六角(蜂窝),两方向夹角 60.26° |
| 孔距 | 27.082 像素与 27.038 像素;沿水平方向 27.082,相邻行间距 23.477 |
| 旋转 | 1.670° |
| 灰度通道 | 平均通道。结构强度:蓝 0.04,绿 0.00,红 0.00,最大值 0.04,平均 0.05 |
| 晶格来源 | 分区自相关,9 个区域里 6 个结论一致 |
| 分块 | 88 块中 40 块结构清楚 |
| 网格节点 | 13928 |
| 直接定位(品红圈) | 1176,占 8.4% |
| 由网格补出(黄圈) | 12458 |
| 排除的误检 | 294 |
| 孔心残差 | 中位数 0.278 像素,95% 分位 0.963 像素 |
| 相对孔距 | 中位残差约为孔距的 1.0% |
| 偏离直线网格的最大弯曲 | 5.53 像素 |
| 模型 | 10 项多项式 + 局部形变场,匹配阈值 0.50 |
| 耗时 | 3.5 秒(含通道选择、归一化、自相关、分块、三轮匹配与拟合) |
结构强度 0.05 属于很弱的一档。能直接看见并定位的孔不到一成,剩下九成以上的节点是按晶格补出来的。补出来之后,那些真正测到的孔心仍然贴在网格上,偏差中位数不到 0.3 像素。
按序处理
1. 通道选择
彩色图先拆开看各通道的孔结构。这张图的绿通道和红通道几乎没有结构,蓝通道只有 0.04,三个通道取平均后结构强度是 0.05,是这张图上最可用的一路。程序保留这一路灰度,后面的周期估计都在这张灰度上进行。

图 3 彩色褪成选用的灰度。亮孔的位置没有变,只是去掉了没有结构的颜色。文件:02-全局.jpg
2. 局部对比度归一化
大范围的明暗(边缘反光、视场一侧偏亮)会盖住孔本身的起伏。用较大窗口估计局部均值和局部起伏,把缓慢变化的照明压掉,留下每个孔自己的高低差。归一化之后,原来埋在暗背景里的小孔在细局部里变成清楚的亮点,固定噪声也一起被抬了出来,所以这一步的画面会显得更「花」,孔的轮廓却更完整。

图 4 局部对比度抬起来之后的全局。文件:03-全局.jpg

图 5 同一窗口的细局部。零星的孔从全黑背景里显出来了。文件:03-细局部.jpg
3. 分区自相关,确定晶格方向
整张图如果直接做一次自相关,会被左侧亮边、成团的阳性孔和空区一起拉偏。程序在 9 个位置各做一块自相关。相关峰离中心的位移就是孔距,两个不共线的峰给出蜂窝的两个方向。9 块里有 6 块得到同一套孔距,就采用这一组:孔距约 27.1 像素,六角排列。
信号再弱、各块对不上时,才会改用亮孔之间的位移做傅里叶,从阳性点反推晶格。这张图的 6/9 已经一致,晶格方向由分区自相关确定。

图 6 两个晶格方向从画面中心长出来,并按这个周期铺开一小片格点。中央窗口内部很空,方向是靠其他区域的相关峰确定的。文件:04-全局.jpg
4. 分块折叠,找出还能看见孔的区域
按这个周期把芯片分成 88 块。每一块按晶格折叠,叠成一个平均孔,再用各向同性响应找这一块的孔心。结构清楚的块画成绿框,看不清孔的块画成灰框。这张图 40 块有效、48 块无效。无效块集中在空区和亮边附近,有效块集中在还能看见亮孔的一侧。

图 7 分块铺开。绿框是折叠后能看见孔的块,灰框是本块没有可用结构。文件:05-全局.jpg
每个有效块给出一个局部孔心,作为后面模板对齐的起点。

图 8 各有效块的孔心。它们还不是最终网格,只是每一块的一个锚。文件:06-全局.jpg
5. 归一化互相关,三轮收紧
用本块折叠出的平均孔当模板,在预测位置附近做归一化互相关,找到真正的孔心。一共三轮,搜索窗从孔距的 40% 收到 28%,再收到 18%。每一轮用稳健拟合丢掉对不齐的点,再用新的网格预测下一轮的位置。
| 轮次 | 搜索窗 | 保留的孔心 |
|---|---|---|
| 第 1 轮 | 孔距的 40% | 1828 |
| 第 2 轮 | 孔距的 28% | 1745 |
| 第 3 轮 | 孔距的 18% | 1562 |
点数一轮比一轮少,是因为空区里的噪声响应被阈值和残差剔掉了。留下来的点更集中在真实亮孔上。

图 9 第 1 轮匹配到的孔心,搜索窗较宽。文件:07-全局.jpg

图 10 第 3 轮,搜索窗收到孔距的 18%,保留 1562 个孔心。文件:09-全局.jpg
6. 多项式和局部形变场
用这些孔心拟合整张网格。整体形状用 10 项多项式描述,包括平移、孔距、旋转和缓慢的镜头弯曲;局部还用形变场把小范围的偏差贴回去。拟合时偏离过大的点不参与,避免碎屑把网格拉偏。
画出来的结果里,品红圈是直接定位到的孔,黄圈是按网格补出的孔,品红线是网格线。13928 个节点里,品红只有 1176 个。黄圈占了绝大多数,它们的位置由晶格外推,间距仍是约 27 像素的蜂窝。

图 11 最终网格,全局。右侧和下方的亮孔团落在品红圈上,空区由黄圈按同一矩阵补齐。文件:10-全局.jpg


图 13 细局部。圈与圈的间距均匀,网格线略有倾斜,对应整图 1.67° 的旋转。文件:10-细局部.jpg
适用场景
孔距大约 27 像素、排列是蜂窝,这些和信号正常的片子是同一类芯片。差别在覆盖率:正常片子上往往有一半以上的孔能直接定位,这张片子只有 8.4%。空区如果单独去找孔,会把传感器噪点当成孔;成团的阳性区如果单独去拟合,又只能得到一小片,对不上整板的行列号。
这张图直接定位的孔心,相对网格的偏差中位数 0.278 像素,95% 不超过 0.963 像素,大约是孔距的 1% 和 3.6%。对微孔阵列的行列编号和后续定量,这个偏差落在同一个孔内,不会串到相邻孔。
