×

Xiraffe桅杆上的智能野生动物观测站

消耗积分:0 | 格式:zip | 大小:0.00 MB | 2022-10-20

h1654155275.0032

分享资料个

描述

项目概念

项目名称“Xiraffe”是“Xilinx”和“Giraffe”的组合。这个

简单来说,该项目的目标是建造一个“动物观测站”,使用安装在高处(长桅杆或树顶上)的稳定的、可平移的相机,从远处观察动物。长焦距(又名变焦)镜头,因此单个单元可以覆盖广阔的区域。野生动物生物学家可以使用这种设备来帮助研究动物习性、迁徙模式等。

同样的设备也可用于动物保护区等地方的动物保护主义者,以检测和防止非法动物偷猎。该设备可以安装在高处,有助于在广阔的区域内保持监视……就像长颈鹿一样!

在这篇文章中,我将尝试记录我尝试构建这种设备的过程。

背景

我使用 Xilinx FPGA 已有一段时间了,并且喜欢在各种项目中使用 Zynq-7000 SOC。我是 SOC 概念的忠实拥护者,过去曾在各种项目中为 Zynq FPGA 找到了一个好地方,尤其是在使用成像传感器时。然而,最近,我一直想探索拥有各种奇特功能的最新 Zynq Ultrascale 设备。这个项目似乎很适合这个。

董事会花了很长时间才到达我的手中,但它终于做到了。我自己使用 Xilinx 设备的经验主要是使用 Vivado 和 SDK,我的大部分设计都是基于裸机或 FreeRTOS,但没有基于 petalinux。由于在这个项目中我需要同时使用 VCU 和 DPU,我知道我必须涉足 linux 领域。这是一个相当长的学习曲线,所以我将尽可能详细地记录我的旅程。

套件

ZCU104 套件包括 ZCU104 板、电源、16GB SD 卡、USB3 集线器和 USB3 摄像头。一切都包装得很好。我需要开始的唯一其他东西是 HDMI 电缆、显示端口电缆和显示器。谢天谢地,我已经有了这些。

启程之旅...

由于在开始了解项目的细节之前有很多东西需要学习(硬件和软件方面),我开始了熟悉这个野兽的旅程,以及可用的工具。

第 1 步:启动电路板并运行出厂映像:我按照套件随附手册中的说明进行操作。这包括一些外围测试以及通过查看 LED 来验证板上的各种电压。

第 2 步:尝试 PYNQ:我一直对 PYNQ 感到非常兴奋,因为通常 python 比 C/C++ 更容易尝试想法。

设置很简单,下载 ZCU104 的图像并按照http://www.pynq.io/上的说明进行操作

我登录到板子并浏览了所有提供的示例,这非常有趣。坦率地说,我希望 PYNQ 能够提供足够的“能力”,让我可以在项目中做我想做的所有事情,至少用于原型制作目的。但是,我很快意识到 PYNQ 不支持使用 DPU 或 VCU,而这两者都是我的项目所需要的。我试图在互联网上进行挖掘,并认为我需要相当多的技能才能在 PYNQ 中集成和使用这些功能,所以我暂时放弃了它,并且

顺便说一句,我最近在这里这里遇到了一些不错的帖子,这些帖子展示了如何将 DPU 与 PYNQ 一起使用。我计划很快尝试一下。对于在 PYNQ 中使用 VPU,我还没有发现任何有用的东西。

第 3 步:尝试 USB3 相机 reVISION 堆栈示例:在尝试查找附带相机的一些信息时,我遇到了这个链接,并决定尝试 ZCU104 上的 reVISION 示例。我发现密集光流示例特别令人着迷,它给了我很好的动力,让我以后在板上尝试类似的东西。我还学习了一些关于在板上使用 gstreamer 管道的知识,这在以后也很有用。

第 4 步:安装 VITIS:此时我确信我需要走 VITIS 路线才能同时使用 DPU 和 VCU。因此,我开始遵循 Adam Taylor 在链接上的出色指南(包括视频)。就我而言,由于我没有专用的 Linux PC,因此我在 VM 中安装了 VITIS(我使用了 VMware,但 VirtualBox 或其他应该可以正常工作)。

a) 一个*必须*使用兼容版本的 Ubuntu。我最初尝试使用 Ubuntu 18.04,但我遇到了意外错误,因此它无法在安装 Vitis 时继续前进。最后,我为 18.04.4 LTS 创建了一个新 VM,一切正常。

b) 创建 VM 时,请确保分配至少 120GB 空间,因为 Vitis 安装不会继续进行,除非它看到它认为需要的所有可用空间。我最初尝试将 100GB 分配给 VM,但它不会继续安装。就我而言,在虚拟机设置中增加分配的磁盘空间后,我使用 Linux 实用程序“GParted”将磁盘扩展至 150GB。后来我了解到,当您开始安装和使用其他赛灵思工具(XRT、petalinux、Vitis-AI 等)时,即使这还不够,我不得不多次调整驱动器的大小,直到 200GB。

在这一点上,我会推荐

第 5 步:跟随 Adam Taylor 的网络研讨会“使用 Vitis 构建加速应用程序”,可在此处获得

当 QEMU 模拟器无法启动时,我最终遇到了一个小问题。仔细查看错误消息,我发现它无法识别关键字“netstat”,因此我在 Ubuntu OS 中打开了一个终端窗口并安装了 net-tools,之后它开始正常工作。

sudo apt-get install net-tools

请注意,本教程将指导您将 DPU 与您的自定义设计集成。此特定网络研讨会未涵盖此 DPU 在 Vitis-AI 中的使用。

第 6 步:Vitis 深度教程:我按照一些 Vitis 深度教程来熟悉 Vitis 中的一些新概念(我过去主要使用 SDK),并熟悉 AI事情的一面,我对此很陌生。这些教程是一个好的开始

https://github.com/Xilinx/Vitis-In-Depth-Tutorial

第 7 步:构建 IVAS TRD 设计:我遇到了 Xilinx 最近发布的 IVAS(智能视频分析系统)参考设计(此处),这似乎是我项目的一个很好的起点,因为它结合了 DPU 用于 AI 推理,如以及用于视频编码/解码的 VPU。

我花了几天时间成功地重新创建设计并运行 Facedetect + reid 演示,但最终我成功了并且对结果非常满意。该设计使用 gstreamer 运行演示,这有好有坏。很好,因为我经常使用 gstreamer,而不好,因为我觉得将我的应用程序构建为 gstreamer 过滤器(如演示中所做的那样)对于我目前的能力水平来说有点太多了。也就是说,我决定使用这个图像作为我的基础平台,并在它之上构建我的应用程序。

构建硬件

该项目的一个重要方面是,当您在非城市环境中工作时,您没有安装摄像机的刚性结构。因此,您可以使用,例如,使用“Guy-lines”吊起的一根长杆,或者可能是一根绑在该地区一棵较高树木的树干顶部的杆,以提供较高的有利位置,并能够观察更大的区域。无论哪种方式,您的相机安装架都会有些不稳定,因此视频输入不稳定......对于图像处理来说不是那么好。我决定通过将相机安装在 3 轴无刷万向节上来解决这个问题,并(最终)在 FPGA 中进行视频稳定以消除剩余的运动伪影。

无刷云台实际上应该有两个好处:1。在很大程度上稳定视频2。允许使用相同的电机来控制相机,因为我们需要在我们的系统中进行平移控制。

对于无刷云台部分,我买了一个便宜的 3 轴无刷云台框架,它配备了 3 个小电机。设计不是最好的,但我还不想在这部分项目上花费太多时间。

我研究了一个很好的无刷云台用于我的设计,并遇到了 Olliw 的“STorm32 BGC 我订购了一个 V1.3 板开始使用,两周后我收到了。我先用 Gopro 试了一下,效果很好,而且很容易设置。我最初的计划是将 ARM Coretx-M3 代码移植到 FPGA 内部实例化的 ARM Cortex-M3 或 ZU7-EV 内部的 Cortex-R5。然而,令我沮丧的是,尽管这个特定云台板的硬件是开源的,但软件却不是。您可以随意使用已编译的二进制文件,但代码未打开。我有点失望,但我不得不继续前进。幸运的是,我发现这个云台允许通过 uart 接口控制位置,所以我决定改用它。

由于我需要一个长焦距(又名“变焦”)镜头,我拧下随附 USB3 相机上的 M12 镜头,并使用中间的 C-to-M12 适配器更换为 35mm C-mount 镜头(链接在项目物料清单)。这为我提供了一个非常狭窄的视野,以及更好的图像质量。

pYYBAGNQkwmAR64tAAEH_FhY1uU665.png
SeeCAM USB3 相机加装了 35 毫米 C 接口镜头
 

下一步是将它安装在我的无刷云台上。我设计并 3D 打印了一个支架,以便我可以将这款相机安装在我的无刷云台设置上。

poYBAGNQkwyAJUayAAEXdvorMjs841.png
 
pYYBAGNQkw6Aa87ZAAEOoZB3u_4274.png
相机安装在无刷云台上
 

我将固件上传到板上,并尝试校准云台。这是我的万向节设置遇到的主要障碍。我发现云台上的电机功率不足以支撑和移动相机+镜头。我可以通过在相机背面添加一些金属片和大量热胶(其中一些在上图中可见)来平衡情况,从而使情况变得更好。但是,一旦我将 USB-C 数据线连接到相机,云台就无法握住或移动相机太多。USB 电缆太重且太硬,无法让微弱的电机稳定并自由移动相机。在尝试了几件事后,我得出结论,我需要更大的无刷电机,并且还要打印自己更大的云台框架,以便能够更好地平衡和移动相机。

此时,由于剩余时间不足,我决定将这部分放在一边,直到我收到更大的电机,并更多地关注软件/FPGA方面的事情。

构建软件

在应用程序级别,我想要的视频处理管道如下:1。在 Scene.2 中检测运动。仅在具有运动的部分场景上运行 AI 识别。3。一旦检测到感兴趣的对象(动物、人或车辆 - 根据作业设置),使用万向节运动跟踪框架内和 3d 空间中的对象。4。text/xml/json 文件中的日志信息(时间戳、运动路径、计数等)。(可选)生成alerts.5。压缩 (H.264/H.265) 并将短视频剪辑保存到磁盘,或根据需要通过网络将实时视频流式传输到大本营。

在使用上述所有内容构建完整系统之前,我需要先制作原型并让各个部分正常工作。

场景中的运动检测:一旦将相机设置为朝某个方向看,使用图像差分检测场景中的运动,然后进行一些 IIR 滤波和斑点分析。我想在 AI 推理之前进入这个阶段有两个原因:

一个。通过不在每一帧上一直运行 DPU 来降低功耗。通过使用更大的输入图像来增加检测范围。图像差分和斑点分析的内存和处理能力要求要小得多,并且可以在全尺寸相机帧上完成。然后,人工智能只能在有运动的部件上运行,并适当缩放,以获得最大的检测性能。

通过用 Halcon 语言编写脚本,我在我的 PC 上对算法进行了原型设计和微调。代码可以在我的 github 页面上找到请注意,我决定对前一个/参考图像使用 IIR 滤波器,因为它让我在运动检测和忽略较小的连续运动(如树叶因风而移动)之间取得了更好的折衷。该算法可以轻松转换为 OpenCV,然后可以使用Vitis Vision Library中的预构建函数将图像差分、腐蚀、膨胀等操作加速到 FPGA 内核中

 

对象跟踪:对于框架内的对象跟踪,我使用这篇文章中的代码作为起点,并根据我的需要进行了修改。由于此代码在 opencv 中,因此可以直接在我的最终应用程序中使用。我的跟踪代码的最新版本可以在我的 github 页面上找到

这是一个关于实际代码的简短视频。当他们在屋顶上散步时,我很高兴跟踪鸟类。

 

AI 检测:这让我进入了这个项目中最有趣的部分,也是需要最大学习曲线的部分。正如我之前在这篇文章的“入门”部分中提到的,到目前为止,我已经确定最好的选择是在IVAS 参考设计之上构建我的应用程序,因为它已经包含了 DPU 和 VPU(两者比赛规则要求的)。

我首先按照页面上的构建步骤进行操作。在开始之前,我强烈建议您确保有足够的空间。例如,如果您在像我这样的虚拟机中运行主机 Ubuntu 操作系统,请确保为虚拟机分配至少 200GB 的空间。如果您拥有像我这样的普通 i7 机器,这将为您节省至少一天的等待时间。要增加磁盘空间分配,首先在 VM 设置中增加分配,然后启动操作系统并使用“GParted”实用程序让操作系统声明新分配的额外空间。

