人脸建模软件毕业论文(初稿).doc

上传人:仙人指路1688 文档编号:3934516 上传时间:2023-03-28 格式:DOC 页数:28 大小:892KB
返回 下载 相关 举报
人脸建模软件毕业论文(初稿).doc_第1页
第1页 / 共28页
人脸建模软件毕业论文(初稿).doc_第2页
第2页 / 共28页
人脸建模软件毕业论文(初稿).doc_第3页
第3页 / 共28页
人脸建模软件毕业论文(初稿).doc_第4页
第4页 / 共28页
人脸建模软件毕业论文(初稿).doc_第5页
第5页 / 共28页
点击查看更多>>
资源描述

《人脸建模软件毕业论文(初稿).doc》由会员分享,可在线阅读,更多相关《人脸建模软件毕业论文(初稿).doc(28页珍藏版)》请在三一办公上搜索。

1、目 录1 引言12 概述22.1 人脸建模软件概述22.2 本设计方案思路32.3 研发方向和技术关键32.4 主要技术指标43 软件设计53.1 软件框架的搭建63.2 特征点的选取63.3 OpenGL环境下3D模型的显示73.4 建模方法83.5 模型文件格式93.6 其他说明94 软件框架的实现104.1 框架概要104.2 图形用户界面的实现104.3 OpenGL环境的实现124.4 照片和特征点的实现155 核心算法的实现175.1 算法概要175.2 数学归化算法175.3 拉普拉斯变形算法185.4 Mask透明截图算法216 调试247 结论26致谢27参考文献281 引言

2、人脸是人类日常情感表达和交流最重要、最直接的载体。人脸的计算机建模应用非常广泛,比如说电影、广告人物动画、电脑游戏、视频会议、人机接口、面部外科手术、电视节目、计算机辅助手语教学以及心理学、认知科学等许多领域。 一个具有真实感的人脸模型能够丰富人机接口,增强系统非口语语言通信及表情信号的能力,使人机接口更令使用者感兴趣,且更易于使用。通过计算机生成具有真实感的三维人脸拥有广阔的应用前景,而且这项技术是近年来计算机图形学、计算机视觉、人工智能等领域中最具挑战性的问题之一。其实,早在20世纪70年代关于人脸建模及动画的研究便开始了。这个开创性的工作是由Parke起步的。接着Waters等人提出了广

3、泛应用的肌肉模型方法。Cohen和Massaro以及其他很多研究者对可视化语音合成进行了初步的尝试。随着网络技术的普及,世界上第一个网上虚拟播音员Ananova在伦敦发布,计算机合成的Ananova可以一天24小时发布新闻。人脸建模的应用现在已经非常广泛,模型的真实程度也较以前有了很大的飞跃。利用三维扫描仪获取三维形状数据和纹理信息是一种直接的人脸建模方法,通常具有较高的精度,但是存在硬件设备造价高、不灵活等不足,一般只适用于某些特殊场合;当前的研究热点主要集中在根据图像和视频序列进行人脸重建,现有基于多张图像的方法普遍存在特征点匹配复杂、效率低等不足。根据单张人脸照片上的少量特征点能够快速、

4、自动地实现特定人脸的建模,是目前三维人脸建模研究中一个极具潜力的研究方向。本设计就是制作一个基于单张人脸照片的快速、自动建立个性化人脸模型的应用软件。其目标是以较少的输入和交互操作,自动建立人脸3D数据模型,所建立的模型与人脸照片中的样本具有较高的相似度。2 概述2.1 人脸建模软件概述一般的,人脸建模软件的设计包括以下3个过程:脸部数据的获取、3D人脸几何建模、纹理图像的合成提取。通过人体测量学对相似的面部进行测量,对其结果进行统计,生成脸的统计学数据。这些统计学数据被当作对参数化表面的约束。对特定人脸的建模依然需要用户输入大量的数据,但现在也可以通过激光扫描仪和立体摄像机等自动实现。人脸几

