让树莓派数清货架商品:IoT 设备调用目标检测器实战

发布时间:2026/10/5 6:34:02
让树莓派数清货架商品:IoT 设备调用目标检测器实战 让树莓派数清货架商品IoT 设备调用目标检测器实战【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners在 IoT-For-Beginners 零售项目的上一课里你已经训练并发布了一个番茄酱库存目标检测器。本课只解决一件事让树莓派或虚拟 IoT 设备自己拍下货架照片调用这个检测器最后数出货架上到底有几件商品。整条链路是换调用 → 阈值过滤 → 读边界框 → 去重计数代码改动量比想象中小。把 classify_image 换成 detect_image改造调用方式制造项目第 2 课你已经跑通过拍照 → 调分类器 → 打印结果的完整流程这套代码在检测场景下几乎可以原样复用唯一的分水岭是 Custom Vision SDK 上调用的方法名和返回结构。拍照环节树莓派用 PiCamera虚拟 IoT 设备则由 CounterFit 的counterfit_shims_picamera模拟同样的接口两种设备共用同一份预测代码。树莓派版的完整调用配置可参考 单板机检测程序。删掉这三行分类调用在你本地的app.py里找到分类入口和它的打印循环整体删掉results predictor.classify_image(project_id, iteration_name, image) for prediction in results.predictions: print(f{prediction.tag_name}:\t{prediction.probability * 100:.2f}%)classify_image是分类器的入口下面那个循环负责逐条打印每个标签的结果检测场景里两者都用不上。换成 detect_image 检测调用在原位置写入新调用三个参数保持不变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是目标检测的入口results.predictions现在是一串预测每条都带着tag_name商品标签和probability置信度。列表推导式只保留高于threshold的结果循环里再逐条打印标签名和百分比。用概率阈值过滤低置信度预测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%四行输出对应货架上的四罐番茄酱每行是一个标签 置信度组合。 换成你自己的拍摄角度后把threshold调到输出既干净又不漏数的位置即可。解析 bounding_box把相对坐标画成边界框检测器与分类器返回结构最大的差异是每个预测多了一个bounding_box它不仅告诉你是什么还告诉你在图的哪个位置。把它追加到打印语句末尾就能看到原始数据print(f{prediction.tag_name}:\t{prediction.probability * 100:.2f}%\t{prediction.bounding_box})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}top、left、width、height四个字段都是 0 到 1 的相对值坐标原点(0, 0)在图片左上角框的下边缘等于top height。你可以把整张图想象成 100×100 的方格纸top 0.4就代表框从第 40 行位置开始与图片实际分辨率无关。以一张宽 600、高 800 像素的照片为例字段相对值像素换算top0.4800 × 0.4 320框顶边距图上沿 320 像素left0.4600 × 0.4 240框左边距图左沿 240 像素height0.3800 × 0.3 240框高 240 像素width0.2600 × 0.2 120框宽 120 像素想让检测效果看得见就装上 Pillow把框直接画在保存的image.jpg上用虚拟 IoT 设备的话要在激活的虚拟环境里运行pip3 install pillow文件顶部加一行导入from PIL import Image, ImageDraw, ImageColor末尾追加绘制逻辑with 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)第一步把四个 0~1 的相对值乘上图片宽高换算成像素left为 0.5、图宽 600 时就是 300 像素再用 2 像素宽的红色线条画出每个边界框最后覆盖保存原图。运行后直接打开image.jpg每罐商品都被红框圈住用 Shapely 剔除重叠边界框数出真实库存货架上的罐头常常前后排叠放检测框会互相压住——重叠太狠时往往说明两个框其实是同一件商品。计数前先装 Shapely树莓派要先装系统依赖sudo apt install libgeos-dev pip3 install shapely顶部加from shapely.geometry import Polygon再定义重叠阈值和边界框转多边形的辅助函数overlap_threshold 0.20 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)]) 0.20 的含义是重叠面积超过较小那个框的 20%就判定为同一物体。随后用双重循环两两比较所有预测to_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)intersection求出两个框的交集多边形.area就是重叠面积判定标准取相对较小框的比例而非绝对值大小不同的框也能公平比较。被判重复的预测先记入to_deletePython 不允许遍历列表时直接删除元素循环结束后统一移除命中即在内层循环break。最后打印去重后的数量后面的画框环节也只用这份去重后的列表。虚拟设备的示例代码把overlap_threshold调成了 0.002可对比观察不同阈值对剔除结果的影响见 虚拟设备版计数代码Counted 4 stock items这段去重策略刻意做得很粗——碰到重叠就删掉配对中的第一个一个框完全套在另一个框里这类边界情形也没处理生产系统需要更细致的规则。但它已足够把len(predictions)变成一个可用的库存数字。下一步把库存数字接进补货链路把计数结果上报给 IoT Hub Functions 之类的 IoT 服务库存低于水位线时自动发出补货告警借助 Azure IoT Edge 把目标检测器搬到设备边缘运行减少对云端往返的依赖换一组新商品重新训练检测器观察概率阈值与重叠阈值是否要重新校准。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考