细化算法它的原理也很简单:

我们对一副二值图像进行骨架提取,就是删除不需要的轮廓点,只保留其骨架点。假设一个像素点,我们定义该点为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点是一个边界点,而不是一个内部点。等于0时候,周围没有等于1的像素,所以p1为孤立点,等于1的时候,周围只有1个灰度等于1的像素,所以是端点(注:端点是周围有且只能有1个值为1的像素)。

b. p2->p9的排列顺序中,01模式的数量为1,比如下面的图中,有p2p3 => 01, p6p7=>01,所以该像素01模式的数量为2。

之所以要01模式数量为1,是要保证删除当前像素点后的连通性。比如下面的图中,01模式数量大于1,如果删除当前点p1,则连通性不能保证。

c. P2*p4*p6 = 0

d. p4*p6*p8 = 0

在第一次子迭代中,只是移去东南的边界点,而不考虑西北的边界点,注意p4,p6出现了2次,就是说它们有一个为0,则c,d就满足。

2. 接下来,把目地图像再次复制到临时图像,接着对临时图像进行一次扫描,如果不为0的点它的八邻域满足以下4个条件,则在目地图像中删除该点(就是设置该像素为0)

a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6

b. p2->p9的排列顺序中,01模式的数量(这里假设二值图非零值为1)为1。

c. p2*p4*p8 = 0

d. p2*p6*p8 = 0

第二次迭代则相反,会移去西北的边界点,注意p2,p8出现了2次,就是说它们有一个为0,则c,d就满足。

执行完上面两个步骤后,就完成了一次细化算法,我们可以多次迭代执行上述过程,得到最终的骨架图。

细化算法代码如下:

以上部分原理是转载(迈克老狼2012)http://www.cnblogs.com/mikewolf2002/p/3321732.html

接下来发布的是在我电脑上通过的测试代码:

编译环境为win7+VS2015+OpenCV3.0

 void cvThin(IplImage* src, IplImage* dst, int iterations)
{
//此时的src是一个二值化的图片
CvSize size = cvGetSize(src);
cvCopy(src, dst); int n = , i = , j = ;
for (n = ; n < iterations; n++)//开始进行迭代
{
IplImage* t_image = cvCloneImage(dst);
for (i = ; i < size.height; i++)
{
for (j = ; j < size.width; j++)
{
if (CV_IMAGE_ELEM(t_image, uchar, i, j) == )
{
int ap = ;
int p2 = (i == ) ? : CV_IMAGE_ELEM(t_image, uchar, i - , j);
int p3 = (i == || j == size.width - ) ? : CV_IMAGE_ELEM(t_image, uchar, i - , j + );
if (p2 == && p3 == )
{
ap++;
} int p4 = (j == size.width - ) ? : CV_IMAGE_ELEM(t_image, uchar, i, j + );
if (p3 == && p4 == )
{
ap++;
} int p5 = (i == size.height - || j == size.width - ) ? : CV_IMAGE_ELEM(t_image, uchar, i + , j + );
if (p4 == && p5 == )
{
ap++;
} int p6 = (i == size.height - ) ? : CV_IMAGE_ELEM(t_image, uchar, i + , j);
if (p5 == && p6 == )
{
ap++;
} int p7 = (i == size.height - || j == ) ? : CV_IMAGE_ELEM(t_image, uchar, i + , j - );
if (p6 == && p7 == )
{
ap++;
} int p8 = (j == ) ? : CV_IMAGE_ELEM(t_image, uchar, i, j - );
if (p7 == && p8 == )
{
ap++;
} int p9 = (i == || j == ) ? : CV_IMAGE_ELEM(t_image, uchar, i - , j - );
if (p8 == && p9 == )
{
ap++;
}
if (p9 == && p2 == )
{
ap++;
} if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < )
{
if (ap == )
{
if (!(p2 && p4 && p6))
{
if (!(p4 && p6 && p8))
{
CV_IMAGE_ELEM(dst, uchar, i, j) = ;//设置目标图像中像素值为0的点
}
}
}
} }
}
} cvReleaseImage(&t_image); t_image = cvCloneImage(dst);
for (i = ; i < size.height; i++)
{
for (int j = ; j < size.width; j++)
{
if (CV_IMAGE_ELEM(t_image, uchar, i, j) == )
{
int ap = ;
int p2 = (i == ) ? : CV_IMAGE_ELEM(t_image, uchar, i - , j);
int p3 = (i == || j == size.width - ) ? : CV_IMAGE_ELEM(t_image, uchar, i - , j + );
if (p2 == && p3 == )
{
ap++;
}
int p4 = (j == size.width - ) ? : CV_IMAGE_ELEM(t_image, uchar, i, j + );
if (p3 == && p4 == )
{
ap++;
}
int p5 = (i == size.height - || j == size.width - ) ? : CV_IMAGE_ELEM(t_image, uchar, i + , j + );
if (p4 == && p5 == )
{
ap++;
}
int p6 = (i == size.height - ) ? : CV_IMAGE_ELEM(t_image, uchar, i + , j);
if (p5 == && p6 == )
{
ap++;
}
int p7 = (i == size.height - || j == ) ? : CV_IMAGE_ELEM(t_image, uchar, i + , j - );
if (p6 == && p7 == )
{
ap++;
}
int p8 = (j == ) ? : CV_IMAGE_ELEM(t_image, uchar, i, j - );
if (p7 == && p8 == )
{
ap++;
}
int p9 = (i == || j == ) ? : CV_IMAGE_ELEM(t_image, uchar, i - , j - );
if (p8 == && p9 == )
{
ap++;
}
if (p9 == && p2 == )
{
ap++;
}
if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < )
{
if (ap == )
{
if (p2*p4*p8 == )
{
if (p2*p6*p8 == )
{
CV_IMAGE_ELEM(dst, uchar, i, j) = ;
}
}
}
}
} } }
cvReleaseImage(&t_image);
} }

细化结果因为我的图不方便展示,大家可以参考迈克老狼2012的哦,效果是很像的,他采用的mat类,而我采用的iplimage类。

OpenCV细化算法简单解析的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. Adaboost 算法实例解析

    Adaboost 算法实例解析 1 Adaboost的原理 1.1 Adaboost基本介绍 AdaBoost,是英文"Adaptive Boosting"(自适应增强)的缩写,由 ...

  9. 2. Attention Is All You Need(Transformer)算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

随机推荐

  1. 关于redis-windows环境下的一些配置:

    如果报错: The Windows version of Redis allocates a memory mapped heap for sharing with the forked proces ...

  2. 类的继承与super()的意义以即如何写一个正确的异常类

    这些东西都是我看了许多名师课程和自己研究的成果,严禁转载,这里指出了如何正确的自己定义一个异常类并看一看sun写的java的源代码话题一:子类的构造器执行是否一定会伴随着父类的构造执行? 1.this ...

  3. bat 操作数据库(附加,分离,删除,还原)

    BAT代码: @echo off Title DataBase Color 0A :caozuo echo. echo ═══════════════════════════════════════ ...

  4. 【3】循序渐进学 Zabbix:配置 Zabbix Web

    上一篇 [2]循序渐进学 Zabbix:安装配置 Zabbix Server 服务端 配置 Zabbix Web 访问 上一篇完成了 Zabbix Server 的安装,但是那对于我们而言只是一个服务 ...

  5. Nginx部署静态页面及引用图片有效访问的两种方式

    nginx安装百度一下有很多,直接正题: 静态文件目录结构 file#文件位置 /home/service/file/ css js images html fonts 配置nginx.conf核心代 ...

  6. E - 稳定排序(结构体)

    大家都知道,快速排序是不稳定的排序方法. 如果对于数组中出现的任意a[i],a[j](i<j),其中a[i]==a[j],在进行排序以后a[i]一定出现在a[j]之前,则认为该排序是稳定的. 某 ...

  7. 形态形成场(矩阵乘法优化dp)

    形态形成场(矩阵乘法优化dp) 短信中将会涉及前\(k\)种大写字母,每个大写字母都有一个对应的替换式\(Si\),替换式中只会出现大写字母和数字,比如\(A→BB,B→CC0,C→123\),代表 ...

  8. P2115 [USACO14MAR]破坏Sabotage

    题意:给你一个正整数序列,让你删去一段区间内的数[l,r] $1<l\le r <n$ 使得剩余的数平均值最小$n\le 10^5$ 1.不难想到暴力,用前缀和优化$O(n^2)$ #in ...

  9. Runtime常用的几个应用场景

    Runtime常见的几个应用场景. Runtime常见应用场景 具体应用拦截系统自带的方法调用(Method Swizzling黑魔法) 实现给分类增加属性 实现字典的模型和自动转换 JSPatch替 ...

  10. pytorch实现depthwise convolution

    深度分离卷积是Xception这个模型中提出来的(不太确定,但肯定是它让这个概念为大众周知),具体来说分为两步,depthwise conv和pointwise conv,前者对输入特征图的每个通道进 ...