1. 在树莓派上部署TensorFlow Lite图像分类模型
任务目标
在树莓派(Raspberry Pi 4B/5,64位系统)上安装TensorFlow Lite运行时,使用Python API加载MobileNet V2图像分类模型,调用USB摄像头或树莓派Camera Module拍摄单帧图像,完成预处理、推理,并在终端输出Top-1类别标签与置信度。
环境与依赖
- 硬件:树莓派4B/5(建议2GB+内存),USB摄像头或CSI摄像头
- 系统:Raspberry Pi OS(64-bit,Bookworm或更新版本)
- Python:3.9+
- 关键依赖:
tflite-runtime(无需完整TensorFlow)、opencv-python-headless、numpy、Pillow
安装命令:
sudo apt update
sudo apt install -y python3-pip libatlas-base-dev libopenblas-dev
pip3 install --break-system-packages tflite-runtime opencv-python-headless numpy Pillow
模型与标签文件
下载MobileNet V2量化模型(float16)及ImageNet标签文件:
wget https://storage.googleapis.com/download.tensorflow.org/models/tflite/mobilenet_v2_1.0_224_quantized.tgz
tar -xzf mobilenet_v2_1.0_224_quantized.tgz
wget https://storage.googleapis.com/download.tensorflow.org/models/tflite/mobilenet_v2_1.0_224_quantized_labels.txt
模型文件为mobilenet_v2_1.0_224_quantized.tflite,标签文件每行一个类别名,共1001行(含背景类)。
完整实现代码
将以下代码保存为classify_camera.py:
import cv2
import numpy as np
from PIL import Image
import tflite_runtime.interpreter as tflite
MODEL_PATH = "mobilenet_v2_1.0_224_quantized.tflite"
LABEL_PATH = "mobilenet_v2_1.0_224_quantized_labels.txt"
CAMERA_ID = 0 # USB摄像头通常为0,CSI摄像头请使用libcamera配置
def load_labels(path):
with open(path, "r") as f:
return [line.strip() for line in f.readlines()]
def preprocess_image(image):
# 输入尺寸224x224,MobileNet V2要求像素值范围[0,1]
img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
img = img.resize((224, 224))
img = np.array(img, dtype=np.float32) / 255.0
# 增加batch维度: (1, 224, 224, 3)
return np.expand_dims(img, axis=0)
def main():
# 加载模型
interpreter = tflite.Interpreter(model_path=MODEL_PATH)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# 检查输入类型(量化模型可能需要uint8输入)
input_dtype = input_details[0]["dtype"]
print(f"模型输入类型: {input_dtype}")
# 打开摄像头
cap = cv2.VideoCapture(CAMERA_ID)
if not cap.isOpened():
raise RuntimeError("无法打开摄像头,请检查设备ID或连接")
ret, frame = cap.read()
cap.release()
if not ret:
raise RuntimeError("摄像头采集失败")
# 预处理
input_data = preprocess_image(frame)
if input_dtype == np.uint8:
input_data = (input_data * 255.0).astype(np.uint8)
# 推理
interpreter.set_tensor(input_details[0]["index"], input_data)
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]["index"])[0]
# 后处理:量化模型输出为uint8,需反量化
output_scale, output_zero_point = output_details[0]["quantization"]
if output_scale != 0.0:
output_data = (output_data.astype(np.float32) - output_zero_point) * output_scale
# 获取Top-1结果
labels = load_labels(LABEL_PATH)
top_index = np.argmax(output_data)
confidence = output_data[top_index]
print(f"类别: {labels[top_index]}")
print(f"置信度: {confidence:.4f}")
if __name__ == "__main__":
main()
运行方式
python3 classify_camera.py
验证方法与通过标准
- 基本运行验证:程序能正常启动,摄像头指示灯亮起,约2~5秒后终端输出一行类别和一行置信度,无报错退出。
- 功能正确性验证:将摄像头对准常见物体(如键盘、水杯、手机),输出的类别应与物体语义一致。例如对准键盘时,预期输出类别包含"keyboard";对准水杯时,预期输出包含"coffee mug"或"water bottle"等相近类别。
- 置信度合理性:在光线充足、物体完整入镜时,Top-1置信度应大于0.5;若置信度持续低于0.3,说明预处理或模型输入类型可能不匹配,需检查
input_dtype打印值是否为uint8。 - 异常路径验证:拔掉摄像头后运行,程序应抛出
RuntimeError并提示"无法打开摄像头",而非静默崩溃。
常见问题
- 摄像头无法打开:执行
ls /dev/video*查看设备节点,若为/dev/video1则修改CAMERA_ID=1。CSI摄像头需先运行sudo libcamera-hello确认驱动正常。 - 模型输入类型不匹配:本模型为uint8量化模型,代码已自动适配。若使用其他模型,需根据
input_details[0]["dtype"]调整预处理。 - 推理速度慢:树莓派4B上CPU推理约需200~400ms/帧,属正常现象。若需加速,可改用GPU delegate或Edge TPU(需额外硬件)。