上一教程: 基于ARM的Linux系统的交叉编译
下一教程: 使用CUDA为Tegra构建OpenCV
| |
原作者 | Kumataro |
兼容性 | Ubuntu >= 23.04 |
OpenCV >= 4.8.0 |
- 警告
- 本教程可能包含过时信息。
什么是“多架构”
OpenCV可能使用许多第三方库进行视频和图像解码、渲染、加速和复杂的数学算法。第三方组件由CMake在构建主机上找到,交叉编译允许为不同的架构或操作系统构建OpenCV,但是我们会失去大量的组件,并且必须单独交叉编译每个依赖项并在OpenCV构建期间指向它。
Debian/Ubuntu的多架构功能有助于解决这个问题。它允许在主机系统上安装多个不同架构的库,并在OpenCV依赖项解析期间使用它们。
- 警告
- 按照这些步骤将使您的Linux环境略微混乱。如果可能,最好使用虚拟机或容器(例如Docker)。
- 本教程假设主机和目标使用相同的Ubuntu版本。不要使用/混合不同版本的外部库依赖项。
- 良好:主机和目标都是23.04。
- 良好:主机和目标都是23.10。
- 不良:主机是23.04,目标是23.10。
- 不良:主机是23.10,目标是23.04。
- 本教程可用于Debian及其衍生版本,如Raspberry Pi OS。请进行必要的更改。
下载工具
安装交叉编译所需的工具和工具链。
- 基本上需要git、cmake、pkgconf和build-essential。
- ninja-build用于减少编译时间(可选)。
- crossbuild-essential-armhf是armv7目标的工具链包。
- crossbuild-essential-arm64是aarch64目标的工具链包。
sudo apt update -y
sudo apt install -y \
git \
cmake \
pkgconf \
build-essential \
ninja-build \
crossbuild-essential-armhf \
crossbuild-essential-arm64
如果您想启用Python 3包装器,也请安装这些包。
sudo apt install -y \
python3-minimal \
python3-numpy
工作文件夹结构
在本教程中,使用以下工作文件夹结构。
/home
+ kmtr - 请替换您的帐户名。
+ work
+ opencv - 源码,从github克隆
+ opencv_contrib - 源码,从github克隆
+ build4-full_arm64 - 工件(用于aarch64目标),由cmake创建
+ build4-full_armhf - 工件(用于armhf目标),由cmake创建
- 在您的主目录下创建工作文件夹。
- 从存储库克隆OpenCV和OpenCV Contrib到工作目录。
cd ~
mkdir work
cd work
git clone --depth=1 https://github.com/opencv/opencv.git
git clone --depth=1 https://github.com/opencv/opencv_contrib.git
更新apt和dpkg设置
这些步骤在主机上执行。
apt
和dpkg
是Ubuntu和Debian中使用的包管理系统。
以下是使用多架构的设置步骤。
步骤1. 添加arm64和armhf的apt源
执行sudo apt edit-sources
以在文件末尾添加外部架构库。
示例1:适用于Ubuntu 23.04的arm64和armv7
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar main restricted
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar-updates main restricted
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar universe
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar-updates universe
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar multiverse
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar-updates multiverse
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar-backports main restricted universe multiverse
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar-security main restricted
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar-security universe
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports lunar-security multiverse
示例2:适用于Ubuntu 23.10的arm64和armv7
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic main restricted
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic-updates main restricted
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic universe
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic-updates universe
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic multiverse
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic-updates multiverse
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic-backports main restricted universe multiverse
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic-security main restricted
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic-security universe
deb [arch=arm64,armhf] http://ports.ubuntu.com/ubuntu-ports mantic-security multiverse
步骤2. 更新apt数据库
更新apt数据库以应用新的apt源。
执行sudo apt update
。
步骤3. 更新dpkg设置
更新dpkg设置以支持不同的架构。
执行sudo dpkg --add-architecture arm64
和/或sudo dpkg --add-architecture armhf
。
sudo dpkg --add-architecture arm64
sudo dpkg --add-architecture armhf
sudo dpkg --print-architecture
显示主机架构。
sudo dpkg --print-architecture
amd64
而sudo dpkg --print-foreign-architectures
显示支持哪些外部架构。
sudo dpkg --print-foreign-architectures
arm64
armhf
确认pkg-config工作正常
使用多架构,每个架构的多个共享库和pkg-config信息都存储在/usr/lib中。
/usr
+ lib
+ aarch64-linux-gnu - arm64的共享库
+ pkgconfig - arm64库的pkg-config文件
+ arm-linux-gnueabihf - armhf的共享库
+ pkgconfig - armhf库的pkg-config文件
+ share
+ pkgconfig - pkg-config文件(用于头文件)
使用PKG_CONFIG_PATH
、PKG_CONFIG_LIBDIR
和PKG_CONFIG_SYSROOT_DIR
选项确认pkg-config
工作正常。
对于aarch64
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig \
PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu \
PKG_CONFIG_SYSROOT_DIR=/ \
pkg-config --list-all
对于armv7
PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig:/usr/share/pkgconfig \
PKG_CONFIG_LIBDIR=/usr/lib/arm-linux-gnueabihf \
PKG_CONFIG_SYSROOT_DIR=/ \
pkg-config --list-all
交叉编译 aarch64
以下是针对目标平台 (aarch64) 在宿主机 (x86-64) 上进行编译的步骤。
步骤 1. 将目标平台的外部库安装到宿主机
此步骤在宿主机上执行。
将 libfreetype-dev、libharfbuzz-dev 和 FFmpeg 包(arm64 版)安装到宿主机 (x86-64) 上。
sudo apt install -y \
libavcodec-dev:arm64 \
libavformat-dev:arm64 \
libavutil-dev:arm64 \
libswscale-dev:arm64 \
libfreetype-dev:arm64 \
libharfbuzz-dev:arm64
如果您想启用Python 3包装器,也请安装这些包。
sudo apt install -y \
libpython3-dev:arm64
如果安装成功,pkg-config 可以显示这些包的信息。
对于 Freetype2 和 Harfbuzz
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig \
PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu \
PKG_CONFIG_SYSROOT_DIR=/ \
pkg-config freetype2 harfbuzz --cflags --libs
-I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/harfbuzz -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include -L/usr/lib/aarch64-linux-gnu -lfreetype -lharfbuzz
对于 FFmpeg
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig \
PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu \
PKG_CONFIG_SYSROOT_DIR=/ \
pkg-config libavcodec libavformat libavutil libswscale --cflags --libs
-I/usr/include/aarch64-linux-gnu -L/usr/lib/aarch64-linux-gnu -lavcodec -lavformat -lavutil -lswscale
步骤 2. 配置 OpenCV 设置
此步骤在宿主机上执行。
执行 `cmake` 以进行 aarch64 的交叉编译配置。
- 注意
- `-DCMAKE_TOOLCHAIN_FILE` 应该为绝对/真实文件路径,而不是相对路径。
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig \
PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu \
PKG_CONFIG_SYSROOT_DIR=/ \
cmake -S opencv \
-B build4-full_arm64 \
-DCMAKE_TOOLCHAIN_FILE=/home/kmtr/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake \
-DOPENCV_EXTRA_MODULES_PATH=opencv_contrib/modules \
-GNinja
如果要启用 Python 3 包装器,则需要额外的选项。
PYTHON3_REALPATH=`realpath /usr/bin/python3`
PYTHON3_BASENAME=`basename ${PYTHON3_REALPATH}`
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig \
PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu \
PKG_CONFIG_SYSROOT_DIR=/ \
cmake -S opencv \
-B build4-full_arm64 \
-DCMAKE_TOOLCHAIN_FILE=/home/kmtr/work/opencv/platforms/linux/aarch64-gnu.toolchain.cmake \
-DOPENCV_EXTRA_MODULES_PATH=opencv_contrib/modules \
-DPYTHON3_NUMPY_INCLUDE_DIRS="/usr/local/lib/${PYTHON3_BASENAME}/dist-packages/numpy/core/include/" \
-DPYTHON3_INCLUDE_PATH="/usr/include/${PYTHON3_BASENAME};/usr/include/" \
-DPYTHON3_LIBRARIES=`find /usr/lib/aarch64-linux-gnu/ -name libpython*.so` \
-DPYTHON3_EXECUTABLE="/usr/bin/${PYTHON3_BASENAME}" \
-DPYTHON3_CVPY_SUFFIX=".so" \
-GNinja
- 注意
- 最后,需要 "python3.XX" 字符串。因此此脚本会生成它。
- 获取从 "/usr/bin/python3" 到 "/usr/bin/python3.xx" 的真实路径。
- 获取从 "/usr/bin/python3.xx" 到 "python3.xx" 的基本名称。
以下是 cmake 输出。
宿主机
为 Linux x86_64
。
目标平台
为 Linux aarch64
。
- FFmpeg 可用。
-- OpenCV 4.8.0-dev 通用配置 =====================================
-- 版本控制: 408730b
--
-- 额外模块
-- 位置 (额外): /home/kmtr/work/opencv_contrib/modules
-- 版本控制 (额外): faa5468
--
-- 平台
-- 时间戳: 2023-12-01T22:02:14Z
-- 宿主机: Linux 6.5.0-13-generic x86_64
-- 目标平台: Linux 1 aarch64
-- CMake: 3.27.4
-- CMake 生成器: Ninja
-- CMake 构建工具: /usr/bin/ninja
-- 配置: Release
--
-- CPU/HW 特性
-- 基线: NEON FP16
-- 需要: NEON
-- 已禁用: VFPV3
-- 已分派的代码生成: NEON_DOTPROD NEON_FP16 NEON_BF16
-- 已请求: NEON_FP16 NEON_BF16 NEON_DOTPROD
-- NEON_DOTPROD (1 个文件): + NEON_DOTPROD
-- NEON_FP16 (2 个文件): + NEON_FP16
-- NEON_BF16 (0 个文件): + NEON_BF16
--
-- C/C++
-- 构建为动态库?: 是
-- C++ 标准: 11
-- C++ 编译器: /usr/bin/aarch64-linux-gnu-g++ (版本 13.2.0)
:
:
--
-- 视频 I/O
-- DC1394: 否
-- FFMPEG: 是
-- avcodec: 是 (60.3.100)
-- avformat: 是 (60.3.100)
-- avutil: 是 (58.2.100)
-- swscale: 是 (7.1.100)
-- avresample: 否
-- GStreamer: 否
-- v4l/v4l2: 是 (linux/videodev2.h)
--
如果成功启用 Python 3 包装器,则“Python 3:”部分将显示更多信息。
--
-- Python 3
-- 解释器: /usr/bin/python3.11 (版本 3.11.6)
-- 库: /usr/lib/aarch64-linux-gnu/libpython3.11.so
-- numpy: /usr/local/lib/python3.11/dist-packages/numpy/core/include/ (版本未定义 - 由于交叉编译,无法探测)
-- 安装路径: lib/python3.11/dist-packages/cv2/python-3.11
--
-- Python (用于构建): /usr/bin/python3.11
--
步骤 3. 构建和归档 OpenCV 库和头文件
此步骤在宿主机上执行。
构建和安装。(此处的“安装”仅指将构件复制到 `install` 文件夹。)
cmake --build build4-full_arm64
sudo cmake --install build4-full_arm64
使用 tar 命令将构件(已构建的库和头文件)归档到 `opencv_arm64.tgz` 中。
tar czvf opencv_arm64.tgz -C build4-full_arm64/install .
并将 `opencv_arm64.tgz` 发送到目标平台。
步骤 4. 在目标平台上安装依赖库
此步骤在目标系统上执行。
在目标平台上安装 OpenCV/OpenCV contrib 库的依赖运行时库。
sudo apt install -y \
libavcodec60 \
libavformat60 \
libavutil58 \
libswscale7 \
libfreetype6 \
libharfbuzz0b
sudo ldconfig
如果您想启用Python 3包装器,也请安装这些包。
sudo apt install -y \
python3-minimal \
python3-numpy
- 警告
- 如果运行时库和/或程序的版本已递增,则 apt 包名称可能会更改(例如,Ubuntu 23.04 使用 `libswscale6`,但 Ubuntu 23.10 使用 `libswscale7`)。可以使用 `apt search` 命令或 https://packages.ubuntu.com/ 搜索。
- 警告
宿主机和目标平台之间的外部库版本应该相同。请尽可能同时更新到最新版本的库。
即使宿主机和目标平台的操作系统版本相同,由于对库的额外更新,版本也可能不同。这将导致意外问题。
例如:
- 在宿主机上,OpenCV 已使用目标平台的外部库 A (v1.0) 构建。
- 库 A (v1.1) 可能已更新。
- 在目标平台上,安装了库 A (v1.1) 用于 OpenCV。
- 在这种情况下,库 A 的版本在编译和运行之间存在差异。
- 警告
如果忘记/错配安装某些必要的库,OpenCV 将无法正常工作。
`ldd` 命令可以检测依赖项。如果存在任何“未找到”的情况,请安装必要的库。
ldd /usr/local/lib/libopencv_freetype.so
(不好) `freetype 模块` 需要 `libharfbuzz.so.0`,但尚未安装。
linux-vdso.so.1 (0xABCDEFG01234567)
libopencv_imgproc.so.408 => /usr/local/lib/libopencv_imgproc.so.408 (0xABCDEF001234567)
libfreetype.so.6 => /lib/aarch64-linux-gnu/libfreetype.so.6 (0xABCDEF001234567)
libharfbuzz.so.0 => 未找到
libopencv_core.so.408 => /usr/local/lib/libopencv_core.so.408 (0xABCDEF001234567)
:
(良好) 已安装 `freetype 模块` 所需的所有库。
linux-vdso.so.1 (0xABCDEFG01234567)
libopencv_imgproc.so.408 => /usr/local/lib/libopencv_imgproc.so.408 (0xABCDEF001234567)
libfreetype.so.6 => /lib/aarch64-linux-gnu/libfreetype.so.6 (0xABCDEF001234567)
libharfbuzz.so.0 => /lib/aarch64-linux-gnu/libharfbuzz.so.0 (0xABCDEF001234567)
libopencv_core.so.408 => /usr/local/lib/libopencv_core.so.408 (0xABCDEF001234567)
:
步骤 5. 将 OpenCV 库安装到目标平台
此步骤在目标平台上执行。
从宿主机接收 `opencv_arm64.tgz`(在步骤 3 中生成),并解压到 `/usr/local`。
sudo tar zxvf opencv_arm64.tgz -C /usr/local
sudo ldconfig
您可以像自行编译一样使用 OpenCV 库。以下是 OpenCV 示例代码。在目标平台上编译并运行它。
Makefile
a.out : main.cpp
g++ main.cpp -o a.out \
-I/usr/local/include/opencv4 \
-lopencv_core
main.cpp
#include <iostream>
{
return 0; 0;
}
const String & getBuildInformation()
返回完整的配置时间 cmake 输出。
int main(int argc, char *argv[])
定义 highgui_qt.cpp:3
执行 make
并运行它。
如果要启用 Python 3 包装器,请执行以下命令进行确认。
python3 -c "import cv2; print(cv2.getBuildInformation())"
交叉编译到 armv7
以下是针对目标平台 (armhf) 在主机 (x86-64) 上进行编译的方法。
- 为了解决依赖关系,需要安装 `linux-libc-dev:armhf`。
- 为了使用 neon 优化,需要添加 `-DENABLE_NEON=ON`。
sudo apt install -y \
linux-libc-dev:armhf \
libavcodec-dev:armhf \
libavformat-dev:armhf \
libavutil-dev:armhf \
libswscale-dev:armhf \
libfreetype-dev:armhf \
libharfbuzz-dev:armhf
PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig:/usr/share/pkgconfig \
PKG_CONFIG_LIBDIR=/usr/lib/arm-linux-gnueabihf \
PKG_CONFIG_SYSROOT_DIR=/ \
cmake -S opencv \
-B build4-full_armhf \
-DENABLE_NEON=ON \
-DCMAKE_TOOLCHAIN_FILE=/home/kmtr/work/opencv/platforms/linux/arm-gnueabi.toolchain.cmake \
-DOPENCV_EXTRA_MODULES_PATH=opencv_contrib/modules \
-GNinja
cmake --build build4-full_armhf
sudo cmake --install build4-full_armhf
tar czvf opencv_armhf.tgz -C build4-full_armhf/install .
以下是 cmake 输出。
宿主机
为 Linux x86_64
。
- 目标平台是 `Linux arm`。
- FFmpeg 可用。
-- OpenCV 4.8.0-dev 通用配置 =====================================
-- 版本控制: 408730b
--
-- 额外模块
-- 位置 (额外): /home/kmtr/work/opencv_contrib/modules
-- 版本控制 (额外): faa5468
--
-- 平台
-- 时间戳:2023-12-02T03:39:58Z
-- 宿主机: Linux 6.5.0-13-generic x86_64
-- 目标平台:Linux 1 arm
-- CMake: 3.27.4
-- CMake 生成器: Ninja
-- CMake 构建工具: /usr/bin/ninja
-- 配置: Release
--
-- CPU/HW 特性
-- 基线:NEON
-- 请求:DETECT
-- 需要: NEON
-- 已禁用: VFPV3
--
-- C/C++
-- 构建为动态库?: 是
-- C++ 标准: 11
-- C++ 编译器:/usr/bin/arm-linux-gnueabihf-g++ (版本 13.2.0)
:
:
--
-- 视频 I/O
-- DC1394: 否
-- FFMPEG: 是
-- avcodec: 是 (60.3.100)
-- avformat: 是 (60.3.100)
-- avutil: 是 (58.2.100)
-- swscale: 是 (7.1.100)
-- avresample: 否
-- GStreamer: 否
-- v4l/v4l2: 是 (linux/videodev2.h)
--