行业资讯
基于reTerminal与Pi摄像头的嵌入式AI物体检测实战指南
1. 从零开始为什么选择 reTerminal 与 Pi 摄像头做物体检测如果你对嵌入式AI和物联网应用感兴趣想亲手搭建一个能“看见”并“理解”周围世界的智能终端那么“reTerminal Pi摄像头”这个组合绝对是一个绝佳的起点。我最近刚完成了一个基于这个平台的物体检测项目整个过程下来感觉它完美地平衡了性能、成本和开发友好度特别适合开发者、创客甚至是有一定动手能力的学生来实践。reTerminal 本质上是一台高度集成、工业级的 Raspberry Pi CM4 计算模块载体。它自带一块5英寸的触摸屏、丰富的接口包括专门用于摄像头的CSI接口、可编程按键甚至还有环境光传感器和IMU。这意味着你拿到手的就是一个完整的、带交互界面的嵌入式设备省去了自己组装屏幕、连接各种外设的麻烦。而 Raspberry Pi 官方摄像头简称 Pi 摄像头则是经过充分验证的视觉传感器与树莓派生态无缝兼容驱动成熟图像质量稳定。将这两者结合做物体检测核心价值在于你可以在一个巴掌大小、功耗极低的设备上实现实时的、本地的AI视觉推理无需依赖云端网络。想象一下你可以用它做一个智能门铃识别门口的是人还是包裹或者做一个生产线上的零件检测工站甚至是一个能自动识别宠物的智能喂食器。这一切都运行在本地数据隐私有保障响应速度也快。最近业界对像嘉楠K230这类端侧AI芯片的讨论很热其核心诉求也是边缘计算与低功耗而我们用现成的树莓派生态CM4摄像头就能快速验证类似的概念门槛要低得多。接下来我将详细拆解从硬件准备、软件环境搭建、模型选择与优化到最终部署和界面交互的完整流程。我会重点分享我在这个过程中踩过的坑和总结出的实用技巧目标是让你看完就能动手复现一个属于自己的物体检测终端。2. 硬件准备与环境配置避开第一个大坑工欲善其事必先利其器。硬件连接看起来简单但这里往往是第一个容易出错的地方。2.1 硬件清单与正确连接你需要准备以下核心硬件reTerminal 设备确保是搭载了 Raspberry Pi Compute Module 4CM4的版本。Raspberry Pi 摄像头模块推荐使用 Pi Camera Module 3因为它支持自动对焦画质也更好。Camera Module 2 或 HQ Camera 也可以但注意接口兼容性。CSI 排线一般摄像头会附带。这里有个关键细节reTerminal 的 CSI 接口是垂直向上的而排线有金属触点的一面必须朝向 reTerminal 的 PCB 板方向通常是与网口、USB口相反的方向。插入后轻轻拉一下黑色卡扣两侧的耳朵锁紧排线。连接不牢是导致“无法识别摄像头”的最常见原因。电源与存储为 reTerminal 准备一个 5V/3A 的 Type-C 电源。CM4的eMMC存储已预装系统无需额外SD卡。连接好后启动 reTerminal。第一次启动可能需要几分钟初始化。你会看到基于 Raspberry Pi OS 的桌面环境。2.2 操作系统与基础软件安装reTerminal 预装的系统可能不是最新或者我们需要一个更干净的环境。我推荐从 Seeed Studio 官网下载专为 reTerminal 适配的 Raspberry Pi OS 镜像它包含了屏幕、按键等所有硬件的驱动。步骤一更新系统与启用摄像头打开终端首先进行全系统更新sudo apt update sudo apt full-upgrade -y sudo reboot更新后需要确保摄像头接口已启用。虽然 reTerminal 的专用镜像通常已配置好但检查一下更稳妥sudo raspi-config在配置界面中选择Interface Options-Legacy Camera或Camera取决于系统版本确保其被设置为Enable。完成后退出并重启。步骤二验证摄像头工作重启后用一个简单命令测试摄像头libcamera-hello -t 0这个命令会打开一个实时预览窗口。如果能看到图像说明摄像头硬件连接和驱动完全正常。按CtrlC退出。注意传统的raspistill命令在最新的 Bullseye/Buster 系统上可能已被弃用或无法工作libcamera系列命令是新的标准务必使用它。步骤三安装 Python 环境与核心库我们的项目将主要使用 Python。安装 pip 和虚拟环境工具管理项目依赖会更干净sudo apt install -y python3-pip python3-venv然后创建一个项目目录并进入建立虚拟环境mkdir ~/object_detection_project cd ~/object_detection_project python3 -m venv venv source venv/bin/activate激活虚拟环境后命令提示符前会出现(venv)标识。接下来安装核心的计算机视觉库。这里有个选择OpenCV。在树莓派上安装 OpenCV 如果从 pip 直接安装opencv-python可能会遇到性能问题或缺少某些优化。我推荐使用针对 ARM 架构预编译的版本或者从源码编译耗时较长。一个更快捷稳定的方法是安装libopencv系统包和 Python 绑定sudo apt install -y python3-opencv在虚拟环境中链接到系统已安装的 OpenCVpip install opencv-python-headless此外我们还需要安装图像处理库 PIL/Pillow以及用于模型推理的框架。由于我们可能使用 TensorFlow Lite 或 ONNX Runtime 等轻量级引擎先一并安装pip install pillow numpy pip install tflite-runtimetflite-runtime是 TensorFlow Lite 的精简版比安装完整的tensorflow包体积小得多更适合嵌入式设备。3. 物体检测模型的选择、获取与优化模型是物体检测的大脑。在资源受限的 reTerminalCM4通常为2GB或4GB内存上我们不能直接使用像 YOLOv8 原生 PyTorch 版本这样的大型模型必须进行精心的选择和优化。3.1 模型选型在精度与速度间寻找平衡对于边缘设备我们的选型标准依次是模型大小、推理速度FPS、精度mAP、易用性。以下是几个经过实战检验的候选MobileNet SSD (TensorFlow Lite)经典中的经典。基于 MobileNet 骨干网络的单次检测器SSD模型小约几MB到20MB速度极快在 COCO 数据集上能识别80类常见物体。缺点是对于小物体和密集场景的精度一般。YOLOv5/v8 Nano/Small (导出为 TFLite 或 ONNX)YOLO 系列在精度和速度的平衡上做得很好。YOLOv5n 或 YOLOv8n 是专为移动端设计的纳米版本模型大小在 3-5MB 左右在 CM4 上使用适当的推理引擎如 ONNX Runtime可以达到接近实时的速度。EfficientDet-Lite (TensorFlow Lite Model Maker)谷歌专门为 TFLite 优化的 EfficientDet 版本在同等计算量下通常比 MobileNet SSD 精度更高。TFLite Model Maker 工具还能让你用自己的数据轻松微调。我的选择与理由对于初次实践和大多数通用场景我推荐从MobileNet SSD COCO 量化模型开始。原因有三首先它极其成熟社区资料和示例代码最多踩坑容易找到解决方案其次TFLite 运行时在树莓派上优化得很好部署最简单最后它的速度足够快在 reTerminal 上实现 5-10 FPS 的检测预览是可行的能满足很多实时性要求不极端的场景。3.2 获取与准备模型文件以 MobileNet SSD v2COCO 数据集为例我们可以直接从 TensorFlow 官方模型仓库下载预训练的 TFLite 模型。在项目目录下创建一个models文件夹并下载模型mkdir models cd models wget https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip unzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip你会得到detect.tflite模型文件和labelmap.txt标签文件。标签文件定义了模型能识别的 801 个类别1 是背景。重要理解量化模型我们下载的是“量化”Quantized模型。这意味着模型权重从浮点数float32转换成了整数int8。量化能大幅减少模型体积和提升推理速度对 CPU 非常友好是边缘部署的标配。代价是精度会有轻微损失但对于很多应用而言完全可以接受。3.3 测试模型推理编写第一个检测脚本在项目根目录创建一个test_detection.py脚本进行静态图片测试验证整个链路是否通畅。import cv2 import numpy as np import tflite_runtime.interpreter as tflite from PIL import Image # 1. 加载模型和标签 MODEL_PATH ‘models/detect.tflite’ LABEL_PATH ‘models/labelmap.txt’ interpreter tflite.Interpreter(model_pathMODEL_PATH) interpreter.allocate_tensors() # 获取输入输出详情 input_details interpreter.get_input_details() output_details interpreter.get_output_details() _, height, width, _ input_details[0][‘shape’] # 通常为 300x300 with open(LABEL_PATH, ‘r’) as f: labels [line.strip() for line in f.readlines()] # 2. 准备输入图像这里用一张本地测试图或直接用摄像头抓一帧 # 假设有一张 test.jpg image cv2.imread(‘test.jpg’) image_rgb cv2.cvtColor(image, cv2.COLOR_BGR2RGB) image_pil Image.fromarray(image_rgb) # 调整尺寸并归一化量化模型期望输入为 uint8 input_data np.expand_dims(image_pil.resize((width, height)), axis0) # 3. 推理 interpreter.set_tensor(input_details[0][‘index’], input_data.astype(np.uint8)) interpreter.invoke() # 4. 解析输出 boxes interpreter.get_tensor(output_details[0][‘index’])[0] # 边界框 classes interpreter.get_tensor(output_details[1][‘index’])[0] # 类别索引 scores interpreter.get_tensor(output_details[2][‘index’])[0] # 置信度 num interpreter.get_tensor(output_details[3][‘index’])[0] # 检测数量 # 5. 可视化结果 for i in range(int(num)): if scores[i] 0.5: # 置信度阈值 ymin, xmin, ymax, xmax boxes[i] # 将归一化坐标转换为原图坐标 (left, right, top, bottom) (xmin * image.shape[1], xmax * image.shape[1], ymin * image.shape[0], ymax * image.shape[0]) cv2.rectangle(image, (int(left), int(top)), (int(right), int(bottom)), (0, 255, 0), 2) label ‘{}: {:.2f}%’.format(labels[int(classes[i])], scores[i]*100) cv2.putText(image, label, (int(left), int(top)-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.imshow(‘Detection Result’, image) cv2.waitKey(0) cv2.destroyAllWindows()运行这个脚本python test_detection.py如果一切正常你应该能看到图片中的物体被框出并标上了标签。这一步的成功标志着模型和推理环境完全正确。4. 实现实时摄像头流物体检测静态图片测试通过后我们就可以进入核心环节连接 Pi 摄像头进行实时视频流检测。这里的关键是高效地读取摄像头帧并组织一个稳定的推理循环。4.1 使用 libcamera 与 OpenCV 捕获视频如前所述在新版系统上我们使用libcamera作为底层驱动。但 OpenCV 的cv2.VideoCapture默认可能无法直接与libcamera通信。一个可靠的方法是使用libcamera-vid管道或者使用一个名为picamera2的新库它是为libcamera设计的 Python 接口。首先安装picamera2sudo apt install -y python3-picamera2然后我们编写实时检测脚本realtime_detection.pyimport cv2 import numpy as np import tflite_runtime.interpreter as tflite from picamera2 import Picamera2 from PIL import Image import time # 初始化摄像头 picam2 Picamera2() # 配置预览格式主流格式与模型输入兼容 config picam2.create_preview_configuration(main{“size”: (640, 480), “format”: “RGB888”}) picam2.configure(config) picam2.start() # 加载模型和标签同上此处省略以节省篇幅 interpreter tflite.Interpreter(model_path‘models/detect.tflite’) interpreter.allocate_tensors() input_details interpreter.get_input_details() output_details interpreter.get_output_details() _, input_height, input_width, _ input_details[0][‘shape’] # 加载标签 with open(‘models/labelmap.txt’, ‘r’) as f: labels [line.strip() for line in f.readlines()] # 帧率计算 fps_start_time time.time() fps_frame_count 0 fps 0 print(“开始实时检测按 ‘q’ 键退出...”) try: while True: # 从摄像头捕获一帧 frame picam2.capture_array() # 直接得到 numpy array (RGB) if frame is None: continue # 计算并显示FPS fps_frame_count 1 if fps_frame_count 30: fps fps_frame_count / (time.time() - fps_start_time) fps_start_time time.time() fps_frame_count 0 cv2.putText(frame, f“FPS: {fps:.1f}”, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 准备模型输入 img_pil Image.fromarray(frame) input_data np.expand_dims(img_pil.resize((input_width, input_height)), axis0) # 推理 interpreter.set_tensor(input_details[0][‘index’], input_data.astype(np.uint8)) interpreter.invoke() # 获取结果 boxes interpreter.get_tensor(output_details[0][‘index’])[0] classes interpreter.get_tensor(output_details[1][‘index’])[0] scores interpreter.get_tensor(output_details[2][‘index’])[0] num interpreter.get_tensor(output_details[3][‘index’])[0] # 在原图上绘制检测框 for i in range(int(num)): if scores[i] 0.5: # 置信度阈值 ymin, xmin, ymax, xmax boxes[i] left int(xmin * frame.shape[1]) right int(xmax * frame.shape[1]) top int(ymin * frame.shape[0]) bottom int(ymax * frame.shape[0]) cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2) label f“{labels[int(classes[i])]}: {scores[i]*100:.1f}%” cv2.putText(frame, label, (left, top-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) # 显示结果 (BGR格式供OpenCV显示) frame_bgr cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) cv2.imshow(‘Object Detection on reTerminal’, frame_bgr) # 按 ‘q’ 退出 if cv2.waitKey(1) 0xFF ord(‘q’): break finally: # 释放资源 picam2.stop() cv2.destroyAllWindows() print(“程序结束。”)这个脚本创建了一个稳定的检测循环。picamera2直接提供 numpy 数组避免了格式转换的额外开销。我们同时计算并显示了帧率FPS这是评估性能的关键指标。4.2 性能调优与实战踩坑记录直接运行上述脚本你可能会发现 FPS 并不高可能在 2-4 之间。这对于实时体验来说有点卡顿。下面是我经过多次尝试后总结的优化策略1. 降低输入分辨率与巧用线程模型输入是300x300但摄像头捕获是640x480。resize操作是 CPU 计算有开销。我们可以尝试在摄像头配置时就用一个更低的分辨率比如直接匹配模型输入config picam2.create_preview_configuration(main{“size”: (300, 300), “format”: “RGB888”})但这样预览窗口会很小。一个折中方案是用低分辨率做推理高分辨率做显示。我们可以配置摄像头输出两个流still stream 和 preview stream但这稍复杂。更简单实用的优化是使用生产者-消费者模型将图像捕获和模型推理放在两个线程中避免因推理阻塞导致掉帧。2. 模型推理加速 - 使用 Coral USB 加速器可选进阶如果对速度有极致要求例如需要 20 FPS可以考虑添加硬件加速器。Google Coral USB Accelerator 是一个即插即用的边缘 TPU 设备能极大加速量化 TFLite 模型。你需要下载专门编译的、兼容 Edge TPU 的模型文件后缀为_edgetpu.tflite并安装pycoral库。使用后FPS 可以轻松提升一个数量级。这对于需要快速响应的应用如高速流水线检测是质的飞跃。3. 发热与稳定性长时间运行CM4 会发热。reTerminal 的金属外壳有助于散热但在高负载下仍可能过热降频。我建议在/boot/config.txt中添加temp_soft_limit85如果不存在这允许芯片在更高温度下运行。考虑在 reTerminal 背面粘贴小型散热片。对于 24/7 运行的应用最好在代码中添加温度监控在温度过高时暂停检测或降低推理频率。4. 一个常见的坑picamera2的权限问题有时运行脚本会报错提示无法打开摄像头。除了检查物理连接还需要确保用户有访问摄像头的权限。将当前用户加入video组通常可以解决sudo usermod -a -G video $USER然后需要注销并重新登录或者重启系统这个改动才能生效。5. 打造交互式应用利用 reTerminal 的硬件特性reTerminal 不仅仅是一台“无头”的树莓派它的屏幕和按键为我们提供了打造独立交互式应用的绝佳条件。我们可以摆脱对 SSH 和远程桌面的依赖制作一个即开即用的检测终端。5.1 使用 PyGame 或 Kivy 创建本地 GUIOpenCV 的cv2.imshow()窗口在 reTerminal 的桌面环境下可以运行但它不是一个原生的、全屏的、易于控制的应用。为了更好的体验我们可以使用 PyGame 或 Kivy 这类 GUI 库来创建界面。这里以 PyGame 为例因为它更轻量且适合简单的图像显示和按键交互。我们将修改之前的实时检测脚本用 PyGame 窗口替代 OpenCV 的显示。首先安装 PyGamepip install pygame然后创建detection_gui.pyimport pygame import cv2 import numpy as np import tflite_runtime.interpreter as tflite from picamera2 import Picamera2 from PIL import Image import time from threading import Thread, Lock # 初始化 Pygame pygame.init() screen_width, screen_height 800, 480 # reTerminal 屏幕分辨率 screen pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption(“reTerminal Object Detector”) clock pygame.time.Clock() # 摄像头和模型初始化与之前类似略去细节 picam2 Picamera2() config picam2.create_preview_configuration(main{“size”: (640, 480)}) picam2.configure(config) picam2.start() interpreter tflite.Interpreter(model_path‘models/detect.tflite’) interpreter.allocate_tensors() # ... 加载标签等代码 ... # 线程安全的帧和结果存储 current_frame None current_detections [] # 存储格式: [(label, score, (x1,y1,x2,y2)), ...] frame_lock Lock() def inference_thread(): global current_frame, current_detections while True: with frame_lock: if current_frame is None: time.sleep(0.01) continue frame_copy current_frame.copy() # 在此帧上进行推理... # ... 推理代码更新 current_detections ... time.sleep(0.05) # 控制推理频率避免过度占用CPU # 启动推理线程 Thread(targetinference_thread, daemonTrue).start() running True while running: # 处理 Pygame 事件如退出、按键 for event in pygame.event.get(): if event.type pygame.QUIT: running False elif event.type pygame.KEYDOWN: if event.key pygame.K_ESCAPE: # 按ESC退出 running False elif event.key pygame.K_SPACE: # 按空格保存截图 pygame.image.save(screen, f“capture_{int(time.time())}.jpg”) # 从摄像头获取最新帧 frame_rgb picam2.capture_array() with frame_lock: current_frame frame_rgb display_frame frame_rgb.copy() # 在显示帧上绘制检测结果从 current_detections 读取 # ... 绘制矩形和文本的代码 ... # 将 OpenCV 图像RGB转换为 Pygame 表面需要转置和BGR2RGB注意通道 # Pygame 期望的格式是 (width, height, RGB) frame_surface pygame.surfarray.make_surface(np.transpose(display_frame, (1, 0, 2))) # 缩放表面以适应屏幕可选 frame_surface pygame.transform.scale(frame_surface, (screen_width, screen_height)) # 刷新屏幕 screen.blit(frame_surface, (0, 0)) pygame.display.flip() clock.tick(30) # 限制帧率 picam2.stop() pygame.quit()这个框架将图像捕获主线程、模型推理子线程和界面渲染主线程分离保证了界面的流畅性。同时它响应了 reTerminal 的物理按键通过 PyGame 的键盘事件例如用 ESC 键退出用空格键保存当前检测结果的截图。5.2 利用 reTerminal 侧边按键与传感器reTerminal 的侧边有5个可编程按键A, B, C, D, 以及一个功能键。我们可以将这些按键映射为应用功能例如A键切换检测模型例如在“人”检测和“车”检测模型间切换。B键调整置信度阈值。C键开启/关闭检测结果显示仅显示原始视频流。D键拍照并保存。功能键退出应用。在 PyGame 中我们可以通过监听pygame.KEYDOWN事件并判断event.key的值来捕获这些按键。需要先确认 reTerminal 上这些按键映射到了哪个键值通常可以通过写一个简单的测试脚本来打印event.key得知。此外reTerminal 板载的环境光传感器和 IMU惯性测量单元也大有可为。例如可以用环境光传感器自动调节屏幕亮度用 IMU 检测设备姿态当 reTerminal 被拿起或移动时自动唤醒或进入检测模式。这些传感器的访问通常需要通过 I2C 或特定的 Linux 设备文件需要安装额外的 Python 库如smbus2读取 I2C。6. 项目进阶与优化思路一个基础的可视化检测应用完成后我们可以从以下几个方向进行深化让它变成一个更“有用”的项目。6.1 模型定制化训练识别特定物体预训练的 COCO 模型能识别80类物体但如果你只想识别“螺丝刀”、“某种特定零件”或“自家宠物”就需要定制模型。这里推荐使用TensorFlow Lite Model Maker。它大大简化了迁移学习的过程。基本流程如下收集数据为你想要识别的物体例如“咖啡杯”拍摄至少100-200张照片最好在不同的角度、光照和背景下拍摄。用标注工具如 LabelImg标注出物体位置生成 XMLVOC格式或 JSONCOCO格式文件。准备环境在一台性能更强的机器如你的开发电脑上安装 TensorFlow 和 Model Maker。运行训练脚本Model Maker 提供了示例脚本你只需指定数据路径和预训练模型如efficientdet-lite0它就能自动完成数据转换、训练和导出 TFLite 模型。部署将生成的.tflite文件拷贝到 reTerminal替换之前的模型文件更新标签路径你的应用就变成了一个专属检测器。6.2 集成与联动从“看见”到“行动”单纯的检测和显示价值有限真正的威力在于与外部世界联动。网络通信检测到特定物体后通过 reTerminal 的 Wi-Fi 或以太网向服务器如 Home Assistant, MQTT Broker发送一条消息。例如检测到“人”就发送一条person_detected事件到智能家居系统触发灯光或警报。控制 GPIOreTerminal 有可用的 GPIO 引脚通过 40-pin 排针引出。你可以通过gpiozero或RPi.GPIO库控制继电器、LED 灯或蜂鸣器。例如检测到“猫”靠近喂食器就触发 GPIO 信号打开一个舵机放出猫粮。本地日志与存储将检测到的事件时间、物体类别、置信度记录到本地的 SQLite 数据库或 CSV 文件中用于后续分析。6.3 性能与功耗的终极权衡对于电池供电或长期值守的应用功耗是关键。动态帧率不是每一帧都需要检测。当场景静止时可以降低检测频率如每秒1次当 IMU 检测到运动或画面变化剧烈时再提升到全速检测。模型休眠在无人时段可以完全停止摄像头和推理进程让系统进入低功耗的休眠状态由定时器或外部传感器唤醒。选择更优模型对比不同轻量级模型如 YOLO-Fastest, NanoDet在你的特定场景下的精度、速度和功耗选择最优解。经过以上步骤你手中的 reTerminal 就不再只是一个开发板而是一个功能完整、可交互、能解决实际问题的智能视觉终端。从硬件连接、软件配置、模型推理到应用开发整个流程走下来你会对边缘AI视觉项目有一个非常扎实的理解。最重要的是这个过程是可复现、可扩展的你可以基于这个框架去实现任何你想象中的视觉应用。
郑州网站建设
网页设计
企业官网