编辑: 865397499 | 2019-11-27 |
2018 年1月日浙江大学实验报告 课程名称: 计算机动画 实验类型: 综合 实验项目名称:基于网格的二维图像morphing 学生姓名:专业:学号:
31 同组学生姓名:无 指导老师: 金小刚 实验地点: 玉泉 实验日期:
2018 年1月日实验目的和要求 实现基于网格的二维图像morphing(图像的自然渐变): 以基于网格变形的方式把一幅数字图像以一种自然流畅、戏剧性的、超现实主义的方式变换到另一幅数字图像.
实验内容和原理 实验内容: 对源图像进行网格变形到与中间帧图像具有相同形状的源图像 对目标图像进行网格变形到与中间帧图像具有相同形状的目标图像 对两幅warping后的图像对应地进行颜色差值即可得到中间的一系列中间过程图像. 将中间过程图像合成一个视频或制作成一个GIF动图,即可观察到自然的图像 morphing过程. 实验算法流程: 实验器材 实验编译运行平台:win7操作系统VS2010 实验工具软件:图像格式转化、XnView、Photoshop、PicPoint 实验步骤 Ps:参考的代码为github上的代码. 选取两幅图像作为开始源图像和终止目标图像. 用图格式转换工具将两幅彩色图像转化为彩色sgi格式的图像.(自己添加的过程) 用PicPoint工具或Image Analysys手工获取两幅图像morphing过程的对应点的坐标信息. 两幅图像对应点数目相同,为m*n个,四周的对应点固定且相同.将每幅图像的对应点的横坐标和纵坐标一次记录在一个txt文档里,每个数据用空格隔开,且数据类型为float.(自己添加的过程) 主要项目工程代码运行(my_2D_morphing_project):(代码有借鉴有修改也有添加) 输入参数如下:源图像文件名、目标图像文件名、对应两个网格数据txt文档、网格水平方向网格点数目、网格竖直方向网格点数目,以及morphing过程的中间帧数目. 即可获得一系列中间图像
4、利用Xnview工具可以查看sgi图像,并将sgi图像批量转化为jpg图像.
5、然后用photoshop将一系列图像制成GIF动态图. 或者将图片放在pictures_to_avi工程项目目录下并运行(自己添加写的工程),获得的morphing_res.avi文件即为合成的morphing过程视频. 主要代码实现介绍: a.首先调用函数seperate(I1,I2)将彩色图像分离成RGB三个通道的图像BW二进制格式文件.该函数参考网上代码,并做了修改声明为extern函数融合进了主要工程项目里. b.然后调用make_mesh(txt1,txt2,xnum1,ynum2)函数计算获取对应的mesh网格二进制文件.该函数自己参考分离原理思路添加写的.从txt文档里分别读入数据,并按一定的格式将数据处理成二进制数据写入mesh文件并保存在工程项目目录下. c.然后读入bw文件和mesh文件,调用morph(i1,i2,M1,M2,nframes,base_name)分别对R、G、B三个颜色通道的文件进行warp and moph 过程计算.调用代码如下: Morph函数和其调用的meshwarp函数、和calmullRom函数参考了网上代码,并融合进了自己的作业工程项目. Morph函数先调用根据源图像和目标图像对应的两个mesh文件进行插值获得中间过程的mesh文件 调用meshwarp函数传入源图像、目标图像、中间mesh结构后获得使源图像和目标图像变形对齐的一系列对齐图像 并对这些对齐的图像上的点进行颜色线性插值获得一系列morphing的中间过程图像. Meshwarp函数具体实现: 首先获取中间网格数据,然后调用网格点数据对其进行Catmull-Rom样条插值计算,得到网格点数目对应图像像素点数目这么多的网格数据,然后根据插值后的网格数据,将warp变形前图像上每个像素点根据网格形状变形对应的网格点的参数找到对应的像素点的颜色值并赋值,相当于形变过程中像素点的重映射,这个过程调用了函数如下: 整个warp变形过程分成两个部分,首先为水平方向图像对应网格的形变,然后为竖直方向图像对于网格的形变. Catmull-Rom样条插值计算函数实现: 样条插值计算原理: 只能计算p1和p2之间的插值点 计算样条系数代码: 计算输出点坐标代码: d.调用merge()函数将中间过程对应RGB三个通道的结果图像合成一个彩色图像文件. 循环读入对应的RGB三个通道的morphing结果图像,然后按照sgi图像文件格式写入sgi文件,这个过程可以看做是是seperate()函数的逆过程. e.将一系列jpg结果图像合成GIF动画或avi视频 pictures_to_avi工程项目介绍(自己添加的项目): 主要调用opencv库对系列图像进行处理,合成avi视频文件 cvLoadImage读入图像,cvWriteFrame写入视频. 实验结果分析 实验结果展示: 中间生成文件:1r.bw,1g.bw,1b.bw图像由1.sgi图像分离得到.2r.bw,2g.bw,2b.bw图像由2.sgi图像分离得到,morph前缀的文件为中间结果的RGB三通道morphing图像,res前缀的图像由RGB对应三个morphing结果图像合成的结果图像. 实验结果morphing过程图像序列 样例1:有美女变成狮子,由我自己的工程项目做出来的结果图,可以看到morphing过程,但是指定点比较粗糙,4*5个网格控制点,10帧中间渐变画面,所以效果如下: 当指定对应控制点差别距离较大,对应关系不好或有较曲折的变化,就会出现莫名的不想看到的变形,难以控制和预料.如下图所示: 样例2:一个脸上涂鸦的女孩变成一个狮子. 设置了6*5个网格点控制,共10帧渐变画面序列 当增大图像morphing中间图像数目,可以看到morphing过程更加细致 (附有demo视频文件) 基于网格的二维彩色图像morphing可以做到很好的图像morphing结果,如上面所示,而且存在样条插值算法支持网格变形的实现.但是也有很大的限制,过程比较复杂.目前,我所实现的是需要经过图像格式转化,手工指定网格控制点,而且还要手工输入txt文件,还要最终合成视频素材.人工指定对应点无法精确地指定需要多少控制点,而且比较麻烦.而且中间形变难以预知,可能或有较大出人意料的结果.我实验的时候设置的控制点较少的时候可以得到粗糙的morphing过程,一些图像转化过渡还不是很和谐,也有出现指定不好网格点发生奇怪变形的morphing过程.在指定控制点达到一定数目且位置比较合适时,这些弊端可以在一定程度上解决,但是人工指定的手续会更加耗时和复杂. 实验感想与心得 这次作业做的是基于网格的二维图像morphing,开始老师说可以参考网上样例代码,但是要有自己的修改部分,我心里还是很开心的,认为整个作业会比较简单的.但是真的开始着手做这个作业发现还是务必的困难的,很早地开始筹划写这个作业了,但是中间遇到了一个有一个的问题,导致我写写停停,整个作业跨时好几周才最终完成.再找样例代码的工程中,发现关于网格二维morphing的资料和样例代码还是很少的.最后发现一个在github上的一个较有参考意义的项目,是由Yurong Sun and George Wolberg两个人写的c代码移植过来的一个项目.整个项目里的参考代码很零散,又是有一个seperate工程,也有warp工程,也有meshwarp工程,也有merge工程,而且很难联系起来应用.在想放弃这份参考资料的时候发现其他地方也没有什么好的代码参考资料,自己又研究过了一阵子,放弃之前努力不是很舍得,心里很是犹豫,最后在万般斟酌之下还是决定使用这份资料.我很努力地去看懂了这份资料代码算法运行的流程和里面函数的功能.发现它是针对sgi图像文件的操作,于是我就找了很多适合的软件工具用于获取sgi图像和观察sgi图像.首先发现的问题是Seperate的main文件和merge的main文件对应的写入图像的格式,与meshwarp函数读取的图像文件格式不一样,short和int类型不统一肯定会导致读入处理的图像数据不正确,于是我移植了seperate里面的操作二进制文件的函数,在meshwarp中进行对图像数据的获取.还有其中遇到的最大的一个问题之一是不知道mesh文件的数据该如何获得.资料里只附加了代码和一些原理介绍,具体的流程不是很详细地说明.我对它处理的mesh文件很是不能理解.以为是建模软件导出的mesh文件,但是查询建模软件导出的mesh文件内容格式不符合它处理的数据规范.于是就搁置了作业.好不容易在自己一遍又一遍地阅读资料代码和查阅相关原理资料的过程中,发现了mesh文件处理格式的规范需求,于是我决定自己写一个c函数将数据按这个mesh文件格式写入二进制文件中,最后解决了这个问题.开始自己的mesh数据是直接写在代码里的,后来觉得这样对文件数据发生改变时会很麻烦,于是数据改为由txt文件中读取获得.还有遇到的大问题是样条插值计算后meshwarp过程出现了堆栈异常.调试这个bug,花了一天多的时间设断点输出显示,后来回忆老师上课讲的原理发自己指定的mesh网格点数据存在问题,边缘四周的网格点是固定且对应的,我忽略了这个因素,没有在边缘指定网格点数据,所以样条插值出了问题.最终很开心地获得到了结果过程图像.但是整个过程还是一个个项目去运行,比较零散.于是决定自己将主体代码融合为一个工程项目.我于是把seperate、make_mesh、meshwarp、merge过程都融合为了主体项目my_2D_morphing_project.但还是存在一些额外的操作,需要先对图像进行格式转化,对网格控制点进行手工获取,........