5、何建模就是把真实人脸的框架标准化,然后用网格表示出来。这也是本次毕业设计的难点,因为真实人脸几何建模非常困难并且很耗时间,真实的人脸是高度光滑且形状复杂的,并且人们对它的每一个细节都非常熟悉.对于3D人脸几何建模,通常情况下,为了把脸表达得更加详细、生动,总是希望网格数越多越好,但是考虑到计算代价,又不可能把网格数无限制地增加.3D人脸几何建模的最基本要求是,能够表达清楚脸部的明显特征,同时希望网格数尽可能的少.脸部模型生成方法大致可以分为3种:多边形建模技术、曲面建模技术和体网格建模技术.人脸纹理图像的生成也是很重要的一个环节,对模型附加纹理可以极大的提高模型和真实源的相似度,因为纹理图像可

6、以表现出模型本身很难表达出的信息,比如说像睫毛这样细小的细节。通过人脸照片可以直接提取人脸的纹理特征,主要应用的技术有Mask图,Alpha透明度合成等。软件中的建模方法用到了标准人脸变形法,这个方法是将一个已经完成建模的3D人脸模型数据,根据特征化人脸照片及其特征点位置,利用一定的变形算法,通过一般化人脸到特征化人脸的变形来完成建模的。这个方法属于多边形建模法,而且理解起来比较容易,具备一定的可行性。但缺点是模型变形的控制有限,不能还原所有的3D数据。变形完成以后的模型,通过Mask图提取照片中的纹理特征,在提取照片之前还应注意照片中人脸大小的标准化。对提取的特征使用Alpha调节透明度,使

7、之融合在标准的人脸纹理上。本毕业设计中其他的工作点在于软件界面的设计和制作上。为了实现较好的人机交互功能,必须设计好软件的输入和输出操作。因为输入和输出操作是直接对用户可见的。而其他软件操作则是只有软件本身可见的,不对用户开放。所以用户可以不用关心模型的实际建模过程。2.2 设计方案思路本设计中最主要的要点在于1.软件界面的设计和制作;2.图片的导入;3.特征点的调整;4.3D模型的显示;5.对3D模型的交互;6.标准3D模型的变形算法;7.纹理特征图像的提取合成;8.特征点数据的三维化;9.模型文件和纹理文件的保存。1. 利用MFC的框架设计和制作软件界面;2. 利用文件的读取来完成照片图片

8、的导入;3. 通过建立特征点的数据结构,利用MFC提供的图形图像接口完成特征点的显示和控制;4. 建立OpenGL的图形环境,通过文件打开3D模型的OBJ文件,建立3D模型的数据结构,在OpenGL的环境中显示3D模型;5. 使用MFC提供的消息处理机制,完成OpenGL和消息的互动,由此对3D模型进行交互;6. 通过特征点的相对位置,采用拉普拉斯变形算法解决3D模型的变形问题;7. 通过特征点的相对位置,缩放原始照片图像,再用mask图对人脸照片的特征纹理进行提取和合成;8. 利用特征点的2维相对位置,寻找3维模型正面视图的边界点,通过寻找到的边界点完成2维数据的3维化。9. 在建模过程中生

9、成特征模型所需的数据,并建立临时文件,以便保存文件数据。2.3 研发方向和技术关键(1) 建立友好的图形用户界面,方便用户操作;(2) 面向对象的软件编程,MFC的API;(3) OpenGL的环境搭建和消息的传递;(4) 3D模型的显示、交互以及拉普拉斯变形;(5) 特征点2维数据的3维化;(6) 纹理特征的提取和合成。2.4 主要技术指标(1) 软件运行环境: 操作系统:Microsoft Windows XPMicrosoft Windows 7 内存:2GB 硬盘:50MB 软件环境:glmf32.dll; glu32.dll; glut32.dll(2) 模型顶点数:863个(3)

10、模型纹理顶点数:900个(4) 模型面片数:1630个3 软件设计人脸3D模型的建模过程主要包括3部分,第一步是用户输入人脸照片并调整特征点的位置,接着建立3D模型的数据结构和纹理合成,最后将建立好的人脸模型以文件的形式输出,保存到电脑上以便其他建模软件应用。根据建模过程可以将软件分为5个模块:输入模块;模型数据模块;纹理数据模块;核心算法模块(数据处理模块)和输出模块。具体的模块图可参见图3-1:图3-1 人脸建模软件模块图输入模块主要为用户提供人脸正面照片的导入功能,以及在导入照片后自动显示人脸特征点,并使用户可以执行修改这些特征点的操作。输入模块还提供给用户直接打开模型文件的功能。模型数

