2. ISP算法工程环境搭建
做ISP算法部署,第一关不是算法本身,而是把环境搭起来。我见过太多人算法写得飞起,一到嵌入式板子上就各种报错——说白了,就是交叉编译环境没搞对。这一章,咱们就把这些基础活儿做扎实。
2.1 交叉编译工具链配置
嵌入式设备资源有限,没法在上面直接编译代码。我们得在PC上编译好,再把二进制丢到板子上跑。这就是交叉编译。
2.1.1 工具链的选择
市面上常见的工具链有几种,我列个表,你一看就明白:
| 工具链类型 | 适用平台 | 个人评价 |
|---|---|---|
| arm-linux-gnueabihf | ARM Cortex-A系列 | 最通用,海思、瑞芯微都能用 |
| aarch64-linux-gnu | ARM 64位平台 | 现在新板子基本都是这个 |
| mipsel-linux-gnu | MIPS架构 | 老款芯片还在用,慢慢少了 |
我个人习惯用 arm-linux-gnueabihf。为什么?因为大部分安防芯片,比如海思的Hi3516系列、君正的T系列,都支持这个。你想想看,一套工具链能覆盖好几个项目,省事。
2.1.2 安装与验证
安装其实不复杂,解压、配环境变量就行。但有个坑——路径不能有中文和空格。我曾经有个同事,把工具链放在“下载 (2)”文件夹里,折腾了一下午没搞定。
标准步骤:
- 下载工具链压缩包,比如
gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz - 解压到
/opt/目录:sudo tar -xvf gcc-linaro-*.tar.xz -C /opt/ - 配置环境变量,编辑
~/.bashrc,添加:
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
- 使生效:
source ~/.bashrc - 验证:
arm-linux-gnueabihf-gcc --version
/opt/ 下有没有 bin 目录,再确认 PATH 有没有写对。我每次配完都会 echo $PATH 看一眼。
2.2 OpenCV与V4L2集成
ISP算法离不开图像采集和处理。OpenCV做算法验证,V4L2做视频采集,这两个必须打通。
2.2.1 交叉编译OpenCV
OpenCV的交叉编译,嗯,这里要注意——千万别用apt-get安装。PC版和ARM版不通用,必须自己编译。
我整理了一份精简的编译脚本,你照着来:
#!/bin/bash
# 交叉编译OpenCV 4.5.5 for ARM
export TOOLCHAIN=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf
export CC=$TOOLCHAIN/bin/arm-linux-gnueabihf-gcc
export CXX=$TOOLCHAIN/bin/arm-linux-gnueabihf-g++
cmake -DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=arm \
-DCMAKE_C_COMPILER=$CC \
-DCMAKE_CXX_COMPILER=$CXX \
-DCMAKE_INSTALL_PREFIX=./install \
-DWITH_V4L=ON \
-DWITH_LIBV4L=ON \
-DBUILD_opencv_python=OFF \
-DBUILD_SHARED_LIBS=ON \
..
make -j4
make install
这里有几个关键点:
- WITH_V4L 和 WITH_LIBV4L 必须打开,否则没法从摄像头拿数据
- BUILD_opencv_python 关掉,嵌入式板子一般不跑Python
- BUILD_SHARED_LIBS 打开,生成动态库,节省固件空间
-DCMAKE_INSTALL_PREFIX,结果库文件散落在系统目录里,拷贝到板子上时缺了一堆依赖。后来我统一把输出放到 ./install 目录,打包时直接 tar 整个目录,干净利落。
2.2.2 V4L2采集流程
V4L2是Linux下视频采集的标准接口。说白了,就是打开设备、设置格式、申请缓冲区、开始采集。流程很固定:
- 打开设备:
open("/dev/video0", O_RDWR) - 查询能力:
ioctl(fd, VIDIOC_QUERYCAP, &cap) - 设置格式:
ioctl(fd, VIDIOC_S_FMT, &fmt) - 申请缓冲区:
ioctl(fd, VIDIOC_REQBUFS, &req) - 入队、出队循环:
VIDIOC_QBUF/VIDIOC_DQBUF
代码示例(核心片段):
struct v4l2_format fmt = {0};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 1920;
fmt.fmt.pix.height = 1080;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
perror("设置格式失败");
close(fd);
return -1;
}
为什么用NV12格式?因为大部分ISP芯片的硬件编码器直接支持NV12,省去格式转换的开销。你想想看,一帧1080p的NV12数据只有1920×1080×1.5字节,比RGB24少一半,传输和处理都快得多。
2.3 嵌入式Linux系统准备
板子上的Linux系统,说白了就是内核、根文件系统、设备树这三件套。我们做ISP算法部署,不需要从头造轮子,但得知道怎么裁剪和配置。
2.3.1 内核配置要点
内核里跟ISP相关的驱动,必须编译进内核或者作为模块加载。我列个清单:
| 配置项 | 说明 | 建议 |
|---|---|---|
| CONFIG_MEDIA_SUPPORT | 多媒体框架支持 | 必须开启 |
| CONFIG_V4L_PLATFORM_DRIVERS | 平台V4L驱动 | 必须开启 |
| CONFIG_VIDEO_ISP | ISP驱动 | 按芯片开启 |
| CONFIG_VIDEO_SENSOR | sensor驱动 | 按型号开启 |
配置方法:
make ARCH=arm menuconfig
# 进入 Device Drivers -> Multimedia support
# 勾选对应的ISP和sensor驱动
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
2.3.2 根文件系统裁剪
安防设备存储空间有限,根文件系统不能太大。我一般控制在50MB以内。怎么做到?
- 用BusyBox:替代GNU coreutils,一个命令才几十KB
- 删掉man文档:嵌入式设备谁看手册?省掉几十MB
- 只保留必要的库:用
arm-linux-gnueabihf-readelf -d查看依赖,只拷贝用到的so
举个例子,一个最小化的根文件系统结构:
rootfs/
├── bin/ # BusyBox 和基本命令
├── dev/ # 设备节点
├── etc/ # 配置文件
├── lib/ # 动态库(glibc、libpthread等)
├── mnt/ # 挂载点
├── proc/ # procfs
├── sbin/ # 系统管理命令
├── tmp/ # 临时文件
└── usr/ # 用户程序(我们的ISP算法放这里)
└── bin/
└── isp_demo # 编译好的ISP算法可执行文件
2.4 环境验证:跑通第一个ISP流水线
环境搭好没?跑个最简单的例子验证一下。从摄像头采集一帧图像,用OpenCV转成灰度图,再显示出来。虽然嵌入式板子没显示器,但我们可以把结果保存成文件。
#include <opencv2/opencv.hpp>
#include <stdio.h>
int main() {
cv::Mat frame;
cv::VideoCapture cap(0); // 打开 /dev/video0
if (!cap.isOpened()) {
printf("无法打开摄像头\n");
return -1;
}
cap >> frame; // 采集一帧
if (frame.empty()) {
printf("采集失败\n");
return -1;
}
cv::Mat gray;
cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
cv::imwrite("/tmp/test_gray.jpg", gray);
printf("图像已保存到 /tmp/test_gray.jpg\n");
return 0;
}
交叉编译:
arm-linux-gnueabihf-g++ test_isp.cpp -o test_isp \
-I ./install/include/opencv4 \
-L ./install/lib \
-lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_videoio
把 test_isp 和 ./install/lib/ 下的so文件拷贝到板子上,运行。如果生成了 /tmp/test_gray.jpg,恭喜你,环境通了!
export LD_LIBRARY_PATH=/your/lib/path。我刚开始总忘这步,后来写了个启动脚本自动设环境变量。
2.5 本章知识体系
下面这张图,把本章的核心逻辑串起来了:
环境搭建是ISP算法部署的基石。工具链、OpenCV、V4L2、Linux系统,这四个东西拧在一起,才能让算法在板子上跑起来。别嫌麻烦,这一步做扎实了,后面调算法、优化性能才能顺风顺水。