Opencv轮廓跟踪算法源码分析(1)——icvFetchContour()

想要看懂Opencv源码,打算从findContours()开始。

源文件: C:\***\opencv\sources\modules\imgproc\src\contours.cpp

环境:opencv2.4.9 + VS2010

一、findContours() 接口函数

void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
	OutputArray _hierarchy, int mode, int method, Point offset )

Parameters:

image--待处理图,8bit单通道,非零像素被当成1,零像素仍然是0,因此该图被当成二值图来处理(实际在源码中发现,CV_8UC1和CV_32SC1都是允许的)。注意,该函数在提取轮廓的过程中会修改原始图像。(因此,在执行findContours之前将原图备份。)

contours--检测到的轮廓集合,每一个轮廓存储为 a vector of points。

hierarchy--可选的输出向量,包含图像拓扑结构信息。该向量的元素个数等于轮廓的总个数。对于每个轮廓contours[i], hierarchy[i][0], hierarchy[i][1], hierarchy[i][2], hierarchy[i][3]分别代表同级轮廓的后一个轮廓(next contour)、前一个轮廓(previous contour)、第一个子轮廓(first child contour)、母轮廓(paraent contour)。这些轮廓用基于0的序列号表示。如果没有相应的轮廓,则hierarchy[i][j]将被设置为负值。

mode--轮廓跟踪模式。(关于轮廓之间的层次关系)

  • — CV_RETR_EXTERNAL     只提取最外层轮廓。所有轮廓的hierarchy[i][2] =  hierarchy[i][3] =-1.
  • — CV_RETR_LIST     提取所有轮廓但不建立任何层次关系。
  • — CV_RETR_CCOMP     提取所有轮廓,把它们组织成两级结构。第一级是连通域的外边界(external boundaries),第二级是孔边界(boundaries of holes)。如果在孔中间还有另外的连通域,则被当成另一个外边界。
  • — CV_RETR_TREE   提取所有轮廓并把它们组织成完整的层次结构。
method--轮廓近似方法。(关于单个轮廓存储的方法)
  • — CV_CHAIN_CODE   (手册上没有标出)采用Freeman链码的方式存储轮廓。
  • — CV_CHAIN_APPROX_NONE    将Freeman链码转换成点集,并存储轮廓上所有的点。
  • — CV_CHAIN_APPROX_SIMPLE   压缩水平、垂直和斜对角方向的元素,只保留线段端点的那些点。比如说,一个矩形,总共四条线段,只保留四个顶点,顶点之间的点就省略掉,所以最终该矩形轮廓只用4个点表示。
  • — CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPPRX_TC89_KCOS   使用Teh-Chin 链近似方法。
  • — CV_LINK_RUNS  通过连接为1的水平碎片使用完全不同的轮廓提取算法。仅有CV_RETR_LIST 提取模式可以在本方法中使用.
offset-- 可选的偏移量参数。如果是从image ROI中提取出的轮廓,又需要在整个image分析这些轮廓,就要给每个轮廓增加一个坐标偏移量。


手册中给出了该函数参考的算法原始论文[Suzuki85] 。

  • Suzuki, S. and Abe, K., Topological Structural Analysis of Digitized Binary Images by Border Following.CVGIP 30 1, pp 32-46 (1985) 

论文翻译博客地址:http://blog.csdn.net/yiqiudream/article/details/76864722

论文原文及翻译下载地址:

看论文仍然糊里糊涂的,不知道链码跟踪的具体算法是什么。而contours.cpp中的函数较多,内容有点复杂,只能一个一个看,比如单个轮廓的具体跟踪方法,在 icvFetchContours() 。最后对该函数单步调试,列出了每一步执行的步骤,终于明白一点。所以记录下来。

二、icvFetchContours() 源码

为了便于理解代码,先把用到的一些宏定义贴出来。

/* initializes 8-element array for fast access to 3x3 neighborhood of a pixel */
#define  CV_INIT_3X3_DELTAS( deltas, step, nch )            \
	((deltas)[0] =  (nch),  (deltas)[1] = -(step) + (nch),  \
	(deltas)[2] = -(step), (deltas)[3] = -(step) - (nch),  \
	(deltas)[4] = -(nch),  (deltas)[5] =  (step) - (nch),  \
	(deltas)[6] =  (step), (deltas)[7] =  (step) + (nch))
注释:定义了一个3X3 的邻域位置快速查找表。因为在内存中,Mat数据存储的时候是一行一行连续存储的,从像素点(i,j)到像素点(i+1,j),指针偏移了一行的数据,也就是 step的距离。这里step 是指一行像素点所占的字节数,nch是步进距离,后面设置为1,也就是指针偏移一个Byte.  deltas[8]是一个数组,共8个元素,分别代表8个方向。如图。

3 2 1
4   0
5 6 7


static const CvPoint icvCodeDeltas[8] =
{ {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
注释:deltas[8]存的是指针的偏移量,icvCodeDeltas[8] 存的是8个方向相对于中心点坐标的偏移量。

/* Contour retrieval modes */
enum
  • 35
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值