HLS实现图像膨胀和腐蚀运算--xf_dilation和xf_erosion

news2024/11/17 22:13:13

一、图像膨胀和图像腐蚀概念

        我们先定义,需要处理的图片为二值化图像A。图片的背景色为黑色,即像素值为0。图片的目标色为白色,即像素值为1。

        再定义一个结构元S,结构元范围内所有的像素为白色,像素值为1。

1、图像的膨胀

        通俗点说:就是将图像的目标像素往外扩张,使目标的尺寸变大,从而达到膨胀的效果。

        详细点说:一个结构元S从图像左上方开始遍历,结构元上任意一个元素与图像上目标元素重合时,此时将结构元锚点置的像素与对应图像位置的像素求“或运算”,更新像素值到此图像位置(即将结构元锚点位置对应的图像像素更新数值为1,即白色)。以此类推,遍历完图像后,得到的新的图像,即为膨胀后的图像。

        比如上图中,假设使用左侧的3x3结构元,遍历图像时,锚点遍历到原始图像绿色位置。此时可以看到,粉色区域存在数值为1的像素,按照膨胀运算,此时将结构元锚点与原始图像锚点像素进行“或运算”,最终处理后的膨胀像素为1。即原始图像的绿色位置的像素由0变成了1。

2、图像的腐蚀

        通俗点说:就是将图像的目标像素往内收缩,使目标的尺寸变小,从而实现腐蚀的效果。

        详细点说:一个结构元S从图像的左上方开始遍历,若结构元所在的图像区域内,像素值全部为1,那么保持结构元锚点位置的像素值为1,即白色;否则,锚点位置的像素值为0,即黑色。遍历完图像后,得到的新图像,即为腐蚀后的图像。 ​​​​​

        比如上图中,假设使用左侧的3x3结构元,遍历图像时,锚点遍历到原始图像绿色位置。此时可以看到,粉色区域存在数值为0的像素,按照腐蚀运算,锚点处最终处理后的膨胀像素为0。即原始图像的绿色位置的像素由1变成了0。

二、HLS实现

        可能不同资料中讲述腐蚀核膨胀的概念会略有区别,但是核心内容是不变的。本文中重点分析vitis HLS的库函数xf_dilation.hpp和xf_erosion.hpp。

1、xf_dilation.hpp

        在AMD赛灵思提供的解释中,图像膨胀处理,即当前像素被NxN邻域中强度最大值代替。公式表示如下:

         其库函数的调用模板和解释见下面代码:

template <int BORDER_TYPE,     //边界处理方式,目前仅支持XF_BORDER_CONSTANT
          int TYPE,            //图像类型,目前支持8UC1和8UC3
          int ROWS,            //图像最大行数
          int COLS,            //图像最大列数
          int K_SHAPE,         //结构元的形状,支持矩形、十字形和圆形
          int K_ROWS,          //结构元行数
          int K_COLS,          //结构元列数
          int ITERATIONS,      //迭代次数,仅在结构元为矩形时支持多次迭代
          int NPC = 1,         //单个时钟处理的像素数
          int XFCVDEPTH_IN_1 = _XFCVDEPTH_DEFAULT,   //输入图像深度
          int XFCVDEPTH_OUT_1 = _XFCVDEPTH_DEFAULT>  //输出图像深度
void dilate(xf::cv::Mat<TYPE, ROWS, COLS, NPC, XFCVDEPTH_IN_1>& _src,  //输入图像
            xf::cv::Mat<TYPE, ROWS, COLS, NPC, XFCVDEPTH_OUT_1>& _dst, //输出图像
            unsigned char _kernel[K_ROWS * K_COLS])   //输入的结构元数值,处理二值化图像时一般默认都为1

        如何使用该函数,可以自行参考赛灵思提供的示例demo,不再赘述。下面主要解析HLS是怎么实现膨胀运算处理的。

         打开xf_dilation.hpp文件,我们可以看到其c++代码。主要的调用函数有4个如下:

          dilate函数:判断输入图像大小与边界处理方式是否满足函数要求。根据结构元调整参数处理图像膨胀。此函数不进行具体的膨胀处理。

        xfdilate函数:根据结构元大小,考虑到边界情况,创建buf(buf包含图像边界以外行的像素值,初值赋为0)。以便处理第一行图像像素的膨胀。该函数主要考虑行边界预处理,缓存图像数据的数组定义为buf。

        Process_function_d函数:根据结构元大小。考虑到边界情况,给src_buf赋予初值(初值为0),以便处理第1列图像像素的膨胀,。该函数主要考虑列边界的预处理,缓存图像数据的数组定义为src_buf,最后得到与结构元大小一致的src_buf_temp_med_apply,然后提取送入到膨胀处理模块进行处理。

        dilate_function_apply函数:该函数判断窗口区域的图像数据中的最大值,赋值给锚点。该函数为图像膨胀的核心处理函数。

        下面举例说明膨胀函数的处理方式:以8*8的二值化8bits深度的图像,结构元大小为3*3的矩形,NPPC=1。(选取这些参数主要是为了减少篇幅且容易理解)

