前言

前面写过一篇obj格式解析的博客,但是这篇文章中可视化的工作是参考PRNet的源码进行的,后来细细思考了一下,有点问题,具体看下面。

问题来源

PRNet源码的render.py中有个函数render_texture,是作者用于将uv展开图重新映射回3D模型中,具体流程可以看出是:

  • 找到当前三角形的uv坐标和3D坐标

  • 将三个顶点的uv图颜色取平均,作为当前面片的颜色

    tri_tex = (colors[:, triangles[0,:]] + colors[:,triangles[1,:]] + colors[:, triangles[2,:]])/3.
    
  • 将三个顶点的3D深度值取平均,作为当前面片的深度值:

     tri_depth = (vertices[2, triangles[0,:]] + vertices[2,triangles[1,:]] + vertices[2, triangles[2,:]])/3.
    
  • 按像素着色,若当前像素在3D三角面中,且深度值大于当前像素点记录的深度值,则更新深度值和此3D点的像素,反之不更新不记录。

然而,最近用meshlab看低模人体模型的时候发现一个细节,如下图

那么问题显而易见了,眼睛这里的三角面的颜色根本不可能是通过三个顶点的平均色产生的

那么可能的解决方法就是,将uv里面的三角面片仿射变换到3D图像中的三角面片。

修正效果

为了验证上述的仿射变换思想是否可行,直接手撕一波,顺便把上一篇博客没有关注的深度值也加进去,整一个完整的代码出来。

读取OBJ信息的代码就不说了,就是一行行遍历,通过第一个字段判断是顶点还是法线还是面片等的信息。

直接进入核心实现:

首先需要通过所有顶点的前两个维度判断当前渲染图的大小:

render_width = int(np.ceil(np.max(vertices[...,0])))
render_height = int(np.ceil(np.max(vertices[...,1])))

最终的渲染图的每个面片必须需要深度信息指引是否渲染,深度值大的覆盖小的:

render_img = np.zeros((render_height,render_width,3),dtype=np.uint8)
depth = np.zeros((render_height,render_width),dtype=np.float32)
depth = depth-9999

为了将uv中的三角面片变换到渲染图中,必须先分别把两个面片取出来

# get uv texture map triangle
triangle_uv = np.float32([[vertex_tex[texcoords[i][0]][0]*height,(1-vertex_tex[texcoords[i][0]][1])*width],
[vertex_tex[texcoords[i][1]][0]*height,(1-vertex_tex[texcoords[i][1]][1])*width],
[vertex_tex[texcoords[i][2]][0]*height,(1-vertex_tex[texcoords[i][2]][1])*width]])
#get corresponding triangle in 3D face model
triangle_3d = np.float32([[vertices[triangles[i][0]][0],vertices[triangles[i][0]][1]],
[vertices[triangles[i][1]][0],vertices[triangles[i][1]][1]],
[vertices[triangles[i][2]][0],vertices[triangles[i][2]][1]]])

接下来进行仿射变换:

 # get affine transform matrixwarp_mat = cv2.getAffineTransform(triangle_uv,triangle_3d)dst = cv2.warpAffine(uv_map,warp_mat,(height,width))

因为是按照面片着色,所以必须获取当前面片的mask:

# get draw mask
mask = np.zeros((height,width,3),dtype=np.uint8)
cv2.drawContours(mask,[triangle_3d[np.newaxis,...].astype(np.int)],-1,(255,255,255),-1)

当前面片的深度信息

# judge depth
mask_idx = np.argwhere(mask[...,0]==255)
curr_depth = (vertices[triangles[i][0]][2]+vertices[triangles[i][1]][2]+vertices[triangles[i][2]][2])/3

最开始想的是用render_img = cv2.copyTo(dst,mask,render_img)去按照面片把整个面片复制过去,但是想来可能有面片叠加的情况,所以还是按照PRNet作者思想,逐像素复制。注意根据深度信息去判断是否覆盖当前像素即可:

for idx in range(mask_idx.shape[0]):x = mask_idx[idx,0]y = mask_idx[idx,1]if(curr_depth>=depth[x,y]):render_img[x,y] = dst[x,y]depth[x,y] = curr_depth

对比一下meshlab和映射三角面的结果

可以发现中图和右图在颜色上有差距,主要原因在于Meshlab是一款展示3D模型的软件,它内置了灯光,依据3D模型的法线产生了阴影,因此立体感会更强了,而我写的可视化并没有加入法线信息,仅仅是对展开的uv纹理图进行3D映射,所以照片既视感更强。

后记

主要还是对之前忽视的细节做个记录。

完整的python脚本实现放在微信公众号的简介中描述的github中,有兴趣可以去找找,同时文章也同步到微信公众号中,有疑问或者兴趣欢迎公众号私信。

OBJ可视化——UV还原(修正)相关推荐

  1. (牛哇牛哇)读取OBJ文件及其详解

    原文链接:https://blog.csdn.net/zb1165048017/article/details/109103791 前言 最近处理一些网格渲染的时候,需要解析Obj文件,从Free3D ...

  2. 3D可视化大屏是如何实现的?

    3D可视化是指拥有3D效果的数据可视化,对于所要展示的数据可视化内容还原出真实场景,并实时接入数据,在面对复杂操作时灵活应对,使得整个场景在大屏上的展示更具立体.更具科技感.更具易用性. 物联网时代, ...

  3. CST STUDIO SUITE 2021.04 SP4

    CST Studio Suite 2021.04 -发布说明 此补丁是一个推荐的更新,其中包括以下修正和改进. 许可 CST Studio Suite前端包括CST Studio Suite Bio ...

  4. 卡通角色表情驱动系列二

    前言 之前介绍了使用传统算法求解BS系数的表情驱动方法,其中提到过的三种方法之一是基于网格形变迁移做的,那么这篇文章就是对<Deformation Transfer for Triangle M ...

  5. 黑马程序员_Java基础_前期准备02-1

    ---------------------------------------- JavaEE+云物联.期待与您交流!----------------------------------------- ...

  6. 活动回顾|图扑软件亮相核电数字化技术与应用大会

    为贯彻"在确保安全的前提下积极有序发展核电"的方针,推进核电数字化转型智能化升级,提高数字化.智能化等信息技术与核能技术融合水平,进一步发挥先进信息技术在保障核电安全发展中的作用, ...

  7. 2020中国DevOps社区峰会(成都站),雄关漫道,砥砺前行

    2020中国DevOps社区峰会 · 成都站 面对VUCA时代的变幻莫测,我们还有很长的一段路要走.不知道这路上会遇到什么样的风景,也不知道这前路漫漫,还有多少坎坷,甚至不知道要走到哪里.就像红军长征 ...

  8. 【Pytorch】基于卷积神经网络实现的面部表情识别

    作者:何翔 学院:计算机学院 学号:04191315 班级:软件1903 转载请标注本文链接: https://blog.csdn.net/HXBest/article/details/1219812 ...

  9. PyTorch实现基于卷积神经网络的面部表情识别

    基于卷积神经网络的面部表情识别(Pytorch实现)----台大李宏毅机器学习作业3(HW3) 一.项目说明 给定数据集train.csv,要求使用卷积神经网络CNN,根据每个样本的面部图片判断出其表 ...

最新文章

  1. java 静态绑定原理_Java方法的静态绑定与动态绑定讲解
  2. 数据结构 - 树(二叉树的 前序、中序、后序 遍历)
  3. between and 效率_科学家改进植物光合作用,使植物光合效率提高40%
  4. 計算機二級-java10
  5. python的动态参数
  6. 我们究竟需要什么!!?
  7. vue里面v-once/ref【获取标签里面的内容】
  8. 基于ObjectCache的应用
  9. 博弈论——人生就是在博弈
  10. Win10获取管理员权限
  11. [转]线性插值双线性插值三线性插值
  12. oracle课堂收录-触发器
  13. 社会生活中十大著名法则
  14. 对不起,今年我真的不敢去拜年了。。。
  15. Android混淆——混淆语法及问题
  16. 清除Windows安全中心保护历史记录方法
  17. 光谱重建: rgb响应曲线估计(已知光源 和 多种颜色反射率已知,对应的rgb值也已知)
  18. HT82V26学习心得
  19. qq机器人插件之舔狗日记
  20. 2021-06-24期权交易中常见问题解答

热门文章

  1. php简单的mysql类_超简单php mysql数据库查询类
  2. 选购计算机五个原则,双十一笔记本电脑推荐
  3. Hike on a Graph HDU - 1252(bfs)
  4. codeforces 1040a (回文数的舞蹈)
  5. matlab中方差直方图,如何规范直方图在MATLAB?
  6. marquee文字起始位置_PS修图改字无痕扫描件复印件截图文字英文日期修改:制作漂亮红色丝绸文字图片的PS教程...
  7. rust怎么不要的墙拆掉_封阳台,栏杆要不要拆掉?栏杆装在玻璃窗里面还是外面...
  8. PAT_B_1029_Java(20分)
  9. java与c语言工作量对比比例,对比平台-- C ++与Java之间的差异
  10. android 调出键盘表情_Android 软键盘和emoji表情切换方案,和微信几乎一样的体验...