Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于本篇论文中,渲染细节的相关问题 #15

Open
520jz opened this issue May 20, 2024 · 10 comments
Open

关于本篇论文中,渲染细节的相关问题 #15

520jz opened this issue May 20, 2024 · 10 comments

Comments

@520jz
Copy link

520jz commented May 20, 2024

亲爱的作者您好!原谅我的菜,我想问一下您这篇论文中一些渲染方面的细节问题,正如您论文中所所说:在初始pose以及截止pose之间进行插值,以获得沿轨迹的每个相机pose,然后将对应的pose的image渲染出来生成一些列的虚拟清晰图像,然后将这些虚拟清晰图像进行混合得到渲染后的blur-image,最后将渲染的blur-image和GT-blur-image做损失,以联合更新并优化pose以及高斯的参数。

我比较好奇的是,原始的gaussian splatting我每次迭代渲染只渲染一张image,然后render后会返回一个bool类型的数组(记录半径大于0的椭球),以及一个记录梯度的数组(在代码中是viewspace_point_tensor, visibility_filter以及radii),这几个数据是会在后面自适应的致密化操作中使用的。但是如果按照您这篇论文的思路的话,假设我插值生成了5个pose,每个pose我渲染出一张virtual-image,那么每次渲染都会返回我上面说的那三个数据,我是要将每次render得到的这三个数据也求平均后再进行致密化吗?
image

我粗略的画了两张图,以便您能更好的理解我的问题:
下面这张图是您这篇论文中我假设的五个pose的情况下,一个大概的流程(主要是下面自适应操作的处理,是做五次自适应操作,还是说将对应的数据求平均后做一次自适应的操作,但是如果求平均的话感觉原理上不太合理,因为有些梯度高的和梯度低的部分的椭球可能会被平均掉,影响自适应的准确性)
image
这张是原始的3DGaussian splatting的流程:
image

@LingzheZhao
Copy link
Member

LingzheZhao commented May 20, 2024

您好! 感谢您对我们论文的关注。我们的代码是基于nerfstudio中的Splatfacto的,它与INRIA的原版3DGS在这里主要的不同就是它把render过程与densification做了解耦,viewspace_point_tensor(xys), visibility_filter(visible_mask)以及radii这三个变量不会在每次render时返回,而是在每次forward(在我们这里就是通过平均virtual sharp image 得到一张blur image,跟input image做loss)再backword之后,再调用一个after_traincallback,在这个callback里面再去根据此时的梯度去做adaptive density control。这里面它的梯度会从blur image传递到每个virtual sharp image再传到各个params(Gaussians & camera poses)。所以这里第一,每个virtual sharp image在梯度计算中都有贡献;第二,在要求Gaussians数量基本不变的前提下,我们也发现densify_grad_thresh这个超参数的设定会跟num_virtual_views有一个线性的关系(我们在补充材料C.2里也提到了,根据推导是求平均的这个操作带来的)。

@520jz
Copy link
Author

520jz commented May 20, 2024

您好! 感谢您对我们论文的关注。我们的代码是基于nerfstudio中的Splatfacto的,它与INRIA的原版3DGS在这里主要的不同就是它把render过程与densification做了解耦,viewspace_point_tensor(xys), visibility_filter(visible_mask)以及radii这三个变量不会在每次render时返回,而是在每次forward(在我们这里就是通过平均virtual sharp image 得到一张blur image,跟input image做loss)再backword之后,再调用一个after_traincallback,在这个callback里面再去根据此时的梯度去做adaptive density control。这里面它的梯度会从blur image传递到每个virtual sharp image再传到各个params(Gaussians & camera poses)。所以这里第一,每个virtual sharp image在梯度计算中都有贡献;第二,在要求Gaussians数量基本不变的前提下,我们也发现densify_grad_thresh这个超参数的设定会跟num_virtual_views有一个线性的关系(我们在补充材料C.2里也提到了,根据推导是求平均的这个操作带来的)。

哦哦哦,好的,非常感谢,我好像明白了,nerfstudio里面的代码是在backword之后再去获取相关信息进行adaptive density control的,不是原始的gs代码那样每次render后返回相关参数后进行adaptive density control。我去看看nerfttudio的源码,谢谢您。

@520jz
Copy link
Author

520jz commented May 22, 2024

您好! 感谢您对我们论文的关注。我们的代码是基于nerfstudio中的Splatfacto的,它与INRIA的原版3DGS在这里主要的不同就是它把render过程与densification做了解耦,viewspace_point_tensor(xys), visibility_filter(visible_mask)以及radii这三个变量不会在每次render时返回,而是在每次forward(在我们这里就是通过平均virtual sharp image 得到一张blur image,跟input image做loss)再backword之后,再调用一个after_traincallback,在这个callback里面再去根据此时的梯度去做adaptive density control。这里面它的梯度会从blur image传递到每个virtual sharp image再传到各个params(Gaussians & camera poses)。所以这里第一,每个virtual sharp image在梯度计算中都有贡献;第二,在要求Gaussians数量基本不变的前提下,我们也发现densify_grad_thresh这个超参数的设定会跟num_virtual_views有一个线性的关系(我们在补充材料C.2里也提到了,根据推导是求平均的这个操作带来的)。

您好,我想再问一个问题,您这篇论文是否考虑了同一运动轨迹下合成的blur-image不唯一的情况呢?比如在同一运动轨迹下,我估计的pose的采样间隔可以不是均匀的,也可以是均匀的等等,那么这样的话我average后得到的模糊图像可能得到不同的模糊图像,我记得您论文中好像用的是插值,也就是估计的timetamp的间隔都是均匀的哦?

@LingzheZhao
Copy link
Member

LingzheZhao commented May 22, 2024

这里我们把CMOS上的2D image记为一个与时间 $t$ 相关的函数: $\mathbf{I}(\mathbf{x};t)$ , 那么我们motion blurred image的物理模型就是:

$$\mathbf{B}(\mathbf{x}) = \lambda \int_0^\tau \mathbf{I}(\mathbf{x}; t) \mathrm{d}t$$

$\tau$ 是曝光时间, $\lambda$ 是一个归一化系数。

然后我们做离散化近似,从这里引入了时间上的等间隔插值:

$$\mathbf{B}(\mathbf{x}) = \lambda \int_0^\tau \mathbf{I}(\mathbf{x}; t) \mathrm{d}t \approx \frac{1}{n}\sum_{i=0}^{n-1}\mathbf{I}_i(\mathbf{x})$$

$n$ 张virtual sharp image去average得到blur image。这里,因为数字图像本身就是离散的,我们只要保证任意相邻两张virtual sharp image之间的optical flow 都小于1个 pixel,就认为这个近似效果是理想的(也是唯一的),反之,就会有artifact (在原版Deblur-NeRF的合成数据集里就有出现)。最暴力的方法就是只要增加 $n$,就可以消除不理想的近似。当然,在 $n$ 不变的情况下,是存在比这个等时间间隔插值更好的方式的,那就是运动快的时候多采样,运动慢的时候少采样,最理想的情况就是让相邻两张virtual sharp image间的optical flow都恰好略小于1个 pixel,不过个人认为这个就是属于优化计算代价的一些工程问题了,这里就没有再深入研究了。

@520jz
Copy link
Author

520jz commented May 28, 2024

这里我们把CMOS上的2D image记为一个与时间 t 相关的函数: I(x;t) , 那么我们motion blurred image的物理模型就是:

B(x)=λ∫0τI(x;t)dt

τ 是曝光时间, λ 是一个归一化系数。

然后我们做离散化近似,从这里引入了时间上的等间隔插值:

B(x)=λ∫0τI(x;t)dt≈1n∑i=0n−1Ii(x)

