十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CNN 与模板匹配混合识别:ONNX 推理 + 置信度仲裁实战

CNN 与模板匹配混合识别:ONNX 推理 + 置信度仲裁实战 CNN 与模板匹配混合识别ONNX 推理 置信度仲裁实战“单模板匹配在角标污损时挂CNN 在奇怪字体上挂。混着用靠置信度仲裁能从 95% 抬到 99%。”一、背景为什么单一方案永远不够前两篇把牌切出来了——两行、每张牌的 bbox 都画好了——但还差最后一步这张牌是几什么花色我先尝试了纯多尺度模板匹配第 56 篇方案JOKER 准确率从 71% → 94%看上去够用了。但上线跑了一晚上发现三个新坑现场现象纯模板匹配纯 CNN角标被手指压住一半模板特征缺失分数 0.6 误识局部特征仍可识别置信度 0.88牌面换皮节日版字体变化匹配度直接归零见过几百张的训练集置信度 0.82极小牌角标3px × 8px多尺度插值糊了分数波动32×32 缩放后特征仍在置信度 0.91三种场景单一方案必有一个挂。怎么办混着用。二、方案CNN 优先 模板兜底 置信度仲裁核心思路preprocess_digit把所有牌统一缩放到 32×32 黑底居中灰度图CNN 推理onnxruntime2 层 CNN softmax得到 13 个点数的置信度分布CNN 置信度 0.7直接采纳 CNN 结果CNN 置信度 0.7回退到多尺度模板匹配模板匹配分 阈值返回?拒识实测准确率方案准确率单帧耗时CPU纯模板匹配94.2%8 ms纯 CNN95.1%22 ms混合CNN 优先 模板兜底98.7%14 ms混合方案既比纯方案准又比纯 CNN 快——因为 70% 的牌 CNN 一次过只有难牌才走模板。三、第一步preprocess_digit 统一输入口径CNN 和模板匹配都要同样的图。我从采集训练样本时就把口径写死defpreprocess_digit(sub_rgb,is_red,out_size32):统一预处理RGB 牌面数字区 → 32×32 灰度 float32 数组0~1 归一化。 与 _collect_point_tiles 采集口径一致 上半 55% → 颜色掩码定位 bbox → 灰度 → 居中缩放。 subsub_rgb.copy()ifsub.ndim3:subcv2.cvtColor(sub,cv2.COLOR_RGB2BGR)h,wsub.shape[:2]# 取上半 55%数字 花色都在上半uppersub[:int(h*0.55),:]# HSV 颜色掩码定位 bbox红用红 mask黑用灰度暗像素hsvcv2.cvtColor(upper,cv2.COLOR_BGR2HSV)ifis_red:mask((hsv[:,:,0]10)|(hsv[:,:,0]170))(hsv[:,:,1]100)else:maskupper.mean(axis2)100ys,xsnp.where(mask)iflen(ys)0:returnnp.zeros((out_size,out_size),np.float32)y0,y1ys.min(),ys.max()1x0,x1xs.min(),xs.max()1cropupper[y0:y1,x0:x1]graycv2.cvtColor(crop,cv2.COLOR_BGR2GRAY)# 居中缩放 黑底 paddingscaleout_size/max(gray.shape)new_wmax(1,int(gray.shape[1]*scale))new_hmax(1,int(gray.shape[0]*scale))resizedcv2.resize(gray,(new_w,new_h),interpolationcv2.INTER_AREA)canvasnp.zeros((out_size,out_size),np.uint8)x_off(out_size-new_w)//2y_off(out_size-new_h)//2canvas[y_off:y_offnew_h,x_off:x_offnew_w]resizedreturncanvas.astype(np.float32)/255.0两个关键细节上半 55%——牌面数字 花色都在上半下半是牌背花纹不能要黑底 padding 居中——CNN 训练时输入都是黑底居中推理时也得这样四、第二步CNN 推理模型是个 2 层卷积 2 层全连接~50KB onnx 文件输入 1×1×32×32输出 1×1313 个点数2、3、…、A、J、Q、K。def_match_handband_cnn(canvas):sess_load_point_cnn()ifsessisNone:return(None,0.0)inpcanvas.reshape(1,1,32,32).astype(np.float32)outputssess.run(None,{sess.get_inputs()[0].name:inp})probsoutputs[0][0]idxint(np.argmax(probs))conffloat(probs[idx])points[2,3,4,5,6,7,8,9,10,J,Q,K,A]return(points[idx],conf)onnxruntime启动比 PyTorch 快 5 倍模型加载 100ms。五、第三步混合识别CNN 优先 模板兜底def_match_handband_tile(sub_rgb,hb_templates,is_red):对平铺单张牌的数字区做识别。CNN 优先 模板兜底。# 1. CNN 分支canvaspreprocess_digit(sub_rgb,is_red,locateFalse)point,conf_match_handband_cnn(canvas)ifconf0.7:return(point,conf)# CNN 一次过# 2. 模板兜底用 locateTrue 完整流程 多尺度uppersub_rgb[:int(sub_rgb.shape[0]*0.55),:]seg_red,seg_blacksplit_color(upper)tpl_label,tpl_score_match_handband_point(seg_red,seg_black,hb_templates,is_red)iftpl_score0.78:return(tpl_label,tpl_score*0.9)# 模板匹配打个折# 3. 都没把握拒识return(None,0.0)置信度仲裁策略CNN conf 0.7 → 直接用 CNNtrust CNN否则看模板分数 0.78 才用并 × 0.9 折扣信任度略低于 CNN都不过 → 返回 None记日志不污染推理六、训练样本合成怎么让 CNN 跟得上实时图CNN 训练数据从哪来我直接用游戏里手牌带的截图做训练集——自动采集、自动裁切、自动标注合成流程_auto_play_capture.py进游戏自动截屏_collect_point_tiles在手牌带区域按 RGB → HSV → bbox → 居中缩放裁单牌人工校验前 50 张确认无误后批量采集 1000数据增强随机旋转 ±10°、随机缩放 0.9~1.1、随机加噪 σ5训 100 epochs验证集准确率 98.5%数据增强的目的让训练样本覆盖实时帧的尺度/角度/噪声变化CNN 上线时不需要再做归一化。七、CNN 推理可视化debug 截图CNN 推理时我留了几张 debug 图能直观看到每张牌的置信度看这张图第一行 Card 0~4 raw实时抓到的 5 张牌原图。第一张是 JOKER后面 4 张都是 2不同花色第二行 CNN input经过 preprocess_digit 之后的 32×32 输入。可以看到 JOKER 被裁成 “J” “O” 两行字符的角标其他 4 张牌只剩角标部分黑桃、方块、梅花、红心第三行 Best train match训练集里最像的样本。下标 idx 和距离 dist。注意 Card 0 (JOKER) 的距离 8.845 最小——意味着模型认为它和训练集的 JOKER 最像观察距离越小表示越像。Card 0 (JOKER) 的 dist8.845 是 5 张牌里最小的CNN 给了它最高置信度。这是另一张 debug 图实时抓的一手牌每张牌下面标了红色置信度0.86、0.65、0.57、0.85、0.53、0.35…。注意到没“0.35” 这种低置信度的牌模板兜底就起作用了——CNN 拒识模板匹配接管。八、模板匹配什么时候必须用实测中我总结了 4 类必须走模板兜底的场景场景CNN 表现模板表现原因节日换皮0.4~0.60.85CNN 没见过新字体JOKER 紧贴 UI0.5~0.70.92bbox 裁切被 UI 干扰黑桃/梅花颜色混淆0.6~0.70.80HSV 红黑 mask 切分更准屏幕亮度被压暗 30%0.50.75CNN 归一化吃掉信息模板直方图不变结论CNN 不行的时候模板基本都行——因为模板对字体/亮度不敏感只看形状结构。九、算法优缺点对比方案优点缺点纯多尺度模板匹配快8ms、无需训练、字体外形稳定复杂背景/换皮会挂纯 CNN抗噪、抗局部变形训练集要求高、对未见过字体泛化差混合本文综合最优、互补盲区略复杂14ms vs 8ms直接 YOLOv5 检测端到端、一步到位训练集要求极高、推理慢50ms实战推荐先训 CNN半天加上多尺度模板兜底再半天混合方案上线。十、小结CNN 模板混合识别靠的是置信度仲裁CNN 跑一遍conf 0.7 → 直接用否则回退模板都不过 → 拒识。这套组合拳让牌面识别准确率从 95% →98.7%误报率 6.8% → 0.4%基本可以放心让记牌器自动记了。剩下的最后一个难题怎么让脚本自己点屏幕下一篇讲。系列目录牌面角标识别与阈值校准JOKER 误识踩坑手牌带定位与行分割亮度 HSV 颜色双指标投影实战CNN 与模板匹配混合识别ONNX 推理实战 ← 本文游戏窗口自动化点击与防误点设计本机实测环境Windows 11 Python 3.11 OpenCV 4.8 onnxruntime 1.17 手机 1080×1920 投屏。
返回列表