DIB-R 可微分渲染器使用
?此篇博客轉自本作者在古月居的博客:?https://www.guyuehome.com/34349
前言
? 最近由于一些機會,接觸到了一系列深度學習對稱形狀和紋理和篇文章,并嘗試做了一些實踐。以Learning to Predict 3D Objects with an Interpolation-based Differentiable Renderer舉例,他的思想主要是通過相機視角的RGB圖,用類似于Auto Encoder的模型輸出三維點和紋理信息。然后通過一個渲染器得到在固定角度下的RGB圖像,與之前的輸入形成主要的損失。當然論文還介紹了其他光照什么的,細節就不在討論了,我們主要用他這個可微分渲染器。這里給出這篇文章的開源鏈接:https://github.com/nv-tlabs/DIB-R
?
Differentiable Renderer
? 由于自己不是專門做計算機圖形學的。所以,對于這篇文章中的可微分渲染的理解將表述的很通俗。
? 在NN輸出空間中的三維點的時候,我們希望也知道這些點的RGB像素值是多少。經常,我們可以看到深度相機中帶有色彩的點云,它們描述了幾何特征和紋理特征。但是,這不是連續的。我們可能還希望點能連成面,而色彩則可以也可以連續過渡。所以那篇論文中最有價值的部分莫過于他的基于CUDA的渲染器。有時,我們想輕量級的使用一個渲染器,且希望接口簡單清晰,速度快,易于集成。DIB-R可以是一個很好的選擇。或者有小伙伴,也想從事于深度學習中渲染于幾何物體的相關領域,這就是一個很好的選擇。
? 具體原理的可以看文章中3.2的可微分光柵化。這里主要講述了代碼接口解析,并附上一小段測試的渲染程序以作參考。
環境
? 環境至關重要。我是在Ubuntu18.04上實現的,基于python3.6。python包的依賴可以看github中的requirments.txt 。
? 其次就是CUDA環境,這點我裝可好久,此前我想在Colab上裝合適版本的CUDA(版本為11),然后測試。但是發現demo寫好后,包一些莫名其妙的錯誤。然而,我朋友卻用同樣的demo在極客云上用cuda10.2.89的版本跑了起來。后面,干脆直接在我本地上裝合適的CUDA好了。
? 由?lspci | grep -i nvidia?可以看到我的顯卡是GeForce GTX 1050 Ti Mobile,在https://zh.wikipedia.org/wiki/CUDA?查的自己顯卡計算能力為6.1, 架構是Pascal) 。查表后可以看到支持的cuda版本很多,為了安全起見,我也選擇了10.2.89。
? 由于之前裝了一個低版本的CUDA,所以要進行升級。首先要卸載原來的。
| sudo apt-get --purge remove cuda nvidia* libnvidia-* |
| sudo dpkg -l | grep cuda- | awk '{print $2}' | xargs -n1 dpkg --purge |
| sudo apt-get remove cuda-* |
| sudo apt autoremove |
| sudo apt-get update |
? 然后進行安裝新版本的CUDA。
| wget --no-clobber https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.2.89-1_amd64.deb |
| sudo dpkg -i cuda-repo-ubuntu1804_10.2.89-1_amd64.deb |
| sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub |
| sudo apt-get update |
| sudo apt-get install cuda-10-2 |
? 確定自己安裝的版本可以由以下方式
| cat /usr/local/cuda-10.2/version.txt |
? 在安裝好CUDA之后,便可以編譯和下載(按照github上)
| cd dib-render/cuda_dib_render |
| python build.py install |
? 注意,如果你之前用了其他版本的cuda編譯過,那么就需要將編譯后生成的文件全部刪去后,在進行編譯。上述編譯會在 cuda_dib_render 中多幾個文件夾。
接口及測試
? 編譯后我們甚至可以不考慮那幾個文件中所做了什么,只要直接使用他的接口即可。比較坑的是,他這個代碼沒有像想象那樣進行全部開源,而是給出渲染器和一個小的測試demo。總的工程在 test-all 中進行描述。它總的描述了一個訓練的流程是怎樣的,具有借鑒和學習意義。這里我們主要剝離出渲染的主要成分即可。
? 我寫可以一個渲染測試文件,并對一些內容進行了注釋(原來的demo文件幾乎沒有什么注釋)。測試的效果還行,具體如下
? 從圖中可以看出,顏色以一定的塊(條紋塊)進行分布。車子的幾何特征有點粗糙,這是由于所用的obj文件中的點集是NN訓練得到的,點集數量不多,且與原來形狀有點小差異。對于代碼的解釋,已經全部放在,下面的代碼中。在配置好環境后,修改路徑即可運行。
| # Test file written by JWC |
| import numpy as np |
| import os |
| import sys |
| sys.path.append('/home/jame/Desktop/deguo/DIB-R-master/utils/') |
| sys.path.append('/home/jame/Desktop/deguo/DIB-R-master/dib-render/render_cuda') |
| sys.path.append('/home/jame/Desktop/deguo/DIB-R-master/utils/render') |
| import torch |
| import torchvision.utils as vutils |
| from model.modelcolor import Ecoder |
| from utils.utils_mesh import loadobj, \ |
| face2edge, edge2face, face2pneimtx, mtx2tfsparse, savemesh, savemeshcolor |
| from utils.utils_perspective import camera_info_batch, perspectiveprojectionnp |
| from renderfunc_cluster import rendermeshcolor as rendermesh |
| from utils_render_color2 import linear |
| import cv2 |
| # Automatic GPU/CPU device placement |
| device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') |
| # 加載相機參數 |
| def load_cam( pkl_path): |
| rotntxname = pkl_path |
| rotmtx_4x4 = np.load(rotntxname).astype(np.float32) |
| rotmx = rotmtx_4x4[:3, :3] |
| transmtx = rotmtx_4x4[:3, 3:4] |
| transmtx = -np.matmul(rotmx.T, transmtx) |
| renderparam = (rotmx, transmtx) |
| return renderparam |
| # 得到 obj格式點集的 點和面 描述集 |
| pointnp_px3, facenp_fx3 = loadobj('/home/jame/Desktop/deguo/DIB-R-master/mm/off/car_20.obj') |
| edge_ex2 = face2edge(facenp_fx3) |
| # edgef_ex2 = edge2face(facenp_fx3, edge_ex2) |
| # pneimtx = face2pneimtx(facenp_fx3) |
| tff_fx3 = torch.from_numpy(facenp_fx3).to(device) |
| # 獲得 點,面和邊的數量 |
| pnum = pointnp_px3.shape[0] |
| fnum = facenp_fx3.shape[0] |
| enum = edge_ex2.shape[0] |
| # print(pnum, fnum, enum) |
| # 設定相機FOV, 可以由相機內參矩陣獲得 |
| camfovy = np.arctan(2*64/140) |
| # 這里轉化 相機的FOV向量 |
| camprojmtx = perspectiveprojectionnp(camfovy, 1.0) |
| tfcamproj = torch.from_numpy(camprojmtx).to(device) |
| # print(tfcamproj.shape) |
| # 這里增加一個維度 |
| tfp_1xpx3 = torch.from_numpy(pointnp_px3).to(device).view(1, pnum, 3) |
| # print(tfp_1xpx3) |
| # print(tfcamproj) |
| # 以下將設定一個batch中有兩個 mesh 和 顏色集, 以此來做測試 |
| meshes = [] |
| meshcolors = [] |
| # 重復添加兩個 |
| meshes.append(tfp_1xpx3) |
| meshes.append(tfp_1xpx3) |
| # 設定顏色 |
| temp = [] |
| cout = 0 |
| # 顏色變化處理 |
| for i in range(pnum): |
| if cout==0: |
| temp.append([ 1, 0, 0 ]) |
| elif cout ==1: |
| temp.append([ 0., 1, 0 ]) |
| elif cout ==2: |
| temp.append([ 0., 0, 1 ]) |
| if i%300 ==0: # 300 決定顏色分布塊大小 |
| cout+=1 |
| if cout ==3: |
| cout =0 |
| # mesh color 轉化為向量 |
| mc_bxp3 = np.array(temp,dtype=np.float32) |
| # print(mc_bxp3) |
| # 轉化cuda tensor 后增加一個維度 |
| mc_bxpx3 = torch.from_numpy(mc_bxp3).to(device).view(1, -1, 3) |
| # print(mc_bxpx3) |
| # 和之前mesh一致, 也重復添加兩個 |
| meshcolors.append(mc_bxpx3) |
| meshcolors.append(mc_bxpx3) |
| # print(meshes.shape,meshcolors.shape ) |
| # 轉化為tensor |
| meshesvv = meshes |
| mcvv = meshcolors |
| mesh_vvbxpx3 = torch.cat(meshesvv) |
| mc_vvbxpx3 = torch.cat(mcvv) |
| # print(mesh_vvbxpx3.shape, mc_vvbxpx3.shape) |
| # 加載相機參數,其次變換矩陣保存在 .npy文件中, 注意,物體和相機關系需要轉換 |
| rotat, trans = load_cam("/home/jame/Desktop/deguo/DIB-R-master/mm/datasets/camera_settings/cam_npy/cam_RT_004.npy") |
| # rotat = np.array( [[[1.,0.,0.], [0.,1.,0.], [0.,0.,1.] ]], dtype=np.float32 ) |
| # trans = np.array( [[.0,0.,2]], dtype=np.float32 ) |
| rotat = np.array( [rotat], dtype=np.float32 ) |
| trans = np.array( [trans], dtype=np.float32 ) |
| # print(rotat, trans) |
| # 相機坐標參數 轉化為 cuda 計算 |
| tfcamrot = torch.from_numpy(rotat).to(device) |
| tfcampos = torch.from_numpy(trans).to(device) |
| # 相機參數添加到一個集合中,可能有點冗余,這是為了和 test-all.py中保持一致 |
| tfcams=[[tfcamrot,tfcampos,tfcamproj]] |
| tfcamrot_bx3x3, tfcampos_bx3, _ = tfcams[0] |
| # 由于 前面批量了兩個,所以這里需要重讀添加 |
| tfcamsvv = [[], [], tfcamproj] |
| tfcamsvv[0].append(tfcamrot_bx3x3) |
| tfcamsvv[1].append(tfcampos_bx3) |
| tfcamsvv[0].append(tfcamrot_bx3x3) |
| tfcamsvv[1].append(tfcampos_bx3) |
| tfcamsvv[0] = torch.cat(tfcamsvv[0]) |
| tfcamsvv[1] = torch.cat(tfcamsvv[1]) |
| # print(tfcamsvv[0].shape, tfcamsvv[1].shape) |
| # DIB-R渲染接口,至關重要 |
| tmp, _ = rendermesh(mesh_vvbxpx3, mc_vvbxpx3, tff_fx3, tfcamsvv, linear) |
| # 第一個就是渲染后視野中的圖像 |
| impre_vvbxhxwx3, silpred_vvbxhxwx1 = tmp |
| # 轉化到 RGB 值 |
| img = impre_vvbxhxwx3.cpu().numpy().astype(np.float32) *255.0 |
| # print(np.shape( img )) |
| \# opencv 圖像顯示 |
| cv2.imshow('image', img[0]) |
| cv2.imwrite("./image.jpg",img[0]) |
| cv2.waitKey(0) |
| print("OVER") |
? 以上是作者做的一個大項目中的一個小章節,驗證可微分渲染以此來進行后面深度學習-學習mesh的紋理。此處為今后學習這個小伙伴提供一個參考。
? 另外,這個項目在后續將實踐一個pytorch深度學習學習對稱幾何物體紋理的案例,后面有機會將持續跟進。
總結
以上是生活随笔為你收集整理的DIB-R 可微分渲染器使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【书评】搞车载系统服务?这本入门书或许可
- 下一篇: 高级驾驶辅助系统 (ADAS)教程