嵌入式linux学习之opencv交叉编译/移植并使用CmakeList编译demo

一.交叉编译opencv库

1.下载opencv源码

OpenCV官方源码下载链接为https://opencv.org/releases/,选择3.4.16版本下载。放在ubuntu系统~/opencv文件夹中,解压缩,opencv文件夹中新建build和install文件夹用于存放编译文件和安装文件:
在这里插入图片描述

2. 安装编译工具

  • 安装 cmake 和 cmake-gui 工具
 sudo apt-get install cmake cmake-qt-gui cmake-curses-gui
  • 安装交叉编译器arm-none-linux-gnueabihf,根据自己情况来选择对应交叉编译器

3.安装opencv前安装环境依赖

sudo apt-get install build-essential
sudo apt-get install libopenblas-dev
sudo apt-get install git pkg-config libavcodec-dev libavformat-dev libswscale-dev
处理图像所需的包
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff5-dev libdc1394-22-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev liblapacke-dev
处理视频所需的包
sudo apt-get install libxvidcore-dev libx264-dev 
优化opencv功能
sudo apt-get install libatlas-base-dev gfortran
sudo apt-get install ffmpeg

4. 编译

进入build文件夹,执行命令:

cmake-gui

执行完成后会出现图形化工具 cmake-gui,选择源代码目录,buid目录,这里根据自己的路径填写
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 在 CMAKE_EXE_LINKER_FLAGS 处添加上-lpthread -lrt -ldl。添加这些是是指定依赖库的链接
    在这里插入图片描述
  • CMAKE_INSTALL_PREFIX 处指定安装目录,我们在上面已经新建了 install 安装目录。我们直接指定到该目录即可。如果不指定,它会默认安装到 Ubuntu 系统目录/usr/local 下。
    在这里插入图片描述
  • BUILD_TESTS取消勾选,否则会报错测试不通过
    在这里插入图片描述
  • 在源码目录 opencv-3.4.1/3rdparty/protobuf/src/google/protobuf/stubs/common.cc 这个文件下添加**#define HAVE_PTHREAD** 宏定义才可以编译的过。具体原因是 HAVE_PTHREAD 宏定义了 pthread 库。
    在这里插入图片描述
    进入 build 目录下,可以看到 bulid 目录下已经准备了构建文件。我们直接输入 make 构建即可。结束后make install
    编译完成如下图,如果有出错,先删除 build 目录下的所有文件,cmake-gui开始重新再来一次!
    如果成功安装则会在install目录中出现以下东西
    在这里插入图片描述
    这时可以将这个文件夹中的文件用于程序编写,并和之后生成的可执行文件一同传输至开发板,程序编写参考第二章:

问题汇总:

问题1:

/arm-none-linux-gnueabihf/libc/usr/include/features.h:311:52: error: operator ‘&&’ has no right operand
#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64

  • 解决1:
    在#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64前面 加上
    #define _FILE_OFFSET_BITS 64

问题2

make[1]: *** [modules/core/CMakeFiles/opencv_test_core.dir/all] Error 2
Makefile:160: recipe for target ‘all’ failed
make: *** [all] Error 2

  • 解决2
    configure配置中取消BUILD_TESTS

问题3

usr/lib/gcc-cross/aarch64-linux-gnu/8/…/…/…/…/aarch64-linux-gnu/bin/ld: …/…/lib/libopencv_imgcodecs.so.4.2.0: undefined reference to `png_riffle_palette_neon’
collect2: error: ld returned 1 exit status
make[2]: *** [apps/annotation/CMakeFiles/opencv_annotation.dir/build.make:89:bin/opencv_annotation] 错误 1
make[1]: *** [CMakeFiles/Makefile2:3746:apps/annotation/CMakeFiles/opencv_annotation.dir/all] 错误 2

  • 解决3:
    ./opencv-3.3.1/3rdparty/libpng/pngpriv.h

/*# if (defined(ARM_NEON) || defined(__ARM_NEON)) && */
#if defined(PNG_ARM_NEON) && (defined(ARM_NEON) || defined(__ARM_NEON)) &&
如上所示,把上面的一行注释掉,增加下面一行。删除build文件夹内容,在cmake-gui再次生成文件,再次make即可。
在这里插入图片描述

问题4

arm-linux-gnueabihf/bin/ld: …/…/lib/libopencv_imgcodecs.so: undefined reference to png_do_expand_palette_rgb8_neon' ./../../../arm-linux-gnueabihf/bin/ld: ../../lib/libopencv_imgcodecs.so: undefined reference to png_init_filter_functions_neon’
…/lib/libopencv_imgcodecs.so: undefined reference to `png_init_filter_functions_neon’

  • 解决4:
    在最上面加上添加如下语句:
    SET(ARM 1)
    SET(ENABLE_NEON 1)
    添加完成后在root权限下重新运行cmake-gui,重新配置和生成。

问题5

想用opencv v4l调用usb/csi摄像头的话,需要cmake-gui中勾选WITH_V4L和WITH_LIBV4L
但是使用常规编译器GCC和G++才会出现上面两个选项,使用交叉编译器不会出现。

  • 解决5
    这里名字为Linux,L大写即可出现选项,不用v4l随便命名即可

在这里插入图片描述

问题6

交叉编译4.9.0版本opencv是,在cmake-gui中出现error in configuration process,project files may be invalid

解决
根据上面的错误定位到libjpeg-turbo的CmakeLists.txt中,${CMAKE_SYSTEM_PROCESSOR} 无输出
在这里插入图片描述
在这行之前输入:
set(CMAKE_SYSTEM_NAME Linux) #设置目标系统名字
set(CMAKE_SYSTEM_PROCESSOR arm) #设置目标处理器架构

二.cpp程序编写

1.CMakeList.txt编写

1.库文件

编译完成在install目录中有bin/include/lib等文件夹,其中include存放的头文件,lib存放的libopencv*.so库文件在这里插入图片描述

2.示例程序

在任何位置创建一个文件夹demo,这里就在install目录中新建了,编写测试程序gpio.cpp、CMakeLists.txt、rv1103.cmake,各自代码如下,完成功能:从板内读取一张图片,转为灰度图片并保存。

(1) gpio.cpp:

#include <opencv2/opencv.hpp> 
//如果include目录中是opencv4则改成include<opencv4/opencv2/opencv.cpp>
#include <iostream>  
using namespace cv;  
using namespace std;  
int main() {
    
      	
	// 读取图片  
    cv::Mat image = cv::imread("result.jpg");  
    // 检查图片是否成功读取  
    if (image.empty()) {
    
      
        std::cout << "Could not read the image: " << "path_to_your_image.jpg" << std::endl;  
        return -1;  
    }  
    // 创建灰度图像矩阵  
    cv::Mat grayImage;  
    // 将彩色图像转换为灰度图像  
    cvtColor(image, grayImage, cv::COLOR_BGR2GRAY);  
    cv::imwrite("reshui.jpg",grayImage);
	 // 等待按键,如果按下'q'键则退出循环  
	waitKey(1);  
    return 0;  
}

3.CMakeLists.txt:

  1. 如果lib文件夹中没有cmake文件则自己指定需要哪些so库文件:
cmake_minimum_required(VERSION 3.0)
project(opencv)
set(include_DIR /home/tao/opencv/opencv-rv1103/install/include)# 根据自己include目录设置OpenCV的include路径
set(lib_DIR /home/tao/opencv/opencv-rv1103/install/lib)# 根据自己include目录设置OpenCV的lib路径
include_directories(${include_DIR})# 设置包含的头文件路径
link_directories(${lib_DIR})# 设置库文件路径
add_executable(gpio gpio.cpp)# 将源文件添加到此项目的可执行文件。
file(GLOB LIBRARIES ${lib_DIR}/*.so) #链接 lib 文件夹下所有的库文件 假设是 .so 文件。
#如果只有某一个库则不用上一条命令,直接指定:
#set(ONNX_LIBRARY "/home/tao/linux/rk3568/onnxruntime/lib/libonnxruntime.so")  # 根据实际情况修改库文件名  
target_link_libraries(gpio ${LIBRARIES})
  1. 如果有些lib文件夹中除了so库文件还有cmake文件夹则添加opencv库部分时可以改为下面的,不改就完全按照上面的就行:
set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/opencv-mobile-4.9.0-luckfox-pico/lib/cmake/opencv4")#其中有一些*cmake文件
find_package(OpenCV REQUIRED)#自动根据cmake文件查找包
include_directories(${OpenCV_INCLUDE_DIRS})#//include目录
target_link_libraries(main ${LIBS} ${OpenCV_LIBS}) #添加库, OpenCV_INCLUDE_DIRS和OpenCV_LIBS都是根据find_package自动生成的

4.rv1103.cmake

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(tools /home/tao/linux/luckfox/luckfox-pico-main/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/)#交叉编译器目录
set(CMAKE_C_COMPILER ${tools}/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-rockchip830-linux-uclibcgnueabihf-g++)
set(CMAKE_AR ${tools}/bin/arm-rockchip830-linux-uclibcgnueabihf-ar)
set(CMAKE_RANLIB ${tools}/bin/arm-rockchip830-linux-uclibcgnueabihf-ranlib)

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_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

在demo文件夹中创建一个空目录build用于存放编译生成文件,并在命令行中进入build文件夹,demo文件夹内容如下,一个三个文件和一个build目录:

在这里插入图片描述

3.交叉编译

cd build   //进入build目录
cmake -DCMAKE_TOOLCHAIN_FILE=../rv1103.cmake ..     //两个..不是三个点... ,两个点是指返回上一级目录找cmakelist.txt文件
make 

如果失败,修改问题后需要删除build文件夹内容再cmake指令
在这里插入图片描述

4.传输至开发板子

将build文件夹内生成的gpio可执行文件 、最开始opencv编译生成的install文件夹内的东西复制到开发板(可以不在同一个文件夹),如下将其放在同一个文件夹发送至开发板:
在这里插入图片描述

5. chmod -r 777 ./*赋予权限

此时运行会报错找不到库,需要指定库路径:export LD_LIBRARY_PATH=/home/root/install/lib:$LD_LIBRARY_PATH指定opencv编译生成的lib文件夹所在开发板中的路径(当前shell有效),不是虚拟机中的位置,也可以修改/etc/ld.so.conf文件永久生效,如果export后仍然报错…/…/lib*so找不到,那就是可执行文件与库的位置与虚拟机中的相对位置不同。

6. ./gpio执行,如果gpio所在文件夹内存放有result.jpg则会读取图片生成灰度图像

问题汇总

有些编译器出现对‘pthread_create’未定义,对‘dladdr’未定义的引用

则CMakeLists.txt最后改为:链接上pthread和dl库
在这里插入图片描述

如果想包含多个路径下的头文件和库文件:定义其它路径变量,在include_directories内添加多个变量即可,中间空格隔开。

在这里插入图片描述

如果出现cpp程序报错:invalid conversion from ‘void*’ to ‘short unsigned int*’ [-fpermissive]

则可以在CMakeLists.txt中添加编译选项:target_compile_options(gpio PRIVATE -fpermissive)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/tao_sc/article/details/137167594