OBJ可视化——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),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还原(修正)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 径向基函数RBF三维网格变形
- 下一篇: 信用卡销卡会影响信用吗?看完再也不敢乱办