Chapter 07 · 树莓派与嵌入式 Linux

摄像头与多媒体

给树莓派装上眼睛:CSI 摄像头拍照录像,OpenCV 做图像处理,甚至跑起人脸检测。边缘视觉从这里开始。

课程进度58%

关键概念

CSI 摄像头模块
通过 CSI(Camera Serial Interface)排线口连接的官方摄像头,如 Camera Module 3、HQ Camera。它是高速专用接口,比 USB 摄像头延迟低、CPU 占用小、画质好。安装时排线金属触点朝向要正确(一般朝 HDMI 口方向),插反了识别不了。
picamera2 库
树莓派新一代官方 Python 摄像头库(取代老的 picamera),基于 libcamera 框架,系统预装。支持拍照、录像、预览、实时帧捕获、和 OpenCV/NumPy 无缝对接。Bookworm 系统的标准摄像头 API,本章主力。
libcamera
Linux 的现代摄像头栈,取代了树莓派早期的私有 MMAL 栈。它统一了摄像头驱动接口,提供 rpicam-stillrpicam-vid 等命令行工具(旧名 libcamera-*)。picamera2 是它的 Python 封装。
OpenCV
开源计算机视觉库,图像处理的事实标准。提供读写图像、缩放/裁剪/滤波、边缘检测、颜色空间转换、特征检测、人脸/物体识别等海量功能。Python 中 import cv2。图像在 OpenCV 里就是 NumPy 数组,可直接用 NumPy 运算。
帧(Frame)与分辨率
视频是连续图像帧。分辨率(如 1920×1080)决定清晰度,越高越占 CPU/内存/带宽。树莓派做实时处理时常降到 640×480 保证帧率。帧率(FPS)指每秒帧数,实时视觉一般求 15~30 FPS。分辨率与帧率要按算力权衡。
BGR 色彩顺序
OpenCV 历史原因用 BGR(蓝绿红)而非常见的 RGB 顺序存储图像。与其他库(如 PIL、matplotlib 用 RGB)交互时要用 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 转换,否则颜色会红蓝颠倒。这是新手常踩的坑。
Haar 级联分类器
OpenCV 内置的经典人脸/物体检测方法,基于预训练的特征模型(xml 文件)。轻量、CPU 上就能跑,适合树莓派做简单人脸检测。精度不如深度学习模型,但无需 GPU、部署简单,是边缘设备入门首选。
V4L2 与 USB 摄像头
Video4Linux2 是 Linux 的视频设备统一接口。USB 摄像头(UVC 免驱)插上后会出现为 /dev/video0,OpenCV 用 cv2.VideoCapture(0) 即可读取。CSI 摄像头则推荐用 picamera2。两者可在代码里灵活选择。

启用摄像头

新版系统(bookworm)默认自动检测 CSI 摄像头,一般无需手动开启。接好排线后验证:

# 列出检测到的摄像头
rpicam-hello --list-cameras
# 应显示 0 : imx708 [4608x2592] ... 表示识别成功

# 预览 5 秒(接了显示器时可见画面)
rpicam-hello -t 5000

# 命令行直接拍一张照片
rpicam-still -o test.jpg

# 录制 10 秒视频
rpicam-vid -t 10000 -o test.h264

# 如果识别不到:检查排线是否插紧、方向是否正确
# 老系统需在 raspi-config → Interface → Camera 手动启用

# 安装 picamera2(bookworm 通常已预装)
sudo apt install -y python3-picamera2

picamera2 拍照与录像

用 Python 控制摄像头,可编程地拍照、加时间戳、定时抓拍:

# capture.py — 拍一张照片
from picamera2 import Picamera2
from time import sleep

picam = Picamera2()
# 配置静态拍照,设分辨率
config = picam.create_still_configuration(main={"size": (1920, 1080)})
picam.configure(config)

picam.start()
sleep(2)               # 等自动曝光/白平衡稳定
picam.capture_file("photo.jpg")
print("已保存 photo.jpg")
picam.stop()
# timelapse.py — 每分钟拍一张,做延时摄影
from picamera2 import Picamera2
from datetime import datetime
from time import sleep

picam = Picamera2()
picam.configure(picam.create_still_configuration())
picam.start()
sleep(2)

try:
    while True:
        ts = datetime.now().strftime("%Y%m%d_%H%M%S")
        fname = f"frame_{ts}.jpg"
        picam.capture_file(fname)
        print(f"拍摄 {fname}")
        sleep(60)      # 每 60 秒一张
except KeyboardInterrupt:
    picam.stop()
# record.py — 录制 MP4 视频
from picamera2 import Picamera2
from picamera2.encoders import H264Encoder
from picamera2.outputs import FfmpegOutput
from time import sleep

picam = Picamera2()
picam.configure(picam.create_video_configuration())
encoder = H264Encoder(bitrate=10000000)

picam.start_recording(encoder, FfmpegOutput("video.mp4"))
print("录制中 10 秒...")
sleep(10)
picam.stop_recording()
print("已保存 video.mp4")

picamera2 + OpenCV 处理图像

picamera2 可直接把帧输出为 NumPy 数组喂给 OpenCV,实现实时处理。先装 OpenCV:

sudo apt install -y python3-opencv
# 或在虚拟环境:pip install opencv-python
树莓派实时视觉处理流水线 ═══════════════════════════════════════════════════════ CSI 摄像头 picamera2 OpenCV ┌──────────┐ ┌────────────┐ ┌───────────┐ │ 光学传感器│─CSI排线─►│ capture_ │─NumPy──►│ 灰度化 │ │ imx708 │ │ array() │ (BGR) │ 边缘检测 │ └──────────┘ │ 640x480 │ │ 人脸检测 │ └────────────┘ └─────┬─────┘ │ ┌────────────────────────────▼──────┐ │ 结果:保存图片 / 触发 GPIO / MQTT 上报 │ │ (降分辨率保帧率,Haar 级联 CPU 可跑)│ └────────────────────────────────────┘
# edge.py — 实时边缘检测
from picamera2 import Picamera2
import cv2

picam = Picamera2()
# 用较低分辨率保证实时帧率
picam.configure(picam.create_preview_configuration(
    main={"size": (640, 480), "format": "RGB888"}))
picam.start()

while True:
    frame = picam.capture_array()          # 得到 NumPy 图像
    gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
    edges = cv2.Canny(gray, 100, 200)   # Canny 边缘检测
    cv2.imwrite("edges.jpg", edges)        # 保存(headless 无窗口)
    break   # 演示只处理一帧;实时则循环 + cv2.imshow(需桌面)

picam.stop()

简单人脸检测

用 OpenCV 自带的 Haar 级联模型,在树莓派上就能检测人脸并框出:

# face_detect.py — Haar 级联人脸检测
from picamera2 import Picamera2
import cv2

# 加载内置人脸模型(路径随 opencv 安装)
cascade_path = cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(cascade_path)

picam = Picamera2()
picam.configure(picam.create_preview_configuration(
    main={"size": (640, 480), "format": "RGB888"}))
picam.start()

frame = picam.capture_array()
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)

# 检测人脸,返回 [(x, y, w, h), ...] 矩形列表
faces = face_cascade.detectMultiScale(
    gray, scaleFactor=1.1, minNeighbors=5, minSize=(40, 40))

print(f"检测到 {len(faces)} 张人脸")
for (x, y, w, h) in faces:
    # 在每张脸上画绿色框
    cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

# 保存前转 BGR(cv2.imwrite 期望 BGR)
cv2.imwrite("faces.jpg", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
picam.stop()
想要更高精度?用加速器

Haar 级联适合入门但精度有限、对角度敏感。要真正的实时物体检测(YOLO 等),纯树莓派 CPU 吃力。Pi 5 可外接 Hailo AI HAT(树莓派官方 AI 加速器)或 Google Coral USB,把推理卸载到专用芯片,达到几十 FPS。轻量场景也可用 MediaPipe、TensorFlow Lite 在 CPU 上跑量化模型。

USB 摄像头(OpenCV 直读)

免驱 USB 摄像头插上即为 /dev/video0,OpenCV 直接读取,代码与平台无关:

# usb_cam.py — USB 摄像头拍照
import cv2

cap = cv2.VideoCapture(0)        # 0 = /dev/video0
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

ret, frame = cap.read()       # 读一帧,ret 表示成功
if ret:
    cv2.imwrite("usb_photo.jpg", frame)
    print("USB 摄像头拍照成功")
else:
    print("读取失败,检查摄像头连接")

cap.release()
对比项CSI 摄像头(picamera2)USB 摄像头(OpenCV)
接口CSI 专用排线口USB 口
延迟 / CPU低 / 低较高 / 较高
画质控制强(曝光/对焦可编程)受摄像头限制
即插即用需正确插排线插上即用
推荐场景固定安防、延时、AI 视觉临时、多机位、现成设备
隐私与散热提醒

摄像头涉及隐私,部署监控类应用注意合规、告知被拍者。持续处理视频(尤其人脸检测/AI 推理)会让 CPU 满载升温,务必加散热片或风扇,用 vcgencmd measure_temp 盯温度,超 80°C 会降频掉帧。长时间录像还要留意 SD 卡空间和寿命,大量视频建议存 USB 硬盘。

本章小结

树莓派的视觉能力来自摄像头 + 软件栈。CSI 摄像头(官方模块,走专用排线,低延迟低占用)是首选,用 picamera2 库编程:capture_file() 拍照、start_recording() 录 MP4、capture_array() 取 NumPy 帧。命令行可用 rpicam-hello/rpicam-still/rpicam-vid 快速验证。OpenCVimport cv2)做图像处理,图像就是 NumPy 数组,注意它用 BGR 顺序(与 RGB 库交互要 cvtColor 转换)。Haar 级联分类器能在 CPU 上做简单人脸检测,入门够用;要高精度实时检测需 Hailo/Coral 加速器。USB 摄像头免驱为 /dev/video0,OpenCV 用 VideoCapture(0) 直读。实时处理时降分辨率保帧率、加散热防降频、注意隐私合规。下一章我们走出本地,学习网络与 SSH 远程管理。