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

2023-12-10 06:12

本文主要是介绍HLS实现图像膨胀和腐蚀运算--xf_dilation和xf_erosion,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

        我们先定义,需要处理的图片为二值化图像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_CONSTANTint TYPE,            //图像类型,目前支持8UC1和8UC3int 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_CONSTANTint TYPE,            //图像类型,目前支持8UC1和8UC3int 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,则该库函数工作可能不正常,这是由赛灵思库函数的运算算法决定的,感兴趣的可以再自己研究一下。

 

 

 

 

 

这篇关于HLS实现图像膨胀和腐蚀运算--xf_dilation和xf_erosion的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/476227

相关文章

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja