ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

iTop4412移植OpenCV 2.4.9:交叉编译与上板验证

iTop4412移植OpenCV 2.4.9:交叉编译与上板验证 简介面向嵌入式Linux与ARM开发者的OpenCV 2.4.9移植资源包完整对应iTop4412Samsung S5PV210开发板环境解决交叉编译工具链配置、libv4l依赖安装、CMake编译选项调整等常见移植难点。压缩包共含3个文件以OpenCV源码包、libv4l依赖源码包及videodev.h头文件为主整体约86.6MB涵盖从源码编译到头文件补齐的关键环节可大幅减少在嵌入式平台上移植OpenCV时的环境搭建时间。资源已获208人学习说明其在同类移植场景中具备一定参考价值。通过这份资源读者可以拿到OpenCV 2.4.9源码、V4L增强库及V4L头文件并结合官方给出的移植流程逐步完成环境配置、依赖编译、OpenCV构建与示例程序验证从而在iTop4412上实现图像读取、显示和视频处理等能力适合正在开展嵌入式视觉项目或需要快速启用图像处理功能的开发者使用。1. 为什么是 OpenCV 2.4.9 和 iTop4412 这组搭配iTop4412 板子跑 OpenCV 2.4.9 这件事第一反应往往是“交叉编译一把过”。真在板卡上做过一遍就知道卡点不在 OpenCV 本身而在 4412 这一侧的工具链、根文件系统和 V4L 桥接。4412 是 Cortex-A9 四核 ARMv7官方出厂文件系统往往只带 BusyBox 和必要运行库想在板子上直接 apt-get 装 OpenCV 并不现实而 OpenCV 2.4.9 是 2.4 分支里对 GCC 4.4/4.7 和 CMake 检测都比较宽容的版本比 OpenCV 3 的移植条件更容易凑齐。下面把 x86 主机上交叉编译、部署到 rootfs、在 4412 上跑通/dev/video0验证这条链路讲完适合做嵌入式视觉整机的工程师照着落地。2. 移植 OpenCV 2.4.9 的前置资源源码、工具链与依赖库2.1 移植资源清单不要只准备一个 OpenCV 压缩包一个能落到 4412 rootfs 里的 OpenCV通常由四部分拼出来opencv-2.4.9源码、交叉编译器、CMake 工具链文件以及 zlib/libjpeg/libpng 这些被 OpenCV 内部引用的基础库。很多人只下载了源码接着就在 iTop4412 上执行 apt-get结果 apt 源版本不匹配或者 rootfs 根本没有包管理。常见做法是在 x86 主机上做交叉编译再把安装目录同步到目标板这样也方便在 CI 里复现。这里先定一个基本假设你手里已经有一份能启动的 4412 Linux 系统rootfs 是 yaffs2 或 ext4内核带 V4L2 驱动。移植 OpenCV 不需要重编内核但必须先确认CONFIG_VIDEO_DEV、CONFIG_V4L2已经打开不然后面VideoCapture打开/dev/video0时永远返回 false。检查方式是在目标板上执行zcat /proc/config.gz | grep V4L2如果/proc/config.gz不存在就翻内核目录里的.config或在menuconfig里搜索 V4L2。这条链和之前做 4412 移植 Linux、移植 uboot 是同一套思路先保证底层设备节点可见再谈用户态库。2.2 编译器选型GCC 4.4、Linaro 4.7 和 4.8 的取舍iTop4412 官方资料里最常见的编译器是arm-2009q3GCC 4.4.1和 Linaro 4.7这两套都能编译 OpenCV 2.4.9。我的建议是优先用官方 BSP 自带的编译器其次才换成 Linaro 4.7。原因很直接OpenCV 2.4.9 的代码里用了大量针对 GCC 4.4 的兼容宏在 4.4 下编译基本不会有语法门槛而 GCC 4.8 及以上虽然能编但对 OpenCV 自带的 CMake 编译器检测更严格反而容易在-mfpuneon与-mfloat-abisoftfp的搭配上报错。先把编译器跑通再谈其他下面两条命令可以在主机上快速确认工具链是否可用、ABI 是 softfp 还是 hardarm-linux-gnueabihf-gcc -dumpversion arm-linux-gnueabihf-gcc -v 21 | grep -E Target:|--with-float-dumpversion只输出 GCC 主版本号适合脚本判断第二行会把编译器的目标三元组和浮点 ABI 一起打印出来。如果Target是arm-linux-gnueabihf说明工具链默认使用 hard-float如果是arm-linux-gnueabi默认走 softfp。后面 CMake 配置里的ENABLE_NEON能不能开很大程度取决于这个默认值。不同工具链对运行库的影响可以看这个表方便你在选型时直接对照工具链浮点 ABIOpenCV 2.4.9 兼容性常见问题arm-2009q3 (GCC 4.4.1)softfp高对 C11 特性不敏感但编译速度慢Linaro 4.7 gnueabihfhard高需要 rootfs 配套 ld-linux-armhfLinaro 4.8hard中CMake 对__ARM_NEON__自动检测偶发失败这里的判断依据是OpenCV 2.4.9 在打包运行时不只依赖 libopencv_*.so还会把libstdc.so.6、libgcc_s.so.1带进目标系统。如果用 hard-float 工具链编出来的 OpenCV 放到一个仅软浮点的 rootfs 里运行时会直接报Illegal instruction这跟 OpenCV 本身无关。2.3 依赖库的三种拿法3rdparty、交叉编译和放弃OpenCV 2.4.9 需要 zlib、libjpeg、libpng 和 libtiff这四个库在源码包的3rdparty目录都有副本。最省事的做法是在 CMake 阶段把BUILD_ZLIBON、BUILD_JPEGON、BUILD_PNGON、BUILD_TIFFON打开让 OpenCV 直接把依赖编进去不带额外的.so到 4412 上。第二种做法是自己交叉编译这四个库再通过JPEG_LIBRARY、PNG_LIBRARY这些参数告诉 CMake 到哪里找需要接 libv4l 或 FFmpeg 时才这么做。我的经验是在 iTop4412 上做图像处理多数项目只需要 imread 读图和 Mat 运算外部依赖可以全关。只有当你明确要读摄像头时WITH_V4LON才会真正参与编译这个选项依赖 Linux 的 V4L2 头文件不依赖 libv4l 用户态库所以不需要额外交叉编译。少数方案会同时开WITH_LIBV4LON这个开关需要 libv4l 转换层反而多一个依赖我一般建议关掉减少一次“嵌入式移植”里常见的用户态库不匹配事故。3. 用交叉编译配置 OpenCV 2.4.9CMake 核心参数一次讲清3.1 一份可以直接抄的 cmake 命令行先把完整的配置命令给出来下面再逐项解释为什么这么写。整个流程在 x86 主机上执行用单独的build-arm目录隔离产物。INSTALL_DIR$HOME/4412/porting/opencv-arm TOOLCHAINarm-linux-gnueabihf mkdir -p $HOME/4412/porting cd $HOME/4412/porting tar xjf opencv-2.4.9.tar.bz2 cd opencv-2.4.9 mkdir -p build-arm cd build-arm cmake -DCMAKE_SYSTEM_NAMELinux \ -DCMAKE_SYSTEM_PROCESSORarmv7-a \ -DCMAKE_C_COMPILER$TOOLCHAIN-gcc \ -DCMAKE_CXX_COMPILER$TOOLCHAIN-g \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_INSTALL_PREFIX$INSTALL_DIR \ -DWITH_CUDAOFF \ -DWITH_GTKOFF \ -DWITH_QTOFF \ -DWITH_OPENCLOFF \ -DWITH_FFMPEGOFF \ -DWITH_TBBOFF \ -DBUILD_opencv_appsOFF \ -DBUILD_TESTSOFF \ -DBUILD_PERF_TESTSOFF \ -DENABLE_VFPV3ON \ -DENABLE_NEONON \ .. make -j4 make install这段命令的核心是CMAKE_SYSTEM_NAMELinux一旦设置CMake 就认为自己正在为一个非主机目标生成构建规则后续的 include 目录和链接器选项都会以交叉环境处理。只指定CMAKE_C_COMPILER而不写CMAKE_SYSTEM_NAME是很多移植失败的主因因为 CMake 仍会按 x86 宿主检查/usr/include随后生成的参数里混入-m64头一个源文件就过不了。WITH_FFMPEGOFF的理由是 FFmpeg 依赖一堆编码库交叉编译成本远高于收益4412 上用 OpenCV 读视频流走 V4L 就够了。WITH_TBBOFF则省略了第三方线程构建库2.4.9 自带 pthread 支持四核上仍然可以用cv::setNumThreads(4)控制线程后面第五章再展开。3.2 必调开关的参数表与说明配置 OpenCV 2.4.9 时真正影响能否编过、能否运行的开关可以收敛成一张参数表照着填就不容易错CMake 参数建议值为什么不这样会翻车CMAKE_SYSTEM_NAMELinux缺省时按宿主 x86 配置产物不能给 ARM 用CMAKE_SYSTEM_PROCESSORarmv7-a影响部分平台相关代码的编译条件ENABLE_NEONON4412 是 Cortex-A9带 NEON不开浪费浮点性能ENABLE_VFPV3ON配合浮点 ABI矩阵运算速度差别明显WITH_CUDA / WITH_OPENCLOFFARM 上没有可用运行时开着会导致部分模块编译失败WITH_GTK / WITH_QTOFFrootfs 没有 X11/GTK 依赖GUI 部分在 4412 上不需要WITH_FFMPEGOFF省去额外交叉编译 ffmpeg视频来源走 V4L2WITH_V4LON读取/dev/video*的关键开关BUILD_opencv_appsOFF不编译命令行工具能缩短大量构建时间ENABLE_NEONON不是随便开的。它会让 CMake 给编译器加-mfpuneon同时 OpenCV 的cv::resize、cv::cvtColor内部会启用 NEON 内联汇编。如果你的工具链默认 ABI 是 softfp还要确认-mfpuneon与-mfloat-abisoftfp不冲突hard-float 工具链一路开到底即可。ENABLE_VFPV3同理它控制__ARM_VFPV3__的预定义在 Cortex-A9 上两个都开才是正确姿势。3.3 交叉编译最隐蔽的坑缓存污染和构建目录搜索“opencv 2.4.9 arm”最常见的求助是“第一次编译失败删掉 build 目录重新编突然找不到编译器”。这不是 OpenCV 的问题而是 CMakeCache 没有清干净。CMake 首次检测会把CMAKE_HOST_SYSTEM_PROCESSORx86_64、CMAKE_C_COMPILER/usr/bin/gcc等写进build-arm/CMakeCache.txt。第二次换成交叉编译器如果不删 cacheCMake 会继续拿旧的编译器路径做检查或者拿着新编译器去校验旧的CMAKE_LIBC_PTHREAD得到的结论驴唇不对马嘴。所以我的习惯是换编译器、换构建目录、改CMAKE_INSTALL_PREFIX第一步都先删 cachecd $HOME/4412/porting/opencv-2.4.9 rm -rf build-arm删除后重新走到cmake那一步即可。如果使用 CMake 3.x 打开老工程顶部可能会提示 Policy CMP0003 之类不用理会直接按默认处理。4. 把 OpenCV 2.4.9 部署到 4412 的 rootfs 并现场验证4.1 库文件、头文件和运行库的同步方式make install会按照CMAKE_INSTALL_PREFIX生成include/opencv、lib/libopencv_core.so*等目录结构。我在 iTop4412 上习惯把整个opencv-arm目录同步到目标板/usr/local这样头文件、库文件位置和主机上对齐后续交叉编译只需指定同一个-I和-L路径。同步时要用cp -a不能只拷.so或只拷散件。OpenCV 安装目录里有一串符号链接libopencv_core.so指向libopencv_core.so.2.4.9如果按普通文件复制链接关系会断。简便方法是在主机上用 tar 打包再到 4412 上解包同时保住权限和时间戳cd $HOME/4412/porting/opencv-arm tar czf opencv-arm.tgz include lib # 把 opencv-arm.tgz 传到 4412 的 /tmp 后执行 cd /usr/local tar xzf /tmp/opencv-arm.tgz除了 OpenCV 自己目标系统还必须备齐两个运行库libstdc.so.6和libgcc_s.so.1它们不包含在opencv-arm.tgz里。可以从交叉编译器目录拷贝也可以直接在 4412 的 rootfs 里用同版本编译器编译一份。如果工具链是arm-linux-gnueabihf库文件通常在$(dirname $(which arm-linux-gnueabihf-gcc))/../arm-linux-gnueabihf/libc/lib/arm-linux-gnueabihf/把它们同样复制到 rootfs 的/lib或/usr/lib。检查依赖最可靠的是readelf在主机上对交叉编译的产物执行arm-linux-gnueabihf-readelf -d test_opencv | grep NEEDEDNEEDED一栏会列出全部动态依赖。看到libopencv_core.so.2.4、libstdc.so.6才算正常如果冒出 x86 的libc.so.6路径就要回头审查CMAKE_SYSTEM_NAME是不是写漏。4.2 在主机上交叉编译第一段验证程序部署完成后先在主机上交叉编译一段不依赖摄像头的测试程序验证基础矩阵运算。下面代码刻意避开imread因为imread依赖图片格式库格式库版本不一致时会“库文件都在但函数调用报段错误”不利于排查。// test_opencv.cpp #include opencv2/opencv.hpp #include cstdio using namespace cv; int main() { Mat frame Mat::zeros(240, 320, CV_8UC3); // BGR 三通道图像 frame.setTo(Scalar(0, 180, 0)); // 整体设为绿色 frame.atVec3b(12, 30) Vec3b(255, 0, 0); // 改左上角为蓝色 printf(rows%d, cols%d, channels%d, blue%d, green%d\n, frame.rows, frame.cols, frame.channels(), frame.atVec3b(12, 30)[0], frame.atVec3b(0, 0)[1]); return 0; }Mat::zeros创建的是连续内存setTo用来做整幅图像的快速填充验证色彩空间排列。channels()返回 3说明内存布局是 BGR 三通道打印出的 blue 和 green 值能在后续调摄像头时帮你确认不是 YUYV 与 BGR24 的转换问题。用下面命令交叉编译arm-linux-gnueabihf-g test_opencv.cpp \ -I $HOME/4412/porting/opencv-arm/include \ -L $HOME/4412/porting/opencv-arm/lib \ -lopencv_core \ -Wl,-rpath-link,$HOME/4412/porting/opencv-arm/lib \ -o test_opencv-L只负责让链接器找到库文件-Wl,-rpath-link用来让链接器提前解析libopencv_core.so内部引用的外部符号。这里不需要-Wl,-rpath因为运行时不要让程序记住主机上的绝对路径而是让 4412 通过LD_LIBRARY_PATH决定从哪里加载库。4.3 上板验证环境变量、模块选择和摄像头链路把test_opencv传到 4412 上先做一次不带摄像头的验证。在串口或 ssh 终端下执行export LD_LIBRARY_PATH/usr/local/lib:/lib:/usr/lib ./test_opencv预期输出rows240, cols320, channels3, blue255, green180。如果提示error while loading shared libraries: libopencv_core.so.2.4: cannot open shared object file说明LD_LIBRARY_PATH没覆盖到安装目录把/usr/local/lib加进去即可。如果提示libstdc.so.6: version GLIBCXX_3.4.20 not found则是 4412 上的 libstdc 版本太低换成与编译器捆绑的版本再拷一次。摄像头链路要单独验证。2.4.9 的VideoCapture在opencv_highgui模块里所以编译时要增加-lopencv_highgui和-lopencv_imgproc。下面是一段比反复猜更耐用的检测代码// camera_check.cpp #include opencv2/highgui/highgui.hpp #include opencv2/core/core.hpp #include cstdio using namespace cv; int main() { VideoCapture cap(0); if (!cap.isOpened()) { printf(video0 open failed\n); return 1; } Mat frame; cap frame; printf(frame size%dx%d\n, frame.cols, frame.rows); cap.release(); return 0; }编译后放到 4412 上运行。如果video0 open failed先查/dev/video0是否存在存在则用cat /dev/video0 /tmp/cap.yuv采集 3 秒用ls -l /tmp/cap.yuv看字节数是否递增。能采集说明内核 V4L2 没问题问题出在 2.4.9 对目标像素格式的选择上常见做法是用cap.set(CV_CAP_PROP_FOURCC, CV_FOURCC(M,J,P,G))强制 MJPG 格式绕开 YUYV 在 4412 摄像头驱动上分配内存的怪癖。下面一张表把几类现象直接对应到排查方向现象定位方向运行时报 libstdc 版本错交叉编译器带的运行库和 rootfs 冲突运行时报 Illegal instruction硬浮点与软浮点 ABI 不匹配video0 open failed由/proc/config.gz查内核 V4L2 配置cap frame 得到空 Mat强制 MJPG 或调整分辨率5. OpenCV 2.4.9 在 iTop4412 上的优化参数与常见坑5.1 确认 NEON 和 VFPV3 真的参与编译CMake 的ENABLE_NEONON只是把配置写进缓存真正决定编译行为的是编译器参数。上板前可以在主机上检查单条编译命令grep -E C_FLAGS|CXX_FLAGS|NEON|VFPV3 $HOME/4412/porting/opencv-2.4.9/build-arm/CMakeFiles/opencv_core.dir/flags.makeflags.make是 CMake 为opencv_core模块实际生成的编译参数文件。看到-mfpuneon -mfloat-abisoftfp才能确认 NEON 启用生效如果只有默认的-marcharmv7-a说明编译器在检测阶段把 NEON 判定为不满足。Cortex-A9 的 NEON 单元需要-mfpuneon代码层面的CV_NEON宏才会从 0 变为 1。另一个更直观的验证方式是在目标工程里打印编译时信息#include opencv2/core/core.hpp printf(%s\n, cv::getBuildInformation().c_str());getBuildInformation的输出里能看到NEON:YES、VFPV3:YES这一行。如果输出NEON:NO就回查工具链是否真的支持-mfpuneon而不是停在 CMake 缓存这一层。5.2 用模块裁剪缩短 2.4.9 的交叉编译时间第一次全量编译 OpenCV 2.4.9会同时碰calib3d、features2d、flann、stitching等二十多个模块。若你只需要core、imgproc、highgui可以在 cmake 命令行追加这些参数-DBUILD_opencv_calib3dOFF \ -DBUILD_opencv_features2dOFF \ -DBUILD_opencv_flannOFF \ -DBUILD_opencv_mlOFF \ -DBUILD_opencv_stitchingOFF \ -DBUILD_opencv_videostabOFF \ -DBUILD_opencv_superresOFF \ -DBUILD_opencv_photoOFF \ -DBUILD_opencv_objdetectOFF模块依赖关系要记牢highgui依赖imgprocimgproc依赖core这三个保留打开其他按需关闭。把objdetect打开会引入features2d不需要人脸检测的功能可以一并关掉。裁剪后编译时间大约能少三分之一安装目录体积也会从 300MB 级别降到 100MB 出头对 4412 的内核空间压力小很多。5.3 四核 4412 的线程策略和内存边界iTop4412 是四核但 OpenCV 2.4.9 默认不会把每个循环都并行化。建议在初始化时用cv::setNumThreads(2)或 4 控制算法内部线程数避免多路同时调用VideoCapture时把 1GB 内存吃穿。常见坑是imread大图时不用CV_LOAD_IMAGE_GRAYSCALE三通道彩色图会白白多占两倍内存。如果对实时性有要求优先检查是否把 NEON 路径走到了cvtColor上2.4.9 的cvtColor有 NEON 优化版本没有走到时性能差距会明显拉大。测算帧耗时建议用cv::getTickCount和cv::getTickFrequency()不要用clock()后者在 Linux 上返回用户态 CPU 时间不是墙上时间四核调度下会严重误导你。上板后用free -m观察进程内存再用cat /proc/meminfo确认 Cache 占用把这两行检查宏和getTickCount的耗时统计放回构建脚本里以后每次换工具链同步验证一遍即可。本文还有配套的精品资源点击获取
返回列表