东莞做网站建设,招投标信息查询平台,做国厂家的网站,网站建设合同是否缴纳印花税前言
前面写过一篇obj格式解析的博客#xff0c;但是这篇文章中可视化的工作是参考PRNet的源码进行的#xff0c;后来细细思考了一下#xff0c;有点问题#xff0c;具体看下面。
问题来源
在PRNet源码的render.py中有个函数render_texture#xff0c;是作者用于将uv展…前言
前面写过一篇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),dtypenp.uint8)
depth np.zeros((render_height,render_width),dtypenp.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),dtypenp.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_depthdepth[x,y]):render_img[x,y] dst[x,y]depth[x,y] curr_depth 对比一下meshlab和映射三角面的结果 可以发现中图和右图在颜色上有差距主要原因在于Meshlab是一款展示3D模型的软件它内置了灯光依据3D模型的法线产生了阴影因此立体感会更强了而我写的可视化并没有加入法线信息仅仅是对展开的uv纹理图进行3D映射所以照片既视感更强。
后记
主要还是对之前忽视的细节做个记录。
完整的python脚本实现放在微信公众号的简介中描述的github中有兴趣可以去找找同时文章也同步到微信公众号中有疑问或者兴趣欢迎公众号私信。