FPGA实现的连通域识别算法升级_第1页
FPGA实现的连通域识别算法升级_第2页
FPGA实现的连通域识别算法升级_第3页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、FPGA实现的连通域识别算法升级代码在这:还做了个算法演示动画:之前写过这篇文章FPGA实现的实时流水线连通域标记算法。这个文章是两年前写的,里面介绍的算法是四五年前写的。这个版本的算法在对二值图像进行连通域识别之前需要先进行去噪、取边缘操作,然后再对边缘图像进行连通域识别。识别m,n,u,w形的连通域是没有问题的,但遇到螺旋形的就貌似会出问题,会对它视而不见。不过在实际应用中这样会导致问题的形状几乎不会出现,所以这个算法也完全是可应用的。当初想着要把图像进行去噪取边之后再进行连通域识别,主要的考虑是想着如果图像边缘周边噪点多,可能会影响连通域识别算法,把图像变得只剩下严格的边缘之后再进行处理

2、,貌似看起来要简单一些。但后来算法实现起来的那个状态机也有点复杂。不过当时我还沾沾自喜,觉得自己整出来了一个还有点复杂的算法。真是蠢人不知自己蠢。人类就是擅长把简单的事情搞复杂了还自以为很了不起。这个老版本的代码有点复杂,当时也没写多少注释,所以也不便大家使用。最近又想着是不是能改进一下这个算法。首先不需要去噪和取边缘这些预处理,其次处理的流程不需要状态机控制,就像算子法那样流水线的扫过去就能完成识别。仔细想了一下之后发现其实这样也是可以实现的,当年没想到这个算法可能还是因为当年水平低,而且先入为主的就认为这样对于噪点多的图像会很复杂,要考虑很多情况。而现在重新思考一下又发现,噪点多也不会在逻

3、辑上带来更多的麻烦,逻辑还是那个逻辑,逻辑是正确的就可以应对所有情况。并不是有很多情况就需要很多的逻辑去应对,而是几个简单且严密的逻辑就可以应对所有情况。算法也就是好比是一个逻辑处理公式,一个简单的分形公式可以生成千变万化的复杂图像,一个逻辑严密的算法也可以应对任何的图像情况。所以这个算法无需预处理,也不会出错,一个点也会被识别成一个连通域。当然如果你不希望小噪点也被识别出来,可以先进行去噪处理。也可以直接就识别,然后在输出结果时把点数少的连通域忽略掉。在实验这个新思路时我又忽然想到了一个可以在PC上实现的非常简单的连通域识别算法,那就是用递归法来实现。用递归法来实现连通域识别真的非常简单。只

4、需要写一个标记函数,扫描图像时找到一个未标记黑点时就调用这个函数:标记该点,并寻找该点的8邻域中有没有未标黑点,有就递归调用自己。就这样就可以了。我用Python写了个动画来演示这两种连通域识别算法,也就是递归法和并行流水线法。递归法需要随机读取数据,并行流水线法只需要顺序扫描一遍图像就可以了。如果你下载并运行了这个python代码,还可以控制它逐帧的进行查看。Python代码看起来有点长,但很多都是在处理做动画的问题,真正算法部分没多长,尤其是递归法。这个并行流水线法的大致思路是这样的:一个像素点有8个相邻的点。上面3个,下面3个,左边1个,右边一个。当从左往右逐行扫描图像时,正在被扫描的这

5、个点应该被标上什么标记,其实只和在它之前已经被扫描过的点,也就是它邻域中上面3个和左边1个这4个点有关。所以第一个要点就是,某个点该被标记什么标号,只和它前邻域的四个点有关,也就是左边,左上,正上,右上这四个点。那么这个算法其实就相当于用这样一个2x3的算子扫描图像,就能得到结果,只需缓存一行图像。接下来就是对邻域这4个点的情况进行判断来确定当前这个点该怎么标记。总共也就4个点,最多也就是16种情况,但实际上概括起来只有三大种情况:一、 前邻域这4个点都是白点,说明这是一个新连通域的起始点,给它标上一个新的标号。二、4个点中有两个点的标号不同,这个情况只有两种,要么是右上点和左边点的标号不同,

