suzuki 轮廓跟踪算法原理


本文参考了以下文章:

·https://blog.csdn.net/yiqiudream/article/details/75702407 (代码解释)

·https://blog.csdn.net/yiqiudream/article/details/76864722 (论文翻译)

·https://wenku.baidu.com/view/6cb52ede360cba1aa811dad5.html(英文论文解释)

·https://blog.csdn.net/u013631121/article/details/80504032?utm_source=blogxgwz4(另一篇说明,还不错)

Suzuki轮廓跟踪算法

轮廓跟踪算法,顾名思义,就是通过顺序找出边缘点来跟踪边界的本文介绍经典的suzuki 轮廓跟踪算法,此算法也在opencv中有代码实现。

tesseract中,轮廓跟踪算法是建立在种子填充算法得到的二值图之上的,其目的为找到每个连通域的轮廓点,用Freeman链码表示;

下面主要介绍原理:

算法的正式描述

 

在此算法中,当我们说“the neighborhood”,我们指的是4-(8-)邻域,在4-(8-)连接的情况下。假设输入图像 F={fij}.设置最初的NBD=1(F的边框形成了一个特殊的孔边界,分配序列数1;NBD代表当前边界的序列数)。使用光栅扫描器扫描图像,对每一个满足fij≠0的像素点执行以下步骤。每当我们开始扫描新的一行,重置LNBD=1.

 

(1) 确定点边界类型(outer/hole),选择下面的一条:

a)如果 fi,j= 1 且 fi,j-1= 0 则确定像素(i,j)是一个外边界的跟踪起始点,NBD自增,并且 (i2, j2)<-(i, j-1)。

b)否则如果fi,j ≥ 1 且 fi,j+1 = 0,则确定像素(i,j)是一个孔边界的跟踪起始点,NBD自增,(i2, j2)<-(i, j+1) ,当fij>1的情况下,LNBD<-fij。

c)否则,go to (4).

 

(2) 根据最新找到的边界(newly found border)的类型以及带有序列号LNBD的边界(也就是,the last border met on the current row此处是重点,翻译过来就是:在当前行遇到的上一个NBD值,决定了父子轮廓树关系)的类型,决定当前边界的母边界,判断规则如表1.

  

(3) 从起始点 (i,j) 开始,跟踪已检测到的边界:这一步由以下步骤3.1到步骤3.5实现。下面配合实例进行说明:

输入的测试图片(外边界)。为了便于说明,我给边界的每个点标了一个序号,从1到40. 最上面一行最左边一列的那个像素标为1(i,j)=(1,1).

 

(3.1) 从点(i2, j2)开始,顺时针旋转查找点(i,j)的邻域,寻找一个非零点,第一个找到的非零点记做(i1, j1)。如果没有找到非零点,另fij = -NBD,转到(4)。

     

(3.2) (i2,j2)<- (i1,j1) 且 (i3, j3)<- (i, j)。

 

(3.3) 寻找范围在当前点(i3, j3)的邻域中,方向为逆时针方向,出发点为(i2, j2)的下一个元素,查找一个非零点并将第一个找到的非零点设为(i4, j4)。(译者注:比如点(i3, j3)的0方向的点是(i2, j2),则按逆时针方向转一格就到了点(i3, j3)的1方向的点,从这个1方向点开始查找非零点,找到了就设置为(i4, j4))。

(3.4) 根据下面的规则修改点(i3, j3)的NBDfi3,j3:

(a) 如果步骤(3.3)中检查到点(i3, j3+1)是一个0-pixel,则fi3, j3 <- NBD.

即达到了最右侧,也就是碰到两个像素点为10的情况,-NBD设置为负数,防止outer的边界作为hole的起始点,具体讨论参看论文)

(b) 如果步骤(3.3)中检查到点(i3, j3+1)不是一个0-pixel,且fi3, j3 = 1,则fi3, j3<- NBD.

(c) 否则,不要改变fi3, j3。

 

(3.5) 如果(i4, j4)= (i,j) 且 (i3,j3) = (i1, j1) (轮廓跟踪了一圈,回到了开始点),转到步骤(4);否则,(i2, j2)<- (i3, j3),(i3,j3)<-(i4,j4),且回到步骤(3.3)。

(4) 如果fi,j ≠ 1,则 LNBD <- | fi,j| 且 从点(i, j+1)重新开始扫描。当扫描器到达图片的右下角的点则算法终止。

 

(译者注:在这个算法中,(i3,j3)代表当前点,(i2,j2)代表当前点的上一个找到的点,(i4, j4)表示在当前点的邻域中最新找到的非零点。  当前点是不断变化的,这些点的名称是相对的。具体参考开头给出的博文。) 

******************************************************************************

附补充说明:

1.  关于以上步骤(3)的补充讨论。

1输入的测试图片。为了便于说明,我给边界的每个点标了一个序号,从1到40. 最上面一行最左边一列的那个像素标为1.   

边界扫描算法从左上角开始逐行扫描,当发现以下两种情况时,认为找到边界的起始点。(a)情况表示遇到了外边界;(b)情况表示遇到孔。所以对于测试图片,起始点就是第一行遇到的第一个非零像素点。

2)其中定义了几个指针,指向某个像素点。其中

i0: 指向 contour 的起始点。在轮廓跟踪过程中,该指针始终不变。对应上图中,自定义编号中的“1”。是轮廓的第一个像素点。在判断跟踪是否结束的时候用到它;

 

i1: 指向 contour 的最后一个点。在轮廓跟踪过程中,该指针始终不变。对应上图中,自定义编号中的“40”。在判断跟踪是否结束的时候用到它。值得注意的是,轮廓算法中首先找到起始点,紧接着就寻找这个点。找到这个点之后才开始寻找轮廓的第二个像素点;那i1按什么方向搜索呢?算法规定,如果该 contour 是一个 hole, 则从0方向开始;如果是外边界,则从4方向开始。如下图。用 do 循环在i0的邻居内寻找 i1

 

i3: 指向当前中心点。中心点的意思是,当发现某个像素点属于轮廓,则将该点看做中心点,在它的8邻域内寻找下一个轮廓点。在轮廓跟踪过程中,这个指针会随着中心点的改变而改变;

i4: 指向最新找到的非零点。以i3所指向的点为中心,在8邻域内寻找非零点,如果找到了,就用i4指向它。在轮廓跟踪过程中,这个指针会随时改变;

用三张图来表示,(a)图的状态:已经找到i0(第一个轮廓点) 和 i1(最后一个轮廓点), 并且找到了第2个轮廓点i3,此时i3作为中心点,在8邻域内找到了非零点,就是i4.  b)图的状态:经过某种判断标准,发现i4是新的轮廓点(即第3个轮廓点),让i3指向它(更新i3),该点作为当前中心点,在8邻域内寻找非零点,找到了,让i4指向它(更新i4)。 (c)图的状态:经过某种判断标准,发现i4是新的轮廓点(即第4个轮廓点),让i3指向它(更新i3),该点作为当前中心点,在8邻域内寻找非零点,如果找到则 让i4指向它(更新i4.

(a)  b) (c) 指针 i3i4 更新示意图。 

注释: Freeman链码保存的信息并不是点的坐标,而是初始点以及方向值,从第i个边界点到第 i+1 个边界点的移动方向。8个方向的定义在前面的表格中给出了。本例中边界共有40个像素点,那么就有39个方向值。

 

2.  挖掘出轮廓之间的层次关系。

由于边界的层次关系复杂,Suzuki的方法是,找到一个边界,就用一个唯一的数字nbd去标记,最后标记值相同的像素点属于同一个边界,不同边界之间的层次关系通过其标记值保存下来。

Nbd(number of border)就是这个标记值。为什么nbd是从2开始而不是1呢?因为Suzuki 的方法中,一幅二值图的最上一行,最下一行,最左一行和最右一行都被设置为0,因此,这幅图像的最外层就是一个 hole, 这个hole称之为 背景(background),而这最边上的两行两列组成的轮廓就是 一个孔边界,称之为frame.  这个 frame 就用1 来标注。其次其他边界从2开始标注。

 

一个轮廓的nbd标记值可以表示如下:

 

例子:

手推边界

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM