0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用Vitis HLS实现OpenCV仿真的方法

OpenFPGA 来源:OpenFPGA 2023-04-10 09:03 次阅读

这篇文章的基础是《Windows上快速部署Vitis HLS OpenCV仿真》,我们使用的版本是Vitis HLS 2022.2,其他版本BUG不清楚,目前已知2021版本有BUG,只能使用其他方式,本文不适合。

这次选择中值滤波这个常规算法作为演示算法。

算法原理

算法原理很简单,我们先介绍均值滤波,因为线性滤波的基础是均值滤波,中值滤波是在这个基础上发展过来的。

均值滤波

图像均值滤波是一种基本的图像平滑处理方法,也被称为“盒子滤波”或“平滑滤波”。它的主要思想是对图像中的每个像素取一个局部均值,以降低图像噪声和细节对图像边缘检测和其他计算机视觉算法的影响。

具体来说,图像均值滤波涉及在图像中移动一个固定尺寸的窗口,例如 的窗口。对于每个窗口,计算窗口内所有像素的平均值,并将该值分配给窗口中心的像素。这个过程将重复应用于整个图像,用于生成平滑的输出图像。

在进行图像处理时,一张图片可以看做一个矩阵,假设有个6x6图片,如下:

a0ef85ca-d73a-11ed-bfe3-dac502259ad0.png

处理内核如下:

a1019b52-d73a-11ed-bfe3-dac502259ad0.png

动画演示处理过程如下

特点

具有非常不具代表性的值的单个像素会显着影响其邻域中所有像素的平均值。

滤波器邻域跨越边缘时,滤波器将为边缘上的像素插入新值,从而模糊该边缘。如果输出中需要尖锐的边缘,这可能是个问题。

这两个问题都由中值滤波器解决,中值滤波器通常是比均值滤波器更好的降噪滤波器,但计算时间更长。

通常,均值滤波器充当低通频率滤波器 ,因此减少了图像中存在的空间强度导数。

上图描绘了一个包含更广泛不同空间频率的场景。用 3×3 均值滤波器平滑一次后,我们得到

背景中的低空间频率信息并未受到过滤的显着影响,但前景对象的(曾经清晰的)边缘已被明显平滑。用 7×7 均值滤波器过滤后,得到下图

将此结果与通过在原始图像上传递 3×3 均值滤波器三次获得的结果进行比较

上两图说明一个问题:对一幅图像应用大窗口的滤波器和应用多次小窗口滤波器效果差不多。

常见变体

此处讨论的均值平滑滤波器的变体包括:阈值平均,其中仅当其原始值与平均值之间的差大于预设阈值时才改变中心像素值的条件下应用平滑。这具有平滑噪声的效果,图像细节的损失较小。

其他不计算邻域均值的卷积滤波器也经常用于平滑。其中最常见的一种是高斯平滑滤波器。

中值滤波

图像中值滤波是一种常用的非线性滤波方法,也被称为排序滤波器。它的主要原理是将图像中每个像素周围的像素排序,并将排序后的中间值作为该像素的输出值。

中值滤波可以有效地抑制图像中的噪声,同时保留图像中细节和边缘信息。相对于其他线性滤波器(如均值滤波器),它可以在更好地去除噪声的同时保留图像的细节和边缘上提供更好的性能。

a1bfd626-d73a-11ed-bfe3-dac502259ad0.png

具体地,对于每个像素,中值滤波器会包括 个邻域像素,其中 和 是正奇数。它们将以该像素为中心构成一个矩形窗口或一个圆形窗口。

a1eb36b8-d73a-11ed-bfe3-dac502259ad0.png

窗口大小是中值滤波器的重要参数。在选择窗口大小时,应该考虑噪声的特性以及需要保留的图像细节。通常情况下,窗口大小越大,中值滤波器能够去除的噪声越大,但也会导致图像模糊。

然后,对于每个像素,将邻域像素按灰度值进行排序,取排序后的中间值作为该像素的输出值。这个输出值将取代原始图像中的像素值,从而产生一个平滑且噪声减少的图像。

中值滤波器的优点是它可以在去除噪声的同时保留图像中的边缘和细节,但它的缺点是计算成本较高,并且可能导致图像的细节丢失。此外,当噪声水平很高时,这种滤波器可能无法完全去除噪声。

所有平滑技术都可以有效去除信号平滑块或平滑区域中的噪声,但会对边缘产生不利影响。通常,在降低信号噪声的同时,保留边缘也很重要。例如,边缘对于图像的视觉特性至关重要。对于小到中等水平的高斯噪声,中值滤波器在去除噪声方面明显优于高斯滤波,同时为给定的固定窗口大小保留边缘。然而,对于高水平的噪声,它的性能并不比高斯模糊好多少,而对于散斑噪声和椒盐噪声(脉冲噪声),它特别有效。正因为如此,中值滤波在数字图像处理中得到了非常广泛的应用。