11、据模块的功能是保存用户导入的人脸模型数据和标准人脸模型数据,为这些数据建立数据结构。这些数据常驻内存,方便软件时刻对数据进行修改和保存。纹理数据模块为人脸模型的纹理图形建立数据结构,并且纹理数据包括用户输入人脸照片的图像数据。核心算法模块(数据处理模块)的功能是利用数学算法对模型数据和纹理数据进行操作。操作的依据是用户输入的照片图像以及用户调整后的人脸特征点的相对位置。由特征点相对位置调整人脸标准模型数据各个顶点的三维坐标,再由用户输入照片的图像数据合成人脸模型的纹理数据,并将这些数据保存至模型数据模块和纹理数据模块。输出模块的功能有OpenGL的显示及交互,它为用户提供良好的模型显示效果以及

12、对模型的控制功能,包括平移、旋转、缩放;还有用户导入照片以及人脸特征点的显示。输出模块的另一个作用是将模型文件(OBJ文件)保存到硬盘。3.1 软件框架的搭建人脸建模软件第一步需要的是一个具有较好交互性的图形用户界面。所有的输入和输出功能,必须体现在所设计的界面元素上。首先,输入功能包括:打开模型文件、建立模型文件、导入照片、对模型显示界面的控制操作、特征点的调整。其次,输出功能包括:保存模型文件、照片列表视图、显示3D模型的OpenGL视图、调整特征点用的照片视图。其中,打开模型文件、建立模型文件、保存模型文件作为软件界面的工具栏元素;导入照片和照片列表视图为照片列表元素;对模型显示界面的控

13、制操作和显示3D模型的OpenGL视图属于模型界面元素;特征点的调整和调整特征点用的照片视图属于特征点调整界面元素。对软件的界面设计如下图(图3-2)所示:图3-2 个性化真实感人脸建模软件界面最上面有两个图像按钮的一层为软件界面的工具栏元素,最左侧显示小照片和照片名称的列表为照片列表元素,中间显示3D人脸模型的就是模型界面元素,最右面用于调整特征点的即是特征点调整界面元素。3.2 特征点的选取人之所以能够通过视觉区别不同的人,主要是因为人面部的特征各有不同。经过专家计算分析,人面部光正面的关键特征点总数就达70个之多。这么多的特征点,对于如何从照片中提取是一个复杂的问题。本设计使用的方法是人

14、工调整这些特征点,那么太多数量的特征点势必增加用户的工作量,而且太多的特征点在数据结构的建立和计算上的难度很大。所以必须使用数量既少,又能较好表现人脸关键特征的特征点。在对其他人脸面部建模软件的调研中发现,FaceGen人脸建模软件使用了11个正面人脸的特征点。这些特征点的位置如下:颧骨的左右两个边界点,这两个特征点相当于是人脸部正面的左右两个边界,直接决定了人面部的宽度。下巴最下部的特征点,这个点即是人面部的下边界。两侧脸颊的中央拐点,这两个点确定了人面部的曲线由颧骨到下巴的趋势,是人面部形状的重点特征。两个眼睛的眼球中点,这两个点直接表示了人双眼的位置。左右两侧鼻翼的边界点,这两个特征点表

15、示了人鼻子的宽度和在面部的位置,通过人眼睛的两个特征点计算,还可以大致判断鼻子的长度。左右嘴角的两个边界点,同鼻翼两侧边界一样,这两点确定了嘴巴的宽度和位置。具体的特征取样如下图3-3所示(以软件中标准面部模型为例):图3-3 标准面部模型正面全部特征点,绿色亮点为特征点标记3.3 OpenGL环境下3D模型的显示为了较好的显示3D模型,软件使用了OpenGL作为3D模型绘制的接口。所以必须要配置OpenGL的图形环境,设置好该环境下的各项数据。首先设置OpenGL的显示环境,确定OpenGL的显示视图,视图的长、宽以及长宽比,还有显示的最小深度和最大深度,确定显示像素的属性。其次是导入模型数