6、要么是右上点和左上点标号不同。不会存在有三个点标号都不同和四个点标号都不同的情况,至于为什么,大家可以自己想一想。之所以会存在这种有两个点标号不同的情况,是因为U,W形连通域的存在,在一开始扫描时会被当作两个连通域,扫描到下面才发现它们两个实际上是连通的,遇到这种情况就需要把这两个连通域的统计数据进行合并,并把右上那个点的标号改为,和当前这个点的标号标为左边点或左上点的标号。这就是顺序扫描法所需要面对的麻烦之处,递归法就不存在这个问题,这里具体是如何处理的大家可参考Python版的代码三、4个点中有1、2、3或4个已标点,但它们的标号都是相同的,就把当前点标上这个标号。实际写代码时,把前面两种

7、情况判断掉之后,剩下的就是这种情况,所以这个情况不需要写很多if判断,写个else就行了。在实现上有一个要点就是,要用另外一个数组存放每个标号连通域的信息,在Verilog实现时会用另外一个RAM,老版算法中也是这么做的。当扫描到某个已标点时,要用它的标号去查这个连通域信息表里面存放的它的真实标号。因为存在标号合并的问题,之前标记的标号可能已经被并入了别的标号,这个改动只会出现在这个连通域信息列表中,不会出现在标记数组中,所以要先去查表获得真实标号再进行判断。这是关键一步。还有一个关键是如何判断一个连通域是否已经全部扫描完成。完成时要输出这个连通域的信息结果。所以如果不知道一个连通域什么时候扫

8、描完成,那这个算法就没有输出。这个算法判断一个连通域是否完成在它完成的那一行还判断不了。要到扫描下一行时查看上面已标点的信息时才能发现,具体如何判断的请参考代码。这个算法的逻辑是严格的,也就是它不会出错,如果大家不信可以拿它的结果和递归法的结果做对比,递归法很容易想明白它是严格不会出错的。Python版的代码还是比较容易理解的。Verilog代码里,除了上述的逻辑判断代码之外,还多了一些处理Ram的读写和流水线寄存器数据一致性的代码。因为这个连通域识别算法和之前FPGA图像处理基本技巧这篇文章中提到的算子法是不一样的。算子法计算之后的数据不需要写回Ram,也不能写回。而连通域识别算法的结果是需

9、要写回的,因为下一行的判断还需要上一行的结果。这需要写回处理起来就麻烦一些,对Ram的读写也和算子法中有所不同。还需要处理流水线寄存器数据一致性的问题。然后最关键的是,由于FPGA实现上的限制,这个Verilog版本的算法不能和前述的算法逻辑做到完全等价,也就是说有个地方它不能完全实现,这样有些特殊结构的连通域就会导致算法输出的统计结果会漏掉一些点。具体什么样的结构会导致问题大家可参考这个图片文件。但在实际应用中遇到奇怪形状的概率并不大,而且统计也只是会漏掉很少的一些点,所以基本并不影响使用。注意,不是会漏扫描标记一些点,只是统计的时候会在特殊情况下丢失掉一些点的数据。这比老版本的算法也算是有进步了,老版本的算法在遇到螺旋形时会直接视而不见,不会给出任何结果。这个算法不会出现视而不见的情况,只是会在特殊情况下可能漏报。这个不等价的原因就是,Verilog在实现时实际上并没有实现用已标点的标号去查询到它的真实标号之后再去获取它真实信息,这样需要读两次RAM,RAM只有两个端口,都用来读数据了就没法再用来写回数据了。所以在扫描合并连通域的时候会把合并的结果也写入到被合并掉的标号中,但之后就不好再更新这个已经被合并掉的标号,如果之后这个被合并掉的标号又再出现了,就有可能会出现信息丢失,因为这个被合并掉的标号中的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论