ARTICLE DETAIL

资讯详情

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

IoT-For-Beginners 零售项目实战:在 IoT 设备上调用目标检测器统计货架库存

IoT-For-Beginners 零售项目实战:在 IoT 设备上调用目标检测器统计货架库存 IoT-For-Beginners 零售项目实战在 IoT 设备上调用目标检测器统计货架库存【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本文基于 IoT-For-Beginners 仓库零售项目Retail第 2 课从 IoT 设备检查库存整理而成。你将学会如何在 Custom Vision 中发布目标检测器的推理迭代iteration从 Raspberry Pi、虚拟 IoT 设备或 Wio Terminal 调用检测 API理解 0–1 归一化边界框bounding box的坐标体系并掌握用重叠度算法去重、最终准确统计货架上库存数量的完整方案。课程定位与清理提示这是零售项目5-retail的最后一课上一课你已学会训练能识别库存如番茄酱罐头的目标检测器本课则把它部署到真实 IoT 设备上完成数数。课程覆盖内容包括库存盘点Stock counting从 IoT 设备调用目标检测器边界框Bounding boxes用真实拍摄数据重新训练模型结合边界框统计库存对应英文原版课程见 5-retail/lessons/2-check-stock-device/README.md捷克语译本见 translations/cs/5-retail/lessons/2-check-stock-device/README.md。注意这是该项目的最后一课。完成本课及课后作业后务必清理你创建的云资源Custom Vision 项目与 Prediction 资源否则会持续计费。清理步骤见仓库根目录的 clean-up.md原文档中为../../../clean-up.md。为什么用目标检测做库存盘点目标检测器可用于两类库存检查清点数量以及确认货物在正确的位置。带相机的 IoT 设备可以部署在门店各处优先覆盖热点区域——即必须保证补货的高价值、低库存区域。课程给出的典型例子一个货架能放 8 罐番茄酱相机对准它检测器只识别出 7 罐说明缺 1 罐需要补货。此时 IoT 设备不仅能发出补货通知还能给出缺失商品的大致位置——如果你使用机器人补货货架这个位置信息至关重要。课程同时提醒只缺一罐时是否触发补货取决于门店策略和商品热度实际项目中需要编写算法结合商品特性、客流等因素决定补货时机。另一类问题是货架上出现错误商品。可能是补货时的人工失误也可能是顾客买了又反悔随手把商品放进第一个空位。对于罐头这类非易腐品只是麻烦对于冷冻、冷藏品则可能因为无法判断它在冷链外停留了多久而直接报废。目标检测器可以识别出预期之外标签的物体及时提醒人员或机器人把商品归位例如番茄酱货架上混入的一罐小玉米。任务一发布目标检测器迭代检测器需要先发布才能从 IoT 设备通过 API 调用。发布操作在 Custom Vision 门户customvision.ai完成登录 Custom Vision 门户打开你的stock-detector项目在顶部选项中选择Performance标签页在侧边Iterations列表中选择最新的迭代点击该迭代对应的Publish按钮在Publish Model对话框中将Prediction resource设置为上一课创建的stock-detector-prediction资源名称保持Iteration2不变点击Publish发布完成后点击Prediction URL按钮查看推理 API 的详细信息。关注标记为If you have an image file的下半部分这正是设备端调用所需的信息。复制其中显示的 URL格式如下https://location.api.cognitive.microsoft.com/customvision/v3.0/Prediction/id/detect/iterations/Iteration2/image其中location是创建 Custom Vision 资源时选用的地域id是由字母和数字组成的项目长 ID。同时复制Prediction-Key的值——这是一个安全密钥调用模型时必须传入只有携带该密钥的应用才能使用模型其他请求会被拒绝。课程留了一个思考题当发布新的迭代时它的名称会不同如Iteration3那么该如何让 IoT 设备切换到新迭代答案在源码里设备端代码正是从这条 URL 中解析出迭代名的因此换迭代就是换 URL详见下文从 URL 解析端点一节。任务二从 IoT 设备调用检测器仓库提供两条设备路径教程文档分别为 single-board-computer-object-detector.md 与 wio-terminal-object-detector.md参考代码在code-detect/目录Raspberry Pi / 虚拟 IoT 设备code-detect/pi/stock-counter/app.py、code-detect/virtual-iot-device/stock-counter/app.pyWio TerminalArduino 平台code-detect/wio-terminal单板机/虚拟设备从分类器改造成检测器库存检测器与之前课程创建的图片分类器大部分代码相同核心区别只有两点调用的 Custom Vision SDK 方法不同classify_image换成detect_image以及返回结果是多个预测而非单一标签。改造方法是删除分类的三行代码results predictor.classify_image(project_id, iteration_name, image) for prediction in results.predictions: print(f{prediction.tag_name}:\t{prediction.probability * 100:.2f}%)替换为检测代码results predictor.detect_image(project_id, iteration_name, image) threshold 0.3 predictions list(prediction for prediction in results.predictions if prediction.probability threshold) for prediction in predictions: print(f{prediction.tag_name}:\t{prediction.probability * 100:.2f}%)这里调用的detect_image方法运行目标检测器然后用阈值threshold 0.3过滤掉低概率预测。与每个标签只返回一个结果的图片分类器不同目标检测器会对图中每处候选对象各返回一条预测低概率的必须过滤。运行示例输出见教程文档piraspberrypi:~/stock-counter $ python3 app.py tomato paste: 34.13% tomato paste: 33.95% tomato paste: 35.05% tomato paste: 32.80%拍摄的图片与这些值都会出现在 Custom Vision 的Predictions标签页中便于核对。threshold需要根据你自己的图片效果调整。从 URL 解析端点迭代名藏在 URL 里参考实现 code-detect/pi/stock-counter/app.py 展示了设备端如何从复制来的 URL 中拆出 SDK 所需的参数prediction_url prediction_url prediction_key prediction key parts prediction_url.split(/) endpoint https:// parts[2] project_id parts[6] iteration_name parts[9] prediction_credentials ApiKeyCredentials(in_headers{Prediction-key: prediction_key}) predictor CustomVisionPredictionClient(endpoint, prediction_credentials)把预测 URL 按/拆分后第 3 段是域名即endpoint第 7 段是project_id第 10 段detect/iterations/Iteration2/image中的迭代名是iteration_name。这也回答了上一节的思考题——设备使用的迭代就编码在 URL 中更新 URL或其中的迭代段即可让设备指向新发布的迭代。Wio TerminalC 版检测调用Wio Terminal 走的是裸 HTTP 路线。code-count/wio-terminal/stock-counter/src/main.cpp 中的detectStock函数用HTTPClient向推理端点 POST JPEG 字节流通过请求头Content-Type: application/octet-stream与Prediction-Key完成认证HTTPClient httpClient; httpClient.begin(client, PREDICTION_URL); httpClient.addHeader(Content-Type, application/octet-stream); httpClient.addHeader(Prediction-Key, PREDICTION_KEY); int httpResponseCode httpClient.POST(buffer, length);收到 200 响应后用DynamicJsonDocument解析 JSON取出predictions数组并按概率阈值过滤threshold过滤逻辑见 main.cpp#L174-L183。拍照与网络交互由buttonPressed函数驱动按 C 键触发camera.startCapture()读入缓冲区后调用detectStockmain.cpp#L191-L212。完整步骤建stock-counterPlatformIO 项目、接入 ArduCam 相机、从分类代码改造见 wio-terminal-object-detector.md其中相机接线复用了制造项目第 2 课的步骤4-manufacturing/lessons/2-check-fruit-from-device/README.md。边界框0–1 归一化坐标体系使用检测器时你拿到的不只是标签 概率还有每个对象的边界框——即检测器以给定概率判定对象所在的位置。边界框是一个包住检测对象的矩形区域。边界框由 4 个值定义top上、left左、height高、width宽。这些值都在 0–1 的尺度上表示占图片尺寸的百分比。原点0,0在图片左上角因此top是距顶边的距离框的底边 top height。课程用一个具体例子讲清了换算上图宽 600 像素、高 800 像素。边界框从 320 像素处开始即top 0.4800 × 0.4 320从左起 240 像素处开始即left 0.4600 × 0.4 240高 240 像素即height 0.3800 × 0.3 240宽 120 像素即width 0.2600 × 0.2 120。坐标值top上0.4left左0.4height高0.3width宽0.2正因为使用 0–1 的百分比值无论图片被缩放到什么尺寸边界框始终从 0.4 处开始占高度 0.3、宽度 0.2。这一点在设备端代码里随处可见例如 Wio Terminal 的rectFromBoundingBox就是直接从 JSON 中取这四个字段并算出右下角坐标main.cpp#L93-L106Rect rectFromBoundingBox(JsonVariant prediction) { JsonObject bounding_box prediction[boundingBox].asJsonObject(); float left bounding_box[left].asfloat(); float top bounding_box[top].asfloat(); float width bounding_box[width].asfloat(); float height bounding_box[height].asfloat(); Point topLeft {left, top}; Point bottomRight {left width, top height}; return {topLeft, bottomRight}; }用边界框 概率评估检测质量检测器可能返回相互重叠的多个对象——极端情况是把同一罐识别成一罐套一罐。你的代码可以检查边界框发现这种物理上不可能的情况然后忽略显著重叠的对象。课程示例中一个框以 78.3% 的概率框住一罐番茄酱另一个略小且完全位于其内部的框给出 64.3%——代码可以判断两者完全重叠丢弃概率较低的那个。课程同样留了思考题什么场景下一个对象在另一个对象内部是合理的提示嵌套包装如礼盒里的商品。任务三用设备实拍数据重新训练模型和图片分类器一样你可以用 IoT 设备拍摄的真实数据重新训练模型——真实数据能确保模型在设备视角下工作良好。区别在于分类器只需给图片打标签而检测器要求你逐一审查模型检测出的每个边界框框住了错误物体就删除位置不对就拖动调整。操作步骤先用 IoT 设备拍摄一系列图片在Predictions标签页选中一张图片可以看到标记检测对象边界框的红色矩形逐个处理边界框先选中它弹出框显示标签用框角的控制点调整大小标签错误则用X按钮删除并添加正确标签框内没有对象则用垃圾桶按钮删除完成后关闭编辑器图片会从Predictions标签页移到Training Images标签页对其余所有预测重复该过程点击Train按钮重新训练训练完成后发布新迭代并更新 IoT 设备让它使用新迭代的 URL重新部署代码并测试 IoT 设备。任务四统计库存——过滤重叠的边界框结合检测到的对象数与边界框就能统计货架库存。核心难点两个框轻微重叠是正常现象但如果重叠过大它们可能指向同一个物体直接计数就会多算。因此需要先剔除显著重叠的框再数剩余框的数量。单板机/虚拟设备Shapely 方案完整步骤与说明见 single-board-computer-count-stock.md最终代码见 code-count/pi/stock-counter/app.py 与 code-count/virtual-iot-device/stock-counter/app.py。流程分三步1. 打印边界框调试手段把for循环中的打印语句改为print(f{prediction.tag_name}:\t{prediction.probability * 100:.2f}%\t{prediction.bounding_box})运行后可看到 0–1 坐标的边界框例如教程示例输出piraspberrypi:~/stock-counter $ python3 app.py tomato paste: 33.42% {additional_properties: {}, left: 0.3455171, top: 0.09916268, width: 0.14175442, height: 0.29405564} tomato paste: 34.41% {additional_properties: {}, left: 0.48283678, top: 0.10242918, width: 0.11782813, height: 0.27467814} tomato paste: 31.25% {additional_properties: {}, left: 0.4923783, top: 0.35007596, width: 0.13668466, height: 0.28304994} tomato paste: 31.05% {additional_properties: {}, left: 0.36416405, top: 0.37494493, width: 0.14024884, height: 0.26880276}2. 用 Pillow 把边界框画到图上安装 Pillowpip3 install pillow在app.py顶部加入from PIL import Image, ImageDraw, ImageColor在文件末尾追加绘图代码参考实现见 code-count/pi/stock-counter/app.py#L76-L92with Image.open(image.jpg) as im: draw ImageDraw.Draw(im) for prediction in predictions: scale_left prediction.bounding_box.left scale_top prediction.bounding_box.top scale_right prediction.bounding_box.left prediction.bounding_box.width scale_bottom prediction.bounding_box.top prediction.bounding_box.height left scale_left * im.width top scale_top * im.height right scale_right * im.width bottom scale_bottom * im.height draw.rectangle([left, top, right, bottom], outlineImageColor.getrgb(red), width2) im.save(image.jpg)代码打开之前保存的image.jpg遍历预测结果取边界框用 0–1 值算出右下角坐标再乘以图片的实际宽高换算成像素坐标例如left 0.5在 600 像素宽的图上就是 300用红框画出每个检测对象最后覆盖保存原图。运行后在 VS Code 中即可看到带框的图片3. 用 Shapely 计算重叠并去重计数在 Raspberry Pi 上先安装系统依赖再安装 Shapely虚拟 IoT 设备需在激活的虚拟环境内执行 pip 命令sudo apt install libgeos-dev pip3 install shapely加入导入与阈值from shapely.geometry import Polygon overlap_threshold 0.20overlap_threshold定义多大比例的重叠就认为是同一个物体0.20 即 20%。把边界框转换为 Shapely 多边形def create_polygon(prediction): scale_left prediction.bounding_box.left scale_top prediction.bounding_box.top scale_right prediction.bounding_box.left prediction.bounding_box.width scale_bottom prediction.bounding_box.top prediction.bounding_box.height return Polygon([(scale_left, scale_top), (scale_right, scale_top), (scale_right, scale_bottom), (scale_left, scale_bottom)])去重核心逻辑参考实现 code-count/pi/stock-counter/app.py#L55-L73to_delete [] for i in range(0, len(predictions)): polygon_1 create_polygon(predictions[i]) for j in range(i1, len(predictions)): polygon_2 create_polygon(predictions[j]) overlap polygon_1.intersection(polygon_2).area smallest_area min(polygon_1.area, polygon_2.area) if overlap (overlap_threshold * smallest_area): to_delete.append(predictions[i]) break for d in to_delete: predictions.remove(d) print(fCounted {len(predictions)} stock items)这段代码的要点外层取第i个预测内层从i1开始两两比较避免 1 比 2、又比 2 比 1 的重复比较用Polygon.intersection求交集面积由于阈值是占比而非绝对值先取两个框中较小框的面积smallest_area当重叠面积超过overlap_threshold × smallest_area时把前一个预测标记删除并break进入下一轮不能在遍历列表时直接删元素所以先收集到to_delete再统一移除。最后打印计数结果Counted N stock items——这个数值就可以发送到 IoT 服务如 IoT Hub触发低库存告警。教程中给出的overlap_threshold是 0.2020%而仓库参考代码里该值实际写为 0.002app.py#L45说明这是一个需要按实际图片与货架布局调参的实验值——教程也建议你调整它观察哪些预测被忽略。教程同时强调这是非常初级的去重方式重叠对里只删第一个生产代码还应考虑多对象之间的重叠关系、或一个框被另一个框完全包含等情形。Wio Terminal不依赖第三方几何库的 C 方案Wio Terminal 端没有 Shapely教程wio-terminal-count-stock.md用纯 C 手写矩形相交Point/Rect结构体加两个函数——area用左上、右下两坐标算矩形面积overlappingArea用max/min求两矩形交叠区无交叠则返回 0main.cpp#L64-L91float overlappingArea(Rect rect1, Rect rect2) { float left max(rect1.topLeft.x, rect2.topLeft.x); float right min(rect1.bottomRight.x, rect2.bottomRight.x); float top max(rect1.topLeft.y, rect2.topLeft.y); float bottom min(rect1.bottomRight.y, rect2.bottomRight.y); if ( right left bottom top ) { return (right-left)*(bottom-top); } return 0.0f; }processPredictions函数main.cpp#L108-L153与 Python 版逻辑一一对应双循环两两比较重叠超过overlap_threshold × smallest_areaoverlap_threshold 0.20f即把该预测标记为不通过并break通过者进入passed_predictions随后打印每个预测的标签、概率和边界框 JSON最后输出计数Connecting to WiFi.. Connected! Image captured Image read to buffer with length 17416 tomato paste: 35.84% {left:0.395631,top:0.215897,width:0.180768,height:0.359364} tomato paste: 35.87% {left:0.378554,top:0.583012,width:0.14824,height:0.359382} tomato paste: 34.11% {left:0.699024,top:0.592617,width:0.124411,height:0.350456} tomato paste: 35.16% {left:0.513006,top:0.647853,width:0.187472,height:0.325817} Counted 4 stock items.挑战与延伸课程给出的进阶挑战Challenge能否检测出错误商品把模型训练成识别多种物体然后更新应用在检测到货架上出现非预期商品时告警。还可以更进一步检测同一货架并排放置的不同商品通过给边界框划定区域限制例如某标签只允许出现在货架的某个坐标范围内判断是否有东西被放错了位置。课后作业是 assignment.md在边缘端使用你的目标检测器。课程还推荐了进一步的自研学习研究边缘缺货检测完整系统架构的设计模式以及观看介绍端到端零售解决方案组合多种 IoT 与云服务的 Hands On! 视频链接见 原版课程 的 Review Self Study 小节。小结本课的知识链路本课展示了一条完整的感知 → 推理 → 决策链路设备端PiCamera/CounterFit 模拟相机或 Wio Terminal 的 OV2640拍摄货架 → HTTP 调用 Custom Vision 推理端点detect_image或 POST Prediction-Key→ 解析概率与 0–1 边界框 → 阈值过滤 重叠去重 → 输出库存计数。三个关键可调参数值得记住threshold0.3概率下限、overlap_threshold0.20/0.002去重比例、以及发布迭代时的Iteration名称决定设备端调用哪一版模型。掌握这套模式后同样的代码结构可迁移到仓库制造项目的果实分级4-manufacturing等场景。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表