本文转载自:亦梦云烟的博客
简介
Xilinx的reVISION栈包含了一系列开发平台、算法和应用的开发资源,它支持流行的神经网络包括AlexNet, GoogleLeNet, VGG, SSD和FCN等,并且该视觉库提供了用于创建和实现CNN神经网络层的库,机器学习的元素被实现为一系列硬件加速的函数库,在应用开发层,Xilinx提供了标准的框架和库包括Caffe和OpenCV, reVISION栈同时也提供了第三方平台的开发平台,包括很多的传感器。
xfOpenCV是使用Xilinx SoC和FPGA优化硬件加速的OpenCV函数库,这些函数全部是用C/C++代码编写,使用高级综合工具(HLS)综合到FPGA中运行。本例程使用SDx2018.2和Zturn board平台进行设计。
OpenCV和xfOpenCV最主要的区别就是传统的OpenCV是在CPU(x86,ARM...)中运行,而xfOpenCV是在Xilinx SoC和FPGA中运行,使用SOC优化的代码可以比嵌入式GPU快40倍,比嵌入式CPU快100倍以上,鉴于所有的代码都是用C/C++编写,很容易移植为自己的机器视觉函数。
本文以Zturnboard为例介绍如何在SDSoC中使用OpenCV,本文在Ubuntu 16 64位,SDSoC2018.2(安装在ubuntu中)中测试通过。
一、概述
下图展示一个单传感器设计的reVISION框图:
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227021-tu_1-1_revisionjia_gou_tu_.jpeg)
图1-1 reVISION架构图
1.1 平台
Xilinx提供了ZCU102和ZCU104的单传感器reVISION平台,它支持以下视频接口。
1.1.1 源
1.1.2 显示
1.2 设计样例
Xilinx提供了一些用于参考的设计样例,它们通常是从一个视频文件中读取每一帧进行处理,使用标准的OpenCV调用(如cv::imread()),然后使用xfopencv函数处理这一帧,最后输出为一个文件(如cv::imwrite())。例程说明了五种不同的xfopencv硬件加速视觉的OpenCV函数。
二、配置系统环境
在本系列教程的基础上修改SDSoC platform。
2.1 配置文件系统
配置文件系统包含OpenCV的动态库
$ cd
//进入菜单选择
PetaLinux Package Groups --->
packagegroup-petalinux-opencv --->
[*] packagegroup-petalinux-opencv
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227022-tu_2-1_pei_zhi_rootfsbao_han_opencv.jpeg)
图2-1 配置rootfs包含opencv
NOTE:在首次链接OpenCV时需要联网,否则会报错!此时需要保证ubuntu能访问网络。
然后编译工程并打包
$ petalinux-build -c rootfs
$ petalinux-package --boot --format BIN --fsbl ./images/linux/zynq_fsbl.elf --fpga ./images/linux/system.bit --u-boot
将新生成的image.ub(大小会增加很多,大约50多MB)替换原来的文件新文件中增加了opencv的动态库文件,放在平台设计文件夹中即可。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227023-tu_2-2_bian_yi_petalinuxgong_cheng_hou_de_images_linuxwen_jian_jia_nei_rong_.jpeg)
图2-2 编译petalinux工程后的images/linux文件夹内容
用此镜像启动系统,查看/usr/lib目录,可以发现增加了opencv的动态库。
root@ZturnTemplate:~# ls /usr/lib
dri libgphoto2.so.6.0.0 libopencv_saliency.so.3.3.0
gconv libgphoto2_port libopencv_shape.so.3.3
gdk-pixbuf-2.0 libgphoto2_port.so.12 libopencv_shape.so.3.3.0
gio libgphoto2_port.so.12.0.0 libopencv_stereo.so.3.3
girepository-1.0 libgstapp-1.0.so.0 libopencv_stereo.so.3.3.0
gstreamer-1.0 libgstapp-1.0.so.0.1202.0 libopencv_stitching.so.3.3
libGL.so.1 libgstaudio-1.0.so.0 libopencv_stitching.so.3.3.0
libGL.so.1.2.0 libgstaudio-1.0.so.0.1202.0 libopencv_structured_light.so.3.3
libICE.so.6 libgstbase-1.0.so.0 libopencv_structured_light.so.3.3.0
libICE.so.6.3.0 libgstbase-1.0.so.0.1202.0 libopencv_superres.so.3.3
libSM.so.6 libgstcheck-1.0.so.0 libopencv_superres.so.3.3.0
libSM.so.6.0.1 libgstcheck-1.0.so.0.1202.0 libopencv_surface_matching.so.3.3
libX11-xcb.so.1 libgstcontroller-1.0.so.0 libopencv_surface_matching.so.3.3.0
libX11-xcb.so.1.0.0 libgstcontroller-1.0.so.0.1202.0 libopencv_tracking.so.3.3
libX11.so.6 libgstnet-1.0.so.0 libopencv_tracking.so.3.3.0
libX11.so.6.3.0 libgstnet-1.0.so.0.1202.0 libopencv_video.so.3.3
libXau.so.6 libgstpbutils-1.0.so.0 libopencv_video.so.3.3.0
libXau.so.6.0.0 libgstpbutils-1.0.so.0.1202.0 libopencv_videoio.so.3.3
libXcomposite.so.1 libgstreamer-1.0.so.0 libopencv_videoio.so.3.3.0
libXcomposite.so.1.0.0 libgstreamer-1.0.so.0.1202.0 libopencv_videostab.so.3.3
libXcursor.so.1 libgstriff-1.0.so.0 libopencv_videostab.so.3.3.0
libXcursor.so.1.0.2 libgstriff-1.0.so.0.1202.0 libopencv_xfeatures2d.so.3.3
libXdamage.so.1 libgsttag-1.0.so.0 libopencv_xfeatures2d.so.3.3.0
libXdamage.so.1.1.0 libgsttag-1.0.so.0.1202.0 libopencv_ximgproc.so.3.3
libXdmcp.so.6 libgstvideo-1.0.so.0 libopencv_ximgproc.so.3.3.0
libXdmcp.so.6.0.0 libgstvideo-1.0.so.0.1202.0 libopencv_xobjdetect.so.3.3
libXext.so.6 libgthread-2.0.so.0 libopencv_xobjdetect.so.3.3.0
libXext.so.6.4.0 libgthread-2.0.so.0.5200.3 libopencv_xphoto.so.3.3
libXfixes.so.3 libgtk-3.so.0 libopencv_xphoto.so.3.3.0
libXfixes.so.3.1.0 libgtk-3.so.0.2200.17 liborc-0.4.so.0
libXft.so.2 libharfbuzz.so.0 liborc-0.4.so.0.27.0
libXft.so.2.3.2 libharfbuzz.so.0.10400.8 libpango-1.0.so.0
libXi.so.6 libhistory.so.7 libpango-1.0.so.0.4000.6
libXi.so.6.1.0 libhistory.so.7.0 libpangocairo-1.0.so.0
libXrandr.so.2 libjpeg.so.62 libpangocairo-1.0.so.0.4000.6
libXrandr.so.2.2.0 libjpeg.so.62.2.0 libpangoft2-1.0.so.0
libXrender.so.1 libkmod.so.2 libpangoft2-1.0.so.0.4000.6
libXrender.so.1.3.0 libkmod.so.2.3.2 libpangoxft-1.0.so.0
libXtst.so.6 libltdl.so.7 libpangoxft-1.0.so.0.4000.6
libXtst.so.6.1.0 libltdl.so.7.3.1 libpci.so.3
libXxf86vm.so.1 liblzma.so.5 libpci.so.3.5.5
libXxf86vm.so.1.0.0 liblzma.so.5.2.3 libpcre.so.1
libatk-1.0.so.0 libmediactl.so.0 libpcre.so.1.2.9
libatk-1.0.so.0.22409.1 libmediactl.so.0.0.0 libpixman-1.so.0
libatk-bridge-2.0.so.0 libopencv_aruco.so.3.3 libpixman-1.so.0.34.0
libatk-bridge-2.0.so.0.0.0 libopencv_aruco.so.3.3.0 libpng16.so.16
libatspi.so.0 libopencv_bgsegm.so.3.3 libpng16.so.16.31.0
libatspi.so.0.0.1 libopencv_bgsegm.so.3.3.0 libpython3.5m.so.1.0
libbz2.so.1 libopencv_bioinspired.so.3.3 libreadline.so.7
libbz2.so.1.0.6 libopencv_bioinspired.so.3.3.0 libreadline.so.7.0
libcairo-gobject.so.2 libopencv_calib3d.so.3.3 libsocketcan.so.2
libcairo-gobject.so.2.11400.10 libopencv_calib3d.so.3.3.0 libsocketcan.so.2.2.1
libcairo.so.2 libopencv_ccalib.so.3.3 libssl.so.1.0.2
libcairo.so.2.11400.10 libopencv_ccalib.so.3.3.0 libstdc++.so.6
libcrypto.so.1.0.2 libopencv_core.so.3.3 libstdc++.so.6.0.24
libdbus-1.so.3 libopencv_core.so.3.3.0 libtbb.so.2
libdbus-1.so.3.14.12 libopencv_dpm.so.3.3 libtbbmalloc.so.2
libdrm.so.2 libopencv_dpm.so.3.3.0 libtbbmalloc_proxy.so.2
libdrm.so.2.4.0 libopencv_face.so.3.3 libtiff.so.5
libdvbv5.so.0 libopencv_face.so.3.3.0 libtiff.so.5.2.6
libdvbv5.so.0.0.0 libopencv_features2d.so.3.3 libv4l
libelf-0.170.so libopencv_features2d.so.3.3.0 libv4l1.so.0
libelf.so.1 libopencv_flann.so.3.3 libv4l1.so.0.0.0
libepoxy.so.0 libopencv_flann.so.3.3.0 libv4l2.so.0
libepoxy.so.0.0.0 libopencv_fuzzy.so.3.3 libv4l2.so.0.0.0
libexif.so.12 libopencv_fuzzy.so.3.3.0 libv4l2rds.so.0
libexif.so.12.3.3 libopencv_highgui.so.3.3 libv4l2rds.so.0.0.0
libexpat.so.1 libopencv_highgui.so.3.3.0 libv4l2subdev.so.0
libexpat.so.1.6.5 libopencv_img_hash.so.3.3 libv4l2subdev.so.0.0.0
libffi.so.6 libopencv_img_hash.so.3.3.0 libv4lconvert.so.0
libffi.so.6.0.4 libopencv_imgcodecs.so.3.3 libv4lconvert.so.0.0.0
libfontconfig.so.1 libopencv_imgcodecs.so.3.3.0 libwebp.so.7
libfontconfig.so.1.9.4 libopencv_imgproc.so.3.3 libwebp.so.7.0.0
libfreetype.so.6 libopencv_imgproc.so.3.3.0 libwebpdemux.so.2
libfreetype.so.6.14.0 libopencv_line_descriptor.so.3.3 libwebpdemux.so.2.0.2
libgailutil-3.so.0 libopencv_line_descriptor.so.3.3.0 libwebpmux.so.3
libgailutil-3.so.0.0.0 libopencv_ml.so.3.3 libwebpmux.so.3.0.0
libgdk-3.so.0 libopencv_ml.so.3.3.0 libxcb-dri2.so.0
libgdk-3.so.0.2200.17 libopencv_objdetect.so.3.3 libxcb-dri2.so.0.0.0
libgdk_pixbuf-2.0.so.0 libopencv_objdetect.so.3.3.0 libxcb-glx.so.0
libgdk_pixbuf-2.0.so.0.3608.0 libopencv_optflow.so.3.3 libxcb-glx.so.0.0.0
libgio-2.0.so.0 libopencv_optflow.so.3.3.0 libxcb-render.so.0
libgio-2.0.so.0.5200.3 libopencv_phase_unwrapping.so.3.3 libxcb-render.so.0.0.0
libglapi.so.0 libopencv_phase_unwrapping.so.3.3.0 libxcb-shm.so.0
libglapi.so.0.0.0 libopencv_photo.so.3.3 libxcb-shm.so.0.0.0
libglib-2.0.so.0 libopencv_photo.so.3.3.0 libxcb.so.1
libglib-2.0.so.0.5200.3 libopencv_plot.so.3.3 libxcb.so.1.1.0
libgmodule-2.0.so.0 libopencv_plot.so.3.3.0 libxml2.so.2
libgmodule-2.0.so.0.5200.3 libopencv_reg.so.3.3 libxml2.so.2.9.4
libgobject-2.0.so.0 libopencv_reg.so.3.3.0 opkg
libgobject-2.0.so.0.5200.3 libopencv_rgbd.so.3.3 python3.5
libgphoto2 libopencv_rgbd.so.3.3.0 ssl
libgphoto2.so.6 libopencv_saliency.so.3.3 systemd
root@ZturnTemplate:~#
2.2 配置xfOpenCV库
将编译rootfs时生成的rootfs.tar.gz文件复制到自己的一个文件夹中(/home/software/SDSoC/rootfs),解压后得到Zynq的文件系统中的文件。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227024-tu_2-3_linuxwen_jian_xi_tong_jie_ya_hou_de_lu_jing_.jpeg)
图2-3 linux文件系统解压后的路径
将该路径添加到Linux系统的环境变量中:
sudo gedit ~/.bashrc
在最后一行添加:
export SYSROOT_arm64=/home/biac/software/SDSoC/rootfs
2.3 配置xfOpenCV库
在SDx IDE中,点击Xilinx -> SDx Libraries,点击下载Xilinx xfOpenCV Library。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227025-tu_2-4_zai_sdx_idezhong_xia_zai_xfopencv.jpeg)
图2-4 在SDx IDE中下载xfOpenCV
NOTE:下载的库可以被添加到任何工程中。
三、测试opencv库
新建一个SDSoC应用工程,命名为opencv_lab1。
添加main.cpp文件,编辑内容如下:
#include
#include
// colordetect
// Description:
// Will detect the colors from the thresholds provided
// Inputs:
// - in_img
// - nLowThresh
// - nHighThresh
// Output:
// - out_img
void colordetect(cv::Mat &_src,
cv::Mat &_dst,
unsigned char nLowThresh[3][3],
unsigned char nHighThresh[3][3]) {
// Temporary matrices for processing
cv::Mat mask1, mask2, mask3, _imgrange, _imghsv;
// Convert the input to the HSV colorspace. Using BGR here since it is the default of OpenCV.
// Using RGB yields different results, requiring a change of the threshold ranges
cv::cvtColor(_src, _imghsv, cv::COLOR_BGR2HSV);
// Get the color of Yellow from the HSV image and store it as a mask
cv::inRange(_imghsv, cv::Scalar(nLowThresh[0][0], nLowThresh[0][1], nLowThresh[0][2]), cv::Scalar(nHighThresh[0][0], nHighThresh[0][1], nHighThresh[0][2]), mask1);
// Get the color of Green from the HSV image and store it as a mask
cv::inRange(_imghsv, cv::Scalar(nLowThresh[1][0], nLowThresh[1][1], nLowThresh[1][2]), cv::Scalar(nHighThresh[1][0], nHighThresh[1][1], nHighThresh[1][2]), mask2);
// Get the color of Red from the HSV image and store it as a mask
cv::inRange(_imghsv, cv::Scalar(nLowThresh[2][0], nLowThresh[2][1], nLowThresh[2][2]), cv::Scalar(nHighThresh[2][0], nHighThresh[2][1], nHighThresh[2][2]), mask3);
// Bitwise OR the masks together (adding them) to the range
_imgrange = mask1 | mask2 | mask3;
cv::Mat element = cv::getStructuringElement( 0,cv::Size(3, 3), cv::Point(-1, -1));
cv::erode(_imgrange, _dst, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT);
cv::dilate(_dst, _dst, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT);
cv::dilate(_dst, _dst, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT);
cv::erode(_dst, _dst, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT);
}
int main(int argc, char **argv)
{
printf("Test for SDSoC platform\n");
//Create the input/output cv::Mat objects
cv::Mat in_img, out_img;
cv::Mat imghsv, imgrange, imgerode, imgdilate1, imgdilate2;
// Define the low and high thresholds
// Want to grab 3 colors (Blue, Green, Orange) for teh input image
unsigned char nLowThresh[3][3] = { { 110, 150, 20 }, // Lower boundary for Blue
{ 38, 0, 20 }, // Lower boundary for Green
{ 10, 150, 20 } }; // Lower boundary for Orange
unsigned char nHighThresh[3][3] = { { 130, 255, 255 }, // Upper boundary for Blue
{ 75, 125, 255 }, // Upper boundary for Green
{ 25, 255, 255 } }; // Upper boundary for Orange
// Read an image
in_img = cv::imread("rock_landscape.jpg", 1);
if (!in_img.data) {
return -1;
}
// Create the output image to match the input image (CV_8U)
int height = in_img.rows;
int width = in_img.cols;
out_img.create(height, width, CV_8U);
// Run the input and thresholds into the colordect function
colordetect(in_img, out_img, nLowThresh, nHighThresh);
// Write out the input image and the output image
cv::imwrite("output.png", out_img);
cv::imwrite("input.png", in_img);
return 0;
}
四、配置编译环境
下载完库文件之后需要将库路径添加到应用工程中。
点击Xilinx -> SDx Libraries,选中Xilinx xfOpenCV Library,点击Add to project下拉框,选择自己的应用工程即可。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227026-tu_4-1_jiang_sdxku_tian_jia_dao_gong_cheng_zhong_.jpeg)
图4-1 将SDx库添加到工程中
此时,所有的opencv头文件和库都将被复制到工程目录的libs目录下(工程目录中的libs文件夹中),所有需要设置的选项也相应的自动进行设置好了。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227027-tu_4-2_tian_jia_xfopencvku_hou_de_mu_lu_.jpeg)
图4-2 添加xfOpencv库后的目录
在编译选项中,opencv_前缀的链接库都自动添加到工程的设置中。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227028-tu_4-3_zi_dong_tian_jia_opencvlian_jie_ku_.jpeg)
图4-3 自动添加opencv链接库
添加路径:右键点击工程,选择Properties -> C/C++ General -> Paths and Symbols -> Includes,在GNU C和GNU C++中都添加xfopencv的include路径。如图1-9所示。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227029-tu_4-4_tian_jia_xfopencvde_ku_lu_jing_.jpeg)
图4-4 添加xfopencv的库路径
添加链接:右键点击工程,选择Properties -> C/C++ Build -> Tool Settings -> SDSCC Compiler -> Inferred Options -> Software Platform
Software platform Inferred Flags中输入:
-I${SYSROOT_arm64}/usr/include -hls-target 1
Properties -> C/C++ Build -> Tool Settings -> SDS++ Compiler -> Inferred Options -> Software Platform中执行同样的操作。
Properties -> C/C++ Build -> Tool Settings -> SDS++ Linker -> Miscellaneous -> Linker Flags中添加:
--sysroot=${SYSROOT_arm64} -Wl,-rpath-link=${SYSROOT_arm64}/lib,-rpath-link=${SYSROOT_arm64}/usr/lib
编译工程。
可能出现错误,根据错误进行修改
错误提示:
arm-linux-gnueabihf-g++.exe: error: unrecognized command line option '-mstrict-align'; did you mean '-Wstrict-aliasing'?
解决方法:在Properties -> C/C++ Build -> Settings -> SDSCC Compiler和 SDS++ Compiler中的Miscellaneous,删除other flags中的编译选项,只留-c -fmessage-length=0 -MT"$@" -hls-target 1。
编译成功后, 将sd_card目录中的所有文件复制到SD卡中,并将例程中的图片复制到SD卡中。
执行程序:
$ mount /dev/mmcblk0p1 /mnt/
$ cd /mnt/
$ ./opencv_lab1.elf
$ ls
System Volume Information
UPDATE
image.ub
input.png
opencv_lab1.elf
output.png
rock_landscape.jpg
sds_trace_data.dat
执行成功后在SD卡中生成了两个图片文件: input.png和output.png。
图4-5 output.jpg
五、硬件加速opencv
以xilinx在xfopencv中提供的样例做测试,复制xfopencv/examples/histogram目录中的C文件到自己的SDx工程中,安装前文所讲配置编译环境。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227031-tu_5-1_histogramgong_cheng_wen_jian_jie_gou_.jpeg)
图5-1 histogram工程文件结构
添加Hardware Functions:
展开libs/include/imgproc/xf_histogram.hpp/xf
右键选择calcHist函数,选择Toggle HW/SW,将dilate函数作为硬件实现的函数,默认时钟为100MHz。
![](http://xilinx.eetrend.com/files/2021-11/%E5%8D%9A%E5%AE%A2/100555285-227032-tu_5-2_tian_jia_ying_jian_jia_su_han_shu_.jpeg)
图5-2 添加硬件加速函数
编译完成后,拷贝sd_card中所有文件到SD开根目录,执行程序:
mount /dev/mmcblk0p1 /mnt/
cd /mnt/
./opencv_lab1.elf im0.jpg
Start sw accel function
elapsed time 9366176
Start hw accel function
elapsed time 13883070
可以看到硬件加速的函数自行时间比软件还要长,后面讲分析原因。
参考资料
[1] ug1233-xilinx-opencv-user-guide.pdf
[2] https://github.com/Xilinx/Revision-Getting-Started-Guide/tree/2018.2-tut...
[3] https://github.com/Xilinx/SDSoC-Tutorials/tree/master/opencv-to-xfopencv...