交叉编译armv7运行环境以及嵌入式opencv的编译示例

原文地址

原文链接

前言

最近在做嵌入式下计算机视觉相关功能的实现,那么交叉编译和opencv库基本上就是必要条件了,这里记录下相关内容的构建以及猜的一些坑

实现

交叉编译环境的构建

首先我们的构建环境是CentOS Stream release 8 x86_64 GNU/Linux以及Ubuntu 18.04.6 LTS x86_64 GNU/Linux,运行环境为armv7l GNU/Linux

ubuntu

Ubuntu的交叉编译环境构建比较简单,直接使用apt-get下载即可,参考opencvCross compilation for ARM based Linux systems,构建环境中可选项根据需求安装,但是如果不是特别熟悉opencv建议全装

centos

Centos的交叉编译工具链相对稍微麻烦点,首先我们去arm.com下载相关工具链,Downloads,我们可以看到分别为不同编译环境下的不同运行环境需求提供了工具了,根据我们的构建和运行,需要选择X86_64下的AArch32 target with hard float

下载后解压tar -xf /usr/local/arm/*.tar.xz,然后再添加环境变量,export PATH=$PATH:/usr/local/arm/arm-none-linux-gnueabihf/bin,如果需要永久添加的话将命令写入/etc/profile/etc/environmentsource即可

至此最基本的交叉编译工具链就构建完成了

为运行环境编译opencv库

如果我希望在嵌入式环境中使用opencv,理所当然需要将opencv编译成他的形状,那么首先下载源码

mkdir /usr/local/opencv && cd /usr/local/opencv
git clone https://github.com/opencv/opencv.git

然后找到提供的cmake示例,我们这里是为Linux平台构建

cd opencv-*/platforms/linux/

根据我们编译以及运行平台,这里选择arm-gnueabi.toolchain.cmake,但是需要稍微做一些改变适应我们的需求

cp arm-gnueabi.toolchain.cmake arm-gnueabi.toolchain.cmake.bak && vim arm-gnueabi.toolchain.cmake

小伙伴们可以自行增加减少,更多CMake选项参考CMake Introduction

set(GCC_COMPILER_VERSION "" CACHE STRING "GCC Compiler version")
set(GNU_MACHINE "arm-linux-gnueabi" CACHE STRING "GNU compiler triple")

#指定工具链
set(CMAKE_C_COMPILER /usr/local/arm/arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER /usr/local/arm/arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-g++)

#生成静态库而不是动态库
set(BUILD_SHARED_LIBS OFF)
#构建详细输出
set(CMAKE_VERBOSE_MAKEFILE ON)
#opencv生成pkconfig便于编译
set(OPENCV_GENERATE_PKGCONFIG ON)
#生成Release版本
set(CMAKE_BUILD_TYPE Release)

#补充构建和链接
set(BUILD_ZLIB ON)
set(BUILD_OPENEXR ON)
set(BUILD_ILMIMF ON)
set(BUILD_TBB ON)
set(BUILD_JASPER ON)
set(BUILD_PNG ON)
set(BUILD_JPEG ON)
set(BUILD_TIFF ON)
set(CMAKE_EXE_LINKER_FLAGS "-pthread -ldl -lrt")

include("${CMAKE_CURRENT_LIST_DIR}/arm.toolchain.cmake")

然后生成Makefile,同时指定工具链和库安装目录

mkdir build && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=../arm-gnueabi.toolchain.cmake -DCMAKE_INSTALL_PREFIX=/usr/local/opencv/install/ ../../..

最后构建以及安装

make && make install

测试

现在我们以及在编译机器上构建了运行机所需要的opencv相关库,根据上面的编译命令,opencv相关头文件可以在/usr/local/opencv/install/include中获得,而静态库可以在/usr/local/opencv/install/lib中获得,但是我们如何知道在编译的时候要引用哪些库参加编译呢。这个时候就需要pkg-config以及opencv生成的.pc文件来协助插入正确的编译器选项,定位需要的库

当然,如果不想用pkg-config,那么直接查看/usr/local/opencv/install/lib/pkgconfig/*.pc,让根据自己的需求将所需库拷贝到编译命令中也一样可以就是了

如果希望使用pkg-config,我们需要添加环境变量,让他可以查找到opencv.pc文件,同样,如果需要永久添加的话将命令写入/etc/profile/etc/environmentsource即可

export PKG_CONFIG_PATH=/usr/local/opencv/install/lib/pkgconfig:$PKG_CONFIG_PATH

使用命令pkg-config --cflags --libs --static opencv4检查是否以及成功被检测到

-I/usr/local/opencv/install/include/opencv4 -L/usr/local/opencv/install/lib -lopencv_gapi -lopencv_highgui -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_video -lopencv_calib3d -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_core -L/usr/local/opencv/install/lib/opencv4/3rdparty -llibprotobuf -lade -littnotify -llibjpeg-turbo -llibwebp -llibpng -llibtiff -llibopenjp2 -lIlmImf -lzlib -lquirc -ltegra_hal -ldl -lm -lpthread -lrt 

然后我们编写一个简单的测试程序,main.cpp

#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <iostream>

int main(int argc, char* argv[]) {
    std::cout << "start test" << std::endl;
    const char* diskImg = "/test/test.jpg";
    cv::Mat img = cv::imread(diskImg, 1);
    if (img.empty()) {
        std::cout << "img not found" << std::endl;
        return -1;
    } else {
        std::cout << "loaded img" << std::endl;
    }
    cv::resize(img, img, cv::Size(100, 100));
    cv::imwrite("/test/new.jpg", img);
    std::cout << "convert finish" << std::endl; 
    return 0;
}

然后编译

arm-none-linux-gnueabihf-g++  main.cpp -o testcv  -std=c++11 -static  $(pkg-config --cflags --libs  --static opencv4)

生成可执行文件后,将文件传到运行机器上,直接运行

即可获得模糊后的图片

细心的小伙伴可能发现了,我们在编译的时候使用了-static来强制让g++使用静态库,而不是默认的优先使用动态库。这样做好处是基本动态库,比如libstdc++.so,不会因为运行环境和编译环境gcc版本不同而报错,因为有些项目是需要相对高版本的gcc编译的。但坏处是可执行文件过大,不同程序引用相同库没有共享库导致占用运行环境磁盘空间,以及即使是静态引用也不能保证你这个程序就是独立的,因为你静态引用的库仍然可能动态引用其他库,这个就是当我们使用-static编译时候,会报出

/usr/local/arm/arm-none-linux-gnueabihf/bin/../lib/gcc/arm-none-linux-gnueabihf/10.3.1/../../../../arm-none-linux-gnueabihf/bin/ld: /usr/local/opencv/install/lib/libopencv_core.a(opencl_core.cpp.o): in function `opencl_check_fn(int)':
opencl_core.cpp:(.text._ZL15opencl_check_fni+0x10c): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

警告的的原因,但是如果我们使用默认的优先动态链接的方式去构建,就需要关注运行环境的基本库和构建环境的基本库版本是否相同的问题了,否则就会报出

/lib/libm.so.6: version `GLIBC_2.29' not found 
/lib/libstdc++.so.6: no version information available

这样的错误

原文地址

原文链接

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值