16、据,调用OpenGL绘制函数,将模型的顶点、面片在图形显示视图上显示出来。最后打开纹理图像,为图形赋予纹理,同样须通过OpenGL的接口。其中需要注意的是,OpenGL的显示环境在配置好以后不宜任意改变,所以对于不可改变的显示环境,并不能匹配所有的模型文件。这样的话就不能提高软件的适用范围,而且局限了软件能够使用的模型文件。这样的话,我们在导入模型数据以后,为了使模型的数据适应到OpenGL的显示环境,必须对这些数据进行归化。本软件使用的归化方法是将所有的顶点坐标控制在-1, 1之间,这样OpenGL环境配置只需要考虑完全显示-1, 1之间的信息就可以了。3.4 建模方法本设计应用到的建模方法

17、是标准化模型变形建模法。软件自身含有一个标准的人脸模型,通过对这个标准模型的面部形状和纹理进行特征化的变形合成后,生成一个具备一定特征的人脸模型。这个方法中最重要的部分就是如何使用用户照片中的人脸数据。首先,通过用户自己完成对特征点的调整。具体的调整方法参照3.2中叙述的特征点位置的选取。之后,使用提取到的顶点坐标,将坐标值归化在-1, 1之间。如此是为了使2维坐标与3维坐标相对应。3维坐标在显示模型时已经进行了-1, 1之间的归化。这样的话就可以将2维的数据信息映射到3维视图中了,通过这些信息标定3维顶图形对应顶点的目标位置,通过这个位置,就可以对3维顶点进行操作了。最后,使用拉普拉斯变形,

18、将对应顶点移动到标定的位置即可。以上为3维模型的数据建模过程,建模方法中还应有一步,即提取和合成照片中人脸的纹理图像。提取纹理过程的前两步和建模时的相同,都是对特征点信息的操作,方法也是一样的。纹理提取还应注意的是特征点的划分,因为特征点的位置具有一般性,所以必须将每个特征点位置的含义了解清楚。比如,哪个特征点是眼睛,哪个是鼻子。将特征点划分好后就可以分块截图了。分块做的目的主要是为了准确的提取特征,因为每个人的面部特征都是不尽相同的,不可能用一个标准的模子提取出准确的特征。之后就可以提取具体特征了,使用制作好的mask图。每张mask图都对应一张分块截图,使用mask图提取的特征即可以合成到

19、纹理图像上了。这里的合成方法是半透明合成法,分别取特征和标准纹理的50%进行合成,这样合成的纹理既可以保持一定的特征性,又可以和标准纹理相融合,比较符合建模的要求。3.5 模型文件格式本软件支持的模型文件格式为OBJ格式的文件,OBJ格式为三维模型文件的一般格式。它主要保存的信息有:模型注释信息;3维点集;2维纹理点集;3维面片集;2维纹理面片集。OBJ文件是未经压缩的模型数据文件,这些数据的编码为ASCII码。一般来说,对于点、面片数量庞大的模型文件,OBJ格式的文件读取速度较慢。但就信息查询来说,它能直观的反应点和面片的数据信息,对调试程序有很大的帮助。而且本软件用到的高模人脸模型的总记录

20、数约在25200-27200之间。但就读取文件来说不会对性能造成太大的影响,所以本软件以OBJ文件作为模型的输入输出文件。下面介绍详细的文件格式:数据标识符介绍详细说明#注释信息注释信息o模型来源说明模型的制作软件g纹理名称纹理图像名称的前缀s分组信息将模型从1开始分组v模型顶点模型的空间坐标(x, y, z)vt纹理顶点模型的纹理图像坐标(x, y)f面片模型面片所含顶点的序号/面片分隔符左边为模型序号,右边为纹理序号表格3-1 标准面部模型正面全部特征点3.6 其他说明本软件使用的编程环境是visual studio 2008下的MFC,所用到的图像操作接口除了MFC提供的之外,还有CXI

21、mage。CXImage是一款免费的图像操作接口,它的功能非常强大,这里主要用到了它对图像数据的操作,如:图像裁剪,图像提取等等。需要注意的是CXImage中对于图像(0, 0)点的位置与MFC中窗口的默认原点不同,CXImage使用左下角第一个点作为它的原点。在CXImage与windows窗口进行图像数据传递时必须进行图像坐标的转换。4 软件框架的实现4.1 框架概要本软件的框架内容如第3章软件设计中介绍的那样,包含图形用户界面和基本的输入、输出功能。具体实现时,我们把它分开成3个模块:第一模块为界面模块,即软件的图形用户界面的实现;第二模块为OpenGL环境模块,它代理所有有关OpenG

22、L的接口调用;第三模块为照片和特征点模块,这个模块管理用户导入的人脸照片、并提供给用户调整特征点的接口。上述为了软件基础框架的实现所分成的3个模块与设计中依据功能划分的模块不同,这3个模块的划分主要是为了编程的实际操作的方便划分的,这3个模块在实现时会同时完成功能模块中提到的内容。那么下面就围绕具体实践来介绍这3大模块的编程实现。4.2 图形用户界面的实现对于现在的软件程序,图形用户界面的编写非常的容易,因为所有的接口都已经被设计好,并且我们只需要调用它的方法就好了。尤其对于基于MFC的程序来说,图形界面的编程非常的方便,很多方法visual studio 2008已经代劳。那么我在这里将不再

23、赘述一个windows环境下软件图形窗口的建立,而是直接介绍用于窗口排版的程序接口,以便大家了解窗口的样式是如何实现的。软件的界面在第3章已为大家展示过了,为了方便阅读,仍然在下面附上软件的截图,并换张明星的照片以防审美疲劳。图 4-1 软件界面如上图所示:软件的框体按界面元素分可以分成3个部分:第一部分是菜单栏,第二部分是工具栏,第三部分是分隔栏分割成的3个视图。菜单栏和工具栏的创建都是MFC自动完成的,其实MFC自动完成的还应该有窗口底层的状态栏,我在软件中屏蔽了状态栏的生成。我想在这里主要说一下自定义工具栏的实现和分割视图的方法,让它们以上图所示的布局出现主要依靠了两个类,分别是CToo

24、lBar以及CSplitterWnd。因为工具栏系统已经生成好了,所以我们在这里的自定义工具栏只要重新设置一些参数就好了。当然也可以新建一个工具栏类,这样的话就可以在其他程序里方便的使用自定义的工具栏了。这里需修改的参数主要有,工具栏的大小,工具栏的贴图。修改工具栏大小很简单,在资源视图中打开工具栏属性直接就能修改,我这里设置的大小是宽64p,高48p。而且资源视图也提供工具栏图像的修改,但是它提供的色彩范围有限,只提供了256色,所以为了界面的美观,还是以贴图形式来美化工具栏的好。制作图片的步骤在此略过,只论贴图方法吧。为CToolBar贴图需要在修改程序,添加贴图函数。添加贴图函数的过程如

25、下:首先制作的图像需要保存到一个CImageList中;之后我们需要让CToolBar产生一个消息“CToolBar.SendMessage(TB_SETIMAGELIST, 0, (LPARAM)CImageList.m_hImageList)”,让这个消息告知程序来显示我们自定义的工具栏图标;产生消息后,要释放CImageList资源,以便减轻内存负担。如此,我们就实现了自定义工具栏的制作。CSplitterWnd是实现视图分割的系统类,人脸建模软件里的视图被分成了1行3列的3块,分别显示了照片列表,人脸模型和含特征点的照片。视图切割是这样执行的。首先,所分成的三个视图是不同的视图,需要我

26、们重新定义它们的类结构。例如显示模型的视图我们定义它的类为CModelView,并继承CView类,在主函数中定义这些视图的变量。创建好它们3个不同的视图类后,我们就可以初始化CSplitterWnd了。通过函数CreateStatic将总视图划分为1行3列的结构,接着利用CreateView函数将视图绑定到相应的位置,例如CModelView在中间,那么它的位置就是0行1列(行号、列号从0开始计算)。我们最后将创建好的视图利用GetPane赋值给我们在主函数定义的视图变量就完成视图创建了。需要注意的是,所有的代码需在OnCreateClient消息里完成,即在窗体空间开始创建之前。而且如果创

27、建的分割有行中列或列中行的情况则需要一个新的CSplitterWnd类来分割上一个CSplitterWnd的子视图。4.3 OpenGL环境的实现为了观察一个3D模型,我们必须为软件配置一个能够展示三维效果的显示环境,我们选择OpenGL作为3D模型的显示环境。OpenGL是一个图形用户接口,它里面定义了大量的函数,可以方便的调用,而且它是跨平台的,功能非常强大。为了使用OpenGL,首先需要配置OpenGL的运行环境。配置环境的循序是这样的,首先要获取视图对象,从中得到HDC,这样OpenGL就可以利用HDC来绘制图形了;接着设置OpenGL绘图的像素格式,这是为了控制OpenGL的显示信息

28、,例如颜色的位数,Alpha通道之类的设置等等;下一步是把OpenGL中的HRC关联到视图的HDC上;接着需要设置场景信息,例如场景的显示大小长宽,可见的最大最小距离,视口的长宽比等等。现在我们的OpenGL环境就初始化完成了。不过为了达到好的显示效果,我们还可以继续为OpenGL的环境添加内容。一般的模型都会贴附一些纹理图像,我们在初始化OpenGL时往往会将这些需要用到的纹理也一同创建好。在创建纹理时,我们首先要打开计算机中的纹理图像文件,将这些图像按OpenGL的图像结构绑定,接着设置好纹理的显示方式就好了。OpenGL中常用到的设置还有阴影显示效果、背景颜色、深度缓存、透视修正方式、模

29、型材质和光照等等。为了提高模型的显示效果,我们可以把这些设置提高,不过这样必然导致显示速度会变慢。一般来说这些设置应该对用户可见,即用户可以根据自己设备的性能选择到底是显示优先还是速度优先。完成了OpenGL的配置,我们就可以绘图了,利用OpenGL提供的glBegin、glEnd就可以绘制图形了,下面是我绘制人脸面片的一段代码,由于既有三角面片又有矩形面片,所以程序在绘制时分开讨论了:glPushMatrix();for(int i=1, index=0; i=pts.m_nFNum; i+)if(i = pts.m_nIndexFlatindex)/ 选择纹理glBindTexture(G

30、L_TEXTURE_2D, pts.m_TextureIndexindex); index +;if(pts.m_nFlati3 = 0) / 三角面片glBegin(GL_TRIANGLES);glTexCoord2f(pts.m_fVertexTexturepts.m_nFlatTexturei00, pts.m_fVertexTexturepts.m_nFlatTexturei01);glVertex3f(pts.m_fVertexpts.m_nFlati00, pts.m_fVertexpts.m_nFlati01, pts.m_fVertexpts.m_nFlati02);glTex

31、Coord2f(pts.m_fVertexTexturepts.m_nFlatTexturei10, pts.m_fVertexTexturepts.m_nFlatTexturei11);glVertex3f(pts.m_fVertexpts.m_nFlati10, pts.m_fVertexpts.m_nFlati11, pts.m_fVertexpts.m_nFlati12);glTexCoord2f(pts.m_fVertexTexturepts.m_nFlatTexturei20, pts.m_fVertexTexturepts.m_nFlatTexturei21);glVertex3

32、f(pts.m_fVertexpts.m_nFlati20, pts.m_fVertexpts.m_nFlati21, pts.m_fVertexpts.m_nFlati22);glEnd();else / 矩形面片glBegin(GL_QUADS);glTexCoord2f(pts.m_fVertexTexturepts.m_nFlatTexturei00, pts.m_fVertexTexturepts.m_nFlatTexturei01);glVertex3f(pts.m_fVertexpts.m_nFlati00, pts.m_fVertexpts.m_nFlati01, pts.m_

33、fVertexpts.m_nFlati02);glTexCoord2f(pts.m_fVertexTexturepts.m_nFlatTexturei10, pts.m_fVertexTexturepts.m_nFlatTexturei11);glVertex3f(pts.m_fVertexpts.m_nFlati10, pts.m_fVertexpts.m_nFlati11, pts.m_fVertexpts.m_nFlati12);glTexCoord2f(pts.m_fVertexTexturepts.m_nFlatTexturei20, pts.m_fVertexTexturepts.

34、m_nFlatTexturei21);glVertex3f(pts.m_fVertexpts.m_nFlati20, pts.m_fVertexpts.m_nFlati21, pts.m_fVertexpts.m_nFlati22);glTexCoord2f(pts.m_fVertexTexturepts.m_nFlatTexturei30, pts.m_fVertexTexturepts.m_nFlatTexturei31);glVertex3f(pts.m_fVertexpts.m_nFlati30, pts.m_fVertexpts.m_nFlati31, pts.m_fVertexpt

35、s.m_nFlati32);glEnd();glPopMatrix();/交换缓冲显示图像SwapBuffers(m_hDC);这里的交换缓冲显示图像很重要,如果没有这行代码,绘制的模型将不会显示在视图中。当然这里的绘制只能绘制了3D模型的一种显示角度,对于不同角度的显示须有用户的交互来实现。对模型的平移,旋转和缩放才是3D环境的真谛,下面我们来谈谈如何实现OpenGL中对于镜头的操作。我们可以把OpenGL视图看做一个摄像机的镜头,如果我们想观察物体的其他角度,要么使物体改变,要么就改变我们自己这台摄像机,当然也这两种改变也可以同时存在。在我的程序中平移和缩放是通过改变摄像机来实现的,而旋转

