本文以第一人称记录笔者做冷柜资产数字化时的架构设计、算法取舍与踩过的坑,偏技术实现,不谈市场。
一、问题定义:这不是一个 IoT 问题
刚接到需求时,笔者的第一反应也是"给冰柜装个联网模块不就完了"。真正调研完存量设备才发现,这条路走不通。
企业手里的冷柜是多年间分批投放的,型号杂、批次乱,大量早期设备连预留的通信接口都没有。逐台加装意味着上门改造、供电改造、SIM 卡管理、离线补传,运维半径大到不可控。更麻烦的是,改造只能覆盖新投的柜子,存量那部分依然是黑盒。
于是笔者把问题重新定义了一次:这不是"如何给设备联网",而是"如何在不改造设备的前提下,周期性获取每台设备的位置、存在性与内部状态"。
一旦这样定义,答案就变了------一线人员本就要按路线到店拜访,把拜访动作本身当作数据采集器,用手机相机做传感器。数据频次从"秒级实时"降到"按拜访周期",但覆盖率从"部分新柜"提到"全量存量柜"。对资产管理场景,后者更重要。
二、整体架构分四层
笔者把系统拆成四层:
- 任务调度层:按资产台账与核查策略生成拜访任务,把"需核查冰柜的门店"注入一线人员的拜访路线,控制核查频次与优先级。
- 采集与校验层:负责拍照采集、端侧质量检查、翻拍与重复提交检测,保证进入识别环节的图像是"此时此地此柜"。
- 识别与计算层:检测柜内商品、归类品牌与 SKU、计算排面占比,输出纯净度分值与结构化陈列结果。
- 业务闭环层:按阈值分级生成处置任务,同步更新资产台账,并把纯净度回写到费用核销与投放回报测算。
这四层里,第三层最容易被高估,第二层最容易被低估。
三、翻拍与重复提交检测:第二层为什么最容易被低估
早期版本笔者只做了识别,没做采集校验,结果很快出现了三类脏数据:
- 翻拍:拍屏幕里的旧照片交差。
- 复用:同一张图在不同门店重复提交。
- 偏拍:只拍冰柜达标的那一格,避开混放区域。
对应的处理思路:
- 翻拍检测:屏幕翻拍会引入摩尔纹、异常的高频能量分布和偏色。笔者的做法是先用轻量分类模型做初判,再叠加频域特征做二次确认,单一手段误杀率都偏高。
- 重复检测:对图像算感知哈希(pHash / dHash),与该门店历史图像和全局近期图像做汉明距离比对,低于阈值直接拦截。注意不能只在门店内比对,跨门店复用才是高发场景。
- 偏拍治理:这个靠算法解决不了,得靠采集规范。强制要求整柜正面构图,识别侧对画面中冰柜边框的完整性做校验,检测不到完整柜体轮廓就要求重拍。
一个简化的重复检测逻辑大致是这样:
python
def is_duplicate(new_hash, history_hashes, threshold=6):
"""基于感知哈希的重复图像检测,threshold 需按实际业务分布调参"""
for h in history_hashes:
if hamming_distance(new_hash, h) <= threshold:
return True
return False
阈值调参上,笔者踩过一个坑:初期把 threshold 设得偏大,把"同一门店不同时间、陈列几乎没变化"的正常照片误判成了重复提交,一线抱怨很大。后来改成"重复判定不直接拦截,而是标记进入人工复核队列",才把误伤压下去。在有人工参与的业务流里,宁可降级为提醒,也别做强拦截。
四、识别与纯净度计算:难点不在检测,在归一化
第三层的技术栈本身不新鲜:目标检测定位商品,再做细粒度分类识别品牌与 SKU。真正花时间的是从检测框到"纯净度"这个业务指标的换算。
笔者踩的第一个坑是用商品件数算占比 。冰柜里瓶装和盒装体积差异极大,按件数算会严重失真。后来改成按投影面积算:
纯净度 = Σ(本企业商品检测框面积) / Σ(全部可陈列区域有效面积)
第二个坑是分母怎么定。一开始用整张图的面积,结果拍照角度稍微一变,分值就跟着抖。改成先分割出冰柜内部的有效陈列区域,再在这个区域内做归一化,分值稳定性明显改善。
第三个坑是遮挡与层叠。冰柜商品前后堆叠,后排大面积被遮,直接算面积会低估后排。笔者的处理是只统计前排可见面(这本来也符合"排面"的业务定义),并在规范里明确纯净度衡量的是可见排面而非库存。
第四个坑是长尾竞品 。自家 SKU 样本充足,竞品和无关商品的样本极度稀疏。硬做多分类,长尾类别精度很差。后来改成二段式:先做"本企业 / 非本企业"的二分类,保证纯净度这个核心指标稳定;竞品的细分品牌识别作为独立任务、独立评估,不阻塞主指标。指标口径要和模型能力对齐,别让一个不稳的子任务拖垮主链路。
五、纯净度不能只做成一个数字
早期笔者只输出一个分值,业务侧拿到之后不知道该干什么。后来加了两件事,指标才真正被用起来。
一是分级。按阈值划档,不同档位对应不同动作:轻度偏低走现场沟通与排面调整并留证,中度偏低标记异常、上级复核并纳入履约考核,重度偏低或设备失联则触发资产核查流程。阈值必须做成可配置项,不同品类、不同渠道的合理区间差别很大,写死在代码里一定会返工。
二是回写。纯净度不只是一个陈列指标,它同时是资产健康度的先行信号------设备被挪用、协议实际失效的门店,往往先在纯净度上出现持续异常。所以笔者把它同时回写到两条链路:资产台账的状态字段,以及费用核销的修正系数。
后者的口径是把实际纯净度与协议约定纯净度的比值作为系数,参与投放回报测算:
ROI = (单柜年产出 × 纯净度系数 − 年摊销成本 − 实际陈列费用) / 总投入
这个设计的意义在于,纯净度从"一个报表数字"变成了"影响结算的变量",链路才有闭环压力。
六、几个工程上的注意点
- 拍照点即盘点点。采集时必须一并回传定位与门店绑定关系,否则识别结果再准,也回答不了"这台柜子现在在哪"。
- 端侧要做质量前置。模糊、逆光、过曝的图直接在端上拦下重拍,比传到云端再退回效率高得多,也省流量。
- 识别结果要可申诉。模型不可能全对,必须给一线留复核入口并把纠正样本沉淀回训练集,否则一线会用"随便拍"来对抗系统。
- 冷启动别追全量。先在少量品类、少量区域跑通"采集---校验---识别---分级---回写"的最小闭环,再扩样本、扩品类。
七、结语
回头看,这套系统里真正难做的不是模型,而是问题定义的转向:放弃"给每台设备联网"的执念,改用既有人力动线做周期性采集,用算法保证采集数据的可信度。约束条件想清楚了,方案自然就收敛了。
笔者长期从事快消行业渠道执行与图像识别方向的系统设计,上述踩坑均来自实际项目,欢迎在评论区交流不同的实现思路。