在我已经安装了 Vitis 工具的 Ubuntu 主机上,我首先在 home 下设置了新目录并克隆了完整的存储库。在新终端中:

cd ~
mkdir IVAS_TRD
cd IVAS_TRD
git clone --recurse-submodules https://github.com/Xilinx/Vitis-In-Depth-Tutorial
cd ~/IVAS_TRD/Vitis-In-Depth-Tutorial/Runtime_and_System_Optimization/Design_Tutorials/02-ivas-ml

源 Vitis 和 petalinux 脚本

source /tools/Xilinx/Vitis/2020.1/settings64.sh
source /tools/Xilinx/PetaLinux/2020.1/settings.sh

在进一步移动之前,我应用了与 rootfs 分区大小相关的推荐补丁

sudo cp vitis_patch/mkfsImage.sh ${XILINX_VITIS}/scripts/vitis/util

现在我们可以制作提供的zcu104_vcu平台

cd platform/dev/zcu104_vcu
make

这在我运行在 i7 机器上的普通虚拟机上花费了很长时间。我也用完了分配的空间,不得不重新开始,所以请确保不要重复错误。但是,最后,不知何故 BIF 文件没有被创建:错误:无法生成 BIF 文件,文件“/home/saadtiwana/IVAS_TRD/Vitis-In-Depth-Tutorial/Runtime_and_System_Optimization/Design_Tutorials/02-ivas-ml/平台/dev/zcu104_vcu/petalinux/project-spec/hw-description/xilinx_zcu104_vcu_202010_1.bit”不存在。Makefile:52:目标“bootimage”的配方失败

为了解决这个问题,我根据脚本手动复制了文件,这解决了我的问题并使我能够继续前进。

cp /home/$USER/IVAS_TRD/Vitis-In-Depth-Tutorial/Runtime_and_System_Optimization/Design_Tutorials/02-ivas-ml/platform/dev/zcu104_vcu/petalinux/components/plnx_workspace/device-tree/device-tree/xilinx_zcu104_vcu_202010_1.bit /home/$USER/IVAS_TRD/Vitis-In-Depth-Tutorial/Runtime_and_System_Optimization/Design_Tutorials/02-ivas-ml/platform/dev/zcu104_vcu/petalinux/project-spec/hw-description/

平台搭建成功后,解压安装sysroot

cd ../../repo/xilinx_zcu104_vcu_202010_1/sysroot
./sdk.sh -d `pwd` -y

现在,我们需要构建 Vitis 设计。首先,获取 XRT 设置脚本:

source /opt/xilinx/xrt/setup.sh

接下来,应用补丁(仅应用一次!)

cd ~/IVAS_TRD/Vitis-In-Depth-Tutorial/Runtime_and_System_Optimization/Design_Tutorials/02-ivas-ml
cd hw_src/Vitis_Libraries

patch -p1 < ../vision_lib_area_resize_ii_fix.patch

然后构建设计

cd ../..
cd hw_src
make

此时,我意识到我需要先安装 Vitis-AI 库,然后再继续。为此,我需要先安装 petalinux。对于 petalinux,我从这篇文章中获得了指导,并立即安装了它。

之后,我按照此页面上的说明安装了 Vitis-AI 。

制作安装目录

mkdir ~/petalinux_sdk

之后,下载安装脚本(sdk-2020.1.0.0.sh)并执行

./sdk-2020.1.0.0.sh

出现提示时,我按照页面上的说明提供了以下安装路径:~/petalinux_sdk

完成后,获取脚本

source ~/petalinux_sdk/environment-setup-aarch64-xilinx-linux

下载 Vitis-AI 压缩文件并解压

tar -xzvf vitis_ai_2020.1-r1.2.0.tar.gz -C ~/petalinux_sdk/sysroots/aarch64-xilinx-linux

在这个阶段,Vitis-AI 库已经建立。尽管 IVAS 设计不需要,但我继续执行页面上的其余说明以尝试示例。

现在,我需要安装 Vitis-AI docker 容器才能编译 densebox 和 reid 模型。要安装这些,我按照这里的简单步骤进行操作,没有任何问题(我使用了预构建的 docker 映像)。我还在这里找到了 Vitis-AI v1.2 的一些很好的资源,这些资源在接下来的几天里非常有用。

