用多边形曲线逼近 Freeman 链
CvSeq* cvApproxChains( CvSeq* src_seq, CvMemStorage* storage,int method=CV_CHAIN_APPROX_SIMPLE, double parameter=0, int minimal_perimeter=0, int recursive=0 );
-
src_seq
- 涉及其它链的链指针 storage
- 存储多边形线段位置的缓存 method
-
逼近方法 (见函数
cvFindContours 的描述).
parameter
- 方法参数(现在不用). minimal_perimeter
-
仅逼近周长大于
minimal_perimeter
轮廓。其它的链从结果中除去。
recursive
-
如果非 0, 函数从
src_seq
中利用 h_next
和 v_next links
连接逼近所有可访问的链。如果为 0, 则仅逼近单链。
这是一个单独的逼近程序。 对同样的逼近标识,函数 v_next
v_next
域来访问
初始化链读取
void cvStartReadChainPoints( CvChain* chain, CvChainPtReader* reader );
-
chain
链的指针 reader
链的读取状态
函数
得到下一个链的点
CvPoint cvReadChainPoint( CvChainPtReader* reader );
-
reader
- 链的读取状态
函数
用指定精度逼近多边形曲线
CvSeq* cvApproxPoly( const void* src_seq, int header_size, CvMemStorage* storage,int method, double parameter, int parameter2=0 );
-
src_seq
- 点集数组序列 header_size
- 逼近曲线的头尺寸 storage
- 逼近轮廓的容器。如果为 NULL, 则使用输入的序列 method
-
逼近方法。目前仅支持
CV_POLY_APPROX_DP
, 对应 Douglas-Peucker 算法.(依次找轮廓上离线段最远的点,直至这个最远的距离小于parameter1)
parameter
-
方法相关参数。对
CV_POLY_APPROX_DP
它是指定的逼近精度
parameter2
-
如果
src_seq
是序列,它表示要么逼近单个序列,要么在 src_seq
的同一个或低级层次上逼近所有序列 (参考 cvFindContours 中对轮廓继承结构的描述). 如果 src_seq
是点集的数组 ( CvMat*) , 参数指定曲线是闭合 ( parameter2
!=0) 还是非闭合 (parameter2
=0).
函数
计算点集的最外面(up-right)矩形边界
CvRect cvBoundingRect( CvArr* points, int update=0 );
-
points
-
二维点集,点的序列或向量 (
CvMat
)
update
-
更新标识。下面是轮廓类型和标识的一些可能组合:
- update=0, contour ~ CvContour*: 不计算矩形边界,但直接由轮廓头的
rect
域得到。(cvcounter有一个成员rect,保存轮廓的自己的边界框) - update=1, contour ~ CvContour*: 计算矩形边界,而且将结果写入到轮廓头的
rect
域中 header. - update=0, contour ~ CvSeq* or CvMat*: 计算并返回边界矩形
- update=1, contour ~ CvSeq* or CvMat*: 产生运行错误 (runtime error is raised)
- update=0, contour ~ CvContour*: 不计算矩形边界,但直接由轮廓头的
除了cvBoundingRect外,还有一个函数cvMinAreaRect2,这个函数返回包围轮廓的最小长方形,这个长方形很有可能是倾斜的。而上面的函数求出的长方形都是方正的,不能倾斜。
函数
计算整个轮廓或部分轮廓的面积
double cvContourArea( const CvArr* contour, CvSlice slice=CV_WHOLE_SEQ );
-
contour
- 轮廓 (定点的序列或数组). slice
- 感兴趣轮廓部分的起始点,缺省是计算整个轮廓的面积。
函数
NOTE: fabs()
计算轮廓周长或曲线长度
double cvArcLength( const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 );
-
curve
- 曲线点集序列或数组 slice
- 曲线的起始点,缺省是计算整个曲线的长度 is_closed
-
表示曲线是否闭合,有三种情况:
- is_closed=0 - 假设曲线不闭合
- is_closed>0 - 假设曲线闭合
- is_closed<0 - 若曲线是序列,检查 ((CvSeq*)curve)->flags 中的标识 CV_SEQ_FLAG_CLOSED 来确定曲线是否闭合。否则 (曲线由点集的数组 (CvMat*) 表示) 假设曲线不闭合。
- 还有个函数cvCounterPerimiter也是计算周长的,调用了cvArcLength,传递的is_close为1
函数
创建轮廓的继承表示形式
CvContourTree* cvCreateContourTree( const CvSeq* contour, CvMemStorage* storage, double threshold );
-
contour
- 输入的轮廓 storage
- 输出树的容器 threshold
- 逼近精度
函数 contour
threshold
threshold
threshold
由树恢复轮廓
CvSeq* cvContourFromContourTree( const CvContourTree* tree, CvMemStorage* storage, CvTermCriteria criteria );
-
tree
- 轮廓树 storage
- 重构的轮廓容器 criteria
- 停止重构的准则
函数 criteria
用树的形式比较两个轮廓
double cvMatchContourTrees( const CvContourTree* tree1, const CvContourTree* tree2,int method, double threshold );
-
tree1
- 第一个轮廓树 tree2
- 第二个轮廓树 method
-
相似度。仅支持
CV_CONTOUR_TREES_MATCH_I1
。
threshold
- 相似度阈值
函数 threshold
, 则中断比较过程,且返回当前的差值。
计算几何
对两个给定矩形,寻找矩形边界
CvRect cvMaxRect( const CvRect* rect1, const CvRect* rect2 );
-
rect1
- 第一个矩形 rect2
- 第二个矩形
函数
旋转的二维盒子
typedef struct CvBox2D {CvPoint2D32f center; CvSize2D32f size; float angle; } CvBox2D;
寻找盒子的顶点
void cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] );
-
box
- 盒子 pt
- 顶点数组
函数
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 );
-
points
- 点集的序列或数组
函数 size
2D 或 3D 点集的直线拟合
voidcvFitLine( const CvArr* points, int dist_type, double param, double reps, double aeps, float* line );
-
points
- 2D 或 3D 点集,32-比特整数或浮点数坐标 dist_type
- 拟合的距离类型 (见讨论). param
- 对某些距离的数字参数,如果是 0, 则选择某些最优值 reps, aeps
- 半径 (坐标原点到直线的距离) 和角度的精度,一般设为0.01。 line
-
输出的直线参数。2D 拟合情况下,它是包含 4 个浮点数的数组
(vx, vy, x0, y0),其中
(vx, vy)
是线的单位向量而 (x0, y0)
是线上的某个点. 对 3D 拟合,它是包含 6 个浮点数的数组 (vx, vy, vz, x0, y0, z0),
其中 (vx, vy, vz)
是线的单位向量,而 (x0, y0, z0)
是线上某点。
函数
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 );
-
points
- 2D 点集的序列或数组,32-比特整数或浮点数坐标 hull_storage
- 输出的数组(CvMat*) 或内存缓存 (CvMemStorage*),用以存储凸外形。 如果是数组,则它应该是一维的,而且与输入的数组/序列具有同样数目的元素。输出时修改头使得数组裁减到外形的尺寸。输出时,通过修改头结构将数组裁减到凸外形的尺寸。 orientation
-
凸外形的旋转方向: 逆时针或顺时针 (
CV_CLOCKWISE
or CV_COUNTER_CLOCKWISE
)
return_points
-
如果非零,点集将以外形 (hull) 存储,而不是
hull_storage
为数组情况下的顶点形式 (indices) 以及 hull_storag
为内存存储模式下的点集形式(points)。
函数 hull_storage
return_points
的值,创建一个包含外形的点集或指向这些点的指针的序列。
例子. 由点集序列或数组创建凸外形
#include "cv.h" #include "highgui.h" #include <stdlib.h> #define ARRAY0 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 );
-
contour
- 被测试轮廓 (点序列或数组).
函数
用来描述一个简单轮廓凸性缺陷的结构体
typedef struct CvConvexityDefect {CvPoint* start; CvPoint* end; CvPoint* depth_point; float depth; } CvConvexityDefect;
Picture. Convexity defects of hand contour.
发现轮廓凸形缺陷
CvSeq* cvConvexityDefects( const CvArr* contour, const CvArr* convexhull,CvMemStorage* storage=NULL );
-
contour
- 输入轮廓 convexhull
-
用
cvConvexHull2 得到的凸外形,它应该包含轮廓的定点或下标,而不是外形点的本身,即 cvConvexHull2 中的参数 return_points
应该设置为 0.
storage
- 凸性缺陷的输出序列容器。如果为 NULL, 使用轮廓或外形的存储仓。
函数
对给定的 2D 点集,寻找最小面积的包围矩形
CvBox2DcvMinAreaRect2( const CvArr* points, CvMemStorage* storage=NULL );
-
points
- 点序列或点集数组 storage
- 可选的临时存储仓
函数
Picture. Minimal-area bounding rectangle for contour
对给定的 2D 点集,寻找最小面积的包围圆形
int cvMinEnclosingCircle( const CvArr* points, CvPoint2D32f* center, float* radius );
-
points
- 点序列或点集数组 center
- 输出参数:圆心 radius
- 输出参数:半径
函数
计算轮廓的 pair-wise 几何直方图
void cvCalcPGH( const CvSeq* contour, CvHistogram* hist );
-
contour
- 输入轮廓,当前仅仅支持具有整数坐标的点集 hist
- 计算出的直方图,必须是两维的。
函数