第七章 采用AAM和POSIT的3D头部姿态估计(3)
三角剖分——Trangulaiton
因为我们正在寻找的形状可能被歪曲,例如张开嘴的一个实例,我们需要将我们的纹理映射到一个均值形状,然后对这个标准化的纹理应用PCA。为了这样做,我们将使用三角剖分。它的概念非常简单:我们创建三角形包含我们标记的点,然而从一个三角形映射到另外一个三角形。OpenCV带有一个标记的函数,叫做cvCreateSubdivDelaunay2D,它创建一个空的Delaunay三角剖分。你可以仅认为这是一个好的三角剖分,它可以避免瘦长三角形。
注释:
在数学和计算几何上,平面内一个点集P的Delaunay三角剖分是一个这样的一个三角剖分:P中的每一个点都不会落在任何三角形的外接圆内。在三角剖分中,Delaunay三角剖分最大化三角形中所有角的最小角。从1934年之后,三角剖分以Boris Delaunay在这个方面的工作而命名。
一个Delaunay划分初始化之后,我们将使用cvSubdivDelaunay2DInsert函数将这些点填充到三角划分中。下面的代码行将说明一个三角剖分的直接使用将是什么样的: CvMemStorage* storage; CvSubdiv2D* subdiv;
CvRect rect = { 0, 0, 640, 480 }; storage = cvCreateMemStorage(0);
subdiv = cvCreateSubdivDelaunay2D(rect,storage); std::vector
//iterate through points inserting them in the subdivision//迭代遍历所有点,将它们插入到细分中 for(int i=0;i CvPoint2D32f floatingPoint = cvPoint2D32f(x, y); cvSubdivDelaunay2DInsert( subdiv, floatingPoint ); } 注意我们的点都是在一个矩形框架内,这个矩形将作为一个参数传递给cvCreateSubdivDelaunay2D。为了创建一个划分,我们也需要创建和初始化一个内存存储器。这可以在先前的代码的前5行看到。然而,为了创建三角剖分,我们需要使用cvSubdivDelaunay2DInset函数插入这些点。这发生在先前代码的for循环中。请注意点应当已经被初始化,因为它们是我们正在使用作为输入的点。下面的截图展示了三角剖分可能是什么样子: 这个截图是针对一组点先前的代码的输出,是使用Delaunay算法产生的三角剖分。 尽管划分的创建是OpenCV的一个非常便利的函数,迭代遍历所有的三角剖分可能不是非常简单。下面的代码展示了如何迭代遍历一个子划分的边。 void iterate(CvSubdiv2D* subdiv, CvNextEdgeType triangleDirection){ CvSeqReader reader; //序列阅读器 CvPoint buf[3]; //存储三角形的顶点 int i, j, total = subdiv->edges->total;//边的总数 int elem_size = subdiv->edges->elem_size;//边的大小,用来步进 cvStartReadSeq((CvSeq*)(subdiv->edges), &reader, 0);//初始化阅读器 for(i = 0; i < total; i++){ CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);//将阅读器的指针初始化为四方边缘指针 if(CV_IS_SET_ELEM(edge)){ CvSubdiv2DEdge t = (CvSubdiv2DEdge)edge;//获取四方边缘的一条边 for(j=0;j<3;j++){ CvSubdiv2DPoint* pt = cvSubdiv2DEdgeOrg(t);//获取边的原点 if(!pt) break; buf[j] = cvPoint(cvRound(pt->pt.x), cvRound(pt->pt.y));//将点存储起来 t = cvSubdiv2DGetEdge(t, triangleDirection);//获取下一条边 } } CV_NEXT_SEQ_ELEM(elem_size, reader);//使阅读器指向下一个元素 } } 给定一个剖分,我们初始化它的边读器(edge reader)称为cvStartReadSeq函数。从OpenCV的文献中,我们引用如下的定义: 函数初始化reader的状态,然后,所有序列元素,从第一个到最后一个,在前向阅读的情况下,可以通过调用子序列的宏CV_READ_SEQ_ELEM,在反向阅读的情况下,调用宏CV_REV_READ_SEQ_ELEM.。这两个宏将序列元素放入到read_elem并且移动reading 指针指向下一个元素。 获得接下来的元素的一个可替代的方式是使用宏CV_NEXT_SEQ_ELEM(elem_size,reader),如何序列元素很多,它是首选的。在这种情况下,我们使用CvQuadEdge2D *edge=(CvQuadEge2D*)(reader.ptr)来访问边缘,这仅是一个从一个reader指针到CvQuadEdge2D指针的一个强制转换。宏CV_IS_SET_ELEM仅检查指定的边是否被占用。给定一个边,我们需要调用cvSubdiv2DEdgeOrg函数来获得该边的源点。 为了遍历一个三角形,我们重复的调用cvSubdiv2DEdge并且传递三角形方向,例如它可以是AROUND_LEFT或者CV_NEXT_AROUND_RIGHT. 三角纹理变形(映射)——Triangle texture warping 既然我们能够 迭代的访问一个划分的三角形,我们能够将一个原始标记的图像变换到一个产生的扭曲的图像。这对于将原始形状的纹理映射到扭曲的形状很有用。下面的代码将引导这个过程: void warpTextureFromTriangle(Point2f srcTri[3], Mat originalImage, Point2f dstTri[3], Mat warp_final){ Mat warp_mat(2, 3, CV_32FC1);//仿射变换矩阵 Mat warp_dst, warp_mask; CvPoint trianglePoints[3]; trianglePoints[0] = dstTri[0]; trianglePoints[1] = dstTri[1];
相关推荐:
- [学前教育]MC9S12XS256RMV1 xs128芯片手册4
- [学前教育]安东尼语录经典语录
- [学前教育]e级gps控制测量技术设计书
- [学前教育]苏教版2022-2022学年八年级下学期期末
- [学前教育]装修公司推广 营销
- [学前教育]家政服务合同(完整版)
- [学前教育]湖北省2016届高三联考语文试题
- [学前教育]爱立信无涯学习系统LTE题库1-LTE基础知
- [学前教育]揭秘大众柴油车作弊软件原理
- [学前教育]人才流失原因及对策分析
- [学前教育]房屋建筑施工工程劳务分包合同
- [学前教育]国际贸易实务试卷A卷09.6
- [学前教育]校园废品回收活动计划方案书范文格
- [学前教育]电大成本会计试题及答案
- [学前教育]大学物理实验 华南理工出版社 绪论答案
- [学前教育]爱丁堡产后抑郁量表
- [学前教育]液压冲击的危害、产生原因与防止方法(
- [学前教育]学生工作总结高一学生期中考试总结_020
- [学前教育]人民医院医疗废物管理规章制度大全
- [学前教育]阳光维生素的巨大抗癌潜能阅读题答案.d
- 马云在云锋基金江苏论坛闭幕式的发言
- 试论小学体育教育中的心理健康教育-教
- 语文A版一年级下册《语文乐园一》教学
- 2021四川大学物理化学考研真题经验参考
- [人教A版]2015-2016学年高中数学 第二
- 终端网点销售返利协议书
- 江苏省2015年眼科学主治医师青光眼考试
- 2017年部编人教版八年级语文上册教案
- 十一中学七年级英语上册Unit7Howmuchar
- 以赛促教的创新性实验教学机制建设实践
- 平凉市崆峒区2015七年级下生物期末试题
- 琶洲(地块五)A、B塔楼1、2#塔吊基础
- 一级医院工作制度与人员岗位职责
- 2018北京西城区高三二模理科数学试题及
- 炒股密码线技术 - 图文
- 职高学生生涯发展辅导教案
- 语文人教版四年级上册8 世界地图引出的
- 最新最新人教版二年级上册全册数学教案
- 2017高考英语全国2卷精彩试题(有问题
- 普通心理学笔记




