DIB-R 可微分渲染器使用
?此篇博客轉(zhuǎn)自本作者在古月居的博客:?https://www.guyuehome.com/34349
前言
? 最近由于一些機(jī)會(huì),接觸到了一系列深度學(xué)習(xí)對(duì)稱(chēng)形狀和紋理和篇文章,并嘗試做了一些實(shí)踐。以Learning to Predict 3D Objects with an Interpolation-based Differentiable Renderer舉例,他的思想主要是通過(guò)相機(jī)視角的RGB圖,用類(lèi)似于Auto Encoder的模型輸出三維點(diǎn)和紋理信息。然后通過(guò)一個(gè)渲染器得到在固定角度下的RGB圖像,與之前的輸入形成主要的損失。當(dāng)然論文還介紹了其他光照什么的,細(xì)節(jié)就不在討論了,我們主要用他這個(gè)可微分渲染器。這里給出這篇文章的開(kāi)源鏈接:https://github.com/nv-tlabs/DIB-R
?
Differentiable Renderer
? 由于自己不是專(zhuān)門(mén)做計(jì)算機(jī)圖形學(xué)的。所以,對(duì)于這篇文章中的可微分渲染的理解將表述的很通俗。
? 在NN輸出空間中的三維點(diǎn)的時(shí)候,我們希望也知道這些點(diǎn)的RGB像素值是多少。經(jīng)常,我們可以看到深度相機(jī)中帶有色彩的點(diǎn)云,它們描述了幾何特征和紋理特征。但是,這不是連續(xù)的。我們可能還希望點(diǎn)能連成面,而色彩則可以也可以連續(xù)過(guò)渡。所以那篇論文中最有價(jià)值的部分莫過(guò)于他的基于CUDA的渲染器。有時(shí),我們想輕量級(jí)的使用一個(gè)渲染器,且希望接口簡(jiǎn)單清晰,速度快,易于集成。DIB-R可以是一個(gè)很好的選擇。或者有小伙伴,也想從事于深度學(xué)習(xí)中渲染于幾何物體的相關(guān)領(lǐng)域,這就是一個(gè)很好的選擇。
? 具體原理的可以看文章中3.2的可微分光柵化。這里主要講述了代碼接口解析,并附上一小段測(cè)試的渲染程序以作參考。
環(huán)境
? 環(huán)境至關(guān)重要。我是在Ubuntu18.04上實(shí)現(xiàn)的,基于python3.6。python包的依賴可以看github中的requirments.txt 。
? 其次就是CUDA環(huán)境,這點(diǎn)我裝可好久,此前我想在Colab上裝合適版本的CUDA(版本為11),然后測(cè)試。但是發(fā)現(xiàn)demo寫(xiě)好后,包一些莫名其妙的錯(cuò)誤。然而,我朋友卻用同樣的demo在極客云上用cuda10.2.89的版本跑了起來(lái)。后面,干脆直接在我本地上裝合適的CUDA好了。
? 由?lspci | grep -i nvidia?可以看到我的顯卡是GeForce GTX 1050 Ti Mobile,在https://zh.wikipedia.org/wiki/CUDA?查的自己顯卡計(jì)算能力為6.1, 架構(gòu)是Pascal) 。查表后可以看到支持的cuda版本很多,為了安全起見(jiàn),我也選擇了10.2.89。
? 由于之前裝了一個(gè)低版本的CUDA,所以要進(jìn)行升級(jí)。首先要卸載原來(lái)的。
| 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 |
? 然后進(jìn)行安裝新版本的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編譯過(guò),那么就需要將編譯后生成的文件全部刪去后,在進(jìn)行編譯。上述編譯會(huì)在 cuda_dib_render 中多幾個(gè)文件夾。
接口及測(cè)試
? 編譯后我們甚至可以不考慮那幾個(gè)文件中所做了什么,只要直接使用他的接口即可。比較坑的是,他這個(gè)代碼沒(méi)有像想象那樣進(jìn)行全部開(kāi)源,而是給出渲染器和一個(gè)小的測(cè)試demo。總的工程在 test-all 中進(jìn)行描述。它總的描述了一個(gè)訓(xùn)練的流程是怎樣的,具有借鑒和學(xué)習(xí)意義。這里我們主要?jiǎng)冸x出渲染的主要成分即可。
? 我寫(xiě)可以一個(gè)渲染測(cè)試文件,并對(duì)一些內(nèi)容進(jìn)行了注釋(原來(lái)的demo文件幾乎沒(méi)有什么注釋)。測(cè)試的效果還行,具體如下
? 從圖中可以看出,顏色以一定的塊(條紋塊)進(jìn)行分布。車(chē)子的幾何特征有點(diǎn)粗糙,這是由于所用的obj文件中的點(diǎn)集是NN訓(xùn)練得到的,點(diǎn)集數(shù)量不多,且與原來(lái)形狀有點(diǎn)小差異。對(duì)于代碼的解釋,已經(jīng)全部放在,下面的代碼中。在配置好環(huán)境后,修改路徑即可運(yùn)行。
| # 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') |
| # 加載相機(jī)參數(shù) |
| 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格式點(diǎn)集的 點(diǎn)和面 描述集 |
| 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) |
| # 獲得 點(diǎn),面和邊的數(shù)量 |
| pnum = pointnp_px3.shape[0] |
| fnum = facenp_fx3.shape[0] |
| enum = edge_ex2.shape[0] |
| # print(pnum, fnum, enum) |
| # 設(shè)定相機(jī)FOV, 可以由相機(jī)內(nèi)參矩陣獲得 |
| camfovy = np.arctan(2*64/140) |
| # 這里轉(zhuǎn)化 相機(jī)的FOV向量 |
| camprojmtx = perspectiveprojectionnp(camfovy, 1.0) |
| tfcamproj = torch.from_numpy(camprojmtx).to(device) |
| # print(tfcamproj.shape) |
| # 這里增加一個(gè)維度 |
| tfp_1xpx3 = torch.from_numpy(pointnp_px3).to(device).view(1, pnum, 3) |
| # print(tfp_1xpx3) |
| # print(tfcamproj) |
| # 以下將設(shè)定一個(gè)batch中有兩個(gè) mesh 和 顏色集, 以此來(lái)做測(cè)試 |
| meshes = [] |
| meshcolors = [] |
| # 重復(fù)添加兩個(gè) |
| meshes.append(tfp_1xpx3) |
| meshes.append(tfp_1xpx3) |
| # 設(shè)定顏色 |
| 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 決定顏色分布?jí)K大小 |
| cout+=1 |
| if cout ==3: |
| cout =0 |
| # mesh color 轉(zhuǎn)化為向量 |
| mc_bxp3 = np.array(temp,dtype=np.float32) |
| # print(mc_bxp3) |
| # 轉(zhuǎn)化cuda tensor 后增加一個(gè)維度 |
| mc_bxpx3 = torch.from_numpy(mc_bxp3).to(device).view(1, -1, 3) |
| # print(mc_bxpx3) |
| # 和之前mesh一致, 也重復(fù)添加兩個(gè) |
| meshcolors.append(mc_bxpx3) |
| meshcolors.append(mc_bxpx3) |
| # print(meshes.shape,meshcolors.shape ) |
| # 轉(zhuǎn)化為tensor |
| meshesvv = meshes |
| mcvv = meshcolors |
| mesh_vvbxpx3 = torch.cat(meshesvv) |
| mc_vvbxpx3 = torch.cat(mcvv) |
| # print(mesh_vvbxpx3.shape, mc_vvbxpx3.shape) |
| # 加載相機(jī)參數(shù),其次變換矩陣保存在 .npy文件中, 注意,物體和相機(jī)關(guān)系需要轉(zhuǎn)換 |
| 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) |
| # 相機(jī)坐標(biāo)參數(shù) 轉(zhuǎn)化為 cuda 計(jì)算 |
| tfcamrot = torch.from_numpy(rotat).to(device) |
| tfcampos = torch.from_numpy(trans).to(device) |
| # 相機(jī)參數(shù)添加到一個(gè)集合中,可能有點(diǎn)冗余,這是為了和 test-all.py中保持一致 |
| tfcams=[[tfcamrot,tfcampos,tfcamproj]] |
| tfcamrot_bx3x3, tfcampos_bx3, _ = tfcams[0] |
| # 由于 前面批量了兩個(gè),所以這里需要重讀添加 |
| 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渲染接口,至關(guān)重要 |
| tmp, _ = rendermesh(mesh_vvbxpx3, mc_vvbxpx3, tff_fx3, tfcamsvv, linear) |
| # 第一個(gè)就是渲染后視野中的圖像 |
| impre_vvbxhxwx3, silpred_vvbxhxwx1 = tmp |
| # 轉(zhuǎn)化到 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") |
? 以上是作者做的一個(gè)大項(xiàng)目中的一個(gè)小章節(jié),驗(yàn)證可微分渲染以此來(lái)進(jìn)行后面深度學(xué)習(xí)-學(xué)習(xí)mesh的紋理。此處為今后學(xué)習(xí)這個(gè)小伙伴提供一個(gè)參考。
? 另外,這個(gè)項(xiàng)目在后續(xù)將實(shí)踐一個(gè)pytorch深度學(xué)習(xí)學(xué)習(xí)對(duì)稱(chēng)幾何物體紋理的案例,后面有機(jī)會(huì)將持續(xù)跟進(jìn)。
總結(jié)
以上是生活随笔為你收集整理的DIB-R 可微分渲染器使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【书评】搞车载系统服务?这本入门书或许可
- 下一篇: 高级驾驶辅助系统 (ADAS)教程