OpenCV实现

使用OpenCV进行算法验证和Matlab进行算法验证其实思路差不多,先验证算法的效果再验证算法的正确性,这一步使用OpenCV和MatLab一样,我们就使用OpenCV进行验证,这一步就不实际展开了,代码如下:

//-----------------------------------【头文件包含部分】---------------------------------------
//描述:包含程序所依赖的头文件
//----------------------------------------------------------------------------------------------
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"

//-----------------------------------【命名空间声明部分】---------------------------------------
//描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------
usingnamespacecv;

//-----------------------------------【main()函数】--------------------------------------------
//描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
intmain()
{
//载入原图
Matimage=imread("1.jpg");

//创建窗口
namedWindow("中值滤波【原图】");
namedWindow("中值滤波【效果图】");

//显示原图
imshow("中值滤波【原图】",image);

//进行中值滤波操作
Matout;
medianBlur(image,out,7);

//显示效果图
imshow("中值滤波【效果图】",out);

waitKey(0);
}

HLS加速和仿真

上面就完成了算法的介绍和论证,其中论证过程并没有详细介绍,因为本篇文章重点不是这个,后续在介绍这个算法的时候再详细展开。

HLS工程搭建

新建工程

如下:

a22eb654-d73a-11ed-bfe3-dac502259ad0.png

第二页和第三页不用管,后续再进行设置

a2497868-d73a-11ed-bfe3-dac502259ad0.pnga2616310-d73a-11ed-bfe3-dac502259ad0.png

最后一页,需要设置两个地方,注意一个地方

a288066e-d73a-11ed-bfe3-dac502259ad0.png

其中,Uncertainty参数含义见下,默认不设置即可。

在UG1399的set_clock_uncertainty章节有详细介绍。

【uncertainty】:以 ns 为单位指定,表示时钟周期中有多少被用作余量。不确定性也可以指定为时钟周期的百分比。默认的不确定性是时钟周期的 27%。

也可以使用函数:

set_clock_uncertainty

【uncertainty】:以 ns 为单位指定,表示时钟周期中有多少被用作余量。不确定性也可以指定为时钟周期的百分比。默认的不确定性是时钟周期的 27%。

【clock_list】:应用不确定性的时钟列表。如果未提供,它将应用于所有时钟。

添加源文件

新建xf_median_blur_accel.cpp

#include"xf_median_blur_config.h"

staticconstexprint__XF_DEPTH=(HEIGHT*WIDTH*(XF_PIXELWIDTH(TYPE,NPC1))/8)/(PTR_WIDTH/8);

voidmedian_blur_accel(ap_uint*img_in,introws,intcols,ap_uint*img_out){
//clang-formatoff
#pragmaHLSINTERFACEm_axiport=img_inoffset=slavebundle=gmem0depth=__XF_DEPTH
#pragmaHLSINTERFACEm_axiport=img_outoffset=slavebundle=gmem1depth=__XF_DEPTH
#pragmaHLSINTERFACEs_axiliteport=rowsbundle=control
#pragmaHLSINTERFACEs_axiliteport=colsbundle=control
#pragmaHLSINTERFACEs_axiliteport=returnbundle=control
//clang-formaton

xf::MatimgInput(rows,cols);
xf::MatimgOutput(rows,cols);

//clang-formatoff
#pragmaHLSDATAFLOW
//clang-formaton

//Retrievexf::Matobjectsfromimg_indata:
xf::Array2xfMat(img_in,imgInput);

//RunxfOpenCVkernel:
xf::medianBlur(
imgInput,imgOutput);

//Convert_dstxf::Matobjecttooutputarray:
xf::xfMat2Array(imgOutput,img_out);

return;
}//Endofkernel

添加仿真文件

新建xf_median_blur_tb.cpp

#include"common/xf_headers.hpp"
#include"xf_median_blur_config.h"

