用多边形曲线逼近 Freeman 链
CvSeq* cvApproxChains( CvSeq* src_seq, CvMemStorage* storage, int method=CV_CHAIN_APPROX_SIMPLE, double parameter=0, int minimal_perimeter=0, int recursive=0 );
minimal_perimeter
轮廓。其它的链从结果中除去。
src_seq
中利用
h_next
和
v_next links
连接逼近所有可访问的链。如果为 0, 则仅逼近单链。
这是一个单独的逼近程序。 对同样的逼近标识,函数 cvApproxChains 与 cvFindContours的工作方式一模一样。它返回发现的第一个轮廓的指针。其它的逼近模块,可以用返回结构中的 v_next
和 v_next
域来访问
void cvStartReadChainPoints( CvChain* chain, CvChainPtReader* reader );
链的指针
reader
链的读取状态
函数 cvStartReadChainPoints 初始化一个特殊的读取器 (参考 Dynamic Data Structures以获得关于集合与序列的更多内容).
CvPoint cvReadChainPoint( CvChainPtReader* reader );
函数 cvReadChainPoint 返回当前链的点,并且更新读取位置。
CvSeq* cvApproxPoly( const void* src_seq, int header_size, CvMemStorage* storage, int method, double parameter, int parameter2=0 );
CV_POLY_APPROX_DP
, 对应 Douglas-Peucker 算法.(依次找轮廓上离线段最远的点,直至这个最远的距离小于parameter1)
CV_POLY_APPROX_DP
它是指定的逼近精度
src_seq
是序列,它表示要么逼近单个序列,要么在
src_seq
的同一个或低级层次上逼近所有序列 (参考 cvFindContours 中对轮廓继承结构的描述). 如果
src_seq
是点集的数组 ( CvMat*) , 参数指定曲线是闭合 (
parameter2
!=0) 还是非闭合 (
parameter2
=0).
函数 cvApproxPoly 逼近一个或多个曲线,并返回逼近结果。对多个曲线的逼近,生成的树将与输入的具有同样的结构。(1:1 的对应关系).
CvRect cvBoundingRect( CvArr* points, int update=0 );
CvMat
)
rect
域得到。(cvcounter有一个成员rect,保存轮廓的自己的边界框)rect
域中 header.除了cvBoundingRect外,还有一个函数cvMinAreaRect2,这个函数返回包围轮廓的最小长方形,这个长方形很有可能是倾斜的。而上面的函数求出的长方形都是方正的,不能倾斜。
函数 cvBoundingRect 返回二维点集的最外面 (up-right)矩形边界。
double cvContourArea( const CvArr* contour, CvSlice slice=CV_WHOLE_SEQ );
函数 cvContourArea 计算整个轮廓或部分轮廓的面积。 对后面的情况,面积表示轮廓部分和起始点连线构成的封闭部分的面积。如下图所示:
NOTE: 轮廓的方向影响面积的符号。因此函数也许会返回负的结果。应用函数 fabs()
得到面积的绝对值。
double cvArcLength( const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 );
函数 cvArcLength 通过依次计算序列点之间的线段长度,并求和来得到曲线的长度。
CvContourTree* cvCreateContourTree( const CvSeq* contour, CvMemStorage* storage, double threshold );
函数 cvCreateContourTree 为输入轮廓 contour
创建一个二叉树,并返回树根的指针。如果参数threshold
小于或等于 0 ,则函数创建一个完整的二叉树。如果 threshold
大于 0 , 函数用 threshold
指定的精度创建二叉树:如果基线的截断区域顶点小于threshold,该数就停止生长并作为函数的最终结果返回。
CvSeq* cvContourFromContourTree( const CvContourTree* tree, CvMemStorage* storage, CvTermCriteria criteria );
函数 cvContourFromContourTree 从二叉树恢复轮廓。参数 criteria
决定了重构的精度和使用树的数目及层次。所以它可建立逼近的轮廓。 函数返回重构的轮廓。
double cvMatchContourTrees( const CvContourTree* tree1, const CvContourTree* tree2, int method, double threshold );
CV_CONTOUR_TREES_MATCH_I1
。
函数 cvMatchContourTrees 计算两个轮廓树的匹配值。从树根开始通过逐层比较来计算相似度。如果某层的相似度小于 threshold
, 则中断比较过程,且返回当前的差值。
CvRect cvMaxRect( const CvRect* rect1, const CvRect* rect2 );
函数 cvMaxRect 寻找包含两个输入矩形的具有最小面积的矩形边界。
typedef struct CvBox2D { CvPoint2D32f center; CvSize2D32f size; float angle; } CvBox2D;
void cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] );
函数 cvBoxPoints 计算输入的二维盒子的定点。下面是函数代码:
void cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] ) { float a = (float)cos(box.angle)*0.5f; float b = (float)sin(box.angle)*0.5f; pt[0].x = box.center.x - a*box.size.height - b*box.size.width; pt[0].y = box.center.y + b*box.size.height - a*box.size.width; pt[1].x = box.center.x + a*box.size.height - b*box.size.width; pt[1].y = box.center.y - b*box.size.height - a*box.size.width; pt[2].x = 2*box.center.x - pt[0].x; pt[2].y = 2*box.center.y - pt[0].y; pt[3].x = 2*box.center.x - pt[1].x; pt[3].y = 2*box.center.y - pt[1].y; }
CvBox2D cvFitEllipse2( const CvArr* points );
函数 cvFitEllipse 对给定的一组二维点集作椭圆的最佳拟合(最小二乘意义上的)。返回的结构与 cvEllipse中的意义类似,除了 size
表示椭圆轴的整个长度,而不是一半长度。
void cvFitLine( const CvArr* points, int dist_type, double param, double reps, double aeps, float* line );
(vx, vy, x0, y0),其中
(vx, vy)
是线的单位向量而
(x0, y0)
是线上的某个点. 对 3D 拟合,它是包含 6 个浮点数的数组
(vx, vy, vz, x0, y0, z0),
其中
(vx, vy, vz)
是线的单位向量,而
(x0, y0, z0)
是线上某点。
函数 cvFitLine 通过求 sumiρ(ri) 的最小值方法,用 2D 或 3D 点集拟合直线,其中 ri是第 i 个点到直线的距离, ρ(r) 是下面的距离函数之一:
dist_type=CV_DIST_L2 (L2): ρ(r)=r2/2 (最简单和最快的最小二乘法) dist_type=CV_DIST_L1 (L1): ρ(r)=r dist_type=CV_DIST_L12 (L1-L2): ρ(r)=2•[sqrt(1+r2/2) - 1] dist_type=CV_DIST_FAIR (Fair): ρ(r)=C2•[r/C - log(1 + r/C)], C=1.3998 dist_type=CV_DIST_WELSCH (Welsch): ρ(r)=C2/2•[1 - exp(-(r/C)2)], C=2.9846 dist_type=CV_DIST_HUBER (Huber): ρ(r)= r2/2, if r < C C•(r-C/2), otherwise; C=1.345
CvSeq* cvConvexHull2( const CvArr* input, void* hull_storage=NULL, int orientation=CV_CLOCKWISE, int return_points=0 );
CV_CLOCKWISE
or
CV_COUNTER_CLOCKWISE
)
hull_storage
为数组情况下的顶点形式 (indices) 以及
hull_storag
为内存存储模式下的点集形式(points)。
函数 cvConvexHull2 使用 Sklansky 算法计算 2D 点集的凸外形。如果 hull_storage
是内存存储仓, 函数根据 return_points
的值,创建一个包含外形的点集或指向这些点的指针的序列。
#include "cv.h" #include "highgui.h" #include <stdlib.h> #define ARRAY 0 void main( int argc, char** argv ) { IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 ); cvNamedWindow( "hull", 1 ); #if !ARRAY CvMemStorage* storage = cvCreateMemStorage(); #endif for(;;) { int i, count = rand()0 + 1, hullcount; CvPoint pt0; #if !ARRAY CvSeq* ptseq = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour), sizeof(CvPoint), storage ); CvSeq* hull; for( i = 0; i < count; i++ ) { pt0.x = rand() % (img->width/2) + img->width/4; pt0.y = rand() % (img->height/2) + img->height/4; cvSeqPush( ptseq, &pt0 ); } hull = cvConvexHull2( ptseq, 0, CV_CLOCKWISE, 0 ); hullcount = hull->total; #else CvPoint* points = (CvPoint*)malloc( count * sizeof(points[0])); int* hull = (int*)malloc( count * sizeof(hull[0])); CvMat point_mat = cvMat( 1, count, CV_32SC2, points ); CvMat hull_mat = cvMat( 1, count, CV_32SC1, hull ); for( i = 0; i < count; i++ ) { pt0.x = rand() % (img->width/2) + img->width/4; pt0.y = rand() % (img->height/2) + img->height/4; points[i] = pt0; } cvConvexHull2( &point_mat, &hull_mat, CV_CLOCKWISE, 0 ); hullcount = hull_mat.cols; #endif cvZero( img ); for( i = 0; i < count; i++ ) { #if !ARRAY pt0 = *CV_GET_SEQ_ELEM( CvPoint, ptseq, i ); #else pt0 = points[i]; #endif cvCircle( img, pt0, 2, CV_RGB( 255, 0, 0 ), CV_FILLED ); } #if !ARRAY pt0 = **CV_GET_SEQ_ELEM( CvPoint*, hull, hullcount - 1 ); #else pt0 = points[hull[hullcount-1]]; #endif for( i = 0; i < hullcount; i++ ) { #if !ARRAY CvPoint pt = **CV_GET_SEQ_ELEM( CvPoint*, hull, i ); #else CvPoint pt = points[hull[i]]; #endif cvLine( img, pt0, pt, CV_RGB( 0, 255, 0 )); pt0 = pt; } cvShowImage( "hull", img ); int key = cvWaitKey(0); if( key == 27 ) // 'ESC' break; #if !ARRAY cvClearMemStorage( storage ); #else free( points ); free( hull ); #endif } }
int cvCheckContourConvexity( const CvArr* contour );
函数 cvCheckContourConvexity 输入的轮廓是否为凸的。必须是简单轮廓,比如没有自交叉。
typedef struct CvConvexityDefect { CvPoint* start; CvPoint* end; CvPoint* depth_point; float depth; } CvConvexityDefect;
CvSeq* cvConvexityDefects( const CvArr* contour, const CvArr* convexhull, CvMemStorage* storage=NULL );
return_points
应该设置为 0.
函数 cvConvexityDefects 发现输入轮廓的所有凸性缺陷,并且返回 CvConvexityDefect结构序列。
CvBox2D cvMinAreaRect2( const CvArr* points, CvMemStorage* storage=NULL );
函数 cvMinAreaRect2 通过建立凸外形并且旋转外形以寻找给定 2D 点集的最小面积的包围矩形.
int cvMinEnclosingCircle( const CvArr* points, CvPoint2D32f* center, float* radius );
函数 cvMinEnclosingCircle 对给定的 2D 点集迭代寻找最小面积的包围圆形。如果产生的圆包含所有点,返回非零。否则返回零(算法失败)。
void cvCalcPGH( const CvSeq* contour, CvHistogram* hist );
函数 cvCalcPGH 计算轮廓的 2D pair-wise(Hunnish: 不知如何翻译,只好保留) 几何直方图 (pair-wise geometrical histogram :PGH), 算法描述见[Iivarinen97]. 算法考虑的每一对轮廓边缘。计算每一对边缘之间的夹角以及最大最小距离。具体做法是,轮流考虑每一个边缘做为基准,函数循环遍历所有边缘。在考虑基准边缘和其它边缘的时候, 选择非基准线上的点到基准线上的最大和最小距离。边缘之间的角度定义了直方图的行,而在其中增加对应计算出来的最大和最小距离的所有直方块, (即直方图是 [Iivarninen97] 定义中的转置). 该直方图用来做轮廓匹配。