代码在这:https://github.com/becomequantum/kryon

还做了个算法演示动画:https://www.bilibili.com/video/av26067000

《FPGA图像处理基本技巧》:https://zhuanlan.zhihu.com/p/38946857

《FPGA实现的实时流水线连通域标记算法》

之前写过这篇文章《FPGA实现的实时流水线连通域标记算法》。这个文章是两年前写的,里面介绍的算法是四五年前写的。这个版本的算法在对二值图像进行连通域识别之前需要先进行去噪、取边缘操作,然后再对边缘图像进行连通域识别。识别m,n,u,w形的连通域是没有问题的,但遇到螺旋形的就貌似会出问题,会对它视而不见。不过在实际应用中这样会导致问题的形状几乎不会出现,所以这个算法也完全是可应用的。当初想着要把图像进行去噪取边之后再进行连通域识别,主要的考虑是想着如果图像边缘周边噪点多,可能会影响连通域识别算法,把图像变得只剩下严格的边缘之后再进行处理,貌似看起来要简单一些。但后来算法实现起来的那个状态机也有点复杂。不过当时我还沾沾自喜,觉得自己整出来了一个还有点复杂的算法。真是蠢人不知自己蠢。人类就是擅长把简单的事情搞复杂了还自以为很了不起。

这个老版本的代码有点复杂,当时也没写多少注释,所以也不便大家使用。最近又想着是不是能改进一下这个算法。首先不需要去噪和取边缘这些预处理,其次处理的流程不需要状态机控制,就像算子法那样流水线的扫过去就能完成识别。仔细想了一下之后发现其实这样也是可以实现的,当年没想到这个算法可能还是因为当年水平低,而且先入为主的就认为这样对于噪点多的图像会很复杂,要考虑很多情况。而现在重新思考一下又发现,噪点多也不会在逻辑上带来更多的麻烦,逻辑还是那个逻辑,逻辑是正确的就可以应对所有情况。并不是有很多情况就需要很多的逻辑去应对,而是几个简单且严密的逻辑就可以应对所有情况。算法也就是好比是一个逻辑处理公式,一个简单的分形公式可以生成千变万化的复杂图像,一个逻辑严密的算法也可以应对任何的图像情况。所以这个算法无需预处理,也不会出错,一个点也会被识别成一个连通域。当然如果你不希望小噪点也被识别出来,可以先进行去噪处理。也可以直接就识别,然后在输出结果时把点数少的连通域忽略掉。

在实验这个新思路时我又忽然想到了一个可以在PC上实现的非常简单的连通域识别算法,那就是用递归法来实现。用递归法来实现连通域识别真的非常简单。只需要写一个标记函数,扫描图像时找到一个未标记黑点时就调用这个函数:标记该点,并寻找该点的8邻域中有没有未标黑点,有就递归调用自己。就这样就可以了。我用Python写了个动画来演示这两种连通域识别算法,也就是递归法和并行流水线法。递归法需要随机读取数据,并行流水线法只需要顺序扫描一遍图像就可以了。如果你下载并运行了这个python代码,还可以控制它逐帧的进行查看。Python代码看起来有点长,但很多都是在处理做动画的问题,真正算法部分没多长,尤其是递归法。

这个并行流水线法的大致思路是这样的:一个像素点有8个相邻的点。上面3个,下面3个,左边1个,右边一个。当从左往右逐行扫描图像时,正在被扫描的这个点应该被标上什么标记,其实只和在它之前已经被扫描过的点,也就是它邻域中上面3个和左边1个这4个点有关。所以第一个要点就是,某个点该被标记什么标号,只和它前邻域的四个点有关,也就是左边,左上,正上,右上这四个点。那么这个算法其实就相当于用这样一个2x3的算子扫描图像,就能得到结果,只需缓存一行图像。接下来就是对邻域这4个点的情况进行判断来确定当前这个点该怎么标记。总共也就4个点,最多也就是16种情况,但实际上概括起来只有三大种情况:

  • 前邻域这4个点都是白点,说明这是一个新连通域的起始点,给它标上一个新的标号

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

三、4个点中有1、2、3或4个已标点,但它们的标号都是相同的,就把当前点标上这个标号。实际写代码时,把前面两种情况判断掉之后,剩下的就是这种情况,所以这个情况不需要写很多if判断,写个else就行了。

在实现上有一个要点就是,要用另外一个数组存放每个标号连通域的信息,在Verilog实现时会用另外一个RAM,老版算法中也是这么做的。当扫描到某个已标点时,要用它的标号去查这个连通域信息表里面存放的它的真实标号。因为存在标号合并的问题,之前标记的标号可能已经被并入了别的标号,这个改动只会出现在这个连通域信息列表中,不会出现在标记数组中,所以要先去查表获得真实标号再进行判断。这是关键一步。

还有一个关键是如何判断一个连通域是否已经全部扫描完成。完成时要输出这个连通域的信息结果。所以如果不知道一个连通域什么时候扫描完成,那这个算法就没有输出。这个算法判断一个连通域是否完成在它完成的那一行还判断不了。要到扫描下一行时查看上面已标点的信息时才能发现,具体如何判断的请参考代码。这个算法的逻辑是严格的,也就是它不会出错,如果大家不信可以拿它的结果和递归法的结果做对比,递归法很容易想明白它是严格不会出错的。

Python版的代码还是比较容易理解的。Verilog代码里,除了上述的逻辑判断代码之外,还多了一些处理Ram的读写和流水线寄存器数据一致性的代码。因为这个连通域识别算法和之前《FPGA图像处理基本技巧》这篇文章中提到的算子法是不一样的。算子法计算之后的数据不需要写回Ram,也不能写回。而连通域识别算法的结果是需要写回的,因为下一行的判断还需要上一行的结果。这需要写回处理起来就麻烦一些,对Ram的读写也和算子法中有所不同。还需要处理流水线寄存器数据一致性的问题。然后最关键的是,由于FPGA实现上的限制,这个Verilog版本的算法不能和前述的算法逻辑做到完全等价,也就是说有个地方它不能完全实现,这样有些特殊结构的连通域就会导致算法输出的统计结果会漏掉一些点。具体什么样的结构会导致问题大家可参考bug.bmp这个图片文件。但在实际应用中遇到奇怪形状的概率并不大,而且统计也只是会漏掉很少的一些点,所以基本并不影响使用。注意,不是会漏扫描标记一些点,只是统计的时候会在特殊情况下丢失掉一些点的数据。这比老版本的算法也算是有进步了,老版本的算法在遇到螺旋形时会直接视而不见,不会给出任何结果。这个算法不会出现视而不见的情况,只是会在特殊情况下可能漏报。

这个不等价的原因就是,Verilog在实现时实际上并没有实现用已标点的标号去查询到它的真实标号之后再去获取它真实信息,这样需要读两次RAM,RAM只有两个端口,都用来读数据了就没法再用来写回数据了。所以在扫描合并连通域的时候会把合并的结果也写入到被合并掉的标号中,但之后就不好再更新这个已经被合并掉的标号,如果之后这个被合并掉的标号又再出现了,就有可能会出现信息丢失,因为这个被合并掉的标号中的信息不是最新的。

大家研究算法,如果想成为高手,那就得靠自己多琢磨,不能光指望问别人。只有不断的思考,训练自己的思维能力,才能成为高手。别人都给你讲清楚了,你自己得到的训练就少了。所以俺也就只写这么多了,有兴趣研究算法的朋友最好是别看我写的代码,顶多了解个思路然后就去自己琢磨,自己写代码,这样才能真正得到提升。

2019.9.30后记:后来仔细琢磨了一下发现,上面所述的递归法和并行流水线法在形式上看起来很不一样,但实质上是一样的。所有我就又有一个感悟,那就是解决某一个问题的算法有时看起来有很多,但其实只有一个唯一正确的方法,很多方法看起来形式不同,但在本质上是相互等价的。如果你没看出来它们之间的等价性,那是因为你思考的还不够深入。

寻找连通域算法_FPGA实现的连通域识别算法升级相关推荐

  1. 车牌识别算法_易泊车牌识别算法助力智慧城市交通

    引 言 随着科学技术的进步,智慧化的出现让现在生活越来越美,智慧城市.智慧交通等,今天我们的PC端车牌识别,也成为了智慧城市,智慧交通的一份子. 江西山水光电,他们在做智慧城市,目前他们做的一款巡逻车 ...

  2. nlp 命名实体识别 算法_中文命名实体识别算法 Lattice LSTM

    中文命名实体识别 (NER) 算法按照输入的类型,可以大致分为 Character-based (字符) 和 Word-based (单词) 两种.这两种方法都存在一些缺陷,Character-bas ...

  3. 【车道识别】基于WOA-SVM算法的道路标志检测与识别算法的研究,通过MATLAB/FPGA实现

    1.软件版本 MATLAB2017b,Quartusii12.1 2.本算法理论知识 安装在车辆上的摄像机实际采集得到的图像,其往往存在噪声干扰,因此在进行道路标志检测之前,首先需要对图像进行预处理, ...

  4. 人脸识别算法原理过程详解

    本文为转载内容,由于找不到源作者链接,故特此说明. 人脸识别各算法详解 最近,由于工作需要,为了找到一款高效的人脸识别算法,对各种人脸识别算法都研究了一番,以下记录的是各算法的理论基础. 一.MTCN ...

  5. 轻松上手UAI-Train,拍拍贷人脸识别算法优化效率提升85.7%

    2019独角兽企业重金招聘Python工程师标准>>> "UAI-Train平台可以让我们方便地在短时内使用大量的GPU资源,用较低的成本训练海量的数据集,提高算法模型迭代 ...

  6. m基于CNN卷积网络和GEI步态能量图的步态识别算法MATLAB仿真,测试样本采用现实拍摄的场景进行测试,带GUI界面

    目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 目前关于步态识别算法研究主要有两种:基于模型的方法和非基于模型的方法.基于模型的步态识别方法优点在于 ...

  7. 基于模板匹配的车牌识别算法,输出数字和英文字母

    目录 一.理论基础 二.核心程序 三.仿真结论 一.理论基础 车牌识别是计算机视觉领域中的一个重要问题,其目的是从图像中自动识别出车辆的车牌信息.基于模板匹配的车牌识别算法是一种常见的方法,其基本思想 ...

  8. 寻找连通域算法_【车牌识别算法】

    车牌识别技术要求能够将运动中的汽车牌照从复杂背景中提取并识别出来,通过车牌提取.图像预处理.特征提取.车牌字符识别等技术,识别车辆牌号.颜色等信息. 目前车牌识别技术主要分为端到端识别与车牌分割识别两 ...

  9. matlab的车牌照识别,基于MatLab车牌号码识别算法研究与

    <基于MatLab车牌号码识别算法研究与>由会员分享,可在线阅读,更多相关<基于MatLab车牌号码识别算法研究与(15页珍藏版)>请在人人文库网上搜索. 1.基于,MatLa ...

最新文章

  1. 金融领域首个开源中文BERT预训练模型,熵简科技推出FinBERT 1.0
  2. 决策树是如何选择特征和分裂点?
  3. django-ckeditor表情包修改
  4. ajax保存乱码,Ajax 乱码详细
  5. (转)淘淘商城系列——使用maven tomcat插件启动web工程
  6. 年度旗舰机广告片遭电视台泄露 三星:我有句话不知当讲不当讲
  7. ionic使用ImagePicker插件中文显示
  8. python 识别子串的位置_Python基础语法小白这一篇就足够了!
  9. java8 metaspacesize_java-8 – Java8 MetaspaceSize标志不起作用
  10. 怎样从altera下载软件与器件库
  11. Deeping Learning学习与感悟——《深度学习工程师》_3
  12. python+jpype+linux出现内存溢出问题解决方案
  13. 总结 工作法(时间管理+复盘)
  14. 去掉 AD13 PCB网络连线中的双斜杠
  15. ae正在发生崩溃_本专业人才懂的梗 “pr未响应 ae正在发生崩溃”
  16. 记录一直以来看过的电视剧、电影及书籍
  17. 电容的参数-详细描述
  18. 传递关系的复合不一定是传递的
  19. Tableau技巧(五)帕累托分布(二八原则)
  20. Table was not locked with LOCK TABLES

热门文章

  1. java mongodb开发_Java Tutorial:Java操作MongoDB入门
  2. python三维图的坐标_用Python 画个六维图,涨姿势了
  3. 江西省一级计算机考试试题,2江西省计算机一级考试试题
  4. c语言与64位windows不兼容_微软发布可模拟 64 位 x86 程序的 ARM 版 Windows 10
  5. supervisor linux下进程管理工具
  6. discuz插件开发新手入门 超详细[转载]
  7. 关于sha1加密的一个问题。。。。
  8. MoCo不适用于目标检测?MSRA提出对象级对比学习的目标检测预训练方法SoCo!性能SOTA!(NeurIPS 2021)...
  9. 没有残差连接的ViT准确率只有0.15%!北大华为提出用于ViT的增强 Shortcuts,涨点显著!...
  10. 指纹识别开源竞赛启动,5000张指纹图像匹配