OpenCV细化算法简单解析
细化算法它的原理也很简单:
我们对一副二值图像进行骨架提取,就是删除不需要的轮廓点,只保留其骨架点。假设一个像素点,我们定义该点为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细化算法简单解析的更多相关文章
- 手指静脉细化算法过程原理解析 以及python实现细化算法
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8672489.html 文中的一些图片以及思想很多都是参考https://www.cnblogs ...
- OpenCV学习(18) 细化算法(6)
本章我们在学习一下基于索引表的细化算法. 假设要处理的图像为二值图,前景值为1,背景值为0. 索引表细化算法使用下面的8邻域表示法: 一个像素的8邻域,我们可以用8位二进制表示,比如下面的8邻域,表示 ...
- OpenCV学习(13) 细化算法(1)
程序编码参考经典的细化或者骨架算法文章: T. Y. Zhang and C. Y. Suen, "A fast parallel algorithm for thinning digita ...
- OpenCV学习(17) 细化算法(5)
本章我们看下Pavlidis细化算法,参考资料http://www.imageprocessingplace.com/downloads_V3/root_downloads/tutorials/con ...
- OpenCV学习(16) 细化算法(4)
本章我们学习Rosenfeld细化算法,参考资料:http://yunpan.cn/QGRjHbkLBzCrn 在开始学习算法之前,我们先看下连通分量,以及4连通性,8连通性的概念: http://w ...
- OpenCV学习(14) 细化算法(2)
前面一篇教程中,我们实现了Zhang的快速并行细化算法,从算法原理上,我们可以知道,算法是基于像素8邻域的形状来决定是否删除当前像素.还有很多与此算法相似的细化算法,只是判断的条件不一样. ...
- c++opencv中线条细化算法
要达到的效果就是将线条尽量细化成单像素,按照论文上的Hilditch算法试了一下,发现效果不好,于是自己尝试着写了一下细化的算法,基本原理就是从上下左右四个方向向内收缩. 1.先是根据图片中的原则确定 ...
- Adaboost 算法实例解析
Adaboost 算法实例解析 1 Adaboost的原理 1.1 Adaboost基本介绍 AdaBoost,是英文"Adaptive Boosting"(自适应增强)的缩写,由 ...
- 2. Attention Is All You Need(Transformer)算法原理解析
1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...
随机推荐
- Binder学习笔记(四)—— ServiceManager如何响应checkService请求
这要从frameworks/native/cmds/servicemanager/service_manager.c:347的main函数说起,该文件编译后生成servicemanager. int ...
- 总结一下vue里一些小技巧
官方里的我就不细说了,自个撸文档就成,下面是实践里常用的几个小技巧或者说是遇到的坑,若有错误望大家指正)1.当用a标签设置新窗口打开页面,设置url时,建议给href进行v-bind绑定,然后写相对路 ...
- AngularJS(四)——ng-controller(控制器)
前言 上篇大概说了一下指令的应用格式以及创建自定义指令方法,本篇重点介绍一些ng-controller都有哪些小作用. 内容 通过修改控制器部分,修改显示界面. Demo <div ng-app ...
- css边跨实例
<!doctype html><html lang="zh-cn"> <head> <meta http-equiv="Cont ...
- Java之批处理的实现
批处理(batch) 一.批处理介绍 1. 批处理指的是一次操作中执行多条SQL语句 2. 批处理相比于一次一次执行效率会提高很多 3. 批处理主要是分两步: 1.将要执行的SQL语句保存 2.执行S ...
- 2019.2.26考试T2 矩阵快速幂加速DP
\(\color{#0066ff}{题解 }\) 可以发现, 数据范围中的n特别小,容易想到状压 可以想到类似于状压DP的思路,按列进行转移 那么应该有3维,\(f[i][j][k]\)代表到第i列, ...
- U19464 山村游历(Wander) LCT维护子树大小
\(\color{#0066ff}{ 题目描述 }\) 在一个偏远的小镇上,有一些落后的山村.山村之间通过一些道路来连接.当然有的山村可能不连通. 一年当中会发生很多大事,比如说有人提议要在山村\(i ...
- 重装iTunes 错误代码42401 解决办法
昨晚手贱点击从iTunes 11升级到iTunes12,之后发现iTunes 12各种卡,简直不能忍,然后直接拉iTunes 12到AppClear,然后安装iTunes 11,安装完成之后打开iTu ...
- Jupyter Notebook命令
Jupyter Notebook命令 1.启动 tensorboard --logdir=2017_05_03_00_12
- CF580C Kefa and Park dfs
Kefa decided to celebrate his first big salary by going to the restaurant. He lives by an unusual pa ...