36、是通过改变模型来实现的。其实我们应该尽可能的使用摄像机来完成交互,因为改变物体的坐标系会使模型坐标变得复杂,容易引发错误而难以纠正。不过我们的3D显示比较简单,只有一个人脸模型,直接旋转物体比旋转摄像机控制起来容易,所以我才用直接旋转物体的方法来做旋转交互。了解了以上方法,我们就可以直接调用OpenGL的函数来实现交互了。利用gluLookAt()实现平移与缩放,利用glRotatef()实现旋转。首先来看gluLookAt()函数,这个函数的参数是9个立体坐标,分别代表视点,观察点和向上向量。视点就是我们摄像机所在的位置啦,观察点顾名思义,就是我们视觉中心。通过视点和观察点可以决定一个向量,

37、这个向量就代表我们摄像机的朝向。向上向量就是摄像机所在坐标系的纵轴向量。通过摄像机的朝向向量、向上向量,OpenGL就可以计算得出摄像机自身的坐标系,而OpenGL正是通过这个坐标系来计算摄像机的一些数据的。我们移动摄像机,就是改变这个坐标系,平移就是同时等量的改变视点和观察点,缩放就是沿摄像机的朝向减少或增加视点到观察点的距离。而对于旋转中用到的glRotatef()函数,则只要简单的定义旋转的角度和旋转轴就可以了,不需要经过三角函数的计算,这一点比通过gluLookAt()实现要方便。以上便是OpenGL环境的实现,纵观所述,3D界面编程主要包括三维环境的初始化,图形绘制和用户交互三个方面

38、,而这三方面都要用到OpenGL所提供接口,所以才称之为OpenGL的环境实现。4.4 照片和特征点的实现照片和特征点的功能包括:打开图片文件,显示图片和特征点以及对特征点的操作。其中打开图片文件和显示图片都是用到了CxImage的接口;特征点的显示图片是我用PS制作的,是一个绿色的十字标志;对特征点的操作包括拖动单一特征点到指定位置,还有拖动所有特征点到指定位置。用CxImage打开图片非常简单,这里还借助了MFC提供的CFileDialog类,可以通过我们习惯的对话框的方式打开文件。我想要详细介绍的是显示图片和特征点的功能以及对特征点的交互功能。单纯的显示一张图片文件非常方便,而我们不仅仅

39、要在图片区域显示原始的照片,更重要的是要显示特征点,以便我们对其进行操作。这样的话就需要对打开的图片文件进行一定的修改,为其附加上特征点,使他们融合成为一张新的图片。一方面我们可以利用软件计算来绘制一个指定颜色的十字标志,这样做的好处是不用另外保存特征点图像文件,但这样做对图像的绘制速度是有影响的。如果利用计算完成绘制,在我们拖动特征点时会有“卡”的感觉,所以我选择了第二种方法,就是保存一张十字标志的图片,这样绘制时的速度就有了保证。但是保存的图片在导入资源后是BMP格式的,也就是说,这张图片不存在透明区域,直接复制在照片上时,照片上将多出一个矩形,而不是单纯的十字标志。这样的话,就需要引入一

40、个Mask图作为控制透明区域的图像。Mask就是一张灰度图像,我们这里用到的就是一张只有黑和白的Mask图,而更灵活的应用我将在下一章的Mask图透明截图算法中再详细介绍。一张Mask图像,黑色部分表示不透明,白色表示全透明。其原因是这样的:在计算机中,保存色彩信息的RGB格式,黑色的数据是(0,0,0),白色的是(255,255,255),转换成二进制的话,黑则全0,白则全1。如果我们利用这张“黑白分明”的图片对原始照片做“与”操作的话,那么原始照片上与Mask白色对应的部分将没有任何改变,而黑色的对应部分将全部变黑,就好像挖了一个洞一样。再利用Mask图做透明处理时,我们绘制特征点图像的时