用 n 张virtual sharp image去average得到blur image。这里,因为数字图像本身就是离散的,我们只要保证任意相邻两张virtual sharp image之间的optical flow 都小于1个 pixel,就认为这个近似效果是理想的(也是唯一的),反之,就会有artifact (在原版Deblur-NeRF的合成数据集里就有出现)。最暴力的方法就是只要增加 n,就可以消除不理想的近似。当然,在 n 不变的情况下,是存在比这个等时间间隔插值更好的方式的,那就是运动快的时候多采样,运动慢的时候少采样,最理想的情况就是让相邻两张virtual sharp image间的optical flow都恰好略小于1个 pixel,不过个人认为这个就是属于优化计算代价的一些工程问题了,这里就没有再深入研究了。

噢噢噢噢,原来如此,谢谢大佬,那大佬,在代码层面如何保证任意相邻两张virtual sharp image之间的optical flow 都小于1个 pixel呢?我以前试过从图片的起始pose与截止pose之间等间隔的插值pose,然后将所有渲染的清晰图片求取average,但是我发现这样高斯学习不好模糊,虽然loss一直在降低,但是迭代到一定次数就不下降了,而且渲染的模糊肉眼可见跟GT-blur差别很大,这是什么原因呢,还有我想再问一下,就在那个公式推导的部分
image
这个数学推导我看明白了,就是高斯椭球的均值对pose的影响,但是可能是代码实现的问题,就这个梯度我需要在高斯的光栅化部分(cuda部分)进行修改来实现吗?不好意思主要是nerfstudio版本的gs源码不太熟悉,因为一直看的原版的gs源码

@520jz
Copy link
Author

520jz commented May 28, 2024

这里我们把CMOS上的2D image记为一个与时间 t 相关的函数: I(x;t) , 那么我们motion blurred image的物理模型就是:
B(x)=λ∫0τI(x;t)dt
τ 是曝光时间, λ 是一个归一化系数。
然后我们做离散化近似,从这里引入了时间上的等间隔插值:
B(x)=λ∫0τI(x;t)dt≈1n∑i=0n−1Ii(x)
用 n 张virtual sharp image去average得到blur image。这里,因为数字图像本身就是离散的,我们只要保证任意相邻两张virtual sharp image之间的optical flow 都小于1个 pixel,就认为这个近似效果是理想的(也是唯一的),反之,就会有artifact (在原版Deblur-NeRF的合成数据集里就有出现)。最暴力的方法就是只要增加 n,就可以消除不理想的近似。当然,在 n 不变的情况下,是存在比这个等时间间隔插值更好的方式的,那就是运动快的时候多采样,运动慢的时候少采样,最理想的情况就是让相邻两张virtual sharp image间的optical flow都恰好略小于1个 pixel,不过个人认为这个就是属于优化计算代价的一些工程问题了,这里就没有再深入研究了。

噢噢噢噢,原来如此,谢谢大佬,那大佬,在代码层面如何保证任意相邻两张virtual sharp image之间的optical flow 都小于1个 pixel呢?我以前试过从图片的起始pose与截止pose之间等间隔的插值pose,然后将所有渲染的清晰图片求取average,但是我发现这样高斯学习不好模糊,虽然loss一直在降低,但是迭代到一定次数就不下降了,而且渲染的模糊肉眼可见跟GT-blur差别很大,这是什么原因呢,还有我想再问一下,就在那个公式推导的部分 image 这个数学推导我看明白了,就是高斯椭球的均值对pose的影响,但是可能是代码实现的问题,就这个梯度我需要在高斯的光栅化部分(cuda部分)进行修改来实现吗?不好意思主要是nerfstudio版本的gs源码不太熟悉,因为一直看的原版的gs源码

上面是我求平均渲染出来的模糊图片,下面是GT-blur
image
image

@LingzheZhao
Copy link
Member

LingzheZhao commented May 29, 2024

