题目不让带预训练好的 .sol 方案,必须现场建模。常规做法是在 IDE 里把流程搭好、模型训好,导出一个 .sol 运行时加载——这等于把训练好的模板带进考场,不行。所以我没用 IDE 工程,而是直接 new 底层算子对象,训练和推理全在自己的程序里跑,每个 Pattern 都是现场画完 ROI 之后当场 Train() 出来的,从头到尾不读也不写任何预训练文件。
下面说每个算子具体怎么用的。
这个负责定位,是整条链路的地基。用户在样张上画一个裁切框圈出标签的有效区,我拿这块区域往 Pattern 的 RegionList 里塞一个匹配区,调 Train() 训出模板。训完立刻在这张 OK 图上跑一次匹配,把匹配到的中心点和角度记下来当基准(代码里就是 _refMatchX / _refMatchY / _refMatchAngle)。
匹配参数我对齐了 VM 界面那套:MaxMatchNum 设 1(一张图只认一个标签)、搜索角度范围 −45°~45°、最低匹配分 0.5。检测每张新图时,先把 Pattern、InputImage 喂进去 Run(),从 Result.MatchInfoList 取第一个匹配,拿到当前标签的中心和转角,再用它和基准点的差做一次旋转+平移,把训练时画的所有 ROI 映射到当前位置。这样用户只在样张上画一次框,后面每张图的检测区都自动跟着标签的位姿走。
负责印刷区、条码区、二维码区这几类区域的脏污残缺判定。题目要求每个类别能画多个 ROI 并分别调参,我一开始想偷懒一个类别共用一个模型,结果同一个印刷区里 “SHOP NOW” 那块和旁边法语 “MAGASINEZ MAINTENANT” 那块纹理差太大,共用一个 Pattern 会把"正常范围"撑得太宽,该报的不报、不该报的乱报。
所以改成每个 ROI 独立一个 CDefectInspectPattern,列表下标和 ROI 一一对齐。Tool 倒是不用每个都配,复用一个就行,每次 Run() 之前把它的 Pattern 切到当前 ROI 那个。训练时,每张 OK 图先过一遍 HP 匹配定位、把 ROI 映射到这张图标签的实际位置,再裁出来当样本,Label 标 0;如果有 NG 图,同样处理后 Label 标 1 一起喂进去,让模型既见过正常也见过缺陷。检测时读 Result.ResultInfoList 的 Label,非 0 就是这块 NG,Score 一并带出来。FeatureType、InspectScore、DownSampleRate 这几个运行参数在每次 Run 前按建模时定好的值写进去。
一维码、二维码识别,这两个读码器不需要训练,拿来即用。流程很短:设好 InputImage 和 ROI,Run(),再从 Result.CodeInfoList 把内容取出来。二维码区主要用 C2DCodeReaderTool,读到内容就算这块 OK,一个都读不出来判 NG,识别结果也会一并记进检测报表,方便和样张对照。
负责字符级别的残缺、多墨少墨,比读码细一档。先用 CMKSegmentV3 把字符 ROI 切成一个个字符小框,分割方式(按字符 / 按词)和文字极性(亮底暗字 / 暗底亮字)都能配。切好之后给每个字符单独训一个 HP 模板,存进这个模型的字符模板列表。
检测时分两步:每个字符先在自己的预测位置附近跑一次匹配,搜索范围按字符尺寸乘一个容忍系数(默认 1.2)放一圈,匹配分过了精定位阈值(0.5)就把命中的位置和角度填进 Tool 的 InspBoxList;万一某个字符没匹配上,就退回用映射出来的预测位置兜底,保证判定逻辑不断。所有字符位置都填好之后,Tool.Run() 出每个字符的缺陷结果。亮暗阈值、最小缺陷面积、边缘容忍这些参数支持全局统一或者每个 ROI 单独覆盖两种模式。
读标签侧边竖排的批次码,类似 D0387A001。这种窄长带角度的小区域 VM 自带的不太顺手,我外挂了 Tesseract(eng 语言包,LSTM 模式)。裁图时按 ROI 的角度先把它旋正,而不是直接按轴对齐矩形硬裁;对竖排和窄长区域,同时试 0/90/180/270 四个方向各识别一遍,再按置信度、格式特征和长度稳定性挑最优的那个结果,避免标签角度稍变就读成好几个版本。送进引擎之前还做了灰度归一化、轻量二值化、放大和补白边,压一压灯箱背景和边缘噪声。字符白名单限定成数字和大写字母,另外配了个可选的正则格式校验——读得出来且格式对就 OK,读不出或者格式不符判 NG,这样面对会变的批次码也能用。