41、候也是有技巧的,透明区域的颜色必须表示成黑色。这是因为,我们为原图附加Mask了以后也要附加特征点图像,而这步操作用到的是“或”运算。想想看,原图上的色彩或上特征点图像上黑色的点,则色彩不改变,而原图黑色部分的色彩则会完全变成特征点图像上的颜色。这也正是我们在附加Mask图时把待填充区域变成黑色的一个原因。如此,单纯的与或操作就实现了图片的透明化处理。下图为十字标志透明化贴图的示意图:图4-2 利用Mask图实现透明化贴图当然,光显示特征点是不够的,我们显示的目的还是为了交互。交互的实现需要我们为显示照片的View添加消息,即鼠标左键按下OnLButtonDown、鼠标移动OnMouseMov

42、e和鼠标左键抬起OnLButtonUp。按下左键后,我们首先要根据鼠标位置搜索对应的特征点,如果找到,则标记该特征点,如果没有则标记所有特征点(因为我们在没有选择任何特征点并按下鼠标时,将视为改变所有特征点位置)。之后我们记录鼠标按下的布尔值为真并记录鼠标位置。当鼠标移动时,我们首先判断鼠标是否按下的布尔值,若值未假则不作任何处理,若值为真,则记录鼠标位置,通过之前记录的位置作比较求的鼠标的位移,以此位移值来确定控制点的位置。左键按下后,我们只需要将标记点的标记去掉并记鼠标按下的布尔值为假就好了。5 核心算法实现5.1 算法概要本软件涉及到的算法主要是基于图形学的数学算法。其中包括数学归化,拉

43、普拉斯变形算法,Mask透明截图算法等。数学归化是用来统一数据单位长度的算法,其作用是将一个一般化的数学模型统一化到一个固定的坐标系里,这样做有利于对数据的处理和比较。拉普拉斯变形算法是用于对3D人脸模型变形的算法,它主要实现了改变一个顶点并影响与该顶点相关的其他顶点的功能。这样做的好处是可以通过对尽量少的顶点的操作来完成模型整体的变形。Mask透明截图算法是提取图像中指定位置像素值的算法,透明截图即通过Mask掩膜的灰度来判断图像的透明度。Mask透明截图算法可以较好的提取出照片中的人脸特征图像,以提供给合成纹理图片操作。5.2 数学归化算法本软件使用数学归化的目的是将一个任意坐标系的模型坐

44、标缩放到-1, 1的坐标范围内。对于2维图像坐标,即将x坐标和y坐标缩放到-1, 1的坐标范围,对于3维的模型坐标,即将x坐标、y坐标和z坐标缩放到-1, 1的坐标范围。缩放方法是这样的,假设我们要缩放一个2维的图像坐标。我们第一步需要找到这个图像坐标系的极值,即比较坐标系的宽度和长度,选取其较长的一边,取它两端的极值max,min。设归化前得坐标为X,归化后的坐标为x,那么将其缩放到-1, 1的坐标范围的公式是:证明:利用等比性质,缩放后的x减最小极值-1比缩放前X减最小极值min的值等于2比原始坐标系的极值长度,即max-min。需要注意的是,使用这个公式的话,较短边得坐标起点必然从-1开

45、始,而较短边的最大点不在+1处。数学归化算法的软件实现较为简单,首先遍历所有坐标,找到x、y还可能有z的极值,利用极值求的max和min。然后再遍历一边,将所有的数据直接公式带入就可以了。例,模型3维坐标的归化函数:void CModelPointSet:NormalizeCoordinate()/ 寻找最值点for(int i=1; i=m_nVNum; i+)if(m_fVertexi0 m_fXmax) m_fXmax = m_fVertexi0;if(m_fVertexi1 m_fYmax) m_fYmax = m_fVertexi1;if(m_fVertexi2 m_fZmax) m_fZmax = m_fVertexi2;/ 寻找最长边float lenX = m_fXmax - m_fXmin;float lenY = m_fYmax - m_fYmin;float lenZ = m_fZmax - m_fZmin;float longer = lenX lenY ? lenX :

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 办公文档 > 其他范文


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号