第一步:在dilate函数判断图像,结构元类型、迭代次数等信息是否满足要求。

第二步:xfdilate函数中创建buf数组,数组的大小为buf[3][8]。并且给buf赋予初值。buf[0]的8个像素值均赋为0;buf[1]的8个像素赋值为原始图像的第一行图像数据。如下图。

第三步:执行Process_function_d函数。首先读取图像2行的原始数据,保存至buf[2]中。此时buf数据更新为下图。

        此时我们要用到一个新的数组src_buf,其大小为src_buf[3][3]。其初值皆为0。buf数组经过buf_cop数组和src_buf_temp_copy_extract的一系列转换,最终会得到如下的src_buf数组,如下图:

        此时位于src_buf中的的锚点位置在原始图像之外,所以函数中存在一个start_write标志,用于控制何时将锚点结果写入到_dst中。很明显,锚点在图像边界之外的结果不写入到_dst矩阵中。

第四步:在dilate_function_apply函数中,比较src_buf中的像素结果,将src_buf的最大值赋值输出,最后判断是否在图像边界外,若在图像区域内,则写入到_dst矩阵中。

        综上,循环执行第三步和第四步,根据图像行列数据的读取,更新buf和src_buf中的数据,遍历完成完图像后,膨胀操作完成。

2、xf_erosion.hpp

        在AMD赛灵思提供的解释中,图像腐蚀处理,即当前像素被NxN邻域中强度最小值代替。公式表示如下:

         其库函数的调用模板和解释见下面代码:

template <int BORDER_TYPE,     //边界处理方式,目前仅支持XF_BORDER_CONSTANT
          int TYPE,            //图像类型,目前支持8UC1和8UC3
          int ROWS,            //图像最大行数
          int COLS,            //图像最大列数
          int K_SHAPE,         //结构元的形状,支持矩形、十字形和圆形
          int K_ROWS,          //结构元行数
          int K_COLS,          //结构元列数
          int ITERATIONS,      //迭代次数,仅在结构元为矩形时支持多次迭代
          int NPC = 1,         //单个时钟处理的像素数
          int XFCVDEPTH_IN_1 = _XFCVDEPTH_DEFAULT,   //输入图像深度
          int XFCVDEPTH_OUT_1 = _XFCVDEPTH_DEFAULT>  //输出图像深度
void erode(xf::cv::Mat<TYPE, ROWS, COLS, NPC, XFCVDEPTH_IN_1>& _src,  //输入图像
            xf::cv::Mat<TYPE, ROWS, COLS, NPC, XFCVDEPTH_OUT_1>& _dst, //输出图像
            unsigned char _kernel[K_ROWS * K_COLS])   //输入的结构元数值,处理二值化图像时一般默认都为1

       腐蚀函数与膨胀函数的处理方式几乎相同,仅在最后的function_apply中,由取最大值更改为取最小值。所以不再增加篇幅描述了。只要明白了膨胀函数的原理,腐蚀函数自然也不在话下。

这里需要提一下的是,如果你需要使用的结构元kernel的列数大于15,则该库函数工作可能不正常,这是由赛灵思库函数的运算算法决定的,感兴趣的可以再自己研究一下。

 

 

 

 

 

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

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

相关文章

《三十》模块化打包构建工具 Rollup

19的2小时06分钟 Rollup 是一个 JavaScript 的模块化打包工具&#xff0c;可以帮助编译微小的代码到庞大的复杂的代码中&#xff08;例如一个库或者一个应用程序&#xff09;。 Rollup 和 Webpack 的区别&#xff1a; Rollup 也是一个模块化的打包工具&#xff0c;但是它主要…

JUnit 之初体验

文章目录 1.定义2.引入1&#xff09;使用 Maven 工具2&#xff09;使用 Gradle 工具3&#xff09;使用 Jar 包 2.样例0&#xff09;前提1&#xff09;测试类2&#xff09;测试方法3&#xff09;测试断言4&#xff09;实施 总结 1.定义 JUnit 是一个流行的 Java 单元测试框架&a…

精选Axure原型设计模板,RP原型组件库(PC端移动端元件库及Axure函数及运算符说明)

好的原型组件会大大的提高产品经理的工作效率&#xff0c;小7在陆续整理、精选Axure 8的原型设计模板&#xff0c;包含了原型设计的常用元素和AxureRP 8函数及运算符的说明文档&#xff0c;及各种设备模板框架。 本文也是基于小7另一篇文章的补充&#xff0c;更多更详细的资料…

C++编程法则365天一天一条(24)RTTI运行时类型信息typeid和type_info

文章目录 基本用法编译时或运行时判定 基本用法 typeid 是 C 的一个运算符&#xff0c;它用于获取表达式的类型信息。它返回一个 std::type_info 对象引用&#xff0c;该对象包含有关表达式的类型的信息。 要使用 typeid 运算符&#xff0c;需要包含 <typeinfo> 头文件…

FPGA 低延时 TCP UDP IP协议栈兼容1G 10G 25G MAC

在计算和数据中心、军事和航天、政府、仪器与测量、金融服务和广播和视频等行业&#xff0c;需要高可靠性的硬件和软件产品&#xff0c;帮助客户更快地开发部署新一代产品&#xff0c;减少技术和市场风险&#xff0c;我司研发的低延迟TCP/IP的IP核的传输速率高于传统网口&#…

二十一章总结

网络程序设计基础 局域网与互联网 为了实现两台计算机的通信&#xff0c;必须用一个网络线路连接两台计算机。如下图所示 网络协议 1.IP协议 IP是Internet Protocol的简称&#xff0c;是一种网络协议。Internet 网络采用的协议是TCP/IP协议&#xff0c;其全称是Transmission…

Nginx基础篇:Nginx搭建、Nginx反向代理、文件服务器部署配置。

Nginx Linux系统安装以及反向代理的配置 简介优点nginx 环境安装常用Nginx 命令nginx 文件服务器搭建 简介 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点…

AI:94-基于深度学习的微小目标检测与定位

🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的核心代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新…

目标检测、目标跟踪、重识别

文章目录 环境前言项目复现特征提取工程下载参考资料 环境 ubuntu 18.04 64位yolov5deepsortfastreid 前言 基于YOLOv5和DeepSort的目标跟踪 介绍过针对行人的检测与跟踪。本文介绍另一个项目&#xff0c;结合 FastReid 来实现行人的检测、跟踪和重识别。作者给出的2个主…

Dantzig-Wolfe分解

参考资料&#xff1a;Introduction to Linear Programming&#xff0c; Dimitris Bertsimas etc 这篇博客是个人笔记的电子版(●ˇ∀ˇ●)&#xff0c;希望之后的自己也能看懂吧 在这本教材的Dantzig-Wolfe分解章节中&#xff0c;作者主要列举了两个小例子&#xff0c;结合坐标…

深入理解Os--调用劫持

1.调用劫持 以Linux系统为例&#xff0c;介绍三种可实现调用劫持的技术。 1.1.编译时调用劫持 以一个实例展开介绍 (1).main.cpp #include <stdio.h> #include <malloc.h> int main() {int* p (int*)malloc(32);free(p);return (0); }(2).mymalloc.cpp #inclu…

30、卷积 - 参数 stride 的作用

在卷积运算中,还有一个参数叫做 stride,它对卷积的运算以及运算结果影响也很大。 还是先看卷积动图,从图上你能猜到 stride 参数在哪吗? 在卷积操作中,stride 指的是卷积核在滑动过程中每次跳过的像素数量。 stride 决定了卷积核在输入图像上移动的速度。例如,如果 str…

【Angular 开发】Angular 信号的应用状态管理

自我介绍 做一个简单介绍&#xff0c;年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【架构…

STM32基于USB串口通信应用开发

✅作者简介&#xff1a;热爱科研的嵌入式开发者&#xff0c;修心和技术同步精进&#xff0c; 代码获取、问题探讨及文章转载可私信。 ☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。 &#x1f34e;获取更多嵌入式资料可点击链接进群领取&#xff0c;谢谢支持&#xff01;…

使用selenium的edge浏览器登录某为

互联网上基本都是某哥的用法&#xff0c;其实edge和某哥的用法是一样的就有一下参数不一样。 一、运行环境 Python&#xff1a;3.7 Selenium&#xff1a;4.11.2 Edge&#xff1a;版本 120.0.2210.61 (正式版本) (64 位) 二、执行代码 from time import sleepfrom selenium…

Course2-Week4-决策树

Course2-Week4-决策树 文章目录 Course2-Week4-决策树1. 决策树的直观理解2. 构建单个决策树2.1 熵和信息增益2.2 构建决策树——二元输入特征2.3 构建决策树——多元输入特征2.4 构建决策树——连续的输入特征2.5 构建回归树——连续的输出结果(选修)2.6 代码实现-递归构建单个…

基于K-means与CNN的遥感影像分类方法

基于K-means与CNN的遥感影像分类 一、引言 1.研究背景 航天遥感技术是一种通过卫星对地观测获取遥感图像信息数据的技术&#xff0c;这些图像数据在各领域都发挥着不可或缺的作用。遥感图像分类主要是根据地面物体电磁波辐射在遥感图像上的特征&#xff0c;判断识别地面物体的属…

BUUCTF pwn rip WriteUp

文件分析 下载附件&#xff0c;分析文件 可以看到是64位ELF文件&#xff0c;elf可以理解为Linux中的可执行文件&#xff0c;就像Windows中的exe文件 用ida打开文件 查看main函数的伪代码&#xff0c;可以看到有一个15位的字符数组&#xff0c;该数组通过gets函数传值 还有一…

Jupyter notebook修改背景主题

打开Anaconda Prompt&#xff0c;输入以下内容 1. pip install --upgrade jupyterthemes 下载对应背景主题包 出现Successfully installed jupyterthemes-0.20.0 lesscpy-0.15.1时&#xff0c;说明已经下载安装完成 2. jt -l 查看背景主题列表 3. jt -t 主题名称&#xff08;…

AI:92-基于深度学习的红外图像人体检测

🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的核心代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新…