今天的任务是做一个无人零售结算系统,是 AidLux 社区的 AI 悬赏任务。社区官方给的题目参考是这样子的:
题目参考图片花里胡哨的,但其实图片左边部分并不包含在任务内。就最右边是题目的内容,是识别固定摄像头下商品的种类和数量,并生成订单统计出总金额。
题目的数据需要自己准备,好在我之前就做过智能零售的项目,像这种固定摄像头下的商品识别,用 RPC( https://rpc-dataset.github.io/) 数据集再合适不过了。RPC 数据集是旷视提供的及其优秀的结算场景的商品识别数据,其中包含 200 个真实常见商品类别的图像。商品类别跨度很高,包括食品用品日常用品等等。
值得一提的是,本次训练使用的是 RPC 数据集的测试集 24000 张图片,而不是训练集。因为 RPC 数据集本质是为了做领域迁移而设计的,其训练数据画面中只有一个商品,其设计目的是让使用者将这单个商品粘贴到纯色背景中做领域迁移用的。
因为本次主要目的是满足 AI 悬赏任务,识别和系统搭建优先,就不做领域迁移的工作了,直接使用 24000 张测试图片做训练集,另外还有 6000 张验证数据做实际训练中的测试数据。
因为之前参加 AidLux 训练营的时候,学习过 YOLOv5 模型 tflite 模型的导出和在 AidLux 平台上部署的方法,所以本次任务就使用 YOLOv5 模型了。训练的方法没什么好说的,就是选用 YOLOv5s 的训练配置,将选择的 RPC 数据集转换为 YOLO 训练的格式。
在 16 个小时后,训练结束了。因为目标场景背景是固定的,所有商品都具有较大的尺寸,所以训练精度还是非常高的,下面就是模型的导出了。
YOLOv5 模型的 tflite 导出方法还是比较成熟的,官方代码就提供了导出的方法。导出后得到 tflite 文件。导出 tflite 文件后,首先在 PC 端测试模型的正确性。然而在第一次的测试过程中并没有得到正确的结果,模型能够正确检测出所有的商品名字和数量,但是无法正确的绘制出目标框,得到的目标框都无比巨大!
经过一系列的问题排查和在网上搜索线索,最终的问题是 YOLOv5 会对目标框进行归一化,要恢复回归一化的目标框。pt 和 onnx 模型都需要这一步操作,而 tflite 模型不知道在导出的时候发生了怎样的改变,是不需要乘以原图高宽进行归一化的,也就是模型调用代码中,下面这一句需要注释掉:
``` #y[0][..., :4] *= [w, h, w, h] # xywh normalized to pixels<p><strong>这样就能够得到正确的目标框了,检测结果如下:</strong></p>
<p><img src="https://aidlux.oss-cn-beijing.aliyuncs.com/imgs/4temp2266058630807254541680225910717318275.png" alt="" /></p>
<p><strong>验证 tflite 模型的正确性后就可以把模型移植到 AidLux 平台了。AidLux 系统就是个安装在 Android 上的 APP。安装 APK 文件后就可以进入系统。</strong></p>
<p><strong>使用这个系统的好处是,原先在 Andorid 上调用模型需要自己编写 JAVA 的代码,而使用 AidLux 系统,在其中调用模型使用 Python 编程即可,并且支持 OpenCV 等常见 Python 包,而且支持一定程度的图形界面,这大大减少了模型移植以及业务逻辑实现的工作量。</strong></p>
<p><strong>tflite 模型调用方面,只需要做以下修改:</strong></p>
在 PC 上调用 tflite 模型
tflite_path = “weights/yolov5s.tflite”
det_interpreter = tf.lite.Interpreter(model_path=tflite_path)
det_interpreter.allocate_tensors()
det_input_details = det_interpreter.get_input_details()
det_output_details = det_interpreter.get_output_details()
det_input_shape = det_input_details[0][‘shape’]
dummy_np = dummy_torch.data.numpy()
det_interpreter.set_tensor(det_input_details[0][‘index’], dummy_np)
det_interpreter.invoke()
output = det_interpreter.get_tensor(det_output_details[0][‘index’])
在 AidLux 平台上调用 tflite 模型
in_shape = [1 * 3* 640 * 640 * 4]
out_shape = [1 * 25200 * 205 * 4]
aidlite = aidlite_gpu.aidlite()
aidlite.ANNModel(model_path, in_shape, out_shape, 4, 1)
print(“模型已加载:”, model_path)
aidlite.setInput_Float32(image, 640, 640)
模型推理API
aidlite.invoke()
output = aidlite.getOutput_Float32(0)
output = output.copy().reshape(1, 25200, 205)
<p><strong>调用模型的方法熟悉后还是非常简单的,总之能使用自己熟悉的 Python 来写逻辑就能避免很多问题,毕竟 JAVA 还是不怎么熟悉的,语法也比 Python 复杂很多。</strong></p>
<p><strong>模型之前在 PC 上做过正确性测试,这里在 AidLux 平台上测试也能够得到正确的检测结果,所以下面需要做的就是界面了。</strong></p>
<p><strong>界面方面我打算使用 OpenCV 的划线画框画字的方法纯粹绘制出来。因为检测目标是一个视频,视频中每隔 5 帧会变一张结账图片。那么在每一帧读取后,将其粘贴在一整纯色背景上,然后在模型识别后,在纯色背景上绘制出检测的结果,并根据检测结果计算出总价,从而完成结算任务。最终实现的界面如下:</strong></p>
<p><img src="https://aidlux.oss-cn-beijing.aliyuncs.com/imgs/5temp14803138966964709221680225924309198822.png" alt="" /></p>
<p><strong>怎么样,还有模有样的吧。</strong></p>
<iframe src="https://player.bilibili.com/player.html?aid=226837460&bvid=BV1Eh41137Ma&cid=1077252613&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>