intmain(intargc,char**argv){
if(argc!=2){
fprintf(stderr,"Usage:%s",argv[0]);
returnEXIT_FAILURE;
}

cv::Matin_img,out_img,ocv_ref,diff;

//Readingintheimage:
#ifGRAY
in_img=cv::imread(argv[1],0);//readinginthegrayimage
#else
in_img=cv::imread(argv[1],1);//readinginthecolorimage
#endif

if(in_img.data==NULL){
fprintf(stderr,"ERROR:Cannotopenimage%s
",argv[1]);
returnEXIT_FAILURE;
}

//creatememoryforoutputimage
#ifGRAY
ocv_ref.create(in_img.rows,in_img.cols,CV_8UC1);
out_img.create(in_img.rows,in_img.cols,CV_8UC1);//creatememoryforoutputimage
diff.create(in_img.rows,in_img.cols,CV_8UC1);
#else
ocv_ref.create(in_img.rows,in_img.cols,CV_8UC3);
out_img.create(in_img.rows,in_img.cols,CV_8UC3);//creatememoryforoutputimage
diff.create(in_img.rows,in_img.cols,CV_8UC3);
#endif

//OpenCVreference:
cv::medianBlur(in_img,ocv_ref,WINDOW_SIZE);

//OpenCLsection:
#ifGRAY
size_timage_in_size_bytes=in_img.rows*in_img.cols*1*sizeof(unsignedchar);
#else
size_timage_in_size_bytes=in_img.rows*in_img.cols*3*sizeof(unsignedchar);
#endif
size_timage_out_size_bytes=image_in_size_bytes;

//Callthetopfunction
median_blur_accel((ap_uint*)in_img.data,in_img.rows,in_img.cols,(ap_uint*)out_img.data);

//Writedownoutputimages:
cv::imwrite("hls_out.jpg",out_img);//kerneloutput
cv::imwrite("ref_img.jpg",ocv_ref);//referenceimage

absdiff(ocv_ref,out_img,diff);
//Savethedifferenceimagefordebuggingpurpose:
cv::imwrite("error.png",diff);
floaterr_per;
xf::analyzeDiff(diff,10,err_per);
if(err_per>0.0f){
fprintf(stderr,"ERROR:TestFailed.
");
return1;
}else
std::cout<< "Test Passed " << std::endl;

    return 0;
}

设置仿真库

在下面界面设置相关参数:

a2a4fc10-d73a-11ed-bfe3-dac502259ad0.png

在这个界面设置

a2ca8afc-d73a-11ed-bfe3-dac502259ad0.png

1、Top Function

设置主函数的,点击Browse进行选择即可。

2、设置设计文件Edit cflags,添加调用的设计头文件

添加

-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-std=c++0x-IH:/FILE/HLS/meanblur/src/build-I./.-D__SDSVHLS__-std=c++0x

3、设置设计文件Edit csimflags

-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-std=c++0x-IH:/FILE/HLS/meanblur/src/build-I./.-D__SDSVHLS__-std=c++0x

接下来设置仿真库路径

a2ef1804-d73a-11ed-bfe3-dac502259ad0.png

1、设置仿真文件Edit cflags

-IE:/vitis_hls_image/opencv_lib/opencv/build_2/install/include-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-IH:/FILE/HLS/meanblur/src/build-I.-std=c++0x-D__SDSVHLS__-std=c++0x

2、设置仿真文件Edit csimflags

-IE:/vitis_hls_image/opencv_lib/opencv/build_2/install/include-IE:/vitis_hls_image/Vitis_Libraries-2020.2/Vitis_Libraries-2020.2/vision/L1/include-IH:/FILE/HLS/meanblur/src/build-I.-std=c++0x-D__SDSVHLS__-std=c++0x

3、设置Linker Flags,调用OpenCV库文件

-LE:/vitis_hls_image/opencv_lib/opencv/build_2/install/x64/mingw/lib-llibopencv_imgcodecs455-llibopencv_imgproc455-llibopencv_core455-llibopencv_highgui455-llibopencv_flann455-llibopencv_features2d455

4、 设置Input Arguments,这个是调用仿真图片,可以后续再设置

H:/FILE/HLS/meanblur/src/128x128.png

综合

点击综合按钮即可开始综合,结果如下:

a310e5f6-d73a-11ed-bfe3-dac502259ad0.png

仿真

点击仿真按钮得到下图仿真结果

下图从左到右分别为:OpenCV处理的结果、HLS处理的结果以及最后的两个图像差(无差别即全黑)。

联合仿真

点击联合仿真按钮后等待仿真结束,然后点击下面按钮查看波形:

a3746ff4-d73a-11ed-bfe3-dac502259ad0.pnga38dba7c-d73a-11ed-bfe3-dac502259ad0.png

导出IP

点击导出IP按钮等待导出即可。

总结

今天的例程演示完毕,从建立工程到最后导出IP,基本比较详细。但是,上面的例程是不能直接应用到视频里的,原因是上面的接口没经过改动,需要从AXI转成AXI-STREAM接口后再再接入到视频架构中即可,这部分我们后续再详细说明。






审核编辑:刘清

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

    关注

    160

    文章

    7712

    浏览量

    177519
  • 计算机视觉
    +关注

    关注

    8

    文章

    1695

    浏览量

    45910
  • OpenCV
    +关注

    关注

    29

    文章

    625

    浏览量

    41218
  • HLS
    HLS
    +关注

    关注

    1

    文章

    128

    浏览量

    24005

原文标题:如何用 Vitis HLS 实现 OpenCV 仿真

文章出处:【微信号:Open_FPGA,微信公众号:OpenFPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    新手求助,HLS实现opencv算法加速的IP在vivado的使用

    我照着xapp1167文档,HLS实现fast_corners的opencv算法,并生成IP。然后想把这个算法塞到第三季的CH05_AXI_DMA_OV5640_HDMI上,这个de
    发表于 01-16 09:22

    Vivado HLS实现OpenCV图像处理的设计流程与分析

    像素访问对应方法2.3 HLS实现OpenCV应用的实例(快速角点滤波器image_filter)我们通过快速角点的例子,说明通常用Viv
    发表于 07-08 08:30

    FPGA高层次综合HLSVitis HLS知识库简析

    ,Vivado 2019.1之前(包括),HLS工具叫Vivado HLS,之后为了统一将HLS集成到Vitis里了,集成之后增加了一些功能,同时将这部分开源出来了。
    发表于 09-07 15:21

    使用Vitis HLS创建属于自己的IP相关资料分享

    1、使用Vitis HLS创建属于自己的IP高层次综合(High-level Synthesis)简称HLS,指的是将高层次语言描述的逻辑结构,自动转换成低抽象级语言描述的电路模型的过程。对于AMD
    发表于 09-09 16:45

    利用Vitis HLS tcl shell一键跑通视觉加速例程

    高层次综合工具中调用视觉库遇到的大多数问题都和 opencv 库以及Xilinx Vision 库的安装路径有关,如今 Vitis HLS 2020.1 之后的版本都不再提供OpenCV
    的头像 发表于 12-29 11:12 3388次阅读
    利用<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b> tcl shell一键跑通视觉加速例程

    Vitis Vision | 利用Vitis HLS tcl shell 一键跑通视觉加速例程

    在论坛上遇到在高层次综合工具中调用视觉库遇到的大多数问题都和 opencv 库以及Xilinx Vision 库的安装路径有关,如今 Vitis HLS 2020.1 之后的版本都不再提供
    发表于 01-27 06:17 6次下载
    <b class='flag-5'>Vitis</b> Vision | 利用<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b> tcl shell 一键跑通视觉加速例程

    基于Vitis HLS的加速图像处理

    使用Vivado / Vitis工具提供预安装的OpenCV版本。尽管Vitis_hls编译Vision库不需要OpenCV,但是用户测试验证使用时
    的头像 发表于 02-16 16:21 2393次阅读
    基于<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b>的加速图像处理

    Vitis HLS工具简介及设计流程

    Vitis HLS 是一种高层次综合工具,支持将 C、C++ 和 OpenCL 函数硬连线到器件逻辑互连结构和 RAM/DSP 块上。Vitis HLS 可在
    的头像 发表于 05-25 09:43 2305次阅读

    Vitis HLS如何添加HLS导出的.xo文件

    HLS导出的.xo文件如何导入到Vitis里面?需要把.xo文件解压,然后把文件夹导入到Vitis Kernel/src文件夹下吗?
    的头像 发表于 08-03 11:20 3027次阅读
    <b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b>如何添加<b class='flag-5'>HLS</b>导出的.xo文件

    Vitis HLS前端现已全面开源

    Vitis HLS 工具能够将 C++ 和 OpenCL 功能部署到器件的逻辑结构和 RAM/DSP 块上。在 GitHub 上提供 Vitis HLS 前端为研究人员、开发人员和编译
    的头像 发表于 08-03 09:53 918次阅读

    Vitis HLS知识库总结

    对于AMD Xilinx而言,Vivado 2019.1之前(包括),HLS工具叫Vivado HLS,之后为了统一将HLS集成到Vitis里了,集成之后增加了一些功能,同时将这部分开
    的头像 发表于 09-02 09:06 3395次阅读

    理解Vitis HLS默认行为

    相比于VivadoHLS,Vitis HLS更加智能化,这体现在Vitis HLS可以自动探测C/C++代码中可并行执行地部分而无需人工干预添加pragma。另一方面VitisHLS也
    的头像 发表于 11-24 11:42 1793次阅读

    AMD全新Vitis HLS资源现已推出

    AMD Vitis HLS 工具允许用户通过将 C/C++ 函数综合成 RTL,轻松创建复杂的 FPGA 算法。Vitis HLS 工具与 Vivado Design Suite(用于
    的头像 发表于 04-23 10:41 1056次阅读
    AMD全新<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b>资源现已推出

    如何在Vitis HLS GUI中使用库函数?

    VitisHLS 2023.1 支持新的 L1 库向导,本文将讲解如何下载 L1 库、查看所有可用功能以及如何在 Vitis HLS GUI 中使用库函数。
    的头像 发表于 08-16 10:26 1129次阅读
    如何在<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b> GUI中使用库函数?

    Vitis HLS移植指南

    电子发烧友网站提供《Vitis HLS移植指南.pdf》资料免费下载
    发表于 09-13 09:21 0次下载
    <b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b>移植指南