本文主要实现了改进Zhang Suen细化算法的C#实现,相关论文 :“牟少敏,杜海洋,苏平,查绪恒,陈光艺.一种改进的快速并行细化算法[J].微电子学与计算机,2013,(第1期)” 。这篇论文中关于Zhang Suen细化算法的描述,貌似存在问题。本文的算法中的意思是两次标记的点迭代后同时删除。而zhang快速算法,是分为两步删除边界点的。第一步迭代之后,已经做标记的点就需要删除了。如果两步可以放在一起删除的话,为什么不在一次迭代中将几个条件一起判断呢

一:Zhang-Suen细化算法介绍

Zhang-Suen细化算法通常是一个迭代算法,整个迭代过程分为两步:

Step One:循环所有前景像素点,对符合如下条件的像素点标记为删除:

1.      2 <= N(p1) <=6

2.      S(P1) = 1

3.      P2 * P4 * P6 = 0

4.      P4 * P6 * P8 = 0

其中N(p1)表示跟P1相邻的8个像素点中,为前景像素点的个数

S(P1)表示从P2 ~ P9 ~ P2像素中出现0~1的累计次数,其中0表示背景,1表示前景

完整的P1 ~P9的像素位置与举例如下:

其中 N(p1) = 4, S(P1) = 3, P2*P4*P6=0*0*0=0, P4*P6*P8=0*0*1=0, 不符合条件,无需标记为删除。

Step Two:跟Step One很类似,条件1、2完全一致,只是条件3、4稍微不同,满足如下条件的像素P1则标记为删除,条件如下:

1.      2 <= N(p1) <=6

2.      S(P1) = 1

3.      P2 * P4 * P8 = 0

4.      P2 * P6 * P8 = 0

循环上述两步骤,直到两步中都没有像素被标记为删除为止,输出的结果即为二值图像细化后的骨架。

二:代码实现步骤

        #region 改进 Zhang-Suen algorithm

        public Bitmap zhang_thinimage_improve(Bitmap bmp)
{
int imgWidth = bmp.Width;
int imgHeight = bmp.Height;
byte[,] BinaryArray = new byte[imgHeight, imgWidth];
int depth = Bitmap.GetPixelFormatSize(bmp.PixelFormat);
if (depth != )//判断位深度
{
int threshold = ;
BinaryArray = ToBinaryArray(bmp, out threshold);
}
else
{
BinaryArray = BinaryBitmapToBinaryArray(bmp);
}
int[] Zhangmude = new int[];
//int deletecount = 0;
List<Point> deletelist = new List<Point>();
while (true)
{
for (int y = ; y < imgHeight-; y++)
{
for (int x = ; x < imgWidth-; x++)
{
if (BinaryArray[y, x] == )
{
Zhangmude[] = ;
if (BinaryArray[y - , x] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y - , x + ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y, x + ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y + , x + ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y + , x] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y + , x - ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y, x - ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y - , x - ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
int whitepointtotal = ;
for (int k = ; k < ; k++)
{
//得到1的个数
whitepointtotal = whitepointtotal + Zhangmude[k];
}
if ((whitepointtotal >= ) && (whitepointtotal <= ))
{
//得到01的个数
int ap = ;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
//计算bp
int bp = ;
bp += Zhangmude[];
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
if (ap == || bp == || bp == || bp == || bp == || bp == || bp == || bp == || bp == || bp == || bp == )
{
if ((Zhangmude[] * Zhangmude[] * Zhangmude[] == ) && (Zhangmude[] * Zhangmude[] * Zhangmude[] == ))
{
deletelist.Add(new Point(y, x));
}
}
}
}
}
}
if (deletelist.Count() == ) break;
foreach (var deleteItem in deletelist)
{
BinaryArray[deleteItem.X, deleteItem.Y] = ;
}
deletelist.Clear();
for (int y = ; y < imgHeight-; y++)
{
for (int x = ; x < imgWidth-; x++)
{
if (BinaryArray[y, x] == )
{
Zhangmude[] = ;
if (BinaryArray[y - , x] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y - , x + ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y, x + ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y + , x + ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y + , x] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y + , x - ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y, x - ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
if (BinaryArray[y - , x - ] == ) Zhangmude[] = ;
else Zhangmude[] = ;
int whitepointtotal = ;
for (int k = ; k < ; k++)
{
//得到1的个数
whitepointtotal = whitepointtotal + Zhangmude[k];
}
if ((whitepointtotal >= ) && (whitepointtotal <= ))
{
//得到01的个数
int ap = ;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
if ((Zhangmude[] == ) && (Zhangmude[] == )) ap++;
//计算bp
int bp = ;
bp += Zhangmude[];
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
bp += Zhangmude[] << ;
if (ap == || bp == || bp == || bp == || bp == || bp == || bp == || bp == || bp == || bp == || bp == )
{
if ((Zhangmude[] * Zhangmude[] * Zhangmude[] == ) && (Zhangmude[] * Zhangmude[] * Zhangmude[] == ))
{
deletelist.Add(new Point(y, x));
}
}
}
}
}
}
if (deletelist.Count() == ) break;
foreach (var deleteItem in deletelist)
{
BinaryArray[deleteItem.X, deleteItem.Y] = ;
}
deletelist.Clear();
}
Bitmap dstBmp = BinaryArrayToBinaryBitmap(BinaryArray);
return dstBmp; } #endregion

还有一个问题需要注意,找到要删除的点之后不能立即删除,而是把找到的点做标记,等第一步全部遍历完之后才删除标记的点。同样第二步也是这样。

下面是实验结果:

  

本文借鉴了两篇博客,下面是原文地址:

https://blog.csdn.net/u011941438/article/details/54628836

https://blog.csdn.net/jia20003/article/details/52142992

改进Zhang Suen细化算法的C#实现的更多相关文章

  1. Win8 Metro(C#)数字图像处理--2.49Zhang二值图像细化算法

    原文:Win8 Metro(C#)数字图像处理--2.49Zhang二值图像细化算法  [函数名称]   二值图像细化算法      WriteableBitmap ThinningProcess ...

  2. SSE图像算法优化系列三十二:Zhang\Guo图像细化算法的C语言以及SIMD指令优化

    二值图像的细化算法也有很多种,比较有名的比如Hilditch细化.Rosenfeld细化.基于索引表的细化.还有Opencv自带的THINNING_ZHANGSUEN.THINNING_GUOHALL ...

  3. OpenCV学习(13) 细化算法(1)

    程序编码参考经典的细化或者骨架算法文章: T. Y. Zhang and C. Y. Suen, "A fast parallel algorithm for thinning digita ...

  4. OpenCV学习(14) 细化算法(2)

          前面一篇教程中,我们实现了Zhang的快速并行细化算法,从算法原理上,我们可以知道,算法是基于像素8邻域的形状来决定是否删除当前像素.还有很多与此算法相似的细化算法,只是判断的条件不一样. ...

  5. 手指静脉细化算法过程原理解析 以及python实现细化算法

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8672489.html 文中的一些图片以及思想很多都是参考https://www.cnblogs ...

  6. c++opencv中线条细化算法

    要达到的效果就是将线条尽量细化成单像素,按照论文上的Hilditch算法试了一下,发现效果不好,于是自己尝试着写了一下细化的算法,基本原理就是从上下左右四个方向向内收缩. 1.先是根据图片中的原则确定 ...

  7. OpenCV学习(18) 细化算法(6)

    本章我们在学习一下基于索引表的细化算法. 假设要处理的图像为二值图,前景值为1,背景值为0. 索引表细化算法使用下面的8邻域表示法: 一个像素的8邻域,我们可以用8位二进制表示,比如下面的8邻域,表示 ...

  8. OpenCV学习(17) 细化算法(5)

    本章我们看下Pavlidis细化算法,参考资料http://www.imageprocessingplace.com/downloads_V3/root_downloads/tutorials/con ...

  9. OpenCV学习(16) 细化算法(4)

    本章我们学习Rosenfeld细化算法,参考资料:http://yunpan.cn/QGRjHbkLBzCrn 在开始学习算法之前,我们先看下连通分量,以及4连通性,8连通性的概念: http://w ...

随机推荐

  1. C#面试题整理(带答案)

    1.维护数据库的完整性.一致性.你喜欢用触发器还是自写业务逻辑?为什么? 答:尽可能用约束(包括CHECK.主键.唯一键.外键.非空字段)实现,这种方式的效率最好:其次用触发器,这种方式可以保证无论何 ...

  2. koa2入门--02.koa2路由

    首先输入在项目文件下使用cmd,输入 npm install koa-router --save const koa = require('koa');//引入koa const Router = r ...

  3. 关于MySQL中查询大数据量的情况下分页limit的性能优化

    https://blog.csdn.net/weixin_37848710/article/details/80772725

  4. 2017.5.11 昨天晚上看fview直播坚果pro回放

      对话1 彭林: 我以前也是产品经理,身为产品经理,你有没有感觉我们做出过什么之前不被人接受的东西,但是我们却坚持做了,并且得到的反响非常好. 朱萧木: 没有吧,我们没有做颠覆用户认知或者三观的特别 ...

  5. python 找出字符串中出现次数最多的字母

    # 请大家找出s=”aabbccddxxxxffff”中 出现次数最多的字母 # 第一种方法,字典方式: s="aabbccddxxxxffff" count ={} for i ...

  6. Struts2 注释类型

    Struts 2 应用程序可以使用Java5注释作为替代XML和Java属性配置.这里是清单的不同的类别有关的最重要的注解: 命名空间注释(动作注释): @ Namespace注释允许在Action类 ...

  7. 24.configparser&hashlib

    转载:https://www.cnblogs.com/yuanchenqi/article/5732581.html configparser 来看一个好多软件的常见文档格式如下: [DEFAULT] ...

  8. 深入浅出 Viewport 设计原理

    Viewport 是 HTML5 针对移动端开发新增的一个 meta 属性, 它的作用是为同一网页在不同设备的呈现,提供响应式解决方案.这篇文章尝试通过循序渐进的方式,逐层探索 Viewport 的设 ...

  9. $CH5501$ 环路运输 环形$+$单调队列

    CH Description 在一条环形公路旁均匀地分布着N座仓库,编号为1~N,编号为 i 的仓库与编号为 j 的仓库之间的距离定义为 dist(i,j)=min⁡(|i-j|,N-|i-j|),也 ...

  10. Nginx 究竟如何处理事件?

    在了解了网络事件以及事件分发收集器以后,让我们来了解 Nginx 是怎么样处理事件的? Nginx 事件循环 当 Nginx 刚刚启动时,在等待事件部分,也就是打开了 80 或 443 端口,这个时候 ...