分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
查找轮廓
轮廓到底是什么?一个轮廓一般对应一系列的点,也就是图像中的一条曲线.表示的方法可能根据不同情况而有所不同.有多重方法可以表示曲线.在openCV中一般用序列来存储轮廓信息.序列中的每一个元素是曲线中一个点的位置.关于序列表示的轮廓细节将在后面讨论,现在只要简单把轮廓想象为使用CvSeq表示的一系列的点就可以了.
函数cvFindContours()从二值图像中寻找轮廓.cvFindContours()处理的图像可以是从cvCanny()函数得到的有边缘像素的图像,或者是从cvThreshold()及cvAdaptiveThreshold()得到的图像,这时的边缘是正和负区域之间的边界.
图8-2描述了cvFindContours的函数功能,图像的上半部分是神色背景和白色区域(被从A到E标记)的测试图像.下半部分是使用cvFindCountours()函数后会得到的轮廓的说明.这些轮廓被标记为cX或hx,"c"表示"轮廓(contour)","h"表示"孔(hole)","X表述数字".其中一些轮廓用虚划线表示;表明他们是白色区域的外部边界(例如,非0区域).孔(hole)的外部边界(例如,非0区域)即白色区域的内部边界.在图中是用电线表示外部边界的.OpenCV的cvFindContours()函数可区分内部和外部边界.
包含的概念在很多应用中都非常重要.因此.OpenCV允许得到的轮廓被聚合成一个轮廓树,从而把包含关系编码到树结构中.这个测试图的轮廓树在根节点的轮廓叫c0,孔h00和h01是它的字子节点.这些轮廓中直接包含轮廓称为他们的子节点,以此类推.
现在来看cvFindContours()函数
int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int header_size CV_DEFAULT(sizeof(CvContour)), int mode CV_DEFAULT(CV_RETR_LIST), int method CV_DEFAULT(CV_CHAIN_APPROX_SIMPLE), CvPoint offset CV_DEFAULT(cvPoint(0,0)));
第一个参数 image是输入图像,图像必须是8位单通道图像,并且应该被转化成二值的(例如,所有非0像素的值都是一个定值).cvFindContours()运行的时候,这个图像会被直接涂改,因此如果是将来还有用的图像,应该复制之后再传给cvFindContours().
storage 是内存存储器,cvFindContours()找到的轮廓记录在此内存里.正如之前所说,这个存储器的空间应该由cvCreateMemStorage()分配.
first_contour 是指向CvSeq*的一个指针firstContour.无需动手,cvFindContours()会自动分配该指针.实际上,只要在这里传一个指针就可以了函数会自动设置.不需要分配和释放(new/delete或者malloc/free).就是这个指针(例如,*firstContour)指向轮廓树的首地址(head).cvFindContours()返回值是,找到的所有轮廓的个数
cvSeq* firstContout = NULL;
cvFindContours(..., &firstContour, ...);
headerSize告诉cvFindContours()更多有关对象分配的信息,它可以被设定为sizeof(CvContour)或者sizeof(CvChain)(当近似方法参数method被设定为CV_ChAIN_CODE时使用后者).最后是mode和method参数,他们分别指定计算方法和如何计算.
mode变量可以被设置为以下四个选项之一: CV_RETR_ExTERNAL, CV_RETR_LIST, CV_RETR_CCOMP或CV_RETR_TREE.mode的值向cvFindeContours()说明需要的轮廓类型,和希望的放回值形式.具体说来,mode的值决定把找到的轮廓如何挂到轮廓树节点变量(h_prev,h_next,v_prev和v_next)上,图8-3展示了四种可能的mode值所得到的结果的拓扑结构.
每中情况下,结构都可以看成是被"横向"连接(h_next和h_prev)联系和被"纵向"连接(v_next和v_prev)不同的"层次".
CV_RETR_EXTERNAL 只检测出最外的轮廓.图8-2中,只有一个最外轮廓,因此图8-3中第一个轮廓指向最外的序列,除此之外没有别的连接
CV_RETR_LIST 检测所有的轮廓并将他们保存到表(list)中.图8-3描绘了从图8-2样图中得到的表.在这个例子中,有8条轮廓被找到,他们相互之间有h_prev和h_next连接(这里并没有使用v_prev和v_next)
CV_RETR_CCOMP 检出所有的轮廓并将他们组织成双层结构(two-level hierarchy),顶层边界是所有成份的外界边界,第二层边界是空的边界.图8-3中,我们能看到5个外部边界,其中3个包含孔.孔被v_next和v_prev可以只包括一个值,此节点可以只有一个子节点.c0中有两个孔,因为v_next可以值包括一个值,次节点可以只有一个子节点.c0之内的所有孔相互间有h_prev和h_next指针连接.
CV_RETR_TREE 检出所有轮廓并且重新建立网状的轮廓结构.在我们给出的例子中(图8-2和8-3中),这意味着根节点是最外的轮廓c0.c0之下是空h00,在同一层次中与另一个孔h01相连接.同理,每个孔都有子节点(相对应的是c000和c010),这些子节点与父节点被垂直连接起来.这个步骤一直持续到图像最内层的轮廓,这些轮廓会成为树叶节点.
以下的五个值与方法相关(例如轮廓会如何被近似).
CV_CHAIN_CODE 用freeman链码输出轮廓,其他方法输出多边形(顶点的序列)
CV_CHAIN_APPROX_NONE 将链码编码中的所有点转换为点
CV_CHAIN_APPROX_SIMPLE 压缩水平,垂直或斜的部分,只保存最后一个点
CV_CHAIN_APPROX_TC89_L1或CV_CHAIN_APPROX_TC89_KCOS使用Ten-Chin链逼近算法中的一个
CV_LINK_RUNS 与上述算法完全不同的算法,连接所有水平层次的轮廓.此方法只可与Cv_RETR_LIST搭配使用.
使用序列表示轮廓
当调用cvFindContours函数的时候,返回多个序列.序列的类型依赖与调用cvFindContours时 所传递的参数.默认情况下使用CV_RETR_LIST和CV_CHAIN_APPROX_SIMPLE参数.
序列中保存一系列的点,这些点构成轮廓,轮廓是本章的重点.轮廓只是序列所能表示物体的一种.轮廓的点的序列,可以用来表示图像空间中的曲线.这种点的序列很常用,所有需要有专门的函数来帮助我们对他进行处理.下面是一组这样的处理函数.
int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int header_size CV_DEFAULT(sizeof(CvContour)), int mode CV_DEFAULT(CV_RETR_LIST), int method CV_DEFAULT(CV_CHAIN_APPROX_SIMPLE), CvPoint offset CV_DEFAULT(cvPoint(0,0)));
CvContourScanner cvStartFindContours( CvArr* image, CvMemStorage* storage,