教学文库网 - 权威文档分享云平台
您的当前位置:首页 > 精品文档 > 学前教育 >

第七章 采用AAM和POSIT的3D头部姿态估计(3)

来源:网络收集 时间:2026-01-19
导读: 三角剖分——Trangulaiton 因为我们正在寻找的形状可能被歪曲,例如张开嘴的一个实例,我们需要将我们的纹理映射到一个均值形状,然后对这个标准化的纹理应用PCA。为了这样做,我们将使用三角剖分。它的概念非常简

三角剖分——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 points; //initialize points somehow ...

//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];

…… 此处隐藏:1059字,全部文档内容请下载后查看。喜欢就下载吧 ……
第七章 采用AAM和POSIT的3D头部姿态估计(3).doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印
本文链接:https://www.jiaowen.net/wendang/593685.html(转载请注明文章来源)
Copyright © 2020-2025 教文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ:78024566 邮箱:78024566@qq.com
苏ICP备19068818号-2
Top
× 游客快捷下载通道(下载后可以自由复制和排版)
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
注:下载文档有可能出现无法下载或内容有问题,请联系客服协助您处理。
× 常见问题(客服时间:周一到周五 9:30-18:00)