是的,camera pose的梯度中,主要就是高斯椭球的均值对pose的Jacobian需要计算,gsplat v0.1 里面这部分是python实现的,然后最近他们正在用CUDA重构整个代码也包括这个部分

从你提供的图片来看,可能就是pose的梯度中间是断的,所以pose没有被优化,你可以把pose print出来看看是不是没有在被优化

如果想继续在原版gs上开发pose优化的话,一个比较方便的选择就是把diff-gaussian-rasterization换成gsplat,他们最近开源了一个minimal example的仓库,只要改100行左右,这里提到替换之后速度和质量都能有所提升这个branch是对应gsplat 0.1的;main branch 是对应他们正在重构的gsplat 1.0的,感觉可以试下

@520jz
Copy link
Author

520jz commented May 30, 2024

是的,camera pose的梯度中,主要就是高斯椭球的均值对pose的Jacobian需要计算,gsplat v0.1 里面这部分是python实现的,然后最近他们正在用CUDA重构整个代码也包括这个部分

从你提供的图片来看,可能就是pose的梯度中间是断的,所以pose没有被优化,你可以把pose print出来看看是不是没有在被优化

如果想继续在原版gs上开发pose优化的话,一个比较方便的选择就是把diff-gaussian-rasterization换成gsplat,他们最近开源了一个minimal example的仓库,只要改100行左右,这里提到替换之后速度和质量都能有所提升这个branch是对应gsplat 0.1的;main branch 是对应他们正在重构的gsplat 1.0的,感觉可以试下

哦哦哦好的,谢谢大佬,话说,nerfstudio中的Splatfacto这个框架是不是本来就比原本的GS的质量更好速度更快?

@520jz
Copy link
Author

520jz commented May 30, 2024

是的,camera pose的梯度中,主要就是高斯椭球的均值对pose的Jacobian需要计算,gsplat v0.1 里面这部分是python实现的,然后最近他们正在用CUDA重构整个代码也包括这个部分
从你提供的图片来看,可能就是pose的梯度中间是断的,所以pose没有被优化,你可以把pose print出来看看是不是没有在被优化
如果想继续在原版gs上开发pose优化的话,一个比较方便的选择就是把diff-gaussian-rasterization换成gsplat,他们最近开源了一个minimal example的仓库,只要改100行左右,这里提到替换之后速度和质量都能有所提升这个branch是对应gsplat 0.1的;main branch 是对应他们正在重构的gsplat 1.0的,感觉可以试下

哦哦哦好的,谢谢大佬,话说,nerfstudio中的Splatfacto这个框架是不是本来就比原本的GS的质量更好速度更快?

哦对了,大佬,我看论文里面的那个Table3,是deblurring的PSNR,我记得deblur-nerf的数据集(blender数据集)模糊的图片没有对应的清晰GT,只有每间隔为8的一张清晰的GT作为测试集,您table3中的去模糊PSNR是根据什么计算的呢?
image

@LingzheZhao
Copy link
Member

LingzheZhao commented May 30, 2024

哦哦哦好的,谢谢大佬,话说,nerfstudio中的Splatfacto这个框架是不是本来就比原本的GS的质量更好速度更快?

这里有他们的一些测试结果,总体上是能看到一些提升的,他们还在持续更新,后面提升应该会更大;

哦对了,大佬,我看论文里面的那个Table3,是deblurring的PSNR,我记得deblur-nerf的数据集(blender数据集)模糊的图片没有对应的清晰GT,只有每间隔为8的一张清晰的GT作为测试集,您table3中的去模糊PSNR是根据什么计算的呢?

其实是有的,Deblur-NeRF把合成数据集的deblurring的GT放在一个单独的文件夹synthetic_gt里了(合成数据集的主要意义就是能提供这个GT),然后我们从BAD-NeRF开始为了方便和一致性就把他们移动到每个sequence下的images_test文件夹里了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants