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

Computer VisiAlgorithms in Image Algebra,second edition

该算法最初是做前景轮廓跟踪的。

假设使用下面的8邻域,且前景像素值为1,背景像素值为0。

下面是该算法的描述:

1. 求出前景像素的轮廓,并用2表示,如果轮廓点是孤立点,端点或者其它不可删除的点,标记其为3。

2. 在第1步求出的轮廓中判断那些是可以删除的,那些是不可删除的,不可删除的点标记为4。

3. 再次扫描值为2的轮廓点,标记可以删除的点为5。

4. 对值为2和5的点执行删除操作。

重复上述步骤,直到图像中没有可以删除的像素为止。结果如想就是我们要的骨架结构。

第一步是求轮廓的过程,对于一个值为1的像素点。如果它的p0,p2,p4,p6四个点都为1,则该点是内部点,继续循环,判断其它像素。

如果该像素是孤立点或端点,则其像素值标记为3。

如果像素是其它可能改变8连通性的点。比如以下的情况: p3, p7为0,但p4,p5,p6和p0,p1,p2中有非零值,如果删除p点,则连通性会改变。此时都标记当前像素值为3。

第一步后,我们会得到轮廓

第2步对不等于0的像素进行处理

如果像素周围全是2,则标记其为4(不删除)。

还有对于其它不可删除情况,比如下面这种情况,置当前像素为4。

第三步对于值为2的轮廓点再次进行判断,对于可删除的点,标记为5。

第四步删除值为2和5的点。

最终值为4的点为细化后的轮廓点。

算法实现的代码:

void gThin::cvPavlidis(cv::Mat& src, cv::Mat& dst)    {

if(src.type()!=CV_8UC1)        {        printf("只能处理二值或灰度图像\n");return;        }//非原地操作时候,copy src到dstif(dst.data!=src.data)        {        src.copyTo(dst);        }

char erase, n[8];unsigned char bdr1,bdr2,bdr4,bdr5;short k,b;unsigned long i,j;

int width, height;    width=dst.cols;    height= dst.rows;

//把不能于0的值转化为1,便于后面处理for(i=0; i< height; i++)        {for(j=0; j<width; j++)            {if(dst.at<uchar>(i,j)!=0)                {                dst.at<uchar>(i,j) = 1;                }//图像边框像素值为0if(i==0||i==(height-1)||j==0||j==(width-1))                dst.at<uchar>(i,j) = 0;            }        }

    erase =1;    width = width - 1;    height = height - 1;    uchar* img;int step = dst.step;while(erase)         {

        img = dst.data;//第一个循环,取得前景轮廓,轮廓用2表示for(i=1; i< height; i++)            {            img += step;for(j=1; j < width; j++)                {                uchar* p= img+j;

if(p[0]!= 1)continue;

                n[0]=p[1];                n[1]=p[-step+1];                n[2]=p[-step];                n[3]=p[-step-1];                n[4]=p[-1];                n[5]=p[step-1];                n[6]=p[step];                n[7]=p[step+1];

//bdr1是2进制表示的p0...p6p7排列,10000011,p0=1,p6=p7=1                bdr1 =0;for(k=0; k<8; k++)                    {if(n[k]>=1)                        bdr1|=0x80>>k;                    }//内部点,p0, p2, p4, p6都是为1, 非边界点,所以继续循环//0xaa 10101010//  0   1   0   //  1         1//   0   1    0

if((bdr1&0xaa)== 0xaa)continue;//不是内部点,则是边界点,对于边界点,我们标记为2,是轮廓                p[0] = 2;

                b=0;

for(k=0; k<=7; k++)                    {                    b+=bdr1&(0x80>>k);                    }//在边界点中,等于1,则是端点,等于0,则是孤立点,此时标记3if(b<=1 )                    p[0] = 3;

//此条件说明p点是中间点,如果移去会引起断裂// 0x70        0x7         0x88      0xc1        0x1c      0x22      0x82     0x1      0xa0     0x40     0x28    0x10       0xa      0x4// 0 0 0     0  1  1     1  0   0    0   0   0    1  1  0    0   0   1  0  0  1  0 0 0    0  0  0   0 0 0    1  0  0   0  0  0  1  0  1   0 1 0// 1    0     0      1     0       0    0        1    1      0    0        0  0      0  0    1    0      0   0    0    0      0   1      0  0     0    0    0// 1 1 0     0  0  0     0  0   1    0   1   1    0  0  0    1   0   1  0  0  1  0 0 0    1  0  1   0 1 0    1  0  0   0  0  0  0  0  0   0 0 0if((bdr1&0x70)!=0&&(bdr1&0x7)!=0&&(bdr1&0x88)==0)                    p[0] = 3;else if((bdr1&&0xc1)!=0&&(bdr1&0x1c)!=0&&(bdr1&0x22)==0)                    p[0] = 3;  else if((bdr1&0x82)==0 && (bdr1&0x1)!=0)                    p[0] = 3; else if((bdr1&0xa0)==0 && (bdr1&0x40)!=0)                    p[0] = 3; else if((bdr1&0x28)==0 && (bdr1&0x10)!=0)                    p[0] = 3; else if((bdr1&0xa)==0 && (bdr1&0x4)!=0)                    p[0] = 3; 

                }            }//printf("------------------------------\n");//PrintMat(dst);        img = dst.data;for(i=1; i<height; i++)            {            img += step;for(j=1; j<width; j++)                {                uchar* p= img+j;

if(p[0]== 0)continue;

                n[0]=p[1];                n[1]=p[-step+1];                n[2]=p[-step];                n[3]=p[-step-1];                n[4]=p[-1];                n[5]=p[step-1];                n[6]=p[step];                n[7]=p[step+1];

                bdr1 = bdr2 =0;

//bdr1是2进制表示的当前点p的8邻域连通情况,hdr2是当前点周围轮廓点的连接情况for(k=0; k<=7; k++)                    {if(n[k]>=1)                        bdr1|=0x80>>k;if(n[k]>=2)                        bdr2|=0x80>>k;                    }

//相等,就是周围全是值为2的像素,继续if(bdr1==bdr2)                    {                    p[0] = 4; continue;                    }

//p0不为2,继续if(p[0]!=2) continue;//=4都是不可删除的轮廓点//     0x80       0xa     0x40        0x1      0x30   0x6//   0 0 0      1  0 1    0  0  0    0  0  0   0 0 0   0 1 1//   0    0      0     0    0      0    0      1   1    0   0    0//   0 0 1      0  0 0    0  1  0    0  0  0   1 0 0   0 0 0

if(                       (bdr2&0x80)!=0 && (bdr1&0xa)==0 &&//    ((bdr1&0x40)!=0 &&(bdr1&0x1)!=0 ||     ((bdr1&0x40)!=0 ||(bdr1 & 0x1)!=0) &&(bdr1&0x30)!=0 &&(bdr1&0x6)!=0 )                    (    ((bdr1&0x40)!=0 ||(bdr1 & 0x1)!=0) &&(bdr1&0x30)!=0 &&(bdr1&0x6)!=0 )                    )                    {                    p[0]= 4;                     }//else if((bdr2&0x20)!=0 && (bdr1&0x2)==0 &&//((bdr1&0x10)!=0 && (bdr1&0x40)!=0 || ((bdr1&0x10)!=0 || (bdr1&0x40)!=0) &&    (bdr1&0xc)!=0 && (bdr1&0x81)!=0)                    ( ((bdr1&0x10)!=0 || (bdr1&0x40)!=0) &&    (bdr1&0xc)!=0 && (bdr1&0x81)!=0)                    )                    {                    p[0]= 4;                    }

else if((bdr2&0x8)!=0 && (bdr1&0x80)==0 &&//((bdr1&0x4)!=0 && (bdr1&0x10)!=0 || ((bdr1&0x4)!=0 || (bdr1&0x10)!=0) &&(bdr1&0x3)!=0 && (bdr1&0x60)!=0)                    ( ((bdr1&0x4)!=0 || (bdr1&0x10)!=0) &&(bdr1&0x3)!=0 && (bdr1&0x60)!=0)                    )                    {                    p[0]= 4;                    }

else if((bdr2&0x2)!=0 && (bdr1&0x20)==0 &&//((bdr1&0x1)!=0 && (bdr1&0x4)!=0 ||((bdr1&0x1)!=0 || (bdr1&0x4)!=0) &&(bdr1&0xc0)!=0 && (bdr1&0x18)!=0)                    (((bdr1&0x1)!=0 || (bdr1&0x4)!=0) &&(bdr1&0xc0)!=0 && (bdr1&0x18)!=0)                    )                    {                    p[0]= 4;                    }                }            }//printf("------------------------------\n");//PrintMat(dst);        img = dst.data;for(i=1; i<height; i++)            {            img += step;for(j=1; j<width; j++)                {                uchar* p= img+j;

if(p[0]!= 2)continue;

                n[0]=p[1];                n[1]=p[-step+1];                n[2]=p[-step];                n[3]=p[-step-1];                n[4]=p[-1];                n[5]=p[step-1];                n[6]=p[step];                n[7]=p[step+1];

                bdr4 = bdr5 =0;for(k=0; k<=7; k++)                    {if(n[k]>=4)                        bdr4|=0x80>>k;if(n[k]>=5)                        bdr5|=0x80>>k;                    }//值为4和5的像素if((bdr4&0x8) == 0)                    {                    p[0]=5;continue;                    }if((bdr4&0x20) == 0 && bdr5 ==0)                    {                    p[0]=5;continue;                    }

                }            }        erase = 0;//printf("------------------------------\n");//PrintMat(dst);        img = dst.data;for(i=1; i<height; i++)            {            img += step;for(j=1; j<width; j++)                {                uchar* p= img+j;if(p[0]==2||p[0]==5)                    {                    erase = 1;                    p[0] = 0;                    }                }            }//printf("------------------------------\n");//PrintMat(dst);//printf("------------------------\n");        }

    }

程序源代码:参加工程FirstOpenCV11

OpenCV学习(17) 细化算法(5)相关推荐

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

    1.转载链接:http://www.cnblogs.com/mikewolf2002/p/3321732.html 程序编码参考经典的细化或者骨架算法文章: T. Y. Zhang and C. Y. ...

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

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

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

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

  4. OpenCV学习(19) 细化算法(7)

    最后再来看一种通过形态学腐蚀和开操作得到骨架的方法.http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/ 代码非常简单: v ...

  5. 【opencv学习】Fast算法进行角点检测

    今天学习角点检测的一个Fast算法,顾名思义,很快! FAST 算法 1: 在图像中选择一个像素点p,得到其灰度值I_p 2: 以半径r为半径画圆,覆盖p点周围M个像素点,通常设置r=3,则M=16, ...

  6. 【opencv学习】RANSAC算法在图像拼接中的应用实战

    一:单应性变换 我们得到两张图像的图像后,可以通过BFMatcher得到匹配的点,其实就是一个暴力搜索来比较最相近的特征点(128维度的向量,求向量的近似度). 通过匹配的多个关键点的配对信息,我们能 ...

  7. OpenCV学习(21) Grabcut算法详解

    grab cut算法是graph cut算法的改进.在理解grab cut算之前,应该学习一下graph cut算法的概念及实现方式. 我搜集了一些graph cut资料:http://yunpan. ...

  8. 【OpenCV学习】Bresenham算法opencv实现

    作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ /** ==================================================== ...

  9. 【opencv学习】光流算法以及物体追踪算法(Lucas-Kanade算法)

    正所谓的光流估计,就是在视频的前后帧的分析中,能分析出图中的一些object的移动方向和速度,可以做目标追踪使用. Lucas-Kanade算法改进 经典的光流估计是Lucas-Kanade 算法,这 ...

最新文章

  1. 自己实现spring核心功能 三
  2. 自然科学 计算机,计算机科学与自然科学技术的关系
  3. ajax获得excel文件流在前端打开_主流前端技术讲解,面试必考!
  4. 1.11 神经网络的权重初始化
  5. Activity工作流工作笔记001---快速上手_认识工作流
  6. 网络编程(三)--通信循环、链接循环、粘包问题
  7. 吴恩达机器学习视频笔记和编程作业(Python实现)汇总
  8. 软件测试仓库管理信息系统,仓库管理系统测试报告
  9. html5 加入收藏夹,设为首页、添加到收藏夹代码
  10. C++实现离散数学之真值表(试着自写头文件)
  11. bugku-web-滑稽
  12. 进入bios看了,vt 已经开了,为什么打开模拟器还显示未开启?
  13. OpenAI-2018年强化学习领域7大最新研究方向全盘点
  14. 基于JAVA网上家教信息管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
  15. #今日论文推荐# 莫纳什大学最新《长文档摘要》综述,39页pdf长文档摘要的实证研究:数据集、模型和指标
  16. 数据中心双活该如何构建
  17. 三万字,七十图详解计算机网络六十二问(建议收藏)
  18. 镜像制作dockerfile编写
  19. 利用arcgis-ArcMap手动快速检查重庆三调图斑的方法探讨与自动化检查的想法
  20. SpringBoot视频教程 百度云

热门文章

  1. saltstack安装及简单配置
  2. mockit学习(一)
  3. 注释驱动的 Spring cache 缓存介绍
  4. Global GUI map for automation with VS.NET
  5. SLAM的一些基础知识
  6. ROS 启动自带摄像头或者USB摄像头
  7. python3读文件编码格式_使用不同的编码格式读取文件系统标准在Python3中
  8. java 计算器 下载_那里可以下载到JAVA编的计算器程序??
  9. linux awk拼接字符串,shell awk命令字符串拼接
  10. python静态递归函数_Python递归函数