RealityCapure デプスマップ

「instantNeRFで遊ぶ Advent Calendar 2022」の22日目です。

今日はdepth maskを使うためにRealityCaptureのdepth mapを変換する方法を検討しました。

:::note
業務外の個人的な検討活動です。
:::

#### depth mask
depth mapの形式はUint16のようです。

https://github.com/NVlabs/instant-ngp/issues/939

> もし問題があれば、コードの中、特にnerf_loader.cuのenable_depth_loadingのところを見ることをお勧めします。
深度マップはUINT16のpngファイルに量子化される必要があり、量子化スケールはjsonファイルの "integer_depth_scale "で設定される必要があります。このキーがjsonにない場合、depth_mapsは読み込まれません（現在）。
デフォルトでは、depth_supervision_lambdaは0に設定されているので、0 < に変更する必要があることに注意してください。 
(DeepLで翻訳しました　https://www.deepl.com/translator)

#### Reality Captureのdepth map
MESH MODEL / ExportのDepth and Maskを使ってdepth mapを出力できますが、形式がFloat32bitしか選べないようです。またGimpなどで開いてみると背景が真っ黒、前景が真っ白になっていました。
左が入力画像、右が対応する画像の赤枠内のdepth mapです。
ただし背景部分はRealityCapture上で削除しています。
![22a-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/d8c02744-f543-00d6-e0e9-6b5d84163ba6.png)



#### float32 → 上限設定+UINT16変換
openEXR形式のdepth mapを読み込み、距離が無限大扱いになっている数値を変更した上でuint16に変換してpng形式で保存しました。

```
#https://forum.opencv.org/t/imread-openexr-file/10268/2

import os
import glob

os.environ["OPENCV_IO_ENABLE_OPENEXR"] = "1"

import cv2 as cv
import numpy as np

path1 = "./depth/"
fileList = glob.glob(path1+"*")

print(fileList)

for fileName in fileList:
    exr_neg = cv.imread(fileName, cv.IMREAD_UNCHANGED)
    
    #https://note.nkmk.me/python-os-basename-dirname-split-splitext/
    basename_without_ext = os.path.splitext(os.path.basename(fileName))[0]
    #https://note.nkmk.me/python-str-remove-strip/
    basename_without_ext = basename_without_ext.replace('.jpg.','_')
    dstFileName = path1 + basename_without_ext + "_u16.png"
    
    print(fileName, basename_without_ext)
    
    cv.namedWindow('exr_neg',
    cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO | cv.WINDOW_GUI_EXPANDED)
    
    exr_neg = exr_neg.astype(np.float16)
    
    # https://note.nkmk.me/python-numpy-where/
    exr_neg = np.where(exr_neg > 65535.0, 65535.0, exr_neg)
    
    max = exr_neg.max()
    min = exr_neg.min()
    
    print('#1 exr_neg: resolution x {}, y {}; min {} | max {}'.format(exr_neg.shape[0], exr_neg.shape[1], min, max))
    
    exr_neg_minmax = exr_neg.astype('uint16')
    print('#2 exr_neg: resolution x {}, y {}; min {} | max {}; type:{}'.format(exr_neg_minmax.shape[0], exr_neg_minmax.shape[1], exr_neg_minmax.min(), exr_neg_minmax.max(), exr_neg_minmax.dtype))
    
    cv.imshow('exr_neg', exr_neg_minmax)
    cv.waitKey(0)
    
    cv.imwrite(dstFileName, exr_neg_minmax)

cv.destroyAllWindows()
```

変換画像を途中で確認した状態です。デプスが見えるようになりました。
![22a-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/8e3c871f-531c-d130-1ecf-c22495cba357.png)

#### transform.json
さきほどのgithubの書き込みのように記述を追加しました。
![22a-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/a654274c-4ecb-c117-107a-d07ba822870d.png)

#### testbed.exe
instantNeRFを実行しました。

depth maskなし
![22a-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/f25acffe-4ea0-0e63-5051-bcba6f81b9d4.png)

depth maskあり
NeRF training options / Depth supervision strengthの調整が有効になり、洋服も消え気味ですが、背景部分の多くを消すことができました。
Depth supervision strengthの感度が高すぎるので、おそらくdepth mapの最大値やスケールの大きさが適正ではないのかもしれません。
![22a-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/c9a7d792-6f77-8a23-1b7d-3eb0aaa2972e.png)