IoT-For-Beginners:将 Raspberry Pi 与虚拟设备接入 Azure IoT Edge 上的水果图像分类器

发布时间:2026/9/14 14:17:15
IoT-For-Beginners:将 Raspberry Pi 与虚拟设备接入 Azure IoT Edge 上的水果图像分类器 IoT-For-Beginners将 Raspberry Pi 与虚拟设备接入 Azure IoT Edge 上的水果图像分类器【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本篇指南基于 IoT-For-Beginners 制造行业课程的single-board-computer.md文档讲解如何在单板计算机Raspberry Pi / 虚拟 IoT 设备上把fruit-quality-detector项目的图像分类调用从云端 Custom Vision 切换到运行在 Azure IoT Edge 设备上的本地分类器移除云端 SDK 依赖、改用 REST API 发送原始图像字节流并解析边缘端返回的 JSON 预测结果。完成后你将能够让自己的 IoT 设备在局域网内完成图像推理无需经过公网。前提图像分类器已在 IoT Edge 设备上运行本文档是课程第 3 课「在边缘运行水果检测器」的一个环节对应主文档 3-run-fruit-detector-edge/README.md 中「Use your IoT Edge device」章节给出的单板计算机路径。进入本文之前需要已经完成以下工作在 IoT Hub 中注册了一个--edge-enabled的 IoT Edge 设备本教程命名为fruit-quality-detector-edge并安装启动了 IoT Edge 运行时仅支持 Linux 容器可运行在 Raspberry Pi OS、Linux 主机或 Linux 虚拟机上从 Custom Vision 导出了紧凑模型Food (compact) 域的 DockerFile用 Docker 构建并推送为classifier:v1容器镜像至 Azure Container Registry使用部署清单将ImageClassifier模块部署到了边缘设备可用仓库中的 deployment.json 作为清单模板。部署清单中ImageClassifier模块的createOptions说明了本文档中分类器 URL 的由来createOptions: {\ExposedPorts\: {\80/tcp\: {}},\HostConfig\: {\PortBindings\: {\80/tcp\: [{\HostPort\: \80\}]}}}即容器内的 Flask 服务监听0.0.0.0:80这一点可以从 README.md 中iotedge logs ImageClassifier的输出Running on http://0.0.0.0:80/得到印证被映射到宿主机的 80 端口。因此图像分类器的 URL 为http://IP address or name/image其中IP address or name替换为运行 IoT Edge 的计算机的 IP 地址或主机名。为什么必须改用 REST API原文档明确指出了一个关键限制Custom Vision 的 Python 库azure.cognitiveservices.vision.customvision.prediction只支持与托管在云端的模型配合使用无法调用托管在 IoT Edge 上的模型。也就是说上一课「从 IoT 设备检测水果质量」中基于CustomVisionPredictionClient的云端调用方式在这里直接失效必须退回到最底层的 REST API 来调用边缘分类器。这与边缘部署的设计目标一致Custom Vision 导出的容器本身就内置了一个 REST APIFlask 应用与云端版本的接口形态一致只是端点指向了运行容器的边缘设备。此外还有一个重要区别调用边缘分类器不需要 prediction key。主文档在 curl 测试小节中说明由于这不是在调用 Azure 资源安全不再依赖公网端点加 API 密钥而是由内网自身的网络安全策略来保障。任务改造 app.py 以调用 IoT Edge 分类器以下操作步骤完整继承自 single-board-computer.md该文档为课程的阿拉伯语译本与英文原版 4-manufacturing/lessons/3-run-fruit-detector-edge/single-board-computer.md 内容一致并结合仓库中的参考代码进行了注释补充。1. 打开项目并激活虚拟环境在 VS Code 中打开fruit-quality-detector项目如尚未打开。如果使用虚拟 IoT 设备确保虚拟环境已激活。2. 移除云端 SDK 的导入语句打开app.py删除以下两个模块的导入语句azure.cognitiveservices.vision.customvision.predictionmsrest.authentication这两个导入是上一课调用云端 Custom Vision 时引入的CustomVisionPredictionClient与ApiKeyCredentials在边缘场景下不再需要。3. 引入 requests 库在文件顶部添加import requests4. 删除云端调用代码删除图像保存到文件之后的全部代码即从image_file.write(image.read())到文件末尾。被删除的是上一课 single-board-computer-classify-image.md 中添加的云端调用逻辑包括解析 prediction URLparts prediction_url.split(/)提取 endpoint / project_id / iteration_name、创建ApiKeyCredentials与CustomVisionPredictionClient、调用predictor.classify_image(...)以及遍历results.predictions打印结果的代码。5. 添加 REST 调用代码在文件末尾添加如下代码prediction_url URL headers { Content-Type : application/octet-stream } image.seek(0) response requests.post(prediction_url, headersheaders, dataimage) results response.json() for prediction in results[predictions]: print(f{prediction[tagName]}:\t{prediction[probability] * 100:.2f}%)将URL替换为你边缘分类器的实际 URL形如http://192.168.1.50/image。逐行说明这段代码的意图prediction_url指向运行 IoT Edge 的分类器端点路径固定为/imageheaders请求头声明Content-Type: application/octet-stream表示请求体是原始的二进制图像字节流JPEG而非 JSONimage.seek(0)image是上一步io.BytesIO()内存流此前已被读取并写入image.jpg文件指针停在末尾必须回绕到起点requests才能读到完整的图像数据requests.post(..., dataimage)以 POST 方式把整段图像字节流作为请求体发送出去不携带任何 Prediction-Key 请求头与云端调用不同response.json()边缘分类器返回 JSON 格式结果直接反序列化遍历results[predictions]每个预测项包含tagName标签名与probability0 到 1 的浮点数代码将其换算成百分比保留两位小数打印。6. 运行并验证将摄像头对准一些水果真实 Raspberry Pi 相机或准备一组合适的测试图片虚拟 IoT 设备使用摄像头中的水果画面运行(.venv) ➜ fruit-quality-detector python app.py ripe: 56.84% unripe: 43.16%看到两个标签的概率输出即表示单板计算机已成功调用边缘分类器。仓库中提供了两套可直接对照的最终参考代码code-classify/pi/fruit-quality-detector/app.py真实 Raspberry Pi 版本使用picamera的PiCamera采集 640x480 图像code-classify/virtual-iot-device/fruit-quality-detector/app.py虚拟设备版本用 CounterFit 模拟硬件。源码级解读两个设备版本的完整 app.py从源码结构看本文档描述的改造结果正好是上一课云端版本app.py的「去 SDK 化」版本两个版本的前半段采集 存图完全相同只有分类调用段不同。真实 Pi 版code-classify/pi/.../app.py共 28 行的完整结构import io import requests import time from picamera import PiCamera camera PiCamera() camera.resolution (640, 480) camera.rotation 0 time.sleep(2) image io.BytesIO() camera.capture(image, jpeg) image.seek(0) with open(image.jpg, wb) as image_file: image_file.write(image.read()) prediction_url URL headers { Content-Type : application/octet-stream } image.seek(0) response requests.post(prediction_url, headersheaders, dataimage) results response.json() for prediction in results[predictions]: print(f{prediction[tagName]:\t{prediction[probability] * 100:.2f}%)注意第 14 行image.seek(0)采集后为保存文件而回绕与第 23 行的第二次image.seek(0)发送 HTTP 请求前再次回绕——因为image_file.write(image.read())又一次把指针读到了末尾。两次 seek 是这段代码容易踩坑的细节。虚拟设备版code-classify/virtual-iot-device/.../app.py与真实 Pi 版唯一的差异在开头from counterfit_connection import CounterFitConnection CounterFitConnection.init(127.0.0.1, 5000) ... from counterfit_shims_picamera import PiCamera它通过 CounterFit 连接服务127.0.0.1:5000和counterfit_shims_picamera提供的PiCamera垫片类把「物理相机」替换为虚拟图像源因此同一套 REST 调用代码可以原封不动地在没有树莓派相机的开发机上运行。响应体结构predictions 里有什么边缘分类器返回的 JSON 与云端预测 API 的形态一致。README.md 中用 curl 直接测试容器时的示例响应可以帮你核对app.py解析的字段是否正确{ created: 2021-07-05T21:44:39.573181, id: , iteration: , predictions: [ { boundingBox: null, probability: 0.9995615482330322, tagId: , tagName: ripe }, { boundingBox: null, probability: 0.0004384400090202689, tagId: , tagName: unripe } ], project: }其中predictions是数组图像分类器而非目标检测器会为每个已发布的标签各返回一项boundingBox恒为nullprobability是 0–1 的浮点数tagName即训练时定义的标签本项目的ripe/unripe对应模块日志中Loading labels...2 found. Success!加载的 2 个标签tagId、iteration、project等字段在边缘容器中返回的是空字符串——因为它们属于 Custom Vision 云项目元数据容器内并不携带。不运行 Python 代码时也可以直接用 curl 验证分类器容器是否工作file_Name替换为本地测试图片IP address or name替换为运行 IoT Edge 的主机地址同机可用localhostcurl --location \ --request POST http://IP address or name/image \ --header Content-Type: image/png \ --data-binary file_Name边缘部署带来的行为差异切换到 IoT Edge 分类器后有两点与云端方案的行为差异需要注意来自主文档 3-run-fruit-detector-edge/README.md 的「Model retraining」章节隐私与离线能力图像不再上传到云端Custom Vision 控制台的Predictions标签页不会显示这些边缘分类的图片。这是边缘计算的预期行为也是其优势——数据不出内网且设备无网时依然可用。模型改进需要额外通路正因为预测数据不回传云端模型迭代时无法像云端那样直接利用 Predictions 标签页里的图像重新训练需要自行设计一套机制例如把低置信度图像存储下来、人工复核后回传训练。主文档把「设计一种上传图像用于重训分类器的方案」留作思考题。小结本文档的核心结论可以归纳为三条边缘分类器的端点是http://运行 IoT Edge 的主机 IP 或主机名/image端口映射由部署清单中ImageClassifier模块的80/tcp - 80绑定决定Custom Vision 的 Python SDK 只支持云端模型边缘调用必须走 REST APIrequests.postContent-Type: application/octet-stream 原始图像字节流且无需 prediction key改造后的完整代码可直接对照仓库中 code-classify/pi 与 code-classify/virtual-iot-device 两个目录下的app.py虚拟设备版本额外使用 CounterFit 垫片模拟相机使整套代码可在无硬件环境复现。对于使用 Wio Terminal 的用户同课程提供了平行的改造路径修改config.h中的PREDICTION_URL、移除证书与Prediction-Key头、将WiFiClientSecure换成WiFiClient见 wio-terminal.md。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考