RK3568 OpenCV交叉编译与Qt集成避坑手册 简介《ATK-DLRK3568_OpenCV4使用手册》面向具备一定Linux基础、希望在嵌入式平台上开展计算机视觉开发的工程师与学习者围绕正点原子ATK-DLRK3568四核A552.0GHz开发板讲解OpenCV 4.5.5在Buildroot出厂系统中的实际使用路径。压缩包内为1个PDF文件约1.41MB篇幅精炼先说明库文件位置与Python接口调用方式再逐步展开交叉编译工具链安装、C程序编写含命令行、Makefile、CMakeLists、Qt四种工程形态、Python版本编译运行并附常见问题解答可当作配置与排错清单随时查阅。文档中的示例代码与编译流程能帮助读者完成从环境搭建到程序跑通的全过程Qt集成部分尤其适合需要图形界面的视觉项目参考。目前已有120人学习下载适合想快速上手嵌入式OpenCV开发、减少环境踩坑的开发者。1. 四核 A55 上跑 OpenCV这份手册解决的是哪一段路手上有一块 RK3568 开发板四核 A552.0GHz出厂 Buildroot 镜像里已经躺着一份 OpenCV 4.5.5库文件就在/usr/lib下。这是很多人把计算机视觉从 PC 往嵌入式搬时最省事的起点——不用自己裁库、不用调依赖插上电就能imread。这份《OpenCV4 使用手册》讲的正是这条链路的落地段在现成环境上写 C 和 Python 程序用交叉编译把 x86 主机上的源码变成板子能跑的 aarch64 可执行文件再把 OpenCV 接进 Qt 工程。它不教算法教的是工具链怎么装、头文件和库怎么指、四种构建方式各自的边界在哪。适合已经能在 Linux 下敲命令、但还没把嵌入式交叉编译这条路完整走通过的人。2. 交叉编译工具链先立住三元组、sysroot 和那份 .run 安装包2.1 为什么不在板子上直接编译板子的 A55 跑得动 OpenCV 的推理和图像处理但跑不动编译。一个中等规模的 C 视觉工程在板子上make一次可能要十几分钟而且板端 rootfs 里通常没有装 g、cmake、make 这一整套。更现实的问题是磁盘和内存交叉编译工具链本身就有几个 GB塞进 eMMC 之后留给应用和数据的空间会很紧张。交叉编译的思路是把「编译」这一步留在 x86 主机上用一套专门为目标架构生成的编译器产出 aarch64 指令。这套编译器不能随便找它必须和板子上运行的 C 库版本对齐否则编出来的程序在板子上要么找不到符号要么直接段错误。厂商随 SDK 一起打包的那份.run就是把这套对齐关系固化下来的产物——它由 Buildroot 构建系统在生成 rootfs 的同一次流程里产出glibc 版本、动态链接器路径、库的 SONAME 都和出厂镜像一致。这也解释了为什么手册里反复强调「不建议修改安装路径」后面所有的-I、-L、--sysroot都硬编码在这条路径上。常见做法是把它固定装到/opt下和系统自带的工具链隔离升级或换版本时整目录删掉重装即可不会污染/usr/bin。我一般会在/opt下留一个软链接指向当前使用的版本比如/opt/rk3568-toolchain这样工程里的路径写软链接换工具链时只改链接不动工程文件。2.2 安装 .run 包并确认三元组工具链压缩包在随板资料的工具目录里文件名形如rk3568-toolchain-aarch64-buildroot-linux-gnu-x86_64-版本号.run。先把它从 Windows 传到 Ubuntu 主机用 WinSCP 或者scp都行然后给执行权限并运行。# 传上来之后先看文件类型确认是 shell 自解压包而不是压缩包 file rk3568-toolchain-aarch64-buildroot-linux-gnu-x86_64.run # 加可执行权限777 是手册的写法实际 755 就够 chmod 755 rk3568-toolchain-aarch64-buildroot-linux-gnu-x86_64.run # 执行安装交互式会问你安装路径直接回车走默认 /opt/rk3568-toolchain ./rk3568-toolchain-aarch64-buildroot-linux-gnu-x86_64.run安装过程大约一到两分钟速度取决于主机磁盘。脚本会先把内容解压到一个临时目录再整体搬到目标路径所以中间那段时间du -sh看到目录大小在跳是正常的。安装完成后第一件事不是急着编译而是确认三元组前缀和版本。# 确认编译器能被调用并且目标架构是 aarch64 /opt/rk3568-toolchain/bin/aarch64-buildroot-linux-gnu-g -v # 看一眼 gcc 版本和配置参数重点确认 --with-sysroot 指向哪里 /opt/rk3568-toolchain/bin/aarch64-buildroot-linux-gnu-gcc -print-sysroot-print-sysroot输出的那条路径就是这套工具链认定的根文件系统镜像目录。如果它输出的不是/opt/rk3568-toolchain/aarch64-buildroot-linux-gnu/sysroot说明安装路径被改过或者包解压不完整后面所有编译都会在找头文件时失败。这一步花十秒钟能省掉后面半小时的排查。提示/opt目录默认属于 root普通用户执行安装脚本时要加sudo但装完之后要把目录的属主改回自己否则后面make生成文件时会出现权限错误。2.3 sysroot 里到底有什么很多人把交叉编译工具链理解成「一个能编 aarch64 的 g」这个理解会让人在后面反复踩坑。工具链是三层结构bin/下是编译器、链接器、objdump、readelf这些宿主机上运行的程序aarch64-buildroot-linux-gnu/下是目标平台的运行时而sysroot/才是真正的「板子文件系统的镜像」里面有/usr/include、/usr/lib、/lib和板子上的目录结构一一对应。OpenCV 的头文件在sysroot/usr/include/opencv4/opencv2/下注意多出来的那一层opencv4——这是 OpenCV 4.x 相对 3.x 最大的目录变化也是新手第一个fatal error的来源。库文件在sysroot/usr/lib下命名形如libopencv_core.so.4.5.5同时有libopencv_core.so这个开发用软链接指向它-lopencv_core找的就是这个短名。pkg-config 的描述文件在sysroot/usr/lib/pkgconfig/opencv4.pcQt 那套构建系统就是靠它自动推导头文件和库路径的。SYSROOT/opt/rk3568-toolchain/aarch64-buildroot-linux-gnu/sysroot # 确认 OpenCV 版本和头文件位置 ls $SYSROOT/usr/include/opencv4/opencv2/ | head grep -m1 OpenCV_VERSION $SYSROOT/usr/lib/pkgconfig/opencv4.pc # 列出所有可链接的 OpenCV 模块 ls $SYSROOT/usr/lib/libopencv_*.so | sed s#.*/lib##; s#\.so##第二条命令能直接吐出OpenCV_VERSION4.5.5之类的内容这个版本号必须和板子上ls /usr/lib/libopencv_core.so*看到的一致。手册里提到出厂镜像里还带了 freetype 相关支持用来在图像上绘制文字——中文渲染在嵌入式视觉项目里是个高频需求cv::putText只支持 ASCII要写中文得走 contrib 里的 freetype 模块链接时多一个-lopencv_freetype。这一点在 sysroot 里能直接验出来ls $SYSROOT/usr/lib/libopencv_freetype*有输出就说明库在没有就得自己裁一份 contrib 编进去。3. 第一支 OpenCV 程序C 与 Python 两条路的最小闭环3.1 C 版本与它真正依赖的模块先写一个不涉及任何算法的程序读一张图、看一下尺寸、显示出来。选这个而不是边缘检测是因为它能一次性验证三件事——文件系统路径对不对、imgcodecs模块在不在、图形后端能不能起来。任何一件不对你都能从输出上立刻区分开。// opencv_test.cpp #include opencv4/opencv2/opencv.hpp #include iostream int main() { // 板子上的示例图路径换成自己的图片也可以 cv::Mat image cv::imread(/opt/apps/res/sample.png); // 读失败一定要判空否则后面 imshow 会直接抛异常 if (image.empty()) { std::cerr read image failed, check the path std::endl; return -1; } // 先把尺寸打出来避免把图读进来了但内容不对误判成显示问题 std::cout width: image.cols height: image.rows channels: image.channels() std::endl; cv::namedWindow(Image, cv::WINDOW_AUTOSIZE); cv::imshow(Image, image); // 参数 0 表示无限等待单位是毫秒 cv::waitKey(0); cv::destroyAllWindows(); return 0; }头文件的写法opencv4/opencv2/opencv.hpp是嵌入式场景里最省事的一种它把opencv4这一层目录直接写进 include 路径编译时只要把sysroot/usr/include加进去就行。另一种写法是opencv2/opencv.hpp配合-I.../usr/include/opencv4两种都能用但同一份代码里不要混用混着写迟早会在某个子头文件上翻车。这个程序用到了五个模块少一个都链接不过core提供Mat和基础数据结构imgcodecs提供imread/imwritehighgui提供namedWindow/imshow/waitKeyimgproc提供图像处理的基础函数这个例子里没直接调但highgui内部会用到颜色空间转换videoio提供视频采集和编解码后端。手册给出的链接列表正好是这五个不是随手写的。我一般会在这五个之外再补一个-lopencv_imgproc的显式声明——它虽然被隐式依赖但显式写出来在换 OpenCV 版本时更不容易出问题。3.2 Python 版本不用编译但解释器要对Python 这条路省掉了整个交叉编译环节因为 CPython 解释器和 cv2 模块都已经在板子的 rootfs 里了。手册里给的解释器路径在 sysroot 下也有一份但对使用者来说更关心的是板子上那份。# opencv_test.py import cv2 def main(): # 和 C 版本读同一张图方便对照两边结果 image cv2.imread(/opt/apps/res/sample.png) # Python 里读失败返回 None不是抛异常 if image is None: print(read image failed, check the path) return print(width: {}, height: {}, channels: {}.format( image.shape[1], image.shape[0], image.shape[2] if len(image.shape) 3 else 1)) # WINDOW_NORMAL 允许拖拽缩放嵌入式屏幕上比 AUTOSIZE 好用 cv2.namedWindow(Image, cv2.WINDOW_NORMAL) cv2.imshow(Image, image) cv2.waitKey(0) cv2.destroyAllWindows() if __name__ __main__: main()两个版本在显示行为上有一处细节差异C 用的WINDOW_AUTOSIZE会让窗口严格等于图像尺寸小分辨率屏幕上一张大图会超出屏幕Python 用的WINDOW_NORMAL允许后续手动调整。在只有 HDMI 输出、没有触摸屏的调试环境里这个差别会直接影响你能不能看到完整画面。新手常犯的错误是把 C 里的WINDOW_AUTOSIZE原样搬到板子上然后以为程序卡死了——其实是窗口大到屏幕外面去了。还有一点Python 版的cv2是预编译进 rootfs 的不能指望pip install opencv-python在板子上重新装一遍板子上的 pip 装的是源码包没有预编译轮子编译过程会跑几十分钟然后因为内存不足挂掉。要用 Python就用 rootfs 自带的那个。3.3 把可执行文件送到板子上并跑起来C 程序编出来之后是个 ELF 文件得先确认架构对再传到板子。# 主机端编好的文件应该是 ARM aarch64 file opencv_test # 期望输出类似ELF 64-bit LSB pie executable, ARM aarch64, ... # 用 scp 传前提是板子和主机在同一网段且 ssh 服务已起 scp opencv_test root192.168.1.100:/root/ # 或者用 adb板子插 USB OTG 口时更省事 adb push opencv_test /root/传到板子上之后先chmod x opencv_test再加执行权限然后直接./opencv_test跑。如果屏幕是 HDMI 且系统跑的是 Weston你会看到窗口出现可能不在屏幕正中——手册的常见问题里提到过这个现象原因是 Weston 默认把 HDMI 当扩展屏而不是主屏需要在显示配置里把它设成主显示或者旋转 90 度。这不是 OpenCV 的问题是显示合成器的问题改配置即可。如果程序跑起来但提示cannot open display或者Failed to open X11 display说明图形后端没对上。Buildroot 镜像里 OpenCV 的 highgui 通常编的是 GTK 或 Qt 后端跑在 Wayland 上时需要环境变量指路XDG_RUNTIME_DIR/run/user/0和WAYLAND_DISPLAYwayland-0是常见的一组。实在懒得折腾显示就先用imwrite把结果写回文件再拉回主机看验证逻辑比验证显示重要得多。4. 四种构建方式怎么选命令行、Makefile、CMake 与 Qt 的落地写法4.1 命令行一把梭-I / -L / -l 三件套单文件小程序用不着构建系统一条命令编完最直接。这条命令值得背下来因为后面三种方式本质上都是它的封装。SYSROOT/opt/rk3568-toolchain/aarch64-buildroot-linux-gnu/sysroot CXX/opt/rk3568-toolchain/bin/aarch64-buildroot-linux-gnu-g $CXX opencv_test.cpp -o opencv_test \ --sysroot$SYSROOT \ -I$SYSROOT/usr/include/opencv4 \ -L$SYSROOT/usr/lib \ -lopencv_core -lopencv_highgui -lopencv_imgproc \ -lopencv_videoio -lopencv_imgcodecs逐段拆开看--sysroot是最容易被漏掉的一个它告诉编译器和链接器「把 $SYSROOT 当成根目录」之后找libc、找启动文件crt1.o都在这个虚拟根下进行。漏了它编译器会去主机的/usr/lib里找 x86 的crt文件报cannot find crt1.o或者更隐蔽地——找到了但架构不对链接阶段才报错。-I指定头文件搜索路径-L指定库搜索路径-l指定链接哪个库-o决定输出文件名。这四组参数的顺序有讲究-l必须写在源文件之后因为链接器是按顺序解析的放在前面会找不到符号引用。如果你要链接 freetype 做中文绘制在这条命令后面追加-lopencv_freetype注意这个模块属于 contrib不是所有预编译镜像都带。4.2 Makefile把路径收敛成变量一条命令能解决的事一旦文件多了就不行了。Makefile 的价值在于把重复的路径和库列表收敛成变量改一处全局生效。TOOLCHAIN_DIR : /opt/rk3568-toolchain CXX : $(TOOLCHAIN_DIR)/bin/aarch64-buildroot-linux-gnu-g SYSROOT : $(TOOLCHAIN_DIR)/aarch64-buildroot-linux-gnu/sysroot # 头文件路径集中在这里新增依赖目录只改这一行 INCLUDES : -I$(SYSROOT)/usr/include/opencv4 CFLAGS : --sysroot$(SYSROOT) $(INCLUDES) -O2 -Wall # 库列表顺序影响链接结果被依赖的放后面 LDLIBS : -L$(SYSROOT)/usr/lib \ -lopencv_core -lopencv_imgproc -lopencv_imgcodecs \ -lopencv_highgui -lopencv_videoio TARGET : opencv_test SRCS : opencv_test.cpp $(TARGET): $(SRCS) $(CXX) $(CFLAGS) $^ -o $ $(LDLIBS) clean: rm -f $(TARGET) .PHONY: clean$^是 Make 的自动变量展开成所有依赖文件$展开成目标名。这两个符号在单文件工程里看不出好处文件一多就能省掉大量重复书写。-O2在嵌入式上建议默认开着OpenCV 的很多函数有 SIMD 优化分支不开优化性能差一大截-Wall用来提前发现隐式类型转换Mat的尺寸参数是int和size_t混用时的截断问题在板子上会变成花屏。一个常见误用是make clean之后忘了重新make直接拿磁盘上残留的旧可执行文件去跑然后奇怪为什么改了代码没生效。clean删的是产物不是中间状态删完必须重编。另一个误用是库顺序写反-lopencv_highgui放在-lopencv_imgproc前面链接时报 undefined reference把依赖方放在被依赖方前面就好了。4.3 CMakebuild 目录与 toolchain 变量的取舍CMake 的抽象层级比 Makefile 高代价是多了一层配置。交叉编译场景下最稳的写法不是去折腾toolchain.cmake而是在CMakeLists.txt里直接写死编译器和 sysroot简单直接。cmake_minimum_required(VERSION 3.10) project(opencv_demo CXX) set(TOOLCHAIN_DIR /opt/rk3568-toolchain) set(SYSROOT ${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu/sysroot) # 显式指定交叉编译器避免 cmake 自动探测到主机的 gcc set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/aarch64-buildroot-linux-gnu-g) set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/aarch64-buildroot-linux-gnu-gcc) set(CMAKE_SYSROOT ${SYSROOT}) # 交叉编译时必须关掉 cmake 在主机目录里找库的行为 set(CMAKE_FIND_ROOT_PATH ${SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_CXX_STANDARD 14) add_executable(opencv_test opencv_test.cpp) target_include_directories(opencv_test PRIVATE ${SYSROOT}/usr/include/opencv4) target_link_directories(opencv_test PRIVATE ${SYSROOT}/usr/lib) target_link_libraries(opencv_test PRIVATE opencv_core opencv_imgproc opencv_imgcodecs opencv_highgui opencv_videoio)CMAKE_FIND_ROOT_PATH那三行是交叉编译 CMake 工程的关键。不加的话find_package和find_library会在主机的/usr/lib里翻出一个 x86 的libopencv链接时才发现架构不对报错信息还特别绕。加了MODE_LIBRARY ONLY之后所有库搜索都被限制在 sysroot 内主机上装没装 OpenCV 完全不影响结果。构建流程按手册走就行重点是不要在源码目录里直接cmake ..mkdir -p build cd build cmake .. make -j$(nproc) ls -l opencv_test-j$(nproc)按主机核数并行编译单文件工程看不出差别文件多了能快好几倍。build目录的作用是隔离中间产物删掉它等于彻底 clean比make clean干净。我一般会在.gitignore里把build/排除掉避免中间文件混进版本库。注意如果之前在同一目录用主机 gcc 跑过一次cmake缓存里会记着主机编译器换个交叉编译器也不会自动更新。换工具链之后必须删掉整个build目录重新配置。4.4 Qt用 pkg-config 让 qmake 自己找库Qt 工程里不需要手写-I和-L只要.pro里挂上 pkg-configqmake 会去读opencv4.pc把里面Cflags和Libs的全部内容展开。QT core gui widgets CONFIG c17 SOURCES main.cpp mainwindow.cpp HEADERS mainwindow.h FORMS mainwindow.ui # 关键两行打开 pkg-config 支持并声明依赖 opencv4 CONFIG link_pkgconfig PKGCONFIG opencv4link_pkgconfig是一个 qmake 特性打开之后PKGCONFIG里列的每个包都会被pkg-config --cflags --libs展开。前提是 qmake 知道去哪找.pc文件——如果 Qt 的 kit 已经按手册配好了交叉编译环境sysroot 会被自动带上pkg-config会去 sysroot 里查。没有的话就手动设两个环境变量SYSROOT/opt/rk3568-toolchain/aarch64-buildroot-linux-gnu/sysroot export PKG_CONFIG_SYSROOT_DIR$SYSROOT export PKG_CONFIG_LIBDIR$SYSROOT/usr/lib/pkgconfigPKG_CONFIG_LIBDIR和PKG_CONFIG_PATH的区别值得记一下前者是「覆盖」把默认搜索路径整个替换掉后者是「追加」在默认路径后面加。交叉编译必须用前者否则主机的/usr/lib/pkgconfig里那份 x86 的opencv4.pc会先被找到编出来的 Qt 程序一上板就报架构错误。Qt 侧的代码只需要在文件头加 include然后在构造函数里试一下imread即可#include mainwindow.h #include ui_mainwindow.h #include opencv4/opencv2/opencv.hpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-setupUi(this); // 只验证链接和运行时库是否可用不做实际处理 cv::Mat image cv::imread(/opt/apps/res/sample.png); if (!image.empty()) { qDebug() opencv ok, size image.cols x image.rows; } }构建时用 CtrlB 或qmake make。如果 Qt Creator 里能看到编译命令中自动带上了-I.../include/opencv4和一堆-lopencv_*说明 pkg-config 生效了一个都不用手填。5. 避坑与排查交叉编译 OpenCV 时最容易翻车的五个现场5.1 编译期头文件、符号与 ABI现象一fatal error: opencv2/opencv.hpp: No such file or directory。原因基本只有两种include 路径里少了opencv4这一层或者源码里写的是opencv2/opencv.hpp但-I只指到了usr/include。OpenCV 4.x 把原来的opencv目录整体挪进了opencv4下为了和 3.x 共存这是有意为之。 解决方式二选一源码改成opencv4/opencv2/opencv.hpp或者把-I改成-I$SYSROOT/usr/include/opencv4。前者不依赖额外的 include 路径在 Qt 这种不便控制编译参数的工程里更好用后者在纯 Makefile 工程里更清爽。不要两边都加会出现同一份头文件被解析两次、宏重定义的问题。现象二undefined reference to cv::imread(std::string const, int)。编译过了但链接挂了说明头文件找到了、库没链上。imread属于imgcodecsimshow属于highguiMat的基础操作在core里三者是分开的库少一个都会在链接阶段报符号缺失。 解决方式是补-lopencv_imgcodecs。判断该补哪个库有个笨办法错误信息里的cv::后面的函数名去sysroot/usr/lib下用nm -D逐个 grep哪个库里有这个符号就链哪个。实际项目里我一般把常用的六个库一次性全链上多链不会出错只会在体积上多一点strip 之后影响很小。现象三链接报skipping incompatible .../libopencv_core.so。这是最隐蔽的一个。报错说明链接器找到了一个库但判定它架构不匹配——通常是主机上装过 OpenCV/usr/lib里的 x86 版本被-L后面的默认搜索路径捡到了。交叉编译时如果没有--sysroot-L只指定了 OpenCV 的位置libc和依赖库还是会去主机目录找。 解决方式是检查命令里有没有--sysroot以及-L的顺序是否把 sysroot 的usr/lib放在了前面。用$CXX -print-search-dirs能看到编译器实际的搜索路径主机路径出现在里面就说明 sysroot 没生效。5.2 运行期动态库、显示与信号现象四板子上运行报error while loading shared libraries: libopencv_core.so.4.5。程序传上去了、权限也加了起不来。原因是板子的 rootfs 里这份 OpenCV 库不在动态链接器的默认搜索路径上或者干脆没装。 解决分两步。先在板子上find / -name libopencv_core.so*确认库在哪出厂镜像里应该在/usr/lib那是默认路径能找到却加载失败说明是LD_LIBRARY_PATH被别的程序改坏了。库在非标准路径时临时跑一次用LD_LIBRARY_PATH/opt/lib ./opencv_test长期用就在/etc/ld.so.conf.d/下加一行路径再ldconfig。如果压根找不到库说明这个 rootfs 不是你编译时用的那个镜像得把 sysroot 里对应的.so一起拷过去。现象五程序能跑但imshow之后屏幕没反应或者报could not connect to display。这一类几乎全是图形后端的问题和 OpenCV 本身没关系。出厂镜像是 Buildroot Westonimshow走的是 Wayland 通道需要XDG_RUNTIME_DIR和WAYLAND_DISPLAY两个环境变量。从 ssh 登录进去执行时这两个变量通常不在环境里程序就找不到会话。 解决方式是先echo $XDG_RUNTIME_DIR看一眼为空就export XDG_RUNTIME_DIR/run/user/0WAYLAND_DISPLAY一般是wayland-0ls /run/user/0/能看到实际名字。另一个高频现象是窗口出现了但缩在屏幕中间一小块那是 Weston 把 HDMI 当成次级显示器的默认行为按手册里的办法把它设成主屏或者直接旋转输出方向。调试阶段不想纠缠显示就把imshow换成imwrite把结果图拉回主机看效率高得多。现象六编译一切正常上板一跑就Illegal instruction或者秒段错误。这种情况八成是链接阶段混进了主机库或者编译时加了-marchnative。A55 支持的指令集和主机 x86 完全不同-marchnative会让编译器按宿主机 CPU 生成指令编出来的二进制在板子上第一条不认识的指令就崩。还有一个可能是 C 标准库版本不匹配主机上的libstdc版本比板子上的新用到了新 ABI 符号板子上没有。 排查手段是aarch64-buildroot-linux-gnu-readelf -d opencv_test | grep NEEDED把依赖列表打出来逐个看出现libc.so.6之外的陌生库、或者版本号明显偏高的libstdc.so.6就要追一下它是从哪来的。编译选项里去掉-marchnative换成-marcharmv8-a绝大多数 RK3568 场景下够用。6. 把依赖钉死上板前的三项自检与一次瘦身程序编出来别急着拷先做三项自检能省掉大量「上板才发现」的时间。第一项看架构和解释器路径第二项看动态依赖列表第三项用 pkg-config 反向校验编译参数是否和.pc文件一致。SYSROOT/opt/rk3568-toolchain/aarch64-buildroot-linux-gnu/sysroot CROSS/opt/rk3568-toolchain/bin/aarch64-buildroot-linux-gnu- # 1. 架构与动态链接器interpreter 必须是 aarch64 那一条 file opencv_test ${CROSS}readelf -l opencv_test | grep -i interpreter # 2. 动态依赖逐个确认板子上都有 ${CROSS}readelf -d opencv_test | grep NEEDED # 3. 用 sysroot 里的 pc 文件反查对比和你手写的参数是否一致 PKG_CONFIG_SYSROOT_DIR$SYSROOT \ PKG_CONFIG_LIBDIR$SYSROOT/usr/lib/pkgconfig \ pkg-config --cflags --libs opencv4第一项里如果 interpreter 显示的是/lib64/ld-linux-x86-64.so.2说明整个编译过程根本没走交叉工具链回头查CXX变量。第二项输出里出现libopencv_*.so.4.5之外的库名比如某个你没主动链接的第三方库要确认它在目标 rootfs 里存在否则上板必然报not found。第三项是给自己写的 Makefile 做体检——pkg-config输出的Libs里带的库如果比你写的多说明你漏了比你少说明你多链了没用的东西。瘦身这一步看项目阶段。调试期不要 strip保留符号才能在上板崩溃时用addr2line定位到行号。定版前再跑一次${CROSS}strip --strip-unneeded opencv_test ls -lh opencv_test--strip-unneeded只删对动态链接无用的符号比--strip-all安全后者会把动态符号表也一起削掉程序直接起不来。一个典型的 OpenCV 小工具从 200KB 出头能压到 40KB 左右对 eMMC 空间紧张的板子有意义。常用模块和链接名之间的对应关系我整理成一张表放在项目 README 里换工程时直接抄模块链接参数什么时候必须加core-lopencv_core只要用了cv::Mat就离不开imgcodecs-lopencv_imgcodecs读写图片文件imread/imwriteimgproc-lopencv_imgproc缩放、滤波、颜色空间转换highgui-lopencv_highgui窗口显示、按键等待videoio-lopencv_videoio摄像头、视频文件、GStreamer 后端freetype-lopencv_freetype图上绘制中文属 contrib最后说一个习惯。早些年我图省事编完直接scp上板跑不起来就反复改代码有一次折腾了两个小时最后发现是主机/usr/lib里那份 x86 的 OpenCV 被链接进去了代码一个字都没错。从那以后我每次编完必走一遍filereadelf -d这两条命令三十秒的事比在板子上瞎猜快得多。希望帮到你。本文还有配套的精品资源点击获取