要下载 AI 模型,我从AI 模型动物园下载了模型

为了编译,我遵循了 Vitis-AI 指南。比如densebox模型,从model zoo下载模型,解压到~/Vitis-AI/AI-Model-Zoo/models/(其实也可以放到别的地方)。接下来,切换到 quantized/edge 目录

cd ~/Vitis-AI/AI-Model-Zoo/models/cf_densebox_wider_360_640_1.11G_1.2/quantized/Edge

现在,运行 docker 镜像,激活 conda 环境并编译模型

. ~/Vitis-AI/docker_run.sh xilinx/vitis-ai:latest

conda activate vitis-ai-caffe

vai_c_caffe --prototxt ./deploy.prototxt --caffemodel ./deploy.caffemodel --arch /opt/vitis_ai/compiler/arch/DPUCZDX8G/ZCU104/arch.json --output_dir compiled_model --net_name densebox_640_360

编译后的.elf 文件将位于“compiled_model 文件夹”下。请注意,我能够成功编译 tensorflow 模型,但对 Caffe 模型没有同样的运气。我在这里这里寻求帮助出于IVAS 的目的,Xilinx 工程师非常友好地为我提供了模型编译后的 elf 文件,以便我继续前进。

为此,我从一个全新的终端(赛灵思强烈推荐)开始,并获取了环境设置脚本

cd ~/IVAS_TRD/Vitis-In-Depth-Tutorial/Runtime_and_System_Optimization/Design_Tutorials/02-ivas-ml/platform/repo/xilinx_zcu104_vcu_202010_1/sysroot
source ./environment-setup-aarch64-xilinx-linux

接下来,我在适当的地方做了一个目录

cd ~/IVAS_TRD/Vitis-In-Depth-Tutorial/Runtime_and_System_Optimization/Design_Tutorials/02-ivas-ml/

mkdir ml_models

然后将两个elf文件复制到ml_models文件夹中。现在我需要做的就是运行最终的脚本来执行魔法并创建 SD 卡映像:

./go.sh

一旦完成而没有错误,我使用etcher将以下位置的图像刻录到sdcard:hw_src/sd_card_zcu104/sd_card.img

在此之后,我按照此处的最后几个步骤直到页面结束,并且最终能够运行示例应用程序。

我说“最终”是因为这对我来说并不顺利,事实上我花了整整 2 天的时间才弄清楚。最初我尝试运行应用程序,但屏幕上什么也没有显示。我开始进行故障排除并阅读。让 DisplayPort 输出正常工作的一个非常有用的资源是DP Linux 驱动程序页面,其中包含有关显示端口 DRM 驱动程序的大量信息。

我发现的一件事是我的显示器的分辨率为 2560x1440,要在屏幕上看到输出,发送到显示器的图像/视频必须是完全相同的分辨率。经过大量阅读和尝试不同的事情后,我找到了将分辨率设置为 1920x1080 的解决方法,但它也启动了测试模式生成器(42 是来自 modetest -m xlnx 的连接器的 id)

modetest -M xlnx -s 42:1920x1080@RG16 &

接下来,为了解决测试模式的问题,我将终端层的不透明度设置为零

modetest -M xlnx -w 39:alpha:0

这样做的副作用是终端层会消失,但这不是问题,因为无论如何我都是通过串行 uart 登录到板子的,并且对视频本身更感兴趣。现在,我可以成功运行 1920x1080 分辨率的输出,我使用以下 gstreamer 管道使用视频测试源对其进行了测试:

gst-launch-1.0 videotestsrc ! "video/x-raw, width=1920, height=1080" ! queue ! videoscale ! "video/x-raw, width=2560, height=1440" ! queue ! kmssink driver-name=xlnx sync=false

请注意,autovideosink 也适用于 kmssink 驱动程序

gst-launch-1.0 videotestsrc ! "video/x-raw, width=1920, height=1080, format=YUY2" ! queue ! autovideosink sync=false

在此之后,我设法从屏幕上显示的 USB3 摄像头获取实时视频:

gst-launch-1.0 v4l2src device=/dev/video0 ! "video/x-raw, width=1920, height=1080" ! videoconvert ! queue ! autovideosink

最后,我可以运行 IVAS 演示应用程序:

gst-launch-1.0 -v \
	filesrc location=/home/root/videos/dahua2.mp4 ! \
	qtdemux ! \
	h264parse ! \
	omxh264dec internal-entropy-buffers=3 !  \
	tee name=t0 t0.src_0 ! \
		queue ! \
		ivas_xm2m kconfig="/home/root/jsons/kernel_resize_bgr.json" ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_densebox_640_360.json" ! \
		scalem0.sink_master ivas_xmetaaffixer name=scalem0 scalem0.src_master ! \
		fakesink \
	t0.src_1 ! \
		scalem0.sink_slave_0 scalem0.src_slave_0 ! \
		queue ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_crop.json" ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_reid.json" ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_swbbox.json" ! \
		queue ! kmssink driver-name=xlnx sync=false

奖励:要使用任何管道显示 fps,您可以将最后一个元素更改为: fpsdisplaysink sync=false text-overlay=true fullscreen-overlay=1

例如,在以下管道中,我设法让相同的应用程序处理实时视频:

gst-launch-1.0 -v v4l2src device=/dev/video0 io-mode=dmabuf ! "video/x-raw, width=1920, height=1080" ! videoconvert ! video/x-raw,format=NV12 ! tee name=t0 \
	 t0.src_0 ! \
		queue ! \
		ivas_xm2m kconfig="/home/root/jsons/kernel_resize_bgr.json" ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_densebox_640_360.json" ! \
		scalem0.sink_master ivas_xmetaaffixer name=scalem0 scalem0.src_master ! \
		fakesink \
	t0.src_1 ! \
		scalem0.sink_slave_0 scalem0.src_slave_0 ! \
		queue ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_crop.json" ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_reid.json" ! \
		ivas_xfilter kernels-config="/home/root/jsons/kernel_swbbox.json" ! \
		queue ! fpsdisplaysink video-sink="kmssink driver-name=xlnx" sync=false text-overlay=true

重要提示:对于所有管道,在使用 kmssink(xilinx DRM 驱动程序)时,确保最后一个元素的视频与显示器上设置的分辨率相同非常重要!

VideoCompression:此时,我使用 gstreamer 在 VPU 中的视频解码工作正常,并且还想尝试视频编码。这是我遇到障碍的地方。我已经在Xilinx 论坛上写过它。我需要进一步调查。

你可以用我能想到的最简单的编解码管道来试试

gst-launch-1.0 videotestsrc ! "video/x-raw, width=1920, height=1080" ! omxh264enc ! h264parse ! omxh264dec ! queue max-size-bytes=0 ! autovideosink

此时,我想知道如何将 VPU 集成到我的 C++/python 应用程序中,最终我想出了一个非常简单的方法:在我的应用程序中使用 gstreamer。

例如,要使用 VCU 解码 H.264/265 文件或 RTSP 流,请在 opencv 应用程序中使用以下管道(为清楚起见已简化):

<压缩文件/流源> ! omxh264dec !应用程序rc

要从应用程序中编码(压缩)视频帧,请使用以下(简化的)gstreamer 管道将它们发送到 VCU:

应用程序!omxh264enc !....

您可以通过查看此处的代码以及我的项目 github页面上的 C++ 文件来了解更多信息希望能帮助到你!

把这一切放在一起

现在我已经弄清楚并测试了所有的组成部分,并且距离提交截止日期还有几天,我开始将这些部分放在一起。

我制定了一个构建我的应用程序的计划,如下所示:- 在 python 中构建主应用程序,在 IVAS 参考设计图像之上运行- 使用带有“appsink”元素的 gstreamer 管道将视频带入 OpenCV 域。这样,视频可以在来自摄像机的实时视频<或>来自文件或 RTSP 流的压缩视频之间快速切换,由 VPU 解码(使用 gstreamer 管道中的 omxh264dec 元素)。- 在 opencv-python 中预处理视频帧- 使用与 DPU 对话的 Vitis-AI python 绑定——对数据和视频帧进行后处理。使用opencv生成覆盖图形-使用gstreamer管道使用“appsink”元素显示带有覆盖图形的帧,并使用“kmssink”元素发送到displayPort。-此外,使用gstreamer“tee” 管道中的元素使用“omxh264enc”元素将此最终图像发送到 VPU,并作为 RTSP 流发送到 UDP 接收器。尽管在这方面我的编码器驱动程序出现了问题,如前所述,并且在这里

由于 IVAS 示例纯粹是在 gstreamer 中,DPU 处理部分也构建为 gstreamer 管道,这对我来说不是很有用。我通过查看 C++ 示例开始在 python 中编写我的应用程序,这花了我很多时间,而且我在后处理 DPU 数据方面遇到了很多问题(您必须执行几个操作来确定边界框的位置,例如例子)。值得庆幸的是,我在Avnet 的 Mario Bergeron 上找到了一个类似的优秀示例。由于后处理(确定边界框的位置)是相同的,我使用了他的代码作为起点并将其修改为使用 gstreamer 输入,使用为 zcu104 编译的密集盒模型进行处理,并使用 gstreamer 输出到 displayport。很高兴终于可以正常工作,如下面的视频剪辑所示:

 

请注意,在此视频中,我通过 gstreamer 管道使用来自摄像机的实时视频。相机安装了 35 毫米镜头,指向我的手机屏幕,播放来自 YouTube 的随机视频,里面有人物。运行的代码和说明可以在我的 github 链接上找到

进入下一步,因为我实际上需要一个对象检测器而不是人脸检测器,所以我开始修改代码以使用 SSD 对象检测器。尝试运行代码时,我的应用程序会挂起(并超时)等待 DPU。最初我怀疑我的应用程序存在问题,因此我查看了示例以使用相同的对象检测器找到合适的示例。我从 Xilinx 找到了一个使用相同 SSD 模型的 VART 示例,尽管它是用 C++ 编写的。原始代码使用原始(webm)文件进行输入,因此我将其修改为使用 gstreamer 输入和输出,如源代码文件开头所示:

VideoCapture cap("v4l2src device=/dev/video0 io-mode=dmabuf ! video/x-raw, width=1920, height=1080, format=UYVY ! videoconvert ! appsink", CAP_GSTREAMER);

VideoWriter writer("appsrc ! queue ! autovideosink sync=false",
		0,		// fourcc 
		30,		// fps
		Size(1920, 1080), 
		true);	// isColor

我首先使用运行良好的 gstreamer 管道测试了我的输入和输出,然后开始修改其余代码以使用 gstreamer 数据而不是视频帧中的帧。然而此时,在编译并运行应用程序后,我发现它也在等待 DPU 响应。在论坛搜索之后,我能想到的唯一可能的问题是,我使用的 model.elf 文件可能是针对与我的 IVAS 设计的 DPU 不同的 DPU 架构编译的。所以我开始从模型动物园下载模型并尝试在我的主机上重新编译它。这也是我之前在使用 Caffee 模型时遇到的一些问题的地方。我已经发布了在论坛上寻求帮助并等待回复。考虑到那里可能存在版本控制问题,我尝试运行量化,但也遇到了一些问题,我主要归咎于我目前使用 AI 模型的有限经验。我修改后的代码可以在我的 github页面上找到

距离提交截止日期还有一天,我决定在这里暂停一下,并在 hackster 上完成项目进度的记录。

未来的计划

由于我的想法与一个实际项目有关,我希望继续努力,希望也能在其他项目中重用这些知识。一些要点:
- 通过模型编译和测试完整系统来解决问题。
- 更深入地研究 AI 模型的技术细节,尤其是在后处理方面
- 在动物身上训练我自己的模型,甚至可能在旅行恢复后获取我自己的一些数据。
- 在 PL 中实现视频加速内核(图像大小调整、DPU 预处理等),以实现更快的端到端加速 - 在 FPGA 端进行视频稳定,以增强云台稳定并获得最流畅的视频输出。

最后的想法

在开始这个项目时,考虑到 FPGA 项目通常的学习曲线,我已经意识到时间会很紧。我尝试逐步构建,将项目划分为更小的逻辑模块,并在此过程中进行原型设计和学习。尽管最终在达到所有目标之前已经没有时间了,但我对自己取得的进步感到满意。时间限制也帮助我以比通常的“探索”速度更快的速度学习事物。它还帮助我在嵌入式领域学到了很多新东西,并帮助我确定了我未来需要投入更多时间的领域(例如,人工智能)。感谢 Hackster 和 Xilinx 提供这次学习机会。这确实是一次很棒的经历。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.lene-v.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'Xiraffe桅杆上的智能野生动物观测站',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.lene-v.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);