1. 嵌入式Linux相机开发概述
大家好,我是你们这门课的老朋友。做嵌入式Linux相机开发这些年,踩过的坑比吃过的盐还多。今天咱们先不急着写代码,把地基打牢了再说。
你想想看,一个相机系统,说白了就是「采集图像 → 处理图像 → 输出图像」。但嵌入式环境里,每一步都有它的脾气。我刚开始做的时候,以为跟PC上写OpenCV一样简单,结果被V4L2的ioctl折腾得够呛。嗯,这些坑咱们后面都会讲到。
1.1 课程介绍:我们到底要学什么?
这门课的目标很明确——让你能独立完成一个嵌入式Linux相机应用。从硬件选型到软件架构,从驱动调试到UI展示,一条龙走通。
我个人习惯把课程分成四个阶段:
- 基础篇:搞懂V4L2、ISP这些底层机制
- 实战篇:用OpenCV做图像处理,比如人脸检测、二维码识别
- 优化篇:帧率优化、内存管理、多线程流水线
- 产品篇:QT/LVGL做UI,最终跑在板子上
每个阶段我都会拿真实项目举例。比如我在做工业相机项目时,遇到过ISP参数调了一周都没效果的情况——后来发现是sensor的时钟配置错了。这种血泪史,我会毫无保留地分享出来。
1.2 硬件平台选型:树莓派 vs 瑞芯微
选硬件就像选工具,没有最好的,只有最合适的。目前主流的两条路线:
| 对比项 | 树莓派 (Raspberry Pi 4/5) | 瑞芯微 (RK3588/RK3568) |
|---|---|---|
| CPU架构 | ARM Cortex-A72/A76 | ARM Cortex-A76 + A55 |
| ISP能力 | 无硬件ISP,依赖CPU | 自带6TOPS NPU + 3A ISP |
| 社区生态 | 极其丰富,资料多 | 官方SDK完善,但社区偏少 |
| 成本 | 约500-800元 | 约300-600元(核心板) |
| 适合场景 | 学习原型、轻量应用 | 工业级、AI视觉产品 |
1.3 软件栈概览:V4L2、ISP、OpenCV
软件栈这块,我习惯从下往上讲。你想想看,数据流是这样的:
Sensor → V4L2驱动 → ISP处理 → 应用层(OpenCV/QT)
1.3.1 V4L2(Video for Linux 2)
V4L2是Linux下视频设备的标准接口。说白了,它就是你和摄像头硬件之间的翻译官。你通过ioctl命令告诉它「我要采集一帧图像」,它帮你从sensor那里拿数据。
我记得第一次用V4L2时,被它的状态机搞晕了。什么VIDIOC_QUERYCAP、VIDIOC_S_FMT、VIDIOC_REQBUFS... 每个ioctl都有严格的调用顺序。后来我总结了一个口诀:打开设备 → 查询能力 → 设置格式 → 申请缓冲区 → 入队 → 采集 → 出队。这个顺序错一步,系统就罢工给你看。
核心概念: V4L2的缓冲区管理有两种模式:
- Read/Write模式:简单但效率低,每次拷贝数据
- MMAP模式:共享内存,零拷贝,推荐使用
我在项目中只用MMAP模式。曾经有个同事用了Read模式,1080p@30fps直接掉到15fps,CPU还跑满了。嗯,血的教训。
1.3.2 ISP(图像信号处理器)
ISP是相机的大脑。它负责把sensor的原始RAW数据变成我们能看的RGB/YUV图像。主要干这几件事:
- 去马赛克:把Bayer格式转成RGB
- 白平衡:让白色在不同光照下看起来都是白的
- 降噪:去掉传感器噪声
- 自动曝光/自动对焦:3A算法
树莓派没有硬件ISP,这些全靠CPU算。瑞芯微有硬件ISP,参数调好了效果立竿见影。我曾经调RK3588的ISP参数,发现降噪强度设太高,图像边缘都糊了。后来把降噪系数从0.8降到0.3,清晰度提升明显。这种参数调优,没有捷径,就是一遍遍试。
1.3.3 OpenCV
OpenCV在嵌入式上主要做两件事:图像处理和显示。但要注意,OpenCV的cv::imshow在嵌入式上不好使——它依赖GTK或QT,交叉编译起来很麻烦。我一般用OpenCV做算法处理,然后用QT或者LVGL做显示。
1.4 开发环境搭建:交叉编译链、TFTP/NFS
嵌入式开发,环境搭建往往是最磨人的。我见过太多新手卡在这一步。咱们一步步来。
1.4.1 交叉编译链
交叉编译,说白了就是在PC上编译出能在ARM板子上运行的程序。为什么不能直接在板子上编译?因为板子性能太弱了,编译个OpenCV得等一天。
以树莓派为例,我常用的工具链是:
# 安装ARM交叉编译链(Ubuntu 20.04)
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
# 验证安装
arm-linux-gnueabihf-gcc --version
# 编译一个hello world
arm-linux-gnueabihf-gcc -o hello hello.c
file hello # 输出:ELF 32-bit LSB executable, ARM, EABI5
瑞芯微的交叉编译链稍微复杂点,官方提供了buildroot或者SDK,里面自带工具链。我个人习惯用Linaro的gcc 7.5版本,稳定可靠。
1.4.2 TFTP/NFS网络服务
开发过程中,你不可能每次都插拔SD卡来更新程序。TFTP和NFS就是用来解决这个问题的。
- TFTP:简单文件传输,适合传内核、设备树、小文件
- NFS:网络文件系统,板子可以直接挂载PC的目录,像本地文件一样读写
我一般这样用:
# PC端(Ubuntu)配置NFS服务器
sudo apt-get install nfs-kernel-server
sudo mkdir -p /srv/nfs/rootfs
sudo chown nobody:nogroup /srv/nfs/rootfs
# 编辑/etc/exports,添加:
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)
# 重启服务
sudo systemctl restart nfs-kernel-server
# 板子端挂载
mount -t nfs -o nolock 192.168.1.100:/srv/nfs/rootfs /mnt
1.5 本章小结
好了,这一章咱们把整个课程的脉络理清了。硬件选型上,树莓派适合学习,瑞芯微适合产品。软件栈上,V4L2是底层接口,ISP是图像质量的关键,OpenCV是算法利器。开发环境上,交叉编译链和NFS/TFTP是必备技能。
下一章,咱们会真正动手——用V4L2采集第一帧图像。到时候我会手把手带你写代码,从打开设备到显示图像,每一步都讲清楚。嗯,准备好你的板子,咱们下章见。
课后作业:
- 在你的板子上安装交叉编译链,编译一个hello world并运行
- 配置NFS服务,让板子能挂载PC的目录
- 思考:为什么嵌入式开发要用交叉编译,而不是直接在板子上编译?
公众号:蓝海资料掘金营,微信deep3321