如何用 Vitis HLS 实现 OpenCV 仿真

news2025/1/16 3:33:30

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

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

算法原理

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

均值滤波

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

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

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

12fc4b4d65208e90f4460ea73fcad994.png

处理内核如下:

298376fca93231f4b37dad54a2bf977b.png

动画演示处理过程如下:

图片演示:

78dd01d029d5109be281c630749a06f2.png

特点

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

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

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

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

0e359c44668e0635c78728b1c65e6859.png

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

e00c7de959d138c3403dd739daaefd2c.png

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

58893607128448ccfd0c1d975dd7c6f9.png

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

ea2670beb064a8d629bbf312b4e30a16.png

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

常见变体

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

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

中值滤波

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

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

28ad437b9210f56f22c8337c844a0d10.png

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

83192ed473a70cebae1b86536134f5ed.png

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

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

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

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

OpenCV实现

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

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

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

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

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

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

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

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

 waitKey(0);
}
05ad3e48db342618e86ff95bc38c6718.png

HLS加速和仿真

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

HLS工程搭建

新建工程

如下:

343df88d33170dcffea411fc15cae942.png

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

24823079f069723bc963e64e021119a7.png b32b8e1d44bb84e19152666ec419ff15.png

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

21babf22ecf157caa8b4a779d2e6bf20.png

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

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

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

也可以使用函数:

set_clock_uncertainty <uncertainty> <clock_list>

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

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

添加源文件

新建xf_median_blur_accel.cpp

#include "xf_median_blur_config.h"

static constexpr int __XF_DEPTH = (HEIGHT * WIDTH * (XF_PIXELWIDTH(TYPE, NPC1)) / 8) / (PTR_WIDTH / 8);

void median_blur_accel(ap_uint<PTR_WIDTH>* img_in, int rows, int cols, ap_uint<PTR_WIDTH>* img_out) {
// clang-format off
    #pragma HLS INTERFACE m_axi      port=img_in        offset=slave  bundle=gmem0 depth=__XF_DEPTH
    #pragma HLS INTERFACE m_axi      port=img_out        offset=slave bundle=gmem1 depth=__XF_DEPTH
    #pragma HLS INTERFACE s_axilite  port=rows                  bundle=control
 #pragma HLS INTERFACE s_axilite  port=cols                  bundle=control
    #pragma HLS INTERFACE s_axilite  port=return              bundle=control
    // clang-format on

    xf::cv::Mat<TYPE, HEIGHT, WIDTH, NPC1, XF_CV_DEPTH_IN> imgInput(rows, cols);
    xf::cv::Mat<TYPE, HEIGHT, WIDTH, NPC1, XF_CV_DEPTH_OUT> imgOutput(rows, cols);

// clang-format off
    #pragma HLS DATAFLOW
    // clang-format on

    // Retrieve xf::cv::Mat objects from img_in data:
    xf::cv::Array2xfMat<PTR_WIDTH, TYPE, HEIGHT, WIDTH, NPC1, XF_CV_DEPTH_IN>(img_in, imgInput);

    // Run xfOpenCV kernel:
    xf::cv::medianBlur<WINDOW_SIZE, XF_BORDER_REPLICATE, TYPE, HEIGHT, WIDTH, NPC1, XF_CV_DEPTH_IN, XF_CV_DEPTH_OUT>(
        imgInput, imgOutput);

    // Convert _dst xf::cv::Mat object to output array:
    xf::cv::xfMat2Array<PTR_WIDTH, TYPE, HEIGHT, WIDTH, NPC1, XF_CV_DEPTH_OUT>(imgOutput, img_out);

    return;
} // End of kernel

添加仿真文件

新建xf_median_blur_tb.cpp

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

int main(int argc, char** argv) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <INPUT IMAGE PATH 1>", argv[0]);
        return EXIT_FAILURE;
    }

    cv::Mat in_img, out_img, ocv_ref, diff;

//  Reading in the image:
#if GRAY
    in_img = cv::imread(argv[1], 0); // reading in the gray image
#else
    in_img = cv::imread(argv[1], 1); // reading in the color image
#endif

    if (in_img.data == NULL) {
        fprintf(stderr, "ERROR: Cannot open image %s\n ", argv[1]);
        return EXIT_FAILURE;
    }

// create memory for output image
#if GRAY
    ocv_ref.create(in_img.rows, in_img.cols, CV_8UC1);
    out_img.create(in_img.rows, in_img.cols, CV_8UC1); // create memory for output image
    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); // create memory for output image
    diff.create(in_img.rows, in_img.cols, CV_8UC3);
#endif

    // OpenCV reference:
    cv::medianBlur(in_img, ocv_ref, WINDOW_SIZE);

// OpenCL section:
#if GRAY
    size_t image_in_size_bytes = in_img.rows * in_img.cols * 1 * sizeof(unsigned char);
#else
    size_t image_in_size_bytes = in_img.rows * in_img.cols * 3 * sizeof(unsigned char);
#endif
    size_t image_out_size_bytes = image_in_size_bytes;

    // Call the top function
    median_blur_accel((ap_uint<PTR_WIDTH>*)in_img.data, in_img.rows, in_img.cols, (ap_uint<PTR_WIDTH>*)out_img.data);

    // Write down output images:
    cv::imwrite("hls_out.jpg", out_img); // kernel output
    cv::imwrite("ref_img.jpg", ocv_ref); // reference image

    absdiff(ocv_ref, out_img, diff);
    // Save the difference image for debugging purpose:
    cv::imwrite("error.png", diff);
    float err_per;
    xf::cv::analyzeDiff(diff, 10, err_per);
    if (err_per > 0.0f) {
        fprintf(stderr, "ERROR: Test Failed.\n ");
        return 1;
    } else
        std::cout << "Test Passed " << std::endl;

    return 0;
}

设置仿真库

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

186fc8db15da6a82836bffac1b9e4f85.png

在这个界面设置

c5b6849c317b361e37f797bccfb232f8.png

1、Top Function

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

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

添加

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

3、设置设计文件Edit  csimflags

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

接下来设置仿真库路径

7e90af070d99fb34d0d4b1f15eb966c3.png

1、设置仿真文件Edit  cflags

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

2、设置仿真文件Edit  csimflags

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

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

-L E:/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

综合

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

39895525a28ca31ea57de2c62c96602a.png

仿真

点击仿真按钮得到下图仿真结果,原始图像如下:

a20d4c36032cbd093fd2af97d51aa0b6.png

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

fb3517e9c8e533e6b104cffb5d7edf2d.png

联合仿真

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

f842699b0782e7eb2f80cf067d0981a5.png 7f8ca8b8d747820126fe00e9bd3ad7ba.png

导出IP

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

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/415727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot电脑商城项目

目录 系统概述与环境搭建 1 系统开发及运行环境 2 项目分析 3 创建数据库 4 创建Spring Initializr项目 5 配置并运行项目 6 导入前端项目 用户注册 1 用户-创建数据表 2 用户-创建实体类 3 用户-注册-持久层 4 用户-注册-业务层 5 用户-注册-控制器 6 用户-注册…

归并排序(递归实现)

上一次我们说了快排的其他版本&#xff0c;还有就是快排的非递归实现 这次我们就说一哈归并排序&#xff0c;归并排序也是很厉害的一种排序&#xff0c;而且归并排序的时间复杂度可以说成标准的O(n log n) 下面我们就来看一下归并排序 我们先来看一下什么是归并排序 假设我…

Scratch蓝桥杯实战训练 —— 巧解“韩信点兵”难题的五种方式

“韩信点兵”蓝桥杯问题描述&#xff1a; “蓝桥杯”中有一道有趣的 Scratch 编程题&#xff0c;题目要求为&#xff1a;韩信点兵 扩展知识&#xff1a; 这道题叫“中国余数定理”&#xff0c;又叫“孙子定理”&#xff0c;也叫“韩信点兵问题”&#xff0c;是我国古代数学智慧…

Faster-RCNN代码解读3:制作自己的数据加载器

Faster-RCNN代码解读3&#xff1a;制作自己的数据加载器 前言 ​ 因为最近打算尝试一下Faster-RCNN的复现&#xff0c;不要多想&#xff0c;我还没有厉害到可以一个人复现所有代码。所以&#xff0c;是参考别人的代码&#xff0c;进行自己的解读。 ​ 代码来自于B站的UP主&…

Node【三】Buffer 与 Stream

文章目录&#x1f31f;前言&#x1f31f;Buffer&#x1f31f; Buffer结构&#x1f31f; 什么时候用Buffer&#x1f31f; Buffer的转换&#x1f31f; Buffer使用&#x1f31f; 创建Buffer&#x1f31f; 字符串转Buffer&#x1f31f; Buffer转字符串&#x1f31f; 拼接Buffer&…

python 理解BN、LN、IN、GN归一化、分析torch.nn.LayerNorm()和torch.var()工作原理

目录 前言&#xff1a; 简言之BN、LN、IN、GN等归一化的区别&#xff1a; 批量归一化(Batch Normalization&#xff0c;BN) 优点 缺点 计算过程 层归一化(Layer Normalization&#xff0c;LN) 优点 计算过程 总结 分析torch.nn.LayerNorm()工作原理 分析torch.var(…

Vue2-黑马(十一)

目录&#xff1a; &#xff08;1&#xff09;vue2-联调准备 &#xff08;2&#xff09;vue2-登录实战-国际化 &#xff08;3&#xff09;vue2实战-登录-login-index.vue &#xff08;1&#xff09;vue2-联调准备 登录这个请求&#xff0c;并不是发给后台的&#xff0c;现在还…

浙大MBA提面申请材料的三六九等……

每年浙大MBA项目提前批面试申请的每个批次中都会有部分材料因为某些原因而被淘汰&#xff0c;无缘面试资格。考生们由最初的不理解到逐渐隐约的理解&#xff0c;行至今日也可以大体接受材料被刷这个结果&#xff0c;当然其中含有一部分面上资质背景还可以的考生&#xff0c;等到…

Faster-RCNN代码解读2:快速上手使用

Faster-RCNN代码解读2&#xff1a;快速上手使用 前言 ​ 因为最近打算尝试一下Faster-RCNN的复现&#xff0c;不要多想&#xff0c;我还没有厉害到可以一个人复现所有代码。所以&#xff0c;是参考别人的代码&#xff0c;进行自己的解读。 ​ 代码来自于B站的UP主&#xff08;…

中国电子学会2023年03月份青少年软件编程Scratch图形化等级考试试卷四级真题(含答案)

2023-03 Scratch四级真题 分数&#xff1a;100 题数&#xff1a;24 测试时长&#xff1a;90min 一、单选题(共10题&#xff0c;共30分) 1.编写一段程序&#xff0c;从26个英文字母中&#xff0c;随机选出10个加入列表a。空白处应填入的代码是&#xff1f;&#xff08;C&am…

Flink (十二) --------- Flink CEP

目录一、基本概念1. CEP 是什么2. 模式 (Pattern)3. 应用场景二、快速上手1. 需要引入的依赖2. 一个简单实例三、模式 API&#xff08;Pattern API&#xff09;1. 个体模式2. 组合模式3. 模式组4. 匹配后跳过策略四、模式的检测处理1. 将模式应用到流上2. 处理匹配事件3. 处理超…

【高项】项目整体管理、范围管理与进度管理(十大管理)

【高项】项目整体管理与范围管理 文章目录1、项目整体管理1.1 整体管理的过程1.2 制定项目章程&#xff08;启动&#xff09;1.3 制订项目管理计划&#xff08;规划&#xff09;1.4 指导与管理项目执行&#xff08;执行&#xff09;1.5 监控项目工作与实施整体变更控制&#xf…

Systemverilog中operators和expression的记录

1. Equality operators Equality operators有三种&#xff1a; Logical equality&#xff1a;, !&#xff0c;该运算符中如果运算数包含有x/z态&#xff0c;那么结果就是x态。只有在两边的bit都不包含x/z态&#xff0c;最终结果才会为0(False)或1(True)Case equality&#xf…

中云盾DDoS云防护系统

中云盾 DDoS 防护系统作为公司级网络安全产品&#xff0c;为各类业务提供专业可靠的 DDoS/CC 攻击防护。在黑客攻防对抗日益激烈的环境下&#xff0c; DDoS 对抗不仅需要 “降本” 还需要 “增效”。 为什么上云&#xff1f; 云原生作为近年来相当热门的概念&#xff0c;无论…

RHCE-NTP、SSH服务器

1.配置ntp时间服务器&#xff0c;确保客户端主机能和服务主机同步时间​ 服务器端&#xff1a; &#xff08;1&#xff09;首先安装chrony软件&#xff1a; dnf install -y chrony &#xff08;2&#xff09;配置时间同步源&#xff1a; 进入vim /etc/chrony.conf &#xf…

引用和指针

总结 引用&#xff1a; 因为引用是变量的别名&#xff0c;所以引用必须初始化 因为引用不存在自己的地址&#xff0c;所以指针不能指向引用&#xff0c;即不能定义引用的指针 因为引用不是对象&#xff0c;但是引用又要绑定一个对象&#xff0c;所以不能定义引用的引用 in…

一篇文章看懂C++三大特性——多态的定义和使用

目录 前文 一&#xff0c;什么是多态&#xff1f; 1.1 多态的概念 二&#xff0c; 多态的定义及实现 2.1 多态的构成条件 2.2 虚函数 2.3 虚函数的重写 2.3.1 虚函数重写的两个例外 2.4 C override 和 final 2.5 重载,重写(覆盖),隐藏(重定义)的区别 三&#xff0c;抽…

代码随想录刷题-双指针总结篇

文章目录双指针移除元素习题我的解法双指针优化反转字符串习题我的解法剑指 Offer 05. 替换空格习题我的解法正确解法反转字符串里的单词习题我的解法反转链表习题我的解法删除链表的倒数第 N 个节点习题我的解法相交链表习题我的解法环形链表 II习题我的解法三数之和习题我的解…

Unity VFX -- (3)创建环境粒子系统

粒子系统中最常用也最重要的一种使用场景是实现天气效果。只需要做很少修改&#xff0c;场景就能很快从蓝天白云变成雪花飘舞。 和之前看到的粒子系统从一个源头发出粒子的情况不同&#xff0c;天气效果完全围绕着场景。 新增和放置一个新的粒子系统 为了创建下雨或下雪的天气…

【从零开始学Skynet】基础篇(三):服务模块常用API

1、服务模块 Skynet提供了开启服务和发送消息的API&#xff0c;必须要先掌握它们。列出了Skynet中8个最重要的API&#xff0c;PingPong程序会用到它们。 Lua API说明newservice(name, ...) 启动一个名为 name 的新服务&#xff0c;并返回服务的地址。 start(func) …