当前位置:   article > 正文

球谐函数的简单介绍和PlenOctree中的代码实现

plenoctree
  • 关于球谐函数的具体内容有很多很棒的介绍:

  • 球谐函数在PlenOctree和Plenoxel以及大火的3D Gaussian中都用了,用来表示和观察方向相关的颜色。代码实现部分是将球谐系数转换为具体的RGB值。
    球谐函数就是用一组球谐系数对于球谐基加权求和,球谐基就是关于球坐标系下 ( θ , ϕ ) (\theta,\phi) (θ,ϕ)的函数,下面的 y l m y_l^m ylm代表第 l l l阶的的SH Basis的第 m m m个分量:
    (下面这个公式摘抄自PlenOctree:https://arxiv.org/pdf/2103.14024.pdf 的补充材料中)

c ( d ; k ) = S i g m o i d ( ∑ l = 0 l m a x ∑ m = − l l K l m y l m ( d ) ) c(d;k) = Sigmoid(\sum_{l=0}^{l_{max}} \sum_{m=-l}^{l} K_l^m y_l^m(d) ) c(d;k)=Sigmoid(l=0lmaxm=llKlmylm(d))


  • STEP 1 d → ( θ , φ ) d \rightarrow (\theta,\varphi) d(θ,φ):

    d d d ( x , y , z ) (x,y,z) (x,y,z)的单位向量,在单位球坐标系下:

在这里插入图片描述

y l m ( θ , φ ) = { 2 K l m c o s ( m φ ) P l m ( c o s θ ) m > 0 2 K l m s i n ( − m φ ) P l − m ( c o s θ ) m < 0 K l 0 P l 0 ( c o s θ ) m = 0 y_l^m(\theta, \varphi) = \left\{

2Klmcos(mφ)Plm(cosθ)m>02Klmsin(mφ)Plm(cosθ)m<0Kl0Pl0(cosθ)m=0
\right. ylm(θ,φ)= 2 Klmcos(mφ)Plm(cosθ)2 Klmsin(mφ)Plm(cosθ)Kl0Pl0(cosθ)m>0m<0m=0

P n ( x ) = 1 2 n ⋅ n ! d n d x n [ ( x 2 − 1 ) n ] P l m = ( − 1 ) m ( 1 − x 2 ) m 2 d m d x m ( P l ( x ) ) K l m = ( 2 l + 1 ) ( l − ∣ m ∣ ) ! 4 π ( l + ∣ m ∣ ) ! P_n(x) = \frac{1}{2^n \cdot n!} \frac{d^n}{dx^n} [(x^2-1)^n] \\ P_l^m = (-1)^m (1-x^2)^{\frac{m}{2}} \frac{d^m}{dx^m} (P_l(x)) \\ K_l^m = \sqrt{\frac{(2l+1)(l-|m|)!}{4\pi(l+|m|)!} } Pn(x)=2nn!1dxndn[(x21)n]Plm=(1)m(1x2)2mdxmdm(Pl(x))Klm=4π(l+m)!(2l+1)(lm)!

  • STEP 3 开始代入不同的 l , m l,m l,m

P 0 ( x ) = 1 { P 0 0 ( x ) = 1 P_0(x) = 1 \\ \left\{

P00(x)=1
\right. P0(x)=1{P00(x)=1

P 1 ( x ) = x { P 1 0 ( x ) = x P 1 1 ( x ) = − ( 1 − x 2 ) 1 2 P_1(x) = x \\ \left\{

P10(x)=xP11(x)=(1x2)12
\right. P1(x)=x{P10(x)=xP11(x)=(1x2)21

P 2 ( x ) = 3 x 2 − 1 2 { P 2 0 ( x ) = 3 x 2 − 1 2 P 2 1 ( x ) = − 3 x ( 1 − x 2 ) 1 2 P 2 2 ( x ) = 3 ( 1 − x 2 ) P_2(x) = \frac{3x^2-1}{2} \\ \left\{

P20(x)=3x212P21(x)=3x(1x2)12P22(x)=3(1x2)
\right. P2(x)=23x21 P20(x)=23x21P21(x)=3x(1x2)21P22(x)=3(1x2)

  • STEP 4 求SH basis,即 y l m y_l^m ylm:

    { − y 0 0 = K 0 0 \left\{

    y00=K00
    \right. {y00=K00

    { y 1 − 1 = − 2 K 1 − 1 s i n ( φ ) ∣ s i n θ ∣ = − 2 K 1 − 1 y y 1 0 = K 1 0 c o s θ = K 1 0 z y 1 1 = − 2 K 1 − 1 c o s ( φ ) ∣ s i n θ ∣ = − 2 K 1 − 1 x \left\{

    y11=2K11sin(φ)|sinθ|=2K11yy10=K10cosθ=K10zy11=2K11cos(φ)|sinθ|=2K11x
    \right. y11=2 K11sin(φ)sinθ=2 K11yy10=K10cosθ=K10zy11=2 K11cos(φ)sinθ=2 K11x

    { y 2 − 2 = 3 2 K 2 − 2 s i n ( 2 φ ) s i n 2 θ = 6 2 K 2 − 2 x y y 2 − 1 = − 3 2 K 2 − 1 s i n ( φ ) ∣ s i n θ ∣ c o s θ = − 3 2 y z y 2 0 = 3 c o s 2 θ − 1 2 = K 2 0 2 z 2 − x 2 − y 2 2 y 2 1 = − 3 2 K 2 1 c o s ( φ ) ∣ s i n θ ∣ c o s θ = − 3 2 K 2 1 x z y 2 2 = 3 2 K 2 2 c o s ( 2 φ ) s i n 2 θ = 3 2 K 2 2 ( x 2 − y 2 ) \left\{

    y22=32K22sin(2φ)sin2θ=62K22xyy21=32K21sin(φ)|sinθ|cosθ=32yzy20=3cos2θ12=K202z2x2y22y21=32K21cos(φ)|sinθ|cosθ=32K21xzy22=32K22cos(2φ)sin2θ=32K22(x2y2)
    \right. y22=32 K22sin(2φ)sin2θ=62 K22xyy21=32 K21sin(φ)sinθcosθ=32 yzy20=23cos2θ1=K2022z2x2y2y21=32 K21cos(φ)sinθcosθ=32 K21xzy22=32 K22cos(2φ)sin2θ=32 K22(x2y2)

  • STEP 5 求 K l m K_l^m Klm:

    K l m = ( 2 l + 1 ) ( l − ∣ m ∣ ) ! 4 π ( l + ∣ m ∣ ) ! K_l^m = \sqrt{\frac{(2l+1)(l-|m|)!}{4\pi(l+|m|)!} } Klm=4π(l+m)!(2l+1)(lm)!

    K 0 0 = 1 4 π = 0.282094 2 K 1 − 1 = 2 K 1 1 = K 1 0 = 3 4 π = 0.4886 { 6 2 K 2 − 2 = 1.0925 − 3 2 K 2 − 1 = − 1.0925 K 2 0 2 = 0.31539 − 3 2 K 2 1 = − 1.0925 3 2 K 2 2 = 0.54627 K_0^0 = \frac{1}{\sqrt{4\pi}} = 0.282094\\ \sqrt{2}K_1^{-1} = \sqrt{2}K_1^{1} = K_1^0 = \sqrt{\frac{3}{4\pi}} = 0.4886 \\ \\ \left\{

    62K22=1.092532K21=1.0925K202=0.3153932K21=1.092532K22=0.54627
    \right. K00=4π 1=0.2820942 K11=2 K11=K10=4π3 =0.4886 62 K22=1.092532 K21=1.09252K20=0.3153932 K21=1.092532 K22=0.54627

  • 因此PlenOctree的代码

    ( https://github.com/sxyu/plenoctree/blob/master/nerf_sh/nerf/sh.py )

    就解释的通啦:

C0 = 0.28209479177387814
C1 = 0.4886025119029199
C2 = [
    1.0925484305920792,
    -1.0925484305920792,
    0.31539156525252005,
    -1.0925484305920792,
    0.5462742152960396
]
C3 = [
    -0.5900435899266435,
    2.890611442640554,
    -0.4570457994644658,
    0.3731763325901154,
    -0.4570457994644658,
    1.445305721320277,
    -0.5900435899266435
]
C4 = [
    2.5033429417967046,
    -1.7701307697799304,
    0.9461746957575601,
    -0.6690465435572892,
    0.10578554691520431,
    -0.6690465435572892,
    0.47308734787878004,
    -1.7701307697799304,
    0.6258357354491761,
]

def eval_sh(deg, sh, dirs):
    """
    Evaluate spherical harmonics at unit directions
    using hardcoded SH polynomials.
    Works with torch/np/jnp.
    ... Can be 0 or more batch dimensions.

    Args:
        deg: int SH deg. Currently, 0-3 supported
        sh: jnp.ndarray SH coeffs [..., C, (deg + 1) ** 2]
        dirs: jnp.ndarray unit directions [..., 3]

    Returns:
        [..., C]
    """
    assert deg <= 4 and deg >= 0
    assert (deg + 1) ** 2 == sh.shape[-1]
    C = sh.shape[-2]

    result = C0 * sh[..., 0]
    if deg > 0:
        x, y, z = dirs[..., 0:1], dirs[..., 1:2], dirs[..., 2:3]
        result = (result -
                C1 * y * sh[..., 1] +
                C1 * z * sh[..., 2] -
                C1 * x * sh[..., 3])
        if deg > 1:
            xx, yy, zz = x * x, y * y, z * z
            xy, yz, xz = x * y, y * z, x * z
            result = (result +
                    C2[0] * xy * sh[..., 4] +
                    C2[1] * yz * sh[..., 5] +
                    C2[2] * (2.0 * zz - xx - yy) * sh[..., 6] +
                    C2[3] * xz * sh[..., 7] +
                    C2[4] * (xx - yy) * sh[..., 8])

            if deg > 2:
                result = (result +
                        C3[0] * y * (3 * xx - yy) * sh[..., 9] +
                        C3[1] * xy * z * sh[..., 10] +
                        C3[2] * y * (4 * zz - xx - yy)* sh[..., 11] +
                        C3[3] * z * (2 * zz - 3 * xx - 3 * yy) * sh[..., 12] +
                        C3[4] * x * (4 * zz - xx - yy) * sh[..., 13] +
                        C3[5] * z * (xx - yy) * sh[..., 14] +
                        C3[6] * x * (xx - 3 * yy) * sh[..., 15])
                if deg > 3:
                    result = (result + C4[0] * xy * (xx - yy) * sh[..., 16] +
                            C4[1] * yz * (3 * xx - yy) * sh[..., 17] +
                            C4[2] * xy * (7 * zz - 1) * sh[..., 18] +
                            C4[3] * yz * (7 * zz - 3) * sh[..., 19] +
                            C4[4] * (zz * (35 * zz - 30) + 3) * sh[..., 20] +
                            C4[5] * xz * (7 * zz - 3) * sh[..., 21] +
                            C4[6] * (xx - yy) * (7 * zz - 1) * sh[..., 22] +
                            C4[7] * xz * (xx - 3 * yy) * sh[..., 23] +
                            C4[8] * (xx * (xx - 3 * yy) - yy * (3 * xx - yy)) * sh[..., 24])
    return result
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/126549
推荐阅读
相关标签
  

闽ICP备14008679号