Hilditch 细化算法是经典的二值图像细化算法

合集下载

关于手写汉字切分方法的思考

关于手写汉字切分方法的思考
Tseng[11 ]的 文 章 中 提 到 了 一 种 笔 画 连 接 盒 ( Stroke Bounding Box) 的动态算法 。首先利用四方向法提取汉字 的横竖撇捺 ,并将其分长短笔画共得到八类 ,每一类笔画 都采用外接矩形描述 ,称为笔画连接盒 。将过长或不合理 的笔画分割开 ,最后利用基于识别的动态算法合并连接 盒 ,分割效果如图 3 所示 。文中提及 ,在由 50 个人手写的 900 个汉字和 100 个印刷体汉字的组成的样本测试中显 示 ,对于重叠或粘连字有 99 %的正确分割率 ,对粘连且重 叠的汉字为 96 % ,过分汉字为 95 %。
A Survey of Methods in Handwritten Chinese Character Segmentation
SHAO J ie ,CHEN G Yu
(Nanjing University of Aeronautics and Astronautics ,Nanjing 210016 , China)
竖直方向上可能存在多个笔画的问题 ,但对于粘连过紧密 的字符仍不能正确切分 (如图 2 所示) 。
3 基于汉字笔画结构的分割方法 虽然以上两类方法较好地解决了无粘连汉字的分割 ,
但粘连汉字的分割依然是困扰人们的难题 。汉字是由具 有一定排列规律的笔画组合而成的 ,通常情况下 ,使用以 识别为基础的判别规则可以将不属于同一汉字的笔画剔 出 ,以及区分粘连笔画和单一笔画 。因此 ,采用笔画提取 再合并的方法可以从另一个角度解决笔画粘连问题 。
图 3 笔画连接盒算法效果 另一种基于笔画的分割方法[12 ]通过黑游程跟踪法提 取笔画 ,笔画提取前计算了黑像素游程宽度 、字符的平均 宽度 (通过垂直投影法得到) 和高度 。首先从图像中寻找 到一条黑游程 ,作为笔画的开始 ,然后对该黑游程进行逐 行跟踪 ,在当前黑游程的下一行左右的一定范围内 ,找到 所有的黑游程 ,并根据已有的游程平均宽度和游程直线拟 合得到的笔画方向 ,确定归入该笔画的黑游程 ,并确定出 下一行的跟踪范围 ,直到找不到新的游程 ,跟踪结束 ,得到 一个笔画 。从图像中提取的笔画分别用外接矩形和凸包 描述 ,采用一定的算法合并 。在文中 ,由于分割对象是信 函地址 ,笔者将此方法作为预切分的手段 ,之后采用基于 识别的最优路径动态规划算法决定分割路径 。 基于笔画提取的分割方法在很大程度上依赖于笔画 的提取优劣程度 ,至今 ,笔画提取主要有 3 种方法 ,分别基 于二值图像 、细化图像和汉字轮廓 。基于二值图像的笔画 提取省略了对图像的进一步处理 ,所以分割时大多采用这 种笔画提取法 。然而 ,这种笔画提取的方法还没有达到很 高的水平 ,对于横不平竖不直的汉字提取效果不佳 。因 此 ,这种方法的分割正确率也受到限制 ,适用范围不够广 。 此外 ,笔画先提取后合并使算法过于复杂 ,将其作为垂直 投影后的细切分可以更简单省时 。

Hilditch 细化算法是经典的二值图像细化算法

Hilditch 细化算法是经典的二值图像细化算法

Hilditch 细化算法是经典的二值图像细化算法,然而,在网上却很难找到一个详细、正确的介绍和实现。

可以找到一辆个 Hilditch 算法的C实现,但缺乏注释,代码可读性也很差。

在期刊网上找到几篇论文,提及了Hilditch 算法,结果一篇说的罗哩罗嗦根本看不懂,另一篇说的说的易懂,却是错误的!拿来主义是行不通了,于是只好结合着这几个论文和代码,从头写 Hilditch 细化算法。

假设像素p的3×3邻域结构为:Hilditch 细化算法的步骤为:对图像从左向右从上向下迭代每个像素,是为一个迭代周期。

在每个迭代周期中,对于每一个像素p,如果它同时满足6个条件,则标记它。

在当前迭代周期结束时,则把所有标记的像素的值设为背景值。

如果某次迭代周期中不存在标记点(即满足6个条件的像素),则算法结束。

假设背景值为0,前景值为1,则:6个条件为:(I):p 为1,即p不是背景;(2):x1,x3,x5,x7不全部为1(否则把p标记删除,图像空心了);(3):x1-x8 中,至少有2个为1(若只有1个为1,则是线段的端点。

若没有为1的,则为孤立点);(4):p的8连通联结数为1;联结数指在像素p的3*3邻域中,和p连接的图形分量的个数:上图中,左图的4连通联结数是2,8连通联结数是1,而右图的4联通联结数和8联通联结数都是2。

4连通联结数计算公式是:8连通联结数计算公式是:其中,至于公式怎么来的就不管了,直接用就行了。

(5)假设x3已经标记删除,那么当x3为0时,p的8联通联结数为1;(6)假设x5已经标记删除,那么当x5为0时,p的8联通联结数为1。

======在程序中,我使用的是这样的邻域编码:为了方便计算联结数,以0作为前景,1作为背景。

程序如下(完整程序见:/svn/trunk/src/mon/UnmanagedI mage/ImageU8.cs):/// <summary>/// 计算八联结的联结数,计算公式为:/// (p6 - p6*p7*p0) + sigma(pk - pk*p(k+1)*p(k+2)), k = {0,2,4)/// </summary>/// <param name="list"></param>/// <returns></returns>private unsafe Int32 DetectConnectivity(Int32* list){Int32 count = list[6] - list[6] * list[7] * list[0];count += list[0] - list[0] * list[1] * list[2];count += list[2] - list[2] * list[3] * list[4];count += list[4] - list[4] * list[5] * list[6];return count;}private unsafe void FillNeighbors(Byte* p, Int32* list, Int32 width, Byte foreground = 255){// list 存储的是补集,即前景点为0,背景点为1,以方便联结数的计算list[0] = p[1] == foreground ? 0 : 1;list[1] = p[1 - width] == foreground ? 0 : 1;list[2] = p[-width] == foreground ? 0 : 1;list[3] = p[-1 - width] == foreground ? 0 : 1;list[4] = p[-1] == foreground ? 0 : 1;list[5] = p[-1 + width] == foreground ? 0 : 1;list[6] = p[width] == foreground ? 0 : 1;list[7] = p[1 + width] == foreground ? 0 : 1;}/// <summary>/// 使用 hilditch 算法进行细化/// </summary>public unsafe void Thinning(Byte foreground = 255){Byte* start = this.Start;Int32 width = this.Width;Int32 height = this.Height;Int32* list = stackalloc Int32[8];Byte background = (Byte)(255 - foreground);Int32 length = this.Length;using (ImageU8 mask = new ImageU8(this.Width, this.Height)) {mask.Fill(0);Boolean loop = true;while (loop == true){loop = false;for (Int32 r = 1; r < height - 1; r++){for (Int32 c = 1; c < width - 1; c++){Byte* p = start + r * width + c;// 条件1:p 必须是前景点if (*p != foreground) continue;// p3 p2 p1// p4 p p0// p5 p6 p7// list 存储的是补集,即前景点为0,背景点为1,以方便联结数的计算FillNeighbors(p, list, width, foreground);// 条件2:p0,p2,p4,p6 不皆为前景点if (list[0] == 0 && list[2] == 0 && list[4] == 0 && list[6] == 0)continue;// 条件3: p0~p7至少两个是前景点Int32 count = 0;for (int i = 0; i < 8; i++){count += list[i];}if (count > 6) continue;// 条件4:联结数等于1if (DetectConnectivity(list) != 1) continue;// 条件5: 假设p2已标记删除,则令p2为背景,不改变p的联结数 if (mask[r - 1, c] == 1){list[2] = 1;if (DetectConnectivity(list) != 1)continue;list[2] = 0;}// 条件6: 假设p4已标记删除,则令p4为背景,不改变p的联结数 if (mask[r, c - 1] == 1){list[4] = 1;if (DetectConnectivity(list) != 1)continue;}mask[r, c] = 1; // 标记删除loop = true;}}for (int i = 0; i < length; i++){if (mask[i] == 1){this[i] = background;}}}}}。

手写数字体自动识别技术的研究现状

手写数字体自动识别技术的研究现状

浙江万里学院学报2015年3月手写数字体自动识别技术的研究现状胡玲琳,张若男,李培年,王仁芳(浙江万里学院,浙江宁波315100)摘要:脱机手写数字体自动识别一直以来是图像处理与模式识别领域中的研究热点及具有较高的实用价值。

文章对手写数字体研究现状进行概述,着重分析了预处理中的二值化、细化等方法,对特征提取中较重要的统计特征和结构特征分别进行阐述,讨论了分类识别中BP 神经网络、支持向量机等关键技术的各种主流方法。

通过分析,以期使读者对手写数字体识别的进展有较全面的了解,并对未来的研发有切实的帮助。

关键词:手写数字识别;预处理;特征提取;分类识别中图分类号:TP391文献标识码:A 文章编号:1671-2250(2015)02-0072-07收稿日期:2015-01-15基金项目:浙江省科技计划项目(项目编号:2012C21004);浙江省大学生科技创新活动计划(新苗计划)(项目编号:2014R419028)。

作者简介:胡玲琳(1989-),女,浙江建德人,浙江万里学院计算机与信息学院物流工程研究生,研究方向:物流信息技术应用。

通信作者:王仁芳(1974-),男,河南南阳人,浙江万里学院计算机与信息学院教授,研究方向:数字几何处理。

236Vo1.23No.62010年11月November 2010Journal of Zhejiang Wanli University浙江万里学院学报第28卷第2期Vo1.28No.22015年3月March 2015手写数字体识别(Handwritten digits recognition )是光学字符识别技术(Optical Character Recogni -tion ,OCR )的一个分支,其目的是让计算机自动识别出纸张上的手写数字[1]。

近几十年来,国内外学者对识别技术中的各个环节进行了广泛深入的研究,可见手写数字识别问题具有重要的学术意义和实用价值。

细化算法研究

细化算法研究

论文中文摘要毕业设计说明书(论文)外文摘要1 绪论图像的细化是数字图像预处理中的重要的一个核心环节。

图像细化在图像分析和图像识别中如汉子识别、笔迹鉴别。

指纹分析中有着广泛的应用。

图像的细化主要有以下几个基本要求:(1)骨架图像必须保持原图像的曲线连通性。

(2)细化结果尽量是原图像的中心线。

(3)骨架保持原来图形的拓扑结构。

(4)保留曲线的端点。

(5)细化处理速度快。

(6)交叉部分中心线不畸变。

虽然现在人们对细化有着广泛的研究,细化算法的方法有很多。

然而大多数算法如Hilditch算法和Rosenfield算法存在着细化后图形畸变,断点过多,在复杂的情况下关键信息的缺失等问题。

基于上诉考虑,传统的细化算法已经无法满足如今的数字图像处理要求。

因此,需要提出新的一种算法,来解决相关问题。

1.1 相关定义1.1.1串行与并行从处理的过程来看,主要可以分为串行和并行两类,前者对图像中当前象素的处理依据其邻域内象素的即时化结果,即对某一元素进行检测,如果该点是可删除点,则立即删除,且不同的细化阶段采用不同的处理方法;后者对当前的象素处理依据该象素及其邻域内各象素的前一轮迭代处理的结果,至始至终采用相同的细化准则。

即全部检测完汉子图像边缘上的点后再删除可删除点。

1.1.2骨架对图像细化的过程实际上是求一图像骨架的过程。

骨架是二维二值目标的重要拓扑描述,它是指图像中央的骨架部分,是描述图像几何及拓扑性质的重要特征之一。

骨架形状描述的方法是Blum最先提出来的,他使用的是中轴的概念。

如果用一个形象的比喻来说明骨架的含义,那就是设想在t=0的时刻,讲目标的边界各处同时点燃,火焰以匀速向目标内部蔓延,当火焰的前沿相交时火焰熄灭,那么火焰熄灭点的集合就构成了中轴,也就是图像的骨架。

例如一个长方形的骨架是它的长方向上的中轴线,正方形的骨架是它的中心点,圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。

细化的目的就是在将图像的骨架提取出来的同时保持图像细小部分的连通性,特别是在文字识别,地质识别,工业零件识别或图像理解中,先对被处理的图像进行细化有助于突出形状特点和减少冗余信息量。

月球撞击坑分类检测研究

月球撞击坑分类检测研究

地理空间信息GEOSPATIAL INFORMATION2015年4月第13卷第2期Apr.,2015V ol.13,No.2doi:10.3969/j.issn.1672-4623.2015.02.收稿日期:2014-05-06。

项目来源:国家高技术研究发展计划资助项目(2010AA12202)。

月球撞击坑分类检测研究马新凡1,苗 放2,杨文晖3,孟庆凯3(1.成都理工大学 信息科学与技术学院,四川 成都 610059;2.成都理工大学 地球探测与信息技术教育部重点实验室,四川 成都 610059;3.成都理工大学 空间信息技术研究所,四川 成都 610059)摘 要:根据嫦娥二号采集的月球CCD 影像,基于分类检测的方法,对撞击坑进行识别检测研究。

针对简单撞击坑、撞击盆地和复杂撞击坑的不同形态特征和影像特征,采用不同的滤波和检测算子进行识别。

结果表明,对直径在1.5 km 以上且光照条件较好的简单撞击坑和撞击盆地识别效果较好;对于复杂撞击坑,由于其形态结构相对复杂,造成图像边缘特征不突出, 因此识别率相对较低,有待进一步改进。

关键词:撞击坑;撞击坑分类;边缘检测;月球中图分类号:P237.3 文献标志码:B 文章编号:1672-4623(2015)02-0036-03014月球撞击坑是月球表面最显著的特征[1,2]。

对撞击坑进行正确的识别和提取,可为研究月球现状和演化历史提供直接证据。

欧阳自远曾做了月表直径>4 km 的撞击坑分布密度和月表地质年龄的关系图;冯军华等结合梯度信息,利用嫦娥一号CCD 图像, 采用最小二乘法拟合边缘椭圆的方法实现对撞击坑的检测[3]。

目前对于月球撞击坑的检测方法都各有优势,但由于月球撞击坑大小形状和深度不仅与撞击体的大小、密度、结构、撞击速度和撞击角度有密切关系,还受被撞击体的引力场和被撞击体处的岩性影响。

要完成对撞击坑的检测,就必须对撞击坑有一个清晰的认识,对每一类撞击坑特征有明确了解和掌握,这样有利于更准确地检测边缘[4,5]。

二值图像的细化算法

二值图像的细化算法
值 图 像 的 细 化 的 分 析
首先 , 对二 值 图像 进 行 设 定 。这 里 假 定 二值 图像 以 白 色 为 底 , 化黑 色 部 分 , 给 出 的 黑 色 部 分 的 图像 为 连 通 细 且
以下 是 对 链 表 的遍 历 ( 中 的 边 界 点 、 通 点 的 判 断 , 其 连 都 留 到下 面 的算 法 中具 体 的介 绍 ) 在 一 轮 轮 的遍 历 中 , , 逐
我设 定 了一 些 不 同 的颜 色 值 , 作 不 同 情 况 的 判 断 。 而 一 以 轮需 作 两 次 的遍 历 。第 一 次 遍 历 判 断 是 否 为 边 界点 , 考 需
摘 要 : 二值 图像是只有黑 白两种颜 色的 图像 , 二值 图像 的细化是 讨论将一 个图像 中的 黑色部分沿着 它的 中心轴 线
将 其 细化 为一 个像 素 宽 的线 条 的处 理 过 程 , 细化 的 结 果 能基 本 保 留 图形 中 黑 色部 分 的拓 扑 结 构 。介 绍 了一 个 二 值 图 像 的 细化 算 法 , 想 是从 原 图像 的 边 界 逐 层 消 除 黑 色像 素 点 , 同 时 保 持 黑 色 部 分 的 连 通 性 , 到 最 后 得 到 细 化 结 思 但 直
0 引 言
在 计 算 机 领 域 , 像 处 理 的 问题 越来 越 成 为 重 要 的一 图
图像 区域 会 失 去 连 通性 , 体 判 断要 考 虑 该 点 的 8个 方 向 具 的像 素 的颜 色 值 。因 为 在 后 面 的 判 断 中有 两 个 黑 点 去 掉 后 , 色 图 像 区 域 是 否 会 失 去 连 通 性 的 , 们 在 此 定 义 使 黑 我
第 1R 第7 o 期 2 1年 7 01 月

一种简单高效的二值图像并行细化算法PABIT

一种简单高效的二值图像并行细化算法PABIT

扭曲变形的情况. 步骤 2 保形腐蚀 在标记完所有非骨架边缘点后, 如果一次性
删除, 部分区域会出现断点. 仔细分析其原因, 发 现在判断边缘点满足指定模板的时候, 忽略了一 种情况, 即: 当笔划周边都满足边缘点条件 (但不 满足图 4 模板) 时, 会删去所有的外围点, 导致笔 划与笔划的断裂, 如图 5 所示.
提出一种简单易行的二值图像并行细化算法pab该算法通过模板匹配的方式层层剥离原始图像的边缘像素使具有像素点宽度为偶数的笔划保留双像素的中心骨架使像素点宽度为奇数的笔划只保留单像素的中心骨架线最终在此准骨架的基础上通过进一步处理得到最后的笔划宽度为1的细化图案
第 28 卷 第 2 期 2004 年 4 月
© 1995-2006 Tsinghua Tongfang Optical Disc Co., Ltd. All rights reserved.
第 2 期
陈庆虎等: 一种简单高效的二值图像并行细化算法 PAB IT
·271·
个像素称为 P 的八邻域.
P3 P2 P1 P4 P P0
合图 4 中任何一模板, 则该点属于应被删除的边 缘点, 将其标记为 2; 如果是边缘点, 且图 4 中有 至少一个模板与之匹配, 则该点属于图形的端点
5) 若 P 为黑点且 P 0, P 2, P 4, P 6 中仅有一白 点, 称 P 为边缘点或轮廓点.
6) 若删除黑点 P 会破坏图形的连续性, 则称
图 4 保留模板
用数学语言描述上述思想如下: 设 f (P 0) f (P 7) 分 别 代 表 P 点 的 八 邻 域 的 像 素 值, 且
1 当像素为前景点时 f (P i) = 0 当像素为背景点时 (其中 i = 0, …, 7)

hilditch 细化算法 python

hilditch 细化算法 python

Hilditch细化算法是一种用于二值图像细化(或骨架化)的算法。

以下是一个简单的Python实现:
def hilditch(image):
# 获取图像的宽度和高度
width, height = image.shape
# 创建一个与原图大小相同的掩模,所有值初始化为1
mask = image.copy()
# 遍历原图像
for y in range(height):
for x in range(width):
# 如果当前像素是1,则进行细化操作
if image[x][y] == 1:
# 判断上下左右四个方向是否为0
if (x > 0 and image[x-1][y] == 0) or (x < width-1 and image[x+1][y] == 0):
mask[x][y] = 0
if (y > 0 and image[x][y-1] == 0) or (y < height-1 and image[x][y+1] == 0):
mask[x][y] = 0
# 返回细化后的图像
return mask
这个函数接受一个二值图像作为输入,并返回一个细化后的图像。

在函数中,我们首先创建一个与原图大小相同的掩模,并将所有值初始化为1。

然后,我们遍历原图像中的每个像素,如果当前像素是1,则检查其上下左右四个方向是否为0。

如果是,则将当前像素的值设置为0,表示该像素应该被细化掉。

最后,我们返回细化后的图像。

hilditch细化算法python

hilditch细化算法python

Hilditch细化算法是一种用于图像处理的算法,旨在对二值化图像进行细化处理,以消除图像中不必要的细节,从而得到更加清晰的边缘轮廓。

该算法在数字图像处理领域具有广泛的应用,可以帮助我们提取出图像中的有效信息,并且在计算机视觉、模式识别等领域有着重要的作用。

Hilditch细化算法的原理比较复杂,主要包括以下几个步骤:1. 定义细化算法的结构元素:Hilditch细化算法中使用了一个3x3的结构元素,该结构元素用于检测图像中的特定模式,并对其进行处理。

2. 识别图像中的特征点:在细化算法中,首先需要识别图像中的特征点,这些特征点通常指的是图像中的边缘像素点,通过对这些特征点进行分析和处理,可以实现对图像的细化处理。

3. 进行细化处理:一旦特征点被识别出来,就可以开始对图像进行细化处理。

这通常包括对结构元素进行滑动操作,利用结构元素与图像进行匹配,并根据预先设定的条件对结构元素进行处理,以使得图像的边缘轮廓更加清晰。

4. 迭代处理:细化算法通常需要进行多次迭代处理,直到图像中的所有特征点都被处理完毕,并且不再发生变化为止。

Hilditch细化算法虽然在图像处理中有着重要的作用,但是在实际应用中也存在一些问题和挑战。

算法本身的复杂性较高,需要较高的计算和存储资源;另外在处理过程中可能会出现一些误差和不确定性,这也需要我们在实际应用中做出一些改进和调整。

在Python中,我们可以利用一些开源的图像处理库来实现Hilditch 细化算法的功能,比如OpenCV、Pillow等。

这些库提供了丰富的API和功能,可以帮助我们实现图像的二值化处理、特征点的识别以及细化处理等操作。

Python本身具有简洁清晰的语法结构,也使得我们可以比较方便地编写和调试相关的算法代码。

以OpenCV为例,我们可以通过以下步骤来实现Hilditch细化算法:1. 导入OpenCV库:首先需要导入OpenCV库,并读取需要处理的图像数据。

opencv实现二值图像细化的算法

opencv实现二值图像细化的算法

opencv实现⼆值图像细化的算法opencv实现⼆值图像细化的算法细化算法通常和⾻骼化、⾻架化算法是相同的意思,也就是thin算法或者skeleton算法。

虽然很多图像处理的教材上不是这么写的,具体原因可以看这篇论⽂,Louisa Lam, Seong-Whan Lee, Ching Y. Suen,“Thinning Methodologies-A Comprehensive Survey ”,IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE, VOL. 14, NO. 9, SEPTEMBER 1992 ,总结了⼏乎所有92年以前的经典细化算法。

函数:void cvThin( IplImage* src, IplImage* dst, int iterations=1)功能:将IPL_DEPTH_8U型⼆值图像进⾏细化参数:src,原始IPL_DEPTH_8U型⼆值图像dst,⽬标存储空间,必须事先分配好,且和原图像⼤⼩类型⼀致iterations,迭代次数参考⽂献:T. Y. Zhang and C. Y. Suen, “A fast parallel algorithm for thinning digital patterns,” Comm. ACM, vol. 27, no. 3, pp. 236-239, 1984.void cvThin( IplImage* src, IplImage* dst, int iterations=1){CvSize size = cvGetSize(src);cvCopy(src, dst);int n = 0,i = 0,j = 0;for(n=0; n<iterations; n++){IplImage* t_image = cvCloneImage(dst);for(i=0; i<size.height; i++){for(j=0; j<size.width; j++){if(CV_IMAGE_ELEM(t_image,byte,i,j)==1){int ap=0;int p2 = (i==0)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j);int p3 = (i==0 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j+1);if (p2==0 && p3==1){ap++;}int p4 = (j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i,j+1);if(p3==0 && p4==1){ap++;}int p5 = (i==size.height-1 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j+1);if(p4==0 && p5==1){ap++;}int p6 = (i==size.height-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j);if(p5==0 && p6==1){ap++;}int p7 = (i==size.height-1 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j-1);if(p6==0 && p7==1){ap++;}int p8 = (j==0)?0:CV_IMAGE_ELEM(t_image,byte,i,j-1);if(p7==0 && p8==1){ap++;}int p9 = (i==0 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i-1,j-1);if(p8==0 && p9==1){ap++;}if(p9==0 && p2==1){ap++;}if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7){if(ap==1){if(!(p2 && p4 && p6)){if(!(p4 && p6 && p8)){CV_IMAGE_ELEM(dst,byte,i,j)=0;}}}}}}}cvReleaseImage(&t_image);t_image = cvCloneImage(dst);for(i=0; i<size.height; i++){for(int j=0; j<size.width; j++){if(CV_IMAGE_ELEM(t_image,byte,i,j)==1){int ap=0;int p2 = (i==0)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j);int p3 = (i==0 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j+1);if (p2==0 && p3==1){ap++;}int p4 = (j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i,j+1);if(p3==0 && p4==1){ap++;}int p5 = (i==size.height-1 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j+1);if(p4==0 && p5==1){ap++;}int p6 = (i==size.height-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j);if(p5==0 && p6==1){ap++;}int p7 = (i==size.height-1 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j-1); if(p6==0 && p7==1){ap++;}int p8 = (j==0)?0:CV_IMAGE_ELEM(t_image,byte,i,j-1);if(p7==0 && p8==1){ap++;}int p9 = (i==0 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i-1,j-1);if(p8==0 && p9==1){ap++;}if(p9==0 && p2==1){ap++;}if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7) {if(ap==1){if(p2*p4*p8==0){if(p2*p6*p8==0){CV_IMAGE_ELEM(dst, byte,i,j)=0;}}}}}}}cvReleaseImage(&t_image);}}//使⽤举例#include "cxcore.h"#include "cv.h"#include "highgui.h"int main(int argc, char* argv[]){if(argc!=2){return 0;}IplImage *pSrc = NULL,*pDst = NULL,*pTmp = NULL;//传⼊⼀个灰度图像pSrc = cvLoadImage(argv[1],CV_LOAD_IMAGE_GRAYSCALE);if(!pSrc){return 0;}pTmp = cvCloneImage(pSrc);pDst = cvCreateImage(cvGetSize(pSrc),pSrc->depth,pSrc->nChannels);cvZero(pDst);cvThreshold(pSrc,pTmp,128,1,CV_THRESH_BINARY_INV);//做⼆值处理,将图像转换成0,1格式 //cvSaveImage("c://Threshold.bmp",pTmp,0);cvThin(pTmp,pDst,8);//细化,通过修改iterations参数进⼀步细化cvNamedWindow("src",1);cvNamedWindow("dst",1);cvShowImage("src",pSrc);//将⼆值图像转换成灰度,以便显⽰int i = 0,j = 0;CvSize size = cvGetSize(pDst);for(i=0; i<size.height; i++){for(j=0; j<size.width; j++){if(CV_IMAGE_ELEM(pDst,uchar,i,j)==1){CV_IMAGE_ELEM(pDst,uchar,i,j) = 0;}else{CV_IMAGE_ELEM(pDst,uchar,i,j) = 255;}}}//cvSaveImage("c://thin.bmp",pDst);cvShowImage("dst",pDst);cvWaitKey(0);cvReleaseImage(&pSrc);cvReleaseImage(&pDst);cvReleaseImage(&pTmp);cvDestroyWindow("src");cvDestroyWindow("dst");return 0;}。

细化算法 (1)

细化算法 (1)

SPTA细化算法步骤

对右边界的点,就是符合图3(a)模板的p点,即 n4· p· n0=1的p点,若式(a)为0,则为安全点。 布尔表达式中相应像素为黑且未被标记的点的布 尔量为1,否则为0. 同理,对左、上、下边界点的表达式分别如上面 的式(2)、(3)、(4)。


n3
n2
n1
n4
p
n0
n5
Hilditch细化算法的优缺点 优点:细化算法效果好

缺点:运算量大,有一些分支、处理速度慢,在实际应用中难以满足实时处理 的要求。
SPTA细化算法
SPTA细化算法一般需要经过数轮相同的检查过程,每一轮都由2次扫描组 成,每次扫描检查图像的每个像素。扫描过程可以是逐行的,也可以是 逐列的。第一次扫描检查所有的左、右边缘点,如果是非安全点则被标 记;第二次扫描检查所有的上、下边缘点,如果是非安全点则被标记。 当结束一轮扫描后,没有一点被标记,则删除所有被标记的点,算法结 束,否则进入下一轮扫描。 算法: S0=n4(n5+n6+n2+n3)(n0+n1')(n4+n3') S4=n0(n1+n2+n6+n7)(n2+n3')(n6+n5') S2=n6(n7+n0+n4+n5)(n0+n1')(n4+n3') S6=n2(n3+n4+n0+n1)(n4+n5')(n0+n7')其中’‘'’=‘ ▔’
n6
n7
SPTA细化算法优缺点

SPTA细化算法 优点:它代表了笔划的中轴线且保持了连续性 缺点:它需要分四次扫描进行,速度较慢,而且SPTA也难于克服45度 交叉畸变的问题

图像细化算法 2

图像细化算法 2

图像细化算法一、细化算法简介图像细化(Image Thinning),一般指二值图像的骨架化(Image keletonization)的一种操作运算。

所谓的细化就是经过一层层的剥离,从原来的图中去掉一些点,但仍要保持原来的形状,直到得到图像的骨架。

骨架,可以理解为图象的中轴。

好的细化算法一定要满足:∙收敛性;∙保证细化后细线的连通性∙保持原图的基本形状∙减少笔画相交处的畸变∙细化结果是原图像的中心线∙细化的快速性和迭代次数少依据是否使用迭代运算可以分为两类:(1)非迭代算法一次即产生骨架,如基于距离变换的方法。

游程长度编码细化等。

(2)迭代算法即重复删除图像边缘满足一定条件的像素,最终得到单像素宽带骨架。

迭代方法依据其检查像素的方法又可以再分成①串行算法是否删除像素在每次迭代的执行中是固定顺序的,它不仅取决于前次迭代的结果,也取决于本次迭代中已处理过像素点分布情况.②并行算法像素点删除与否与像素值图像中的顺序无关,仅取决于前次迭代的结果二、本文所用算法我所采用的是Zhang并行快速细化算法,它的原理也很简单:我们对一副二值图像进行骨架提取,就是删除不需要的轮廓点,只保留其骨架点。

假设一个像素点,我们定义该点为p1,则它的八邻域点p2->p9位置如下图所示,该算法考虑p1点邻域的实际情况,以便决定是否删除p1点。

假设我们处理的为二值图像,背景为黑色,值为0,要细化的前景物体像素值为1。

算法的描述如下。

首先复制源图像到目地图像,然后建立一个临时图像,接着执行下面操作:1. 把目地图像复制给临时图像,对临时图像进行一次扫描,对于不为0的点,如果满足以下四个条件,则在目地图像中删除该点(就是设置该像素为0),这里p2,…,p9是对应位置的像素灰度值(其为1或者0)。

a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6大于等于2会保证p1点不是端点或孤立点,因为删除端点和孤立点是不合理的,小于等于6保证p1点是一个边界点,而不是一个内部点。

一种对文字图像细化的改进Hilditch算法研究

一种对文字图像细化的改进Hilditch算法研究


种对 文字 图像细化的改进 Hi i h算法研究 lt dc
贾 瑜, 饶建辉
( 汉工业学院 {’ 武 1 算机与信息 与工程 系 , 湖北 武 汉 4 0 2 ) 3 0 3
摘 要: 在分析和研 究了现有细化算 法的基础上 , 出了一种 实用有效的细化 算法。通过对 提 汉字、 字母 、 数字和不 同字体 的文字进行测试 , 表明该细化效果较好 , 并有一定的实用价值。 关键词 : 图像处理; 细化算法; 字符识别; i ih算法 Hl t dc 中图分 类 号 :T 9 . P3 1 4 文 献标 识码 :A
I 引 吾 , 近数十年来 , 签字 印章 、 手写体文字、 件和汽 证 车牌照的识别技术被 广泛地研究 。在这些研究 中, 人们发现 : 这些原始图像中 , 含有大量的对于识别无 用的信息 , 这些信息不利于图像特征的提取 , 而且还 加大 了图像识别过程 中的数 据量 , 增加 了计算机硬 件的负荷 , 影响了处理程序的执行效率。因此 , 人们 在积极研究一系列图像处理 的算法 , 用于图像识别 。 细化处理是在图像处理 中相 当重要和关键的一 环。细化处理的 目的是搜索 图像的骨架 , 去除图像 上多余的像素 , 从而在不改变 图像 主要特征 的前提 下, 减少图像的信息量。细化处理结果的好坏 , 直接
尸l 2 Pl 3 Pl l P2 Pl 0 Pl P9 Pg P2 4 P2 3
‘ l 其它 0
() 5 当满足 条件 n 为背 景像 素 n 并且 为 在 : :, 减 薄过程 中减 掉 的点 或是 图像 黑 点 , 或者 n… 为 减 薄过程 中减 掉 的点 或 是 图像 黑 点 时 , 为 b( :l 记 i ,
其中
() 尸 =∑ (一 i 1 a )

二值图像细化算法的比较与改进

二值图像细化算法的比较与改进

《资料法》分类号:TP 391.41二值图像细化算法的比较与改进3崔凤奎 王晓强 张丰收王永森(洛阳工学院)(洛阳市交通技校)摘要 本文在分析二值线图形的基本细化原理及目前流行的各种细化算法的基础上,提出一种以H ilditch 经典算法为基础并行与串行处理相结合的细化算法。

该算法大大提高了处理速度,满足工程图矢量识别系统对处理速度的要求。

关键词 细化算法 二值图像 图像处理3河南省自然科学基金资助项目崔凤奎:男,1957年生,副教授收稿日期:19972082280 前言线细化是处理线状二值图像的一种重要技术,在图形文字识别,图像数据压缩和线状目标自动跟踪等方面均有应用。

在工程图识别中,为了能快速准确地提取线信息,进行数据压缩和矢量化跟踪,构造一种快速有效的细化算法是非常重要的。

线细化,就是不断去除曲线上不影响连通性的轮廓像素,从而获得单位宽度的中心骨架的过程。

在这个过程中保留曲线的多重像素,直到目标曲线所有点都是多重像素点为止。

对细化的一般要求是[1]:(1)保证细化后曲线的连通性;(2)保留原图的细节特征;(3)细化结果是原曲线的中心线;(4)保留曲线的端点;(5)细化处理速度快;(6)交叉部分中心线不畸变。

针对各种不同的应用,国内外已发表了许多线细化算法,如经典细化算法[2],D eu tsch 算法[3],Pavlidis 异步细化算法[3],Zhang 快速并行细化算法[3]等,本文在分析不同算法处理速度和效果的特点后,以H ilditch 经典细化算法为基础,同时考虑到工程图上各种线存在端点和交叉等复杂情况而提出一种新算法。

经实际应用及对比分析表明:此细化算法具有很好的细化效果和较快的处理速度。

1 基本知识1.1 八邻域及像素代号如图1所示,与图像中任一像素P 相邻的8个像素称为P 的八邻域,用P k 表示(0≤P k ≤7),P k 称为k -近邻。

P 0,P 2,P 4,P 6称为点P 的4-邻点,P 0,P 1,…P 7称为点P 的8-邻点。

C#图像细化:Hilditch细化算法

C#图像细化:Hilditch细化算法

技术专栏专注成就专业,兴趣成就事业C#图像细化:Hilditch细化算法分类: C#开发 2012-04-09 10:55 681人阅读 评论(0) 收藏举报算法c#input图形网络2010上理论:Hilditch 细化算法的步骤为:对图像从左向右从上向下迭代每个像素,是为一个迭代周期。

在每个迭代周期中,对于每一个像素p,如果它同时满足6个条件,则标记它。

在当前迭代周期结束时,则把所有标记的像素的值设为背景值。

如果某次迭代周期中不存在标记点(即满足6个条件的像素),则算法结束。

假设背景值为0,前景值为1,则:6个条件为:(I):p 为1,即p不是背景;(2):x1,x3,x5,x7不全部为1(否则把p标记删除,图像空心了);(3):x1~x8 中,至少有2个为1(若只有1个为1,则是线段的端点。

若没有为1的,则为孤立点);(4):p的8连通联结数为1;联结数指在像素p的3*3邻域中,和p连接的图形分量的个数:(5)假设x3已经标记删除,那么当x3为0时,p的8联通联结数为1;(6)假设x5已经标记删除,那么当x5为0时,p的8联通联结数为1。

以上的理论选择网络博客:/xiaotie/archive/2010/08/12/1797760.html (此博客上有C#版本的Hilditch细化算法,但是使用unsafe的代码不是太好理解的。

我上一个自己写的代码/// <summary>/// Hilditch细化算法/// </summary>/// <param name="input"></param>/// <returns></returns>private int[,] ThinnerHilditch(int[,] input){int lWidth = input.GetLength(0);int lHeight = input.GetLength(1);bool IsModified = true;int Counter = 1;int[] nnb = new int[9];//去掉边框像素for (int i = 0; i < lWidth; i++){input[i, 0] = 0;input[i, lHeight - 1] = 0;}for (int j = 0; j < lHeight; j++){input[0, j] = 0;input[lWidth - 1, j] = 0;}do{Counter++;IsModified = false;int[,] nb = new int[3, 3];for (int i = 1; i < lWidth; i++){for (int j = 1; j < lHeight; j++){//条件1必须为黑点if (input[i, j] != 1){continue;}//取3*3领域for (int m = 0; m < 3; m++){for (int n = 0; n < 3; n++){nb[m, n] = input[i - 1 + m, j - 1 + n];}}//复制nnb[0] = nb[2, 1]==1?0:1;nnb[1] = nb[2, 0]==1?0:1;nnb[2] = nb[1, 0]==1?0:1;nnb[3] = nb[0, 0]==1?0:1;nnb[4] = nb[0, 1]==1?0:1;nnb[5] = nb[0, 2]==1?0:1;nnb[6] = nb[1, 2]==1?0:1;nnb[7] = nb[2, 2]==1?0:1;// 条件2:p0,p2,p4,p6 不皆为前景点if (nnb[0] == 0 && nnb[2] == 0 && nnb[4] == 0 && nnb[6] == 0) {continue;}// 条件3: p0~p7至少两个是前景点int iCount = 0;for (int ii = 0; ii < 8; ii++){iCount += nnb[ii];}if (iCount > 6) continue;// 条件4:联结数等于1if (DetectConnectivity(nnb) != 1){continue;}// 条件5: 假设p2已标记删除,则令p2为背景,不改变p的联结数if (input[i, j - 1] == -1){nnb[2] = 1;if (DetectConnectivity(nnb) != 1)continue;nnb[2] = 0;}// 条件6: 假设p4已标记删除,则令p4为背景,不改变p的联结数if (input[i, j + 1] == -1){nnb[6] = 1;if (DetectConnectivity(nnb) != 1) continue;nnb[6] = 0;}input[i, j] = -1;IsModified = true;}}for (int i = 0; i < lWidth; i++){for (int j = 0; j < lHeight; j++){if (input[i, j] == -1){input[i, j] = 0;}}}} while (IsModified);return input;}希望对大家有用。

基于图像识别的CAD前处理技术

基于图像识别的CAD前处理技术
产业与科技论坛 2012 年第 11 卷第 6 期
基于图像识别的 CAD 前处理技术研究
□罗 姜
【摘 要】本文着重探讨基于图像识别的 CAD 前处理技术和方法,具体包含图像预处理技术和图像矢量化技术,对其中的关键 技术如图像平滑、图像二值化、位图图像转换为矢量图形,Hilditch 算法和 Deutsch 算法做了具体的比较和分析,同时 还基于 INC( Integrated / Intelligent Numerical Control) 中应用对象 2. 5D 的经济型数控机床( 如切割或钻铣机床) 做了具 体的应用方案比较分析。
( 三) 图像识别在 INC 中的应用。INC 是一种基于对制 造过程各个子过程和与企业生产的灰色关联度分析并对其 进行精简化和快捷化,提炼出与制造密切相关的子过程作为 INC 的工作模块,搭建出一种小而精的数字控制平台。针对 不同的对象采用不同的算法,整个图像预处理技术在 INC 中 的应用流程如图 3 所示,左边虚线框即为预处理技术和矢量 化技术在 INC 中的步骤与所在阶段及位置。下面讨论矢量 化技术与方法。
基元; 二是分割优先的方法,即先抽取基元之间的分界点,然 后再逐一用矢量基元来进行拟合。
1. 恢复优先方法。恢复优先的方法可以分为几个步骤 来进行图
细化或中 心线提取
骨 架 线
多边形或折 线断逼近
低 级


图元识别
高 级


图 1 恢复优先法流程图
2. 分割优先方法。分割优先方法主要分以下几个步骤 来进行,一般处理流程如图 2 所示:
【关键词】图像识别; CAD; 矢量化 【作者简介】罗姜( 1979 ~ ) ,女,绵阳职业技术学院助教; 研究方向: 机械控制工程

图像细化

图像细化

细化图像细化(Image Thinning),一般指二值图像的骨架化(Image Skeletonization)的一种操作运算。

所谓的细化就是经过一层层的剥离,从原来的图中去掉一些点,但仍要保持原来的形状,直到得到图像的骨架。

骨架,可以理解为图象的中轴。

好的细化算法一定要满足:收敛性;保证细化后细线的连通性保持原图的基本形状减少笔画相交处的畸变细化结果是原图像的中心线细化的快速性和迭代次数少依据是否使用迭代运算可以分为两类:非迭代算法一次即产生骨架,如基于距离变换的方法。

游程长度编码细化等。

迭代算法即重复删除图像边缘满足一定条件的像素,最终得到单像素宽带骨架。

迭代方法依据其检查像素的方法又可以再分成串行算法是否删除像素在每次迭代的执行中是固定顺序的,它不仅取决于前次迭代的结果,也取决于本次迭代中已处理过像素点分布情况.并行算法像素点删除与否与像素值图像中的顺序无关,仅取决于前次迭代的结果细化算法:Burning Algorithm使用迭代的方法去除图像的边界, 可使用扫描线法来获取边界Zhang并行快速细化算法模板:p3 p2 p9p4 p1 p8p5 p6 p7(其中p1为黑点,如果以下四个条件同时满足,则删除p1,即令p1=0)1. Z0(p1)=1 // 中心为黑点2. 2<=NZ(p1)<=6 // Nz为八邻域中黑点的数目3. p2*p4*p8=0 或者 Z0(p2)!=1 // 避免图像被打断( 其反条件时不可删)4. p2*p4*p6=0 或者 Z0(p4)!=1对图像中的每一个点重复这一步骤,直到所有的点都不可删除为止。

判断一个点是否能去掉, 要根据它的八个相邻点的情况来判断。

(中间的点)(1)不能删,因为它是个内部点,我们要求的是骨架,如果连内部点也删了,骨架也会被掏空的;(2)不能删,和(1)是同样的道理;(3)可以删,这样的点不是骨架;(4)不能删,因为删掉后,原来相连的部分断开了;(5)可以删,这样的点不是骨架;(6)不能删,因为它是直线的端点,如果这样的点删了,那么最后整个直线也被删了,剩不下什么;总结:(1)内部点不能删除;(2)孤立点不能删除;(3)直线端点不能删除;(4)如果P是边界点,去掉P后,如果连通分量不增加,则P可以删除。

图像的细化

图像的细化

图像的细化主要是针对二值图而言所谓骨架,可以理解为图像的中轴,,一个长方形的骨架,是它的长方向上的中轴线,圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。

骨架的获取主要有两种方法:(1)基于烈火模拟设想在同一时刻,将目标的边缘线都点燃,火的前沿以匀速向内部蔓延,当前沿相交时火焰熄灭,火焰熄灭点的结合就是骨架。

(2)基于最大圆盘目标的骨架是由目标内所有内切圆盘的圆心组成我们来看看典型的图形的骨架(用粗线表示)细化的算法有很多种,但比较常用的算法是查表法细化是从原来的图中去掉一些点,但仍要保持原来的形状。

实际上是保持原图的骨架。

判断一个点是否能去掉是以8个相邻点(八连通)的情况来作为判据的,具体判据为:1,内部点不能删除2,鼓励点不能删除3,直线端点不能删除4,如果P是边界点,去掉P后,如果连通分量不增加,则P可删除看看上面那些点。

第一个点不能去除,因为它是内部点第二个点不能去除,它也是内部点第三个点不能去除,删除后会使原来相连的部分断开第四个点可以去除,这个点不是骨架第五个点不可以去除,它是直线的端点第六个点不可以去除,它是直线的端点对于所有的这样的点,我们可以做出一张表,来判断这样的点能不能删除我们对于黑色的像素点,对于它周围的8个点,我们赋予不同的价值,若周围某黑色,我们认为其价值为0,为白色则取九宫格中对应的价值对于前面那幅图中第一个点,也就是内部点,它周围的点都是黑色,所以他的总价值是0,对应于索引表的第一项前面那幅图中第二点,它周围有三个白色点,它的总价值为1+4+32=37,对应于索引表中第三十八项1.图像细化的基本原理⑴ 图像形态学处理的概念数字图像处理中的形态学处理是指将数字形态学作为工具从图像中提取对于表达和描绘区域形状有用处的图像分量,比如边界、骨架以及凸壳,还包括用于预处理或后处理的形态学过滤、细化和修剪等。

图像形态学处理中我们感兴趣的主要是二值图像。

在二值图像中,所有黑色像素的集合是图像完整的形态学描述,二值图像的各个分量是Z2的元素。

Hilditch、Pavlidis、Rosenfeld细化算法

Hilditch、Pavlidis、Rosenfeld细化算法

//************************************************************************** //Thinner.cpp//细化算法实现文件//************************************************************************** #include "StdAfx.h"#include <stdlib.h>#include <malloc.h>#include "Thinner.h"void beforethin(unsigned char *ip, unsigned char *jp,unsigned long lx, unsigned long ly){unsigned long i,j;for(i=0; i<ly; i++){for(j=0; j<lx; j++){//这里要视前景是白点还是黑点而定,可以改动//如果前景是白点,就是这样;反之反过来if(ip[i*lx+j]>0)jp[i*lx+j]=1;elsejp[i*lx+j]=0;}}}///////////////////////////////////////////////////////////////////////////Hilditch细化算法//功能:对图象进行细化//参数:image:代表图象的一维数组// lx:图象宽度// ly:图象高度// 无返回值void ThinnerHilditch(void *image, unsigned long lx, unsigned long ly) {char *f, *g;char n[10];unsigned int counter;short k, shori, xx, nrn;unsigned long i, j;long kk, kk11, kk12, kk13, kk21, kk22, kk23, kk31, kk32, kk33, size;size = (long)lx * (long)ly;g = (char *)malloc(size);if(g == NULL){printf("error in allocating memory!\n");return;}f = (char *)image;for(i=0; i<lx; i++){for(j=0; j<ly; j++){kk=i*ly+j;if(f[kk]!=0){f[kk]=1;g[kk]=f[kk];}}}counter = 1;do{printf("%4d*",counter);counter++;shori = 0;for(i=0; i<lx; i++){for(j=0; j<ly; j++){kk = i*ly+j;if(f[kk]<0)f[kk] = 0;g[kk]= f[kk];}}for(i=1; i<lx-1; i++){for(j=1; j<ly-1; j++){kk=i*ly+j;if(f[kk]!=1)continue;kk11 = (i-1)*ly+j-1;kk12 = kk11 + 1;kk13 = kk12 + 1;kk21 = i*ly+j-1;kk22 = kk21 + 1;kk23 = kk22 + 1;kk31 = (i+1)*ly+j-1;kk32 = kk31 + 1;kk33 = kk32 + 1;if((g[kk12]&&g[kk21]&&g[kk23]&&g[kk32])!=0) continue;nrn = g[kk11] + g[kk12] + g[kk13] + g[kk21] + g[kk23] + g[kk31] + g[kk32] + g[kk33];if(nrn <= 1){f[kk22] = 2;continue;}n[4] = f[kk11];n[3] = f[kk12];n[2] = f[kk13];n[5] = f[kk21];n[1] = f[kk23];n[6] = f[kk31];n[7] = f[kk32];n[8] = f[kk33];n[9] = n[1];xx = 0;for(k=1; k<8; k=k+2){if((!n[k])&&(n[k+1]||n[k+2]))xx++;}if(xx!=1){f[kk22] = 2;continue;}if(f[kk12] == -1){f[kk12] = 0;n[3] = 0;xx = 0;for(k=1; k<8; k=k+2){if((!n[k])&&(n[k+1]||n[k+2]))xx++;}if(xx != 1){f[kk12] = -1;continue;f[kk12] = -1;n[3] = -1;}if(f[kk21]!=-1){f[kk22] = -1;shori = 1;continue;}f[kk21] = 0;n[5] = 0;xx = 0;for(k=1; k<8; k=k+2){if((!n[k])&&(n[k+1]||n[k+2])){xx++;}if(xx == 1){f[kk21] = -1;f[kk22] = -1;shori =1;}elsef[kk21] = -1;}}}while(shori);free(g);}///////////////////////////////////////////////////////////////////////// //Pavlidis细化算法//功能:对图象进行细化//参数:image:代表图象的一维数组// lx:图象宽度// ly:图象高度// 无返回值void ThinnerPavlidis(void *image, unsigned long lx, unsigned long ly) {char erase, n[8];char *f;unsigned char bdr1,bdr2,bdr4,bdr5;short c,k,b;unsigned long i,j;long kk,kk1,kk2,kk3;f = (char*)image;for(i=1; i<lx-1; i++){for(j=1; j<ly-1; j++){kk = i*ly + j;if(f[kk])f[kk] = 1;}}for(i=0, kk1=0, kk2=ly-1; i<lx; i++, kk1+=ly, kk2+=ly) {f[kk1]=0;f[kk2]=0;}for(j=0, kk=(lx-1)*ly; j<ly; j++,kk++){f[j]=0;f[kk]=0;}c=5;erase =1;while(erase){c++;for(i=1; i<lx-1; i++){for(j=1; j<ly-1; j++){kk=i*ly+j;if(f[kk]!=1)continue;kk1 = kk-ly -1; kk2 = kk1 + 1; kk3 = kk2 + 1; n[3] = f[kk1];n[2] = f[kk2];n[1] = f[kk3];kk1 = kk - 1;kk3 = kk + 1;n[4] = f[kk1];n[0] = f[kk3];kk1 = kk + ly -1; kk2 = kk1 + 1; kk3 = kk2 + 1; n[5] = f[kk1];n[6] = f[kk2];n[7] = f[kk3]; bdr1 =0;for(k=0; k<8; k++){if(n[k]>=1)bdr1|=0x80>>k;}if((bdr1&0252)== 0252)continue;f[kk] = 2;b=0;for(k=0; k<=7; k++){b+=bdr1&(0x80>>k);}if(b<=1)f[kk]=3;if((bdr1&0160)!=0&&(bdr1&07)!=0&&(bdr1&0210)==0) f[kk]=3;else if((bdr1&&0301)!=0&&(bdr1&034)!=0&&(bdr1&042)==0)else if((bdr1&0202)==0 && (bdr1&01)!=0)f[kk]=3;else if((bdr1&0240)==0 && (bdr1&0100)!=0)f[kk]=3;else if((bdr1&050)==0 && (bdr1&020)!=0)f[kk]=3;else if((bdr1&012)==0 && (bdr1&04)!=0)f[kk]=3;}}for(i=1; i<lx-1; i++){for(j=1; j<ly-1; j++){kk = i*ly + j;if(!f[kk])continue;kk1 = kk - ly -1;kk2 = kk1 + 1;n[3] = f[kk1];n[2] = f[kk2];n[1] = f[kk3];kk1 = kk - 1;kk2 = kk + 1;n[4] = f[kk1];n[0] = f[kk3];kk1 = kk + ly -1;kk2 = kk1 + 1;kk3 = kk2 + 1;n[5] = f[kk1];n[6] = f[kk2];n[7] = f[kk3];bdr1 = bdr2 =0;for(k=0; k<=7; k++){if(n[k]>=1)bdr1|=0x80>>k;if(n[k]>=2)bdr2|=0x80>>k;}if(bdr1==bdr2){f[kk] = 4;continue;}if(f[kk]!=2)continue;if((bdr2&0200)!=0 && (bdr1&010)==0 && ((bdr1&0100)!=0 &&(bdr1&001)!=0 ||((bdr1&0100)!=0 ||(bdr1 & 001)!=0) &&(bdr1&060)!=0 &&(bdr1&06)!=0)){f[kk] = 4;}else if((bdr2&040)!=0 && (bdr1&02)==0 && ((bdr1&020)!=0 && (bdr1&0100)!=0 ||((bdr1&020)!=0 || (bdr1&0100)!=0) &&(bdr1&014)!=0 && (bdr1&0201)!=0)){f[kk] = 4;}else if((bdr2&010)!=0 && (bdr1&0200)==0 && ((bdr1&04)!=0 && (bdr1&020)!=0 ||((bdr1&04)!=0 || (bdr1&020)!=0) &&(bdr1&03)!=0 && (bdr1&0140)!=0)){f[kk] = 4;}else if((bdr2&02)!=0 && (bdr1&040)==0 &&((bdr1&01)!=0 && (bdr1&04)!=0 ||((bdr1&01)!=0 || (bdr1&04)!=0) &&(bdr1&0300)!=0 && (bdr1&030)!=0)){f[kk] = 4;}}}for(i=1; i<lx-1; i++){for(j=1; j<ly-1; j++){kk = i*ly + j;if(f[kk]!=2)continue;kk1 = kk - ly -1;kk2 = kk1 + 1;kk3 = kk2 + 1;n[3] = f[kk1];n[2] = f[kk2];n[1] = f[kk3];kk1 = kk - 1;kk2 = kk + 1;n[4] = f[kk1];n[0] = f[kk3];kk1 = kk + ly -1;kk2 = kk1 + 1;kk3 = kk2 + 1;n[5] = f[kk1];n[6] = f[kk2];n[7] = f[kk3];bdr4 = bdr5 =0;for(k=0; k<=7; k++){if(n[k]>=4)bdr4|=0x80>>k;if(n[k]>=5)bdr5|=0x80>>k;}if((bdr4&010) == 0){f[kk] = 5;continue;}if((bdr4&040) == 0 && bdr5 ==0) {f[kk] = 5;continue;}if(f[kk]==3||f[kk]==4)f[kk] = c;}}erase = 0;for(i=1; i<lx-1; i++){for(j=1; j<ly-1; j++){kk = i*ly +j;if(f[kk]==2||f[kk] == 5){erase = 1;f[kk] = 0;}}}}}///////////////////////////////////////////////////////////////////////// //Rosenfeld细化算法//功能:对图象进行细化//参数:image:代表图象的一维数组// lx:图象宽度// ly:图象高度// 无返回值void ThinnerRosenfeld(void *image, unsigned long lx, unsigned long ly) {char *f, *g;char n[10];char a[5] = {0, -1, 1, 0, 0};char b[5] = {0, 0, 0, 1, -1};char nrnd, cond, n48, n26, n24, n46, n68, n82, n123, n345, n567, n781;short k, shori;unsigned long i, j;long ii, jj, kk, kk1, kk2, kk3, size;size = (long)lx * (long)ly;g = (char *)malloc(size);if(g==NULL){printf("error in alocating mmeory!\n");return;}f = (char *)image;for(kk=0l; kk<size; kk++){g[kk] = f[kk];}do{shori = 0;for(k=1; k<=4; k++){for(i=1; i<lx-1; i++){ii = i + a[k];for(j=1; j<ly-1; j++){kk = i*ly + j;if(!f[kk])continue;jj = j + b[k];kk1 = ii*ly + jj;if(f[kk1])continue;kk1 = kk - ly -1; kk2 = kk1 + 1; kk3 = kk2 + 1; n[3] = f[kk1];n[2] = f[kk2];n[1] = f[kk3];kk1 = kk - 1;kk3 = kk + 1;n[4] = f[kk1];n[8] = f[kk3];kk1 = kk + ly - 1; kk2 = kk1 + 1; kk3 = kk2 + 1; n[5] = f[kk1];n[6] = f[kk2];n[7] = f[kk3];nrnd = n[1] + n[2] + n[3] + n[4]+n[5] + n[6] + n[7] + n[8];if(nrnd<=1)continue;cond = 0;n48 = n[4] + n[8];n26 = n[2] + n[6];n24 = n[2] + n[4];n46 = n[4] + n[6];n68 = n[6] + n[8];n82 = n[8] + n[2];n123 = n[1] + n[2] + n[3];n345 = n[3] + n[4] + n[5];n567 = n[5] + n[6] + n[7];n781 = n[7] + n[8] + n[1];if(n[2]==1 && n48==0 && n567>0) {if(!cond)continue;g[kk] = 0;shori = 1;continue;}if(n[6]==1 && n48==0 && n123>0) {if(!cond)continue;g[kk] = 0;shori = 1;continue;}if(n[8]==1 && n26==0 && n345>0) {if(!cond)continue;g[kk] = 0;shori = 1;continue;}if(n[4]==1 && n26==0 && n781>0) {if(!cond)continue;g[kk] = 0;shori = 1;continue;}if(n[5]==1 && n46==0){if(!cond)continue;g[kk] = 0;shori = 1;continue;}if(n[7]==1 && n68==0){continue;g[kk] = 0;shori = 1;continue;}if(n[1]==1 && n82==0) {if(!cond)continue;g[kk] = 0;shori = 1;continue;}if(n[3]==1 && n24==0) {if(!cond)continue;g[kk] = 0;shori = 1;}cond = 1;if(!cond)continue;g[kk] = 0;shori = 1;}}for(i=0; i<lx; i++){for(j=0; j<ly; j++){kk = i*ly + j;f[kk] = g[kk];}}}}while(shori);free(g);}///////////////////////////////////////////////////////////////////////////基于索引表的细化细化算法//功能:对图象进行细化//参数:lpDIBBits:代表图象的一维数组// lWidth:图象高度// lHeight:图象宽度// 无返回值BOOL WINAPI ThiningDIBSkeleton (LPSTR lpDIBBits, LONG lWidth, LONG lHeight) {//循环变量long i;long j;long lLength;unsigned char deletemark[256] = {0,0,0,0,0,0,0,1, 0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0, 0,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0, 1,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0, 1,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,1,0,1,1,1,0,0,0,0,0,0,0, 1,0,1,1,1,0,1,1,0,0,1,1,0,0,1,1, 0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,1,1,1,1,0,1,0,0,0,1, 0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,1, 1,1,0,0,1,0,0,0,0,1,1,1,0,0,1,1, 0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,1,1,0,0,1,1, 1,1,0,0,1,1,0,0,1,1,1,1,0,0,1,1, 1,1,0,0,1,1,0,0};//索引表unsigned char p0, p1, p2, p3, p4, p5, p6, p7;unsigned char *pmid, *pmidtemp;unsigned char sum;int changed;bool bStart = true;lLength = lWidth * lHeight;unsigned char *pTemp = (unsigned char *)malloc(sizeof(unsigned char) * lWidth * lHeight);// P0 P1 P2// P7 P3// P6 P5 P4while(bStart){bStart = false;changed = 0;//首先求边缘点(并行)pmid = (unsigned char *)lpDIBBits + lWidth + 1;memset(pTemp, (BYTE) 0, lLength);pmidtemp = (unsigned char *)pTemp + lWidth + 1;for(i = 1; i < lHeight -1; i++){for(j = 1; j < lWidth - 1; j++){if( *pmid == 0){pmid++;pmidtemp++;continue;}p3 = *(pmid + 1);p2 = *(pmid + 1 - lWidth);p1 = *(pmid - lWidth);p0 = *(pmid - lWidth -1);p7 = *(pmid - 1);p6 = *(pmid + lWidth - 1);p5 = *(pmid + lWidth);p4 = *(pmid + lWidth + 1);sum = p0 & p1 & p2 & p3 & p4 & p5 & p6 & p7;if(sum == 0){*pmidtemp = 1;}pmid++;pmidtemp++;}pmid++;pmid++;pmidtemp++;pmidtemp++;}//现在开始串行删除pmid = (unsigned char *)lpDIBBits + lWidth + 1; pmidtemp = (unsigned char *)pTemp + lWidth + 1;for(i = 1; i < lHeight -1; i++){for(j = 1; j < lWidth - 1; j++){if( *pmidtemp == 0){pmid++;pmidtemp++;continue;}p3 = *(pmid + 1);p2 = *(pmid + 1 - lWidth);p1 = *(pmid - lWidth);p0 = *(pmid - lWidth -1);p7 = *(pmid - 1);p6 = *(pmid + lWidth - 1);p5 = *(pmid + lWidth);p4 = *(pmid + lWidth + 1);p1 *= 2;p2 *= 4;p3 *= 8;p4 *= 16;p5 *= 32;p6 *= 64;p7 *= 128;sum = p0 | p1 | p2 | p3 | p4 | p5 | p6 | p7; if(deletemark[sum] == 1){*pmid = 0;bStart = true;}pmid++;pmidtemp++;}pmid++;pmid++;pmidtemp++;pmidtemp++;}}return true;}。

二值图像的细化算法

二值图像的细化算法

二值图像的细化算法作者:林新辉来源:《软件导刊》2011年第07期摘要:二值图像是只有黑白两种颜色的图像,二值图像的细化是讨论将一个图像中的黑色部分沿着它的中心轴线将其细化为一个像素宽的线条的处理过程,细化的结果能基本保留图形中黑色部分的拓扑结构。

介绍了一个二值图像的细化算法,思想是从原图像的边界逐层消除黑色像素点,但同时保持黑色部分的连通性,直到最后得到细化结果。

关键词:二值图像;细化;连通性;边界点;连通点中图分类号:TP312文献标识码:A文章编号:1672-7800(2011)07-0048-作者简介:林新辉(1979-),男,浙江海宁人,硕士,浙江经贸职业技术学院信息技术系助教,研究方向为计算机辅助几何设计。

0引言在计算机领域,图像处理的问题越来越成为重要的一部分,因为现在的数据交流,已不再是简单的数值,而是更多地转换到大量的图片和影音图像上来。

所以一个个的图像处理的问题就摆在了我们的面前。

但形形色色的图像处理的算法,通过抽象处理,都是可以归结为一些简单的处理。

比如多颜色的处理,可以先从两个颜色的情况开始,再进行展开。

二值图像的细化就是这些简单处理中的一个问题。

二值图像就是只有黑白两种颜色构成的图像,二值图像的细化就是将图像中的黑色部分沿着它的中心轴线将其细化为一个象素宽的线条的处理过程。

二值图像的细化在计算机的图像处理领域有重要的意义,它其实是显示了整个图像的一个拓扑结构,它在一些模式识别,点阵图形的矢量化等方面有很好的作用。

1二值图像的细化的分析首先,对二值图像进行设定。

这里假定二值图像以白色为底,细化黑色部分,且给出的黑色部分的图像为连通的。

这样,对任意的黑色图像,必定存在一个合适的n为正整数,使得它在以白色为底的2n×2n的正方形内。

由于假定黑色图像的连通性,则二值图像的细化处理后的图像必定是连通的。

为了便于处理,设计了一个256×256的正方形作为处理二值图像的区域,且在初始的作图中保证黑色部分图像的连通性。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Hilditch 细化算法是经典的二值图像细化算法,然而,在网上却很难找到一个详细、正确的介绍和实现。

可以找到一辆个 Hilditch 算法的C实现,但缺乏注释,代码可读性也很差。

在期刊网上找到几篇论文,提及了Hilditch 算法,结果一篇说的罗哩罗嗦根本看不懂,另一篇说的说的易懂,却是错误的!拿来主义是行不通了,于是只好结合着这几个论文和代码,从头写 Hilditch 细化算法。

假设像素p的3×3邻域结构为:
Hilditch 细化算法的步骤为:
对图像从左向右从上向下迭代每个像素,是为一个迭代周期。

在每个迭代周期中,对于每一个像素p,如果它同时满足6个条件,则标记它。

在当前迭代周期结束时,则把所有标记的像素的值设为背景值。

如果某次迭代周期中不存在标记点(即满足6个条件的像素),则算法结束。

假设背景值为0,前景值为1,则:
6个条件为:
(I):p 为1,即p不是背景;
(2):x1,x3,x5,x7不全部为1(否则把p标记删除,图像空心了);
(3):x1-x8 中,至少有2个为1(若只有1个为1,则是线段的端点。

若没有为1的,则为孤立点);
(4):p的8连通联结数为1;
联结数指在像素p的3*3邻域中,和p连接的图形分量的个数:
上图中,左图的4连通联结数是2,8连通联结数是1,而右图的4联通联结数和8联通联结数都是2。

4连通联结数计算公式是:
8连通联结数计算公式是:
其中,
至于公式怎么来的就不管了,直接用就行了。

(5)假设x3已经标记删除,那么当x3为0时,p的8联通联结数为1;
(6)假设x5已经标记删除,那么当x5为0时,p的8联通联结数为1。

======
在程序中,我使用的是这样的邻域编码:
为了方便计算联结数,以0作为前景,1作为背景。

程序如下(完整程序见:
/svn/trunk/src/mon/UnmanagedI mage/ImageU8.cs):
/// <summary>
/// 计算八联结的联结数,计算公式为:
/// (p6 - p6*p7*p0) + sigma(pk - pk*p(k+1)*p(k+2)), k = {0,2,4)
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
private unsafe Int32 DetectConnectivity(Int32* list)
{
Int32 count = list[6] - list[6] * list[7] * list[0];
count += list[0] - list[0] * list[1] * list[2];
count += list[2] - list[2] * list[3] * list[4];
count += list[4] - list[4] * list[5] * list[6];
return count;
}
private unsafe void FillNeighbors(Byte* p, Int32* list, Int32 width, Byte foreground = 255)
{
// list 存储的是补集,即前景点为0,背景点为1,以方便联结数的计算
list[0] = p[1] == foreground ? 0 : 1;
list[1] = p[1 - width] == foreground ? 0 : 1;
list[2] = p[-width] == foreground ? 0 : 1;
list[3] = p[-1 - width] == foreground ? 0 : 1;
list[4] = p[-1] == foreground ? 0 : 1;
list[5] = p[-1 + width] == foreground ? 0 : 1;
list[6] = p[width] == foreground ? 0 : 1;
list[7] = p[1 + width] == foreground ? 0 : 1;
}
/// <summary>
/// 使用 hilditch 算法进行细化
/// </summary>
public unsafe void Thinning(Byte foreground = 255)
{
Byte* start = this.Start;
Int32 width = this.Width;
Int32 height = this.Height;
Int32* list = stackalloc Int32[8];
Byte background = (Byte)(255 - foreground);
Int32 length = this.Length;
using (ImageU8 mask = new ImageU8(this.Width, this.Height)) {
mask.Fill(0);
Boolean loop = true;
while (loop == true)
{
loop = false;
for (Int32 r = 1; r < height - 1; r++)
{
for (Int32 c = 1; c < width - 1; c++)
{
Byte* p = start + r * width + c;
// 条件1:p 必须是前景点
if (*p != foreground) continue;
// p3 p2 p1
// p4 p p0
// p5 p6 p7
// list 存储的是补集,即前景点为0,背景点为1,以方便联结数的计算
FillNeighbors(p, list, width, foreground);
// 条件2:p0,p2,p4,p6 不皆为前景点
if (list[0] == 0 && list[2] == 0 && list[4] == 0 && list[6] == 0)
continue;
// 条件3: p0~p7至少两个是前景点
Int32 count = 0;
for (int i = 0; i < 8; i++)
{
count += list[i];
}
if (count > 6) continue;
// 条件4:联结数等于1
if (DetectConnectivity(list) != 1) continue;
// 条件5: 假设p2已标记删除,则令p2为背景,不改变p的联结数 if (mask[r - 1, c] == 1)
{
list[2] = 1;
if (DetectConnectivity(list) != 1)
continue;
list[2] = 0;
}
// 条件6: 假设p4已标记删除,则令p4为背景,不改变p的联结数 if (mask[r, c - 1] == 1)
{
list[4] = 1;
if (DetectConnectivity(list) != 1)
continue;
}
mask[r, c] = 1; // 标记删除
loop = true;
}
}
for (int i = 0; i < length; i++)
{
if (mask[i] == 1)
{
this[i] = background;
}
}
}
}
}。

相关文档
最新文档