目录
一、简介
1.1 简要说明
-
WITH_QT是opencv的辅助。如果只想使用opencv处理图片,而不使用窗口显示图片,可以不用勾选WITH_QT。
-
freetype也是opencv的辅助。freetype主要是使opencv支持中文汉字,若要使用putText()在图片中添加中文汉字,则需要编译freetype和harfbuzz。如果没有这个需求可以不交叉编译freetype和harfbuzz。
-
WITH_QT也可以使opencv支持中文显示,即opencv使用QT中的字库,而不依赖freetype。但是opencv使用QT提供的函数addText()在图片中添加中文汉字时,必须首先创建一个窗口。这是QT源码中设定好的,交叉编译好了无法修改。(或许你可以尝试交叉编译之前,将qt中cvAddText()函数中的
if (!guiMainThread) CV_Error(CV_StsNullPtr, "NULL guiReceiver (please create a window)");
注释掉) -
对于opencv的中文显示,也可以自己重写opencv的putText(),使opencv从支持ascii码扩展到支持unicode字符。
opencv添加中文字符支持可以参考这两篇文章:1. 利用OpenCV给图像添加中文标注 2. opencv渲染中文字符链接1和链接2提到的使用freetype方法,是交叉编译了freetype后,还要自己写相关调用的代码。但是其实opencv官方已经提供了调用freetype的方法(https://github.com/opencv/opencv_contrib/tree/4.x/modules/freetype),所以后面的测试,我直接使用了opencv官方示例。
1.2 opencv版本及其背景
- 交叉编译工具链:gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf
- ubuntu平台:ubuntu18.04.1 64bit
- opencv和opencv_contrib版本:opencv-4.5.5和opencv_contrib-4.5.5
- 嵌入式linux开发板内核:NXP CORTEX-A7 IMX6ULL
- cmake版本:cmake-3.25.0(编译工具选择新版本,bug更少)
1.3 步骤
- 交叉编译freetype,harfbuzz,以及其相关的一些依赖库
- 交叉编译Qt
- 交叉编译opencv
- 移植到linux开发板
- 测试
二、交叉编译freetype、harfbuzz及相关依赖库
2.1 编译步骤
- 交叉编译zlib库(libpng,opencv依赖库)
- 交叉编译libpng库(freetype依赖库)
- 交叉编译bzip2库(freetype扩展库,不是必须)
- 交叉编译icu库(harfbuzz依赖库),hafbuzz交叉编译至少依赖Builtin,Glib和ICU中一个,我这里选择ICU库。
- 交叉编译harfbuzz和freetype(freetype和harfbuzz相互依赖)
- 交叉编译eigen,Eigen是一个基于C++模板的开源库,支持线性代数,矩阵和矢量运算,数值分析及其相关的算法。(不是必须)
这里贴一个百度网盘链接,大家可以在官网下载相关的库,也可以直接从这里获取:
链接:https://pan.baidu.com/s/1haqsW4uPdyIV_C2Pi-WRaA
提取码:cm8m
2.2 交叉编译zlib
- 下载zlib,http://zlib.net/。这里我使用的版本是1.2.11.
- 解压:tar -xzvf zlib-1.2.11.tar.gz
- cd zlib-1.2.11
- 设置编译器:export CC=arm-linux-gnueabihf-gcc(因为zlib的configure中没有配置编译器的选项,所以这里设置环境变量)
- 配置编译环境:./configure --prefix=$PWD/tmp --enable-shared
- make
- make install
- cp -rfp /home/book/opencvarm/zlib-1.2.11/tmp/* /home/book/arm-opencv(我把所有的库都放在了arm-opecv目录中,方便之后打包到arm开发板)
2.3 交叉编译libpng
- 下载libpng,http://www.libpng.org/pub/png/libpng.html。这里我使用是版本是1.6.37
- 解压:tar xJf libpng-1.6.37.tar.xz
- cd libpng-1.6.37
- 配置编译环境:./configure --host=arm-linux-gnueabihf --prefix=$PWD/tmp --build=x86_64-linux-gnu -with-zlib-prefix=/home/book/arm-opencv
- 编译安装zlib的过程中如果使用 prefix= 指定输出目录,等到安装libpng库的时候就会显示找不到zlib库的错误,按照以下步骤:
① cp scripts/makefile.linux makefile
② vi makefile
③ 找到zlib相关的两行,修改成实际的zlib/lib和zlib/include,再找到prefix项,修改为你想prefix的目录中,
如果此处是交叉编译的话,还需要在cc那边把gcc修改成您系统的交叉编译器,比如我的交叉编译器:arm-linux-gnueabihf-gcc
④ 保存并且make,make install - cp -rfp /home/book/opencvarm/libpng-1.6.37/tmp/* /home/book/arm-opencv
2.4 交叉编译bzip2
- 下载bzip2,https://sourceware.org/bzip2/downloads.html。这里我使用是版本是1.0.6
- 解压:tar xvzf bzip2-1.0.6.tar.gz
- cd bzip2-1.0.6
- bzip2没有提供configure,所以需要自己修改Makefile-libbz2_so生成动态库,以及修改makefile。
- vi Makefile-libbz2_so,修改CC=arm-linux-gnueabihf-gcc SHELL=/bin/bash
- make -f Makefile-libbz2_so
- 没有configure,直接修改Makefile:
SHELL=/bin/bash
CC=arm-linux-gnueabihf-gcc
AR=arm-linux-gnueabihf-ar
RANLIB=arm-linux-gnueabihf-ranlib
PREFIX=/home/book/opencvarm/bzip2-1.0.6/tmp
最后将all: libbz2.a bzip2 bzip2recover后面的test删除(bzip2在编译完后会生成一个bzip2的可执行文件,由于我们采用交叉工具进行编译那么这个可执行文件是ARM体系的,在宿主机上自然是执行不了,也就会导致test失败。) - make
- make install
- cp -rfp /home/book/opencvarm/bzip2-1.0.6/tmp/* /home/book/arm-opencv
- cp /home/book/opencvarm/bzip2-1.0.6/{libbz2.so.1.0.6,libbz2.so.1.0} /home/book/arm-opencv/lib
- 注:这里可以通过指令
readelf -h ./bzip2
查看bzip2的可执行文件的体系,或者readelf -h ./libbz2.a
查看库文件体系,或者直接使用file命令,如file ./bzip2
。检查文件是否是ARM架构。
2.5 交叉编译ICU
- 注:我这里先按照官方教程编译了icu56.1和icu65.1,但是都不成功。最后尝试编译icu69和icu72.1都成功(编译步骤没变)。最后总结原因:查看icu官网,发现icu官方将icu69以下的都归为旧版本,旧版本可能没维护了,反正都编译失败。所以大家在选择库版本时,先查查该库的稳定版本,最常用版本,如果没有,就选择最新版本试试,毕竟版本更新换代,新版本肯定是解决了之前存在的某些bug。
- 下载ICU,https://icu.unicode.org/download,这里我选择最新版本icu72.1。
- tar xvzf icu-release-72-1.tar.gz
- cd ./icu-release-72-1/icu4c/source
- mkdir arm-build
- cd arm-build
- …/runConfigureICU Linux/gcc
- make
- cd …
- ./configure CXXFLAGS=-std=c++11 --host=arm-linux-gnueabihf --build=x86_64-linux-gnu --target=arm-linux-gnueabihf --prefix=$PWD/tmp --with-cross-build=/home/book/opencvarm/icu-release-72-1/icu4c/source/arm-build --disable-samples --disable-tests CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ AR=arm-linux-gnueabihf-ar
- make
- make install
- cp -rfp /home/book/opencvarm/icu-release-72-1/icu4c/source/tmp/* /home/book/arm-opencv
2.6 交叉编译harfbuzz和freetype
- 因为harfbuzz和freetype相互依赖,所以要么先编译harfbuzz(不带freetype),然后编译freetype(带harfbuzz),然后编译harfbuzz(带freetype);要么就反过来,先编译freetype。我这里选择先编译harfbuzz。
- 下载harfbuzz,https://github.com/harfbuzz/harfbuzz,我这里选择版本2.6.4。下载freetype,https://freetype.org/download.html,我这里选择版本2.10.2。
- 交叉编译harfbuzz(不带freetype)
① 解压:tar xJf harfbuzz-2.6.4.tar.xz
② cd harfbuzz-2.6.4
③ ./configure --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc --prefix=$PWD/tmp --with-freetype=no --with-icu=yes --with-glib=no CPPFLAGS=-I/home/book/arm-opencv/include LDFLAGS=-L/home/book/arm-opencv/lib
⑤ make
⑥ make install
⑦ cp -rfp /home/book/opencvarm/harfbuzz-2.6.4/tmp/* /home/book/arm-opencv - 交叉编译freetype(带harfbuzz)
① 解压:tar xJf freetype-2.10.2.tar.xz
② cd freetype-2.10.2
③ ./configure CC=arm-linux-gnueabihf-gcc --host=arm-linux-gnueabihf ZLIB_CFLAGS=-I/home/book/arm-opencv/include ZLIB_LIBS=-L/home/book/arm-opencv/lib BZIP2_CFLAGS=-I/home/book/arm-opencv/include BZIP2_LIBS=-L/home/book/arm-opencv/lib LIBPNG_CFLAGS=-I/home/book/arm-opencv/include LIBPNG_LIBS=-L/home/book/arm-opencv/lib HARFBUZZ_CFLAGS=-I/home/book/arm-opencv/include/harfbuzz HARFBUZZ_LIBS=-L/home/book/arm-opencv/include/lib --prefix=$PWD/tmp
④ make
⑤ make install
⑥ cp -rfp /home/book/opencvarm/freetype-2.10.2/tmp/* /home/book/arm-opencv - 再交叉编译harfubuzz(带freetype)
① 返回上面harfbuzz源码路径
② ./configure --host=arm-linux-gnueabihf CC=arm-linux-gnueabihf-gcc --prefix=$PWD/tmp --with-freetype=yes --with-icu=yes --with-glib=no CPPFLAGS=-I/home/book/arm-opencv/include LDFLAGS=-L/home/book/arm-opencv/lib FREETYPE_CFLAGS=-I/home/book/arm-opencv/include/freetype2 FREETYPE_LIBS=“-L/home/book/arm-opencv/lib -lfreetype -lpng -lbz2 -lz”
③ make
④ make install
⑤ cp -rfp /home/book/opencvarm/harfbuzz-2.6.4/tmp/* /home/book/arm-opencv
2.7 交叉编译eigen
- 下载eigen,https://eigen.tuxfamily.org/index.php?title=Main_Page,我这里使用目前最新版eigen-3.4.0。
- 解压:tar xvzf eigen-3.4.0.tar.gz
- cd eigen-3.4.0
- mkdir build(创建构建eigen的目录);mkdir tmp(创建安装eigen的目录)
- 使用cmake编译:
- 构建完成后,进入build目录,make,然后make install
- cp -rfp /home/book/opencvarm/eigen-3.4.0/tmp/* /home/book/arm-opencv
三、交叉编译Qt
交叉编译Qt,我是参考的正点原子文档《【正点原子】I.MX6U移植Qt5.12.9_V1.1.pdf》,写的非常详细,非常值得推荐。因为正点原子文档本来就是开源的,这里就写个路径吧。正点原子下载中心----正点原子Linux开发板-----i.MX6ULL Linux阿尔法开发板 ----资料盘 开发板资料链接(这是个百度云网盘链接)----进去后只用下载 10、用户手册.zip------解压后找到 08【正点原子】I.MX6U移植Qt5.12.9_V1.1.pdf。
四、交叉编译opencv
- 下载opencv4.5.5和 opencv_contrib-4.5.5,https://opencv.org/releases/。这里选择opencv4中目前最新的版本,是因为opencv更新换代,CMakeLists.txt肯定是越来越完善,肯定是修复了很多之前版本的bug,会少很多编译错误。
- 解压:unzip opencv-4.5.5.zip,unzip opencv_contrib-4.5.5.zip
- cd opencv-4.5.5,mkdir build,mkdir tmp
- 使用cmake-gui进行构建:
- 在Search一栏,搜索WITH_FREETYPR,并勾选。(没有中文需求的可以不勾选)
- 在Search一栏,搜索WITH_QT,并勾选。(没有窗口需求的可以不勾选)。WITH_QT 的目的在于: opencv交叉编译移植到ARM板上后, opencv需要使用一些窗口类 (例如imshow时候需要调用窗口), 但是交叉编译的opencv是没有窗口类支持的, 在x86环境下opencv是可以调用ubuntu原生窗口的, 所以 WITH_QT 的目的给ARM板上的opencv提供窗口类支持, WITH_GTK是GTK窗口类, 看很多博客表示: GTK类的移植很复杂, 大部分都采用QT窗口类。
- 修改CMAKE_BUILD_TYPE为Release。
- 找到OPENCV_GENERATE_PKGCONFIG,勾选上。这是生成.pc文件的选项。pc文件保存了该库的头文件、库所在的路径信息。
- 勾选上BUILD_TIFF, BUILD_JPEG, BUILD_PNG, WITH_OPENGL, WITH_EIGEN
- 勾选上BUILD_ZLIB,并加上库的路径:在ZLIB_LIBRARY_RELEASE处选择路径:/home/book/arm-opencv/lib/libz.so
- 添加opencv扩展库:在OPENCV_EXTRA_MODULES_PATH处选择路径:/home/book/opencv_contrib-4.5.5/modules
- 选择opencv安装目录:在CMAKE_INSTALL_PREFIX选择路径:/home/book/opencv-4.5.5/tmp
- ENABLE_NEON。当在ARM芯片上进行一些例如图像处理等计算的时候,常常会因为计算量太大造成计算帧率较低的情况。因而,需要选择一种更加简单快捷的计算方式以获得处理速度上的提升。ARM NEON就是一个不错的选择。
- 在CMAKE_EXE_LINKER_FLAGS后面加上-lpthread -ldl -lrt
- 取消WITH_1394。因为OpenCV做相机的采集不支持1394的接口相机,只支持USB接口的相机。
- 取消WITH_WEBP。(可选)。WebP是一个新的图片格式,它为在互联网上的图片提供了有损和无损压缩。网站管理员和Web开发者可以使用WebP图片格式来创建更小的和更丰富的图片来让你的web更快。这里我没有这方面的需求,所以取消。
- 设置好上面后,点击configure。
- configure完成后,取消BUILD_opencv_xfeatures2d,BUILD_opencv_wechar_qrcode,BUILD_opencv_gapi,BUILD_opencv_face。这些模块我都用不到,如果你需要用到,而又出现下载失败的情况,如:
这种情况,可以找到对应的文件,比如上图中的/home/book/opencvarm/opencv-4.5.5/arm-build/CMakeDownloadLog.txt,该文件中记录了所需下载文件的网址,你可以手动下载然后放进相应的目录中。具体可以参考博客:https://blog.csdn.net/qq153471503/article/details/123542363 - 编译框中还有错误:
翻译一下就是:与CMake<2.8.12的兼容性将从CMake的未来版本中删除。解决办法是:更新VERSION参数min值或者使用…max后缀来告诉确保项目不需要与旧版本兼容。
我这里采用第二种方法:
① cd /home/book/opencvarm/opencv-4.5.5/3rdparty/carotene/hal,然后vi CMakeLists.txt,将cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)改为cmake_minimum_required(VERSION 2.8.8…3.25.10 FATAL_ERROR)。
② cd /home/book/opencvarm/opencv-4.5.5/3rdparty/carotene/,然后vi CMakeLists.txt,将cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)改为cmake_minimum_required(VERSION 2.8.11…3.25.10 FATAL_ERROR)。 - 在编辑框中显示freetype2:no;harfbuzz:no。说明没有检测到交叉编译的freetype和harfbuzz库。
① vi /home/book/opencv_contrib-4.5.5/modules/freetype/CMakeLists.txt,查看freetype的构建:
set(the_description "FreeType module. It enables to draw strings with outlines and mono-bitmaps/gray-bitmaps.")
if(APPLE_FRAMEWORK)
ocv_module_disable(freetype)
endif()
ocv_check_modules(FREETYPE freetype2)
ocv_check_modules(HARFBUZZ harfbuzz)
if(OPENCV_INITIAL_PASS)
if(NOT FREETYPE_FOUND)
message(STATUS "freetype2: NO")
else()
message(STATUS "freetype2: YES (ver ${FREETYPE_VERSION})")
endif()
if(NOT HARFBUZZ_FOUND)
message(STATUS "harfbuzz: NO")
else()
message(STATUS "harfbuzz: YES (ver ${HARFBUZZ_VERSION})")
endif()
endif()
if(FREETYPE_FOUND AND HARFBUZZ_FOUND)
ocv_define_module(freetype opencv_core opencv_imgproc WRAP python)
ocv_target_link_libraries(${the_module} ${FREETYPE_LIBRARIES} ${HARFBUZZ_LIBRARIES})
ocv_include_directories( ${FREETYPE_INCLUDE_DIRS} ${HARFBUZZ_INCLUDE_DIRS} )
else()
ocv_module_disable(freetype)
endif()
由此看来,代码是执行到了 message(STATUS “harfbuzz: NO”),就是没有检测到freetype和harfbuzz。所以我们改写一下。
② 修改if(NOT FREETYPE_FOUND)为if(FREETYPE_FOUND)
③ 修改if(NOT HARFBUZZ_FOUND)为if(HARFBUZZ_FOUND)
④ 修改if(FREETYPE_FOUND AND HARFBUZZ_FOUND)为if((NOT FREETYPE_FOUND) AND (NOT HARFBUZZ_FOUND))
⑤ 并在cmake-gui中点击Add Entry,添加FREETYPE_LIBRARIES,HARFBUZZ_LIBRARIES,FREETYPE_INCLUDE_DIRS,HARFBUZZ_INCLUDE_DIRS。即freetype和harfbuzz的库路径和头文件目录。
-
在Search栏搜索qt,在Qt5_DIR中选择路径:/usr/lib/arm-qt/lib/cmake/Qt5
-
点击Configure,再次构建
-
添加QT_QMAKE_EXECUTABLE路径:/usr/lib/arm-qt/bin/qmake
-
在Search栏搜索eigen,在Eigen3_DIR中选择路径:/home/book/arm-opencv/share/eigen3/cmake
-
建议你最后浏览下Search栏下面的显示框,重点检查文件路径是否设置正确。因为有时候ubuntu中存在多个版本的库文件,必须选择交叉编译为arm架构的库,而不是x86_64架构的库。
-
点击Configure,构建成功后,点击Generate。
-
进入opencv构建目录cd /home/book/opencv-4.5.5/build,然后执行make。
执行make,可能会出现“文件找不到的错误”,如:
解决方法:将之前交叉编译的所有库的lib和include目录都复制到交叉编译工具链的lib和include下。
比如我的工具链include位置/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/…/lib/gcc/arm-linux-gnueabihf/4.9.4/include和lib位置 /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/…/lib/gcc/arm-linux-gnueabihf/4.9.4/…/…/…/…/arm-linux-gnueabihf/lib。
(可通过指令echo ‘main(){}’| arm-linux-gnueabihf-gcc -E -v -查看include和lib位置)① cd /home/book/arm-opencv
② sudo cp include/* -rf /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/…/lib/gcc/arm-linux-gnueabihf/4.9.4/include
③ sudo cp lib/* -rfd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/…/lib/gcc/arm-linux-gnueabihf/4.9.4/…/…/…/…/arm-linux-gnueabihf/lib
④ cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/…/lib/gcc/arm-linux-gnueabihf/4.9.4/include/freetype2,使用指令mv ./* …/,将其中的freetype文件夹移到上一层。
⑤ 再次进行编译:make -
编译完成,make install
-
cp -rfp /home/book/opencvarm/opencv-4.5.5/tmp/* /home/book/arm-opencv
五、移植到linux开发板
- 打包:tar cvf arm-opencv.tar arm-opencv
- 通过FileZilla等工具将arm-python.tar传到开发板的 /home/book目录
- 解压:tar xvf arm-opencv.tar
六、测试
- 编写测试代码:vi 111.cpp
#include "opencv2/opencv.hpp"
#include "opencv2/freetype.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
using namespace std;
using namespace cv;
int main(int argc,char **argv)
{
String text = "Hello, 加油!冲冲冲#***#";
int fontHeight = 60;
int thickness = -1;
int linestyle = 8;
int baseline=0;
cout << "Built with OpenCV " << CV_VERSION << endl;
/*参数1:窗口的名字. 参数2:窗口类型,CV_WINDOW_AUTOSIZE 时表明窗口大小等于图片大小。不可以被拖动改变大小。
CV_WINDOW_NORMAL 时,表明窗口可以被随意拖动改变大小。*/
namedWindow("test", WINDOW_AUTOSIZE);
Ptr<freetype::FreeType2> ft2;
ft2 = freetype::createFreeType2();
//下面的字库要自己下载并拷贝到需要的位置
ft2->loadFontData( "simsun.ttc", 0 );
Mat image;
image = imread("test.jpg");
Size textSize = ft2->getTextSize(text,
fontHeight,
thickness,
&baseline);
if(thickness > 0){
baseline += thickness;
}
Point textOrg((image.cols - textSize.width) / 2,
(image.rows + textSize.height) / 2);
rectangle(image, textOrg + Point(0, baseline),
textOrg + Point(textSize.width, -textSize.height),
Scalar(0,255,0),1,8);
line(image, textOrg + Point(0, thickness),
textOrg + Point(textSize.width, thickness),
Scalar(0, 0, 255),1,8);
ft2->putText(image, text, textOrg, fontHeight,
Scalar::all(255), thickness, linestyle, true );
imwrite("test.jpg",image);
imshow("test",image);//在“test”这个窗口输出图片。
waitKey(5000);//等待5秒,程序自动退出。改为0,不自动退出。
return 0;
}
- 交叉编译111.cpp:arm-linux-gnueabihf-g++ -o 111 111.cpp -std=c++11 -I/home/book/arm-opencv/include/opencv4 -L/home/book/arm-opencv/lib -lopencv_imgcodecs -lopencv_imgproc -lopencv_core -ldl -lm -lpthread -lrt -lopencv_freetype -L/home/book/arm-opencv/lib -lfreetype -lharfbuzz -lpng -lz -lopencv_highgui -L/usr/lib/arm-qt/lib -lQt5Widgets -lQt5Test -lQt5Gui -lQt5Core
- 得到111执行文件,将111执行文件传到开发板。先chmod +x 111,给111添加可执行操作;然后export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/book/arm-opencv/lib设置环境变量;最后执行./111。(注意:字库和图片需与执行文件111在同一个目录下)
- 效果: