summaryrefslogtreecommitdiff
path: root/gaussian.py
blob: 10f23f3d0f37780f41a16d6c8f82ddcaeccb6853 (plain) (blame)
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from utils import quat2rot
import numpy as np

class Gaussian:
    def __init__(self, positions, scales, rotations, features_dc, features_rest, opacity):
        self.num_gaussians = positions.shape[0]
        self.positions = positions

        self.scales = scales
        self.rotations = rotations

        # self.scales = np.exp(scales)
        
        # rot_length = np.repeat(np.linalg.norm(rotations, axis=1), 4).reshape(-1, 4)
        # self.rotations = rotations / rot_length

        self.features_dc = features_dc
        self.features_rest = features_rest

        self.opacity = opacity

    def empty_with_cap(cap: int) -> "Gaussian":
        positions = np.zeros((cap, 3))
        scales = np.zeros((cap, 3))
        rotations = np.zeros((cap, 4))
        features_dc = np.zeros((cap, 1, 3))
        features_rest = np.zeros((cap, 15, 3))
        opacity = np.zeros((cap, 1))

        gaussian = Gaussian(positions, scales, rotations, features_dc, features_rest, opacity)
        gaussian.num_gaussians = 0
        return gaussian

    @property
    def sh(self):
        return np.concatenate((self.features_dc, self.features_rest), axis=1)
    
    def calc(self, x, id: int, scale: float):
        x = x * scale
        S = np.diag(self.scales[id])
        R = quat2rot(self.rotations[id])
        M = S @ R

        Sigma = M.T @ M
        Sigma = np.linalg.inv(Sigma)

        return np.dot(x, Sigma @ x)
        # M = R @ S
        # return np.dot(x, M @ M.T @ x)

    def clip_to_box(self, min: np.ndarray, max: np.ndarray):
        indices = ((self.positions > min) & (self.positions < max)).all(axis=1)
        self.apply_filter(indices)
    
    def apply_filter(self, filter):
        self.positions = self.positions[filter]
        self.scales = self.scales[filter]
        self.rotations = self.rotations[filter]
        self.features_dc = self.features_dc[filter]
        self.features_rest = self.features_rest[filter]
        self.opacity = self.opacity[filter]
        self.num_gaussians = self.positions.shape[0]

    def add(self, position, scale, rotation, features_dc, features_rest, opacity):
        n = self.num_gaussians

        self.positions[n] = position
        self.scales[n] = scale
        self.rotations[n] = rotation
        self.features_dc[n] = features_dc
        self.features_rest[n] = features_rest
        self.opacity[n] = opacity

        self.num_gaussians += 1
        return n
    
    def concat(self, other: "Gaussian"):
        self.positions = np.concatenate((self.positions, other.positions), axis=0)
        self.scales = np.concatenate((self.scales, other.scales), axis=0)
        self.rotations = np.concatenate((self.rotations, other.rotations), axis=0)
        self.features_dc = np.concatenate((self.features_dc, other.features_dc), axis=0)
        self.features_rest = np.concatenate((self.features_rest, other.features_rest), axis=0)
        self.opacity = np.concatenate((self.opacity, other.opacity), axis=0)
        self.num_gaussians = self.num_gaussians + other.num_gaussians

    def replace(self, id1: int, id2: int,
                position, scale, rotation, sh, opacity):
        # 用新的 gaussian 替换 id1 位置的 gaussian
        self.positions[id1] = position
        self.scales[id1] = scale
        self.rotations[id1] = rotation
        self.features_dc[id1] = sh[0, :]
        self.features_rest[id1] = sh[1:, :]
        self.opacity[id1] = opacity

        # 把最后一个 gaussian 放到 id2 的位置上
        n = self.num_gaussians
        self.positions[id2] = self.positions[n - 1]
        self.scales[id2] = self.scales[n - 1]
        self.rotations[id2] = self.rotations[n - 1]
        self.features_dc[id2] = self.features_dc[n - 1]
        self.features_rest[id2] = self.features_rest[n - 1]
        self.opacity[id2] = self.opacity[n - 1]
        
        self.num_gaussians -= 1
        pass

    def copy(self) -> "Gaussian":
        positions = np.copy(self.positions)
        scales = np.copy(self.scales)
        rotations = np.copy(self.rotations)
        features_dc = np.copy(self.features_dc)
        features_rest = np.copy(self.features_rest)
        opacity = np.copy(self.opacity)

        return Gaussian(positions, scales, rotations, features_dc, features_rest, opacity)