简介这份《ATK-DLRK3568_OpenCV4使用手册》面向具备Linux基础、希望把计算机视觉程序部署到嵌入式板卡上的开发者围绕正点原子ATK-DLRK3568四核A552.0GHz、默认Buildroot、OpenCV 4.5.5讲解OpenCV4应用的编写、交叉编译与运行。压缩包仅含1个PDF文件约1.41MB篇幅集中、查阅方便。内容从OpenCV4概念与最小示例入手依次覆盖交叉编译工具链安装C版本在命令行、Makefile、CMakeLists和Qt工程中的组织方式Python版本的调用方法并附常见问题排查。读者可据此搭建可复用的编译环境理解不同构建方式的差异掌握Qt项目集成OpenCV的配置要点并在遇到库路径、编译选项等问题时快速定位。已有120人学习适合作为嵌入式视觉入门的案头手册。1. 先对齐版本再动手RK3568 板子上那份 OpenCV 4.5.5 到底在哪有个开发者把 C 版 OpenCV 程序在 Ubuntu 上编译得干干净净scp 拷到板子上一执行就报error while loading shared libraries。查了一下午问题不在代码而在他默认“板子上肯定没装 OpenCV得自己从源码编一份”。实际上出厂 Buildroot 镜像里已经放好了一份 OpenCV 4.5.5运行库在/usr/lib头文件在交叉工具链 sysroot 的/usr/include/opencv4下Python 的cv2接口也一并打包好了连 freetype 字体渲染都在里面。嵌入式开发做计算机视觉最省事的路径往往是最不好找的那条不重新编译 OpenCV而是把手上的交叉编译工具链和板子里的现成库对齐。这也是交叉编译 OpenCV 程序最容易踩坑的地方——工具链版本、sysroot 路径、链接库名三样里有一样对不上编译阶段一路绿灯运行时才报错。这套环境适合手上已有 ATK-DLRK3568四核 A552.0GHz开发板、想跑 C 或 Python 视觉程序的开发者也适合要把 OpenCV 接进 Qt 工程的人。2. 环境清点与交叉编译工具链安装三个路径别写混交叉编译这件事麻烦从来不在敲哪条命令而在于“哪套头文件配哪个编译器”。主机上如果同时装过 x86 的 OpenCV、装过别的板子的工具链环境变量一乱编译器就会悄悄拿主机库去链接编出来的二进制在板子上必然跑不起来。所以装之前先把三件事钉死编译器绝对路径、sysroot 绝对路径、板端库的实际位置。三样都用绝对路径写不依赖 PATH也不依赖pkg-config的默认搜索顺序。2.1 主机与板端的版本对照先把对照关系列出来后面所有命令都从这里取路径。文档里关于系统范围有一句很关键的话所有内容建立在 Buildroot 出厂系统之上Debian 和 Yocto 不在说明范围内。这句话决定了你不能拿 Debian 根文件系统上的库路径去套。项目主机侧Ubuntu 20.04板端Buildroot 出厂系统架构x86_64aarch64armv8编译器前缀aarch64-buildroot-linux-gnu-无不需要工具链安装根/opt/atk-dlrk356x-toolchain无OpenCV 版本由 sysroot 提供与板端一致4.5.5头文件…/sysroot/usr/include/opencv4同左打包进镜像运行库…/sysroot/usr/lib/usr/libPython 接口不需要板端python3cv2有一个细节必须提前说工具链的安装目录名在随板资料的不同章节里出现过atk-dlrk3568-toolchain和atk-dlrk356x-toolchain两种写法。前者是.run安装包默认落地的目录后者是示例命令里用的目录。它们指的不是两个东西但你照抄命令时一旦写成一种、实际装成另一种后面每一条编译命令都会报No such file or directory。常见做法是安装时接受默认路径装完ls /opt看一眼实际目录名然后把后续所有配置统一成那一个名字。我一般会把实际路径记在工程的README里避免几天后自己都记不清。2.2.run工具链的安装步骤与路径确认工具链来自随板资料光盘里的交叉编译工具目录文件名形如atk-dlrk3568-toolchain-arm-buildroot-linux-gnueabihf-x86_64-(版本号).run。它不是通用的 Linaro 工具链而是从这块板子的 SDK 里用 Buildroot 生成后打包出来的好处是不用编 SDK 也能直接拿来开发。这个包用 WinScp 之类的工具传到 Ubuntu 上落地位置随意我习惯放在~/toolchain/下。# 1. 进入安装包所在目录 cd ~/toolchain # 2. 补上可执行权限.run 包默认不带 x 位 chmod 777 atk-dlrk3568-toolchain-arm-buildroot-linux-gnueabihf-x86_64-*.run # 3. 执行安装交互过程中会问安装路径 ./atk-dlrk3568-toolchain-arm-buildroot-linux-gnueabihf-x86_64-*.run执行后会进入交互式安装。第一步是询问安装路径默认是/opt/atk-dlrk3568-toolchain这里建议直接回车接受默认值理由不是“官方推荐”而是后面所有示例、Makefile、CMakeLists里的路径都基于它你改成别的路径并不会报错只会在每次复制别人配置时多一道手工替换。第二步输入y或Y确认安装过程大约一到两分钟速度取决于磁盘。装完不要急着往下走先做下面三件事。安装路径不要带空格、不要放在中文目录下。.run解压出来的脚本和pkgconfig里的路径是按字面拼的路径里有空格时--sysroot后面的参数会在空格处被 shell 截断报出来的错是“找不到某个 .o 文件”跟实际原因完全对不上。2.3 装完三处自检编译器、sysroot、opencv4 头文件这一步很多人跳过然后在第四章花两小时排查。三处自检分别对应后面编译命令里的三个参数来源。# 自检一编译器能不能跑、版本对不对 /opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-g --version # 自检二sysroot 里的 opencv4 头文件在不在 ls /opt/atk-dlrk356x-toolchain/aarch64-buildroot-linux-gnu/sysroot/usr/include/opencv4 # 自检三链接库和 pkgconfig 描述文件在不在 ls /opt/atk-dlrk356x-toolchain/aarch64-buildroot-linux-gnu/sysroot/usr/lib | grep opencv ls /opt/atk-dlrk356x-toolchain/aarch64-buildroot-linux-gnu/sysroot/usr/lib/pkgconfig | grep opencv4第一条要能看到 GCC 的版本输出说明工具链本身解压完整、没有缺动态库。第二条如果输出opencv2目录说明头文件齐了注意这一层是opencv4而不是opencv2——源码里的写法是#include opencv4/opencv2/opencv.hpp两段路径都要对上。第三条重点是libopencv_core.so这类库文件以及opencv4.pc后者决定了 Qt 那套pkgconfig方案能不能用。三处只要有任意一处空目录就不要继续往第三章走。空目录通常意味着两件事之一.run安装被中断过或者你正在看的 sysroot 不是刚装的那份工具链的 sysroot比如系统里还留着一份别的板子的工具链。重新跑一次安装并接受默认路径比对着半份 sysroot 猜要快得多。3. C 程序两种编译法命令行手写与 Makefile 固化程序本身很短短到你会觉得“这也要写一章”。但嵌入式交叉编译的问题从来不发生在代码里而发生在“这四个参数分别对应什么”。命令行版本的价值是让你看清每个参数Makefile 版本的价值是让你不用每次重敲。两版都要走过一遍跳过命令行直接抄 Makefile 的人一旦 Makefile 报错就完全无从下手。3.1 先写一个最小的 OpenCV 程序在 Ubuntu 上建一个工作目录opencv里面放opencv_test.cpp。程序干的事很简单读一张图、开窗、显示、等按键。#include iostream #include opencv4/opencv2/opencv.hpp int main() { // 读板端本地图片换成自己的绝对路径即可 cv::Mat image cv::imread(/opt/apps/src/logo/test_logo.png); // 读失败必须拦一下否则后面 imshow 会抛异常 if (image.empty()) { std::cout 无法读取图片文件 std::endl; return -1; } cv::namedWindow(Image, cv::WINDOW_AUTOSIZE); cv::imshow(Image, image); cv::waitKey(0); // 阻塞等按键0 表示无限等待 cv::destroyAllWindows(); return 0; }两个和主机开发不一样的点。第一图片路径必须是板端的绝对路径因为程序跑在板子上imread读的是板子文件系统在主机上写./test_logo.png编出来的程序拷过去一定读不到。第二WINDOW_AUTOSIZE在嵌入式 Weston 桌面上偶尔会撑满或超出可视区换成WINDOW_NORMAL至少允许你手动缩放调界面的时候省事。Python 版本逻辑一模一样只是不需要编译。3.2 命令行编译把-I -L -l逐个拆开这是整套流程的核心一条命令。注意它是一行反斜杠只是换行。/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-g \ opencv_test.cpp -o opencv_test \ --sysroot/opt/atk-dlrk356x-toolchain/aarch64-buildroot-linux-gnu/sysroot \ -I /opt/atk-dlrk356x-toolchain/aarch64-buildroot-linux-gnu/sysroot/usr/include/opencv4 \ -L /opt/atk-dlrk356x-toolchain/aarch64-buildroot-linux-gnu/sysroot/usr/lib \ -lopencv_core -lopencv_highgui -lopencv_imgproc \ -lopencv_videoio -lopencv_imgcodecs逐段说清。第一行用的是工具链里的gC 程序换成gcc两者不能混。-o opencv_test指定输出文件名不带路径就落在当前目录。--sysroot是这次交叉编译的关键它告诉编译器“所有头文件和库都在这个根下面找”这样即使主机上装了 x86 的 OpenCV也不会被误链进来。-I是头文件搜索路径指到.../usr/include/opencv4这一层。为什么是这一层而不是.../usr/include因为源码里写的是opencv4/opencv2/opencv.hpp编译器要在 include 根下面找到opencv2才能拼出完整路径。有人习惯写-I.../usr/include并在代码里改成#include opencv2/opencv.hpp两种写法等价但不要混用混用的结果就是opencv2/opencv.hpp: No such file。-L指链接库路径--sysroot已经隐式包含了它显式再写一遍是为了防止个别版本的工具链在链接阶段不认 sysroot。-l后面跟的是库名不带lib前缀和.so后缀-lopencv_core对应libopencv_core.so。库名不是猜的去.../sysroot/usr/lib下ls | grep opencv看实际有哪些用到哪个加哪个。编译完成后通过 scp 或 adb 把opencv_test传到板子上执行。执行前记得chmod x opencv_test从 Windows 或某些传输方式过来的文件会丢可执行位报的是Permission denied看着像权限问题其实是传输过程丢位。3.3 Makefile 版本把路径收敛成变量命令行跑通之后把所有绝对路径提成变量写进Makefile。这样换工具链版本时只需要改一处。# 工具链根目录改这一行就够了 TOOLCHAIN_DIR : /opt/atk-dlrk356x-toolchain SYSROOT : ${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu/sysroot INC : ${SYSROOT}/usr/include GXX : ${TOOLCHAIN_DIR}/bin/aarch64-buildroot-linux-gnu-g # 头文件搜索路径opencv4 单独列一行避免和 sysroot 混在一起 CFLAGS : --sysroot${SYSROOT} -I${INC} -I${INC}/opencv4 # 只链真正用到的模块链多了会增加板端加载时间 LD_FLAGS : -L${SYSROOT}/usr/lib \ -lopencv_core -lopencv_highgui -lopencv_imgproc \ -lopencv_videoio -lopencv_imgcodecs all: $(GXX) opencv_test.cpp $(CFLAGS) $(LD_FLAGS) -o opencv_test echo Build Done ... clean: rm -f opencv_test三个变量对应上一节的三个参数TOOLCHAIN_DIR是工具链根SYSROOT是--sysroot的值INC是-I的父目录。写Makefile时$(GXX)和$(CFLAGS)之间的那行缩进必须是Tab不是四个空格。这是 Makefile 的老坑报错是missing separator看字面完全猜不到是缩进问题。在目录里直接make编译make clean清掉产物。每次改完代码先make clean再make不要指望 Makefile 的依赖判断在交叉编译场景下永远正确——头文件换过版本、库路径挪过位置这类变化它感知不到留着旧.o编出来的东西行为会很诡异。4. CMake 与 Qt 工程接入 OpenCV不手写库路径的两种做法Makefile能用之后问题会变成“工程里有十几个源文件怎么办”。CMake 的价值是把编译器、标准、链接库都写成声明不用维护一长串命令Qt 的.pro则是另一套思路靠pkgconfig让 Qt 自己去问 OpenCV 要路径。两条路都能走通区别在于你想不想在工程里看到绝对路径。4.1 CMakeLists 里的交叉编译四件套在源码目录建CMakeLists.txt。交叉编译场景下这个文件比常规 CMake 多了四行“告诉 CMake 用哪个编译器、哪个根”。cmake_minimum_required(VERSION 3.8) # 四件套之一工具链根目录 set(TOOLCHAIN_DIR /opt/atk-dlrk356x-toolchain) set(SYSROOT ${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu/sysroot) # 四件套之二显式指定 C/C 编译器必须在 project() 之前 set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/aarch64-buildroot-linux-gnu-g) set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/aarch64-buildroot-linux-gnu-gcc) # 四件套之三sysroot等价于命令行的 --sysroot set(CMAKE_SYSROOT ${SYSROOT}) # 四件套之四C 标准OpenCV 4.5.5 用 C11 足够 set(CMAKE_CXX_STANDARD 11) include_directories(${SYSROOT}/usr/include) include_directories(${SYSROOT}/usr/include/opencv4) set(OPENCV_LIBS opencv_core opencv_highgui opencv_imgproc opencv_videoio opencv_imgcodecs) project(opencv) add_executable(opencv_test opencv_test.cpp) target_link_libraries(opencv_test ${OPENCV_LIBS})顺序很讲究。set(CMAKE_CXX_COMPILER ...)必须写在project()之前写在后面 CMake 已经在配置阶段选定编译器了这行会被忽略编出来的仍然是 x86 二进制而 CMake 不会给任何警告。这也是判断“我到底交叉编译成功没有”的第一道关用file opencv_test看输出里是不是ARM aarch64是x86-64就说明编译器没切过去。include_directories里两行都要留着。第一行给--sysroot之外可能被引用的系统头第二行专门给opencv4这一层。target_link_libraries用变量传库名列表不要在这里写-lCMake 会自己补前缀后缀。4.2 build 目录、缓存与重新配置如果目录里已经有Makefile上一章留下的CMake 会冲突。标准做法是另建build目录。mkdir -p build cd build cmake .. # 依据上一级 CMakeLists.txt 生成 Makefile 等文件 make # 编译 make clean # 清理产物不删 Makefilecmake ..会在build里生成CMakeCache.txt这个文件缓存了上次探测到的编译器路径和库路径。改了CMakeLists.txt里的TOOLCHAIN_DIR之后光重新make是不够的缓存里还是旧路径症状是新代码编出来行为没变。正确做法是删掉build目录整个重来或者cmake ..时带-D覆盖。我一般直接rm -rf build mkdir build cd build cmake ..比研究缓存依赖快。4.3 Qt 的.pro用 pkgconfig 接 OpenCV4Qt 工程走的是另一条线前提是 Qt 的交叉编译环境本身已经配好工具链的qmake已经能编出板端程序。在这个前提下接 OpenCV 只需要两行。QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets CONFIG c17 # 关键两行开启 pkgconfig并声明依赖 opencv4 CONFIG link_pkgconfig PKGCONFIG opencv4link_pkgconfig让 qmake 在构建时调用pkg-configPKGCONFIG opencv4指定去问opencv4.pc。Qt 拿到.pc里的Cflags和Libs之后自动补 include 和 link 参数工程里不用出现任何绝对路径。这也是 2.3 节要检查pkgconfig/opencv4.pc是否存在的原因——那个文件不在这两行就只是两行字。代码侧只要在用到 OpenCV 的源文件里包含头文件即可注意路径前缀和命令行版本保持一致#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/src/logo/test_logo.png); Q_UNUSED(image); }Q_UNUSED是给编译器的信号这个变量暂时不用别报未使用警告。验证阶段这样就够能编过就说明头文件和库都接上了功能再往后加。构建用 Qt Creator 的 CtrlB或者命令行qmake make构建成功的标志是链接阶段没有undefined reference to cv::...。5. 避坑与排查交叉编译里最容易翻车的五件事下面五条都是我在装这套环境时真实撞过的按撞到的频率排序。每条都按“现象 → 原因 → 解决”写照着对号入座比从头读文档快。第一条编译通过板端执行报error while loading shared libraries: libopencv_core.so.4.5。现象是主机上make一路绿灯scp 到板子上就报缺库。原因不是库没编进去而是板端/usr/lib里的 OpenCV 版本和工具链 sysroot 里的不一致或者程序链接的是某个板端没打包的模块比如opencv_video。解决分两步先在板端ls /usr/lib | grep opencv看清楚实际有哪些.so再把编译命令里的-l列表裁剪成板端真实存在的那些确认版本用strings /usr/lib/libopencv_core.so.4.5 | grep 4.5。这一步不要靠猜两边列出来对照最快。第二条所有命令都报No such file or directory但目录明明存在。现象是aarch64-buildroot-linux-gnu-g: No such file or directoryls过去又能看到文件。原因有两个一是路径写成了atk-dlrk3568-toolchain实际装的是atk-dlrk356x-toolchain这两个名字在不同章节里都出现过二是.run包没加可执行权限就跑了安装其实没完成。解决是先ls /opt确认实际目录名再ls /opt/实际名/bin | head确认编译器在两处都对不上就重装一遍工具链接受默认路径。第三条fatal error: opencv2/opencv.hpp: No such file or directory。现象是编译第一行就挂。原因是-I指到了.../usr/include而不是.../usr/include/opencv4但源码里写的是opencv4/opencv2/opencv.hpp两段前缀叠起来就找不到了。解决是统一写法要么-I.../include/opencv4配#include opencv2/opencv.hpp要么-I.../include配#include opencv4/opencv2/opencv.hpp。工程里出现两种混写时会出现“这个文件能编、那个文件不能编”的诡异现象。第四条Qt 构建报Package opencv4 was not found in the pkg-config search path。现象是.pro里加了PKGCONFIG opencv4之后构建失败提示找不到包。原因有两个sysroot 的usr/lib/pkgconfig下确实没有opencv4.pc或者 qmake 调用的pkg-config是主机的那份它去/usr/lib/pkgconfig找自然找不到交叉编译的包。解决是先ls .../sysroot/usr/lib/pkgconfig | grep opencv4确认文件存在再给pkg-config设PKG_CONFIG_SYSROOT_DIR和PKG_CONFIG_LIBDIR指向 sysroot。别指望改PKG_CONFIG_PATH就行PATH类变量会被默认路径一起搜容易搜到主机那份。第五条程序跑起来窗口不显示或者只出现在屏幕中间一小块。现象是 HDMI 显示器上 Weston 桌面只占中间区域OpenCV 的窗口跟着缩在中间。原因不是 OpenCV是显示输出配置——Weston 默认把某个输出当主屏HDMI 接了但不是主显示时就会这样。解决在显示配置层面把 HDMI 设为主屏或者按屏幕方向旋转 90 度具体改法在随板的显示相关文档里跟 OpenCV 编译无关。这一条放在最后是因为它最容易被误判成“OpenCV 装坏了”实际代码和库都是好的。6. 装完怎么验证从file到一帧图像上屏验证不要只看“有没有报错”。编译通过只能说明头文件和链接参数对了能不能跑是另一回事。我习惯按四层往下走任何一层不过就停下来修不带着问题往下叠。第一层看产物架构。在build目录里执行file opencv_test # 期望输出里出现ELF 64-bit LSB, ARM aarch64 # 如果出现 x86-64说明 CMAKE_CXX_COMPILER 没生效回到 4.1 检查 set 的位置第二层看动态依赖有没有交叉污染。# 用工具链的 readelf 看依赖不要用主机的 ldd /opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-readelf -d opencv_test | grep NEEDED # 期望看到 libopencv_core.so.4.5 等且不应出现主机路径第三层板端库版本对账。把可执行文件传到板子上先别急着跑chmod x opencv_test ls /usr/lib | grep opencv # 板端实际有的库 python3 -c import cv2; print(cv2.__version__) # Python 侧版本应为 4.5.5两边的版本号一致才说明工具链 sysroot 和板端镜像是配套的。第三层不过说明这套工具链根本不是这块板子镜像对应的那份后面所有编译都是白费。第四层跑起来看画面。./opencv_test执行后应该弹出一个窗口显示图片按任意键关闭。能显示就全通了报缺库回到第五章第一条窗口位置不对回到第五章第五条。Python 版本更省事把.py拷过去python3 opencv_test.py直接跑不需要编译也因此它更适合当“板端环境和图片路径对不对”的探针——Python 能跑而 C 不能跑问题一定在编译环节不在环境。验证层命令通过标准失败时先查架构file opencv_test出现 ARM aarch64CMAKE_CXX_COMPILER位置依赖readelf -d只有交叉库无主机路径--sysroot/-L版本板端ls /usr/libcv2.__version__均为 4.5.5工具链与镜像是否配套运行./opencv_test窗口显示图片库缺失 / 图片路径 / 显示配置有一个我踩过的顺序坑值得提一句我曾经在 Python 版本还没跑通的情况下直接去调 Qt 的pkgconfig结果花了一个晚上在.pro和.pc文件之间来回改最后发现是板端镜像的 OpenCV 版本和手上的工具链差了半个小版本。从那以后我每次配这套环境都强制先跑一遍python3 -c import cv2; print(cv2.__version__)和file opencv_test这两条——一个查板端一个查编译产物两条命令十几秒能省掉后面几小时的黑匣子式排查。希望这套流程能帮到你少走一遍我走过的弯路。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?