使用HLS进行基于FPGA的边缘检测

利用HLS函数创建图像处理解决方案,在可编程逻辑中实现边缘检测(Sobel)。

使用HLS进行基于FPGA的边缘检测 - 第1张

这个项目中使用的东西

硬件组件软件应用程序
Zynq-7000 ARM/FPGA SoC开发板Xilinx Vivado
Apeman 1080P高清运动相机Xilnix Vivado HLS

高级合成(HLS)允许我们在开发FPGA应用程序时以更高的抽象水平工作,如果这是一个商业项目,希望节省时间并降低非经常性成本。

HLS的伟大应用之一是图像或信号处理,我们可能用C或C++创建了高级模型,或者我们希望使用开源行业标准框架,如OpenCV。

在这个项目中,我们将研究如何使用HLS构建Sobel边缘检测IP核心,然后将其纳入我们选择的Xilinx FPGA中。

所选设备可以是传统的FPGA,如Spartan Seven或Artix,或者也可以在Zynq 7000或Zynq MPSoC等异构SoC的可编程逻辑中实现。

理论

在我们进入应用程序之前,我应该先轻描淡写地谈谈Sobel算法是如何工作的。Sobel算法的功能是识别图像中的边缘,并强调它们,以便易于识别。通常,这将创建一个灰度图像,其中边缘被标识为灰色/白色阴影。

Sobel边缘检测的工作原理是检测图像在水平和垂直方向上的梯度变化。为此,将两个卷积滤波器应用于原始图像,然后将这些卷积滤波器的结果结合起来,以确定梯度的大小。

使用HLS进行基于FPGA的边缘检测 - 第2张
Sobel卷积滤波器

实施

如果我们使用传统的VHDL/Verilog RTL方法在FPGA中实现这一点,开发时间不会微不足道。因为我们需要为卷积创建线缓冲区,然后实现大小计算。我们还需要创建一个测试台,这样我们就可以确保我们的代码在进行实施之前按预期工作。

幸运的是,当我们使用HLS时,我们真的可以跳过许多繁重的工作,让Vivado HLS实现较低级别的Verilog/VHDL RTL实现。

为了在这个更高层次的抽象中工作,我们将使用Vivado HLS及其HLS_OpenCV和HLS_Video库。

第一个库HLS_OpenCV允许我们使用非常流行的OpenCV框架。而HLS视频库提供了许多图像处理功能,这些功能可以加速到可编程逻辑中。

相当有帮助的是,HLS视频库包括我们创建Sobel IP核心所需的一切,包括:-

  • HLS::CvtColor - 这根据其配置在颜色和灰度之间转换配色方案。
  • HLS::Gaussian - 这将在图像上进行高斯模糊,以减少图像中存在的噪音。
  • HLS::Sobel - 这根据其配置在垂直或水平方向上执行Sobel卷积。我们需要在我们的IP核心中使用两个实现。
  • HLS::AddWeighted - 这允许我们使用垂直和水平Sobel运算符的结果进行结果大小计算。

这些并不是我们将要使用的所有HLS功能,因为我们需要使用其他功能。我们需要包含这些附加功能,以便更轻松地使用HLS优化和与我们的Vivado设计接口。

接口

在可编程逻辑中移动图像数据的最佳内部方法是使用AXI流。

这允许创建高性能图像处理路径,其中元素可以根据需要轻松添加或创建。

Vivado IP库中存在几个IP块,可以在视频输入和输出以及AXI流之间进行转换。以及其他图像处理功能,如混音器和色彩空间转换器。

因此,我们希望我们的Sobel IP核心能够接受AXI Stream输入,并以相同的AXI Stream格式生成其输出。为此,我们使用以下功能,允许在AXI流和HLS函数使用的HLS::Mat格式之间进行转换。

  • HLS::AXIvideo2Mat - 从AXI流转换为HLS::Mat格式,用于AXI流输入。
  • HLS::Mat2AXIvideo - 从HLS::Mat格式转换为AXI流格式,用于AXI流输出。

C合成和优化

与Verilog和VHDL设计不同,我们用来描述设计的高级语言是没有时间的。这意味着当HLS工具将C转换为Verilog或VHDL时,它必须经历多个阶段来创建输出RTL

  • 调度 - 确定操作及其发生的顺序。
  • 绑定 - 将操作分配给设备内可用的逻辑资源。
  • 控制逻辑提取-提取控制逻辑并创建控制结构,例如状态机来控制模块的行为。
使用HLS进行基于FPGA的边缘检测 - 第3张
调度和绑定示例
使用HLS进行基于FPGA的边缘检测 - 第4张
控制逻辑提取示例

由于HLS工具在进行合成时必须在性能和逻辑资源之间进行权衡,因此在实施过程中将遵循一些规则。这些可能会影响生成的IP核心的性能,例如,循环(HLS编码的常见结构)被滚动。

当然,我们可能想要改变HLS工具在C合成期间做出的决定,以获得更好的性能。我们可以在C中使用#pragmas来做到这一点,还有几个我们可以使用

对于此实现,我们将使用数据流实用性来确保我们能够实现尽可能高的帧速率。

为了能够使用这个实用性,我们需要确保HLS合成工具并行执行两个Sobel操作。这将允许我们在HLS C合成期间指定数据流优化,通过函数优化数据流。实际上,数据流优化是粗粒流水线。

使用HLS进行基于FPGA的边缘检测 - 第5张
数据流管道

如果我们执行一个Sobel操作,然后按顺序执行另一个操作,我们将无法应用此优化。

因此,我们需要将高斯模糊的结果分成两条平行路径,我们在AddWeighted Stage重新组合。为此,我们使用这个功能

HLS::Duplicate - 这将输入图像复制到两个独立的输出图像中,我们可以并行处理。

把这一切放在一起

了解这一切,然后我们可以编写用于Sobel IP核心的代码

  1. #include "cvt_colour.hpp"
  2. void image_filter(AXI_STREAM& INPUT_STREAM, AXI_STREAM& OUTPUT_STREAM)//, int rows, int cols)
  3. {
  4. #pragma HLS INTERFACE axis port=INPUT_STREAM
  5. #pragma HLS INTERFACE axis port=OUTPUT_STREAM
  6. RGB_IMAGE img_0(MAX_HEIGHT, MAX_WIDTH);
  7. GRAY_IMAGE img_1(MAX_HEIGHT, MAX_WIDTH);
  8. GRAY_IMAGE img_2(MAX_HEIGHT, MAX_WIDTH);
  9. GRAY_IMAGE img_2a(MAX_HEIGHT, MAX_WIDTH);
  10. GRAY_IMAGE img_2b(MAX_HEIGHT, MAX_WIDTH);
  11. GRAY_IMAGE img_3(MAX_HEIGHT, MAX_WIDTH);
  12. GRAY_IMAGE img_4(MAX_HEIGHT, MAX_WIDTH);
  13. GRAY_IMAGE img_5(MAX_HEIGHT, MAX_WIDTH);
  14. RGB_IMAGE img_6(MAX_HEIGHT, MAX_WIDTH);
  15. ;
  16. #pragma HLS dataflow
  17. hls::AXIvideo2Mat(INPUT_STREAM, img_0);
  18. hls::CvtColor<HLS_BGR2GRAY>(img_0, img_1);
  19. hls::GaussianBlur<3,3>(img_1,img_2);
  20. hls::Duplicate(img_2,img_2a,img_2b);
  21. hls::Sobel<1,0,3>(img_2a, img_3);
  22. hls::Sobel<0,1,3>(img_2b, img_4);
  23. hls::AddWeighted(img_4,0.5,img_3,0.5,0.0,img_5);
  24. hls::CvtColor<HLS_GRAY2RGB>(img_5, img_6);
  25. hls::Mat2AXIvideo(img_6, OUTPUT_STREAM);
  26. }
  27. #include "hls_video.h"
  28. #include <ap_fixed.h>
  29. #define MAX_WIDTH 1280
  30. #define MAX_HEIGHT 720
  31. typedef hls::stream<ap_axiu<24,1,1,1> > AXI_STREAM;
  32. typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3> RGB_IMAGE;
  33. typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC1> GRAY_IMAGE;
  34. void image_filter(AXI_STREAM& INPUT_STREAM, AXI_STREAM& OUTPUT_STREAM);//int rows, int cols);

当然,我们希望能够同时运行C模拟和Co模拟,因此我们需要一个测试台,我们可以用来测试算法。

  1. #include <hls_opencv.h>
  2. #include "cvt_colour.hpp"
  3. #include <iostream>
  4. using namespace std;
  5. int main (int argc, char** argv) {
  6. IplImage* src;
  7. IplImage* dst;
  8. AXI_STREAM src_axi, dst_axi;
  9. src = cvLoadImage("test.bmp");
  10. dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
  11. IplImage2AXIvideo(src, src_axi);
  12. image_filter(src_axi, dst_axi);//src->height,src->width);
  13. AXIvideo2IplImage(dst_axi, dst);
  14. cvSaveImage("op.bmp", dst);
  15. cvReleaseImage(&src);
  16. cvReleaseImage(&dst);
  17. }

当我们运行C模拟时,我们可以看到测试输入图像的结果如下。

使用HLS进行基于FPGA的边缘检测 - 第6张
C和Co模拟的输入测试图像
使用HLS进行基于FPGA的边缘检测 - 第7张
Co模拟Sobel结果

有了预期的C模拟和Co模拟结果,我们可以导出核心并将其添加到Vivado硬件设计中。

然而,在我们这样做之前,您可能需要检查分析,在Vivado HLS中查看,并确认两个Sobel函数是并行运行的。

使用HLS进行基于FPGA的边缘检测 - 第8张
显示并行sobel操作的分析视图

我们可以使用Vivado HLS中的导出RTL选项导出IP核心,如果我们愿意,我们可以进一步配置IP核心参数

使用HLS进行基于FPGA的边缘检测 - 第9张
导出HLS核心

实施核心

导出核心后,您将在<project>/solutionX/imp目录下找到一个zip文件。此目录包含将新创建的Sobel IP核心添加到我们的Vivado设计中所需的所有必要信息。

此文件可以添加到我们的Vivado IP存储库中,然后包含在Vivado框图中

使用HLS进行基于FPGA的边缘检测 - 第10张
Vivado IP库中的IP核心
使用HLS进行基于FPGA的边缘检测 - 第11张
在图像处理链中集成核心(注意HLS符号)

有了这一切,您可以构建应用程序,并针对您选择的开发板。

对于下面的演示视频,我使用Zybo Z7和HDMI输入和HDMI输出将视频应用到Sobel IP核心并显示结果。

本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/8593.html

"愿我的文字能带给您一丝美好"

还没有人赞赏,支持一下

评论

A 为本文作者,G 为游客总数:0
加载中…

提交评论

游客,您好,欢迎参与讨论。

我的购物车

购物车为空

优惠券

没有优惠券