summaryrefslogtreecommitdiff
path: root/similarity.py
blob: fec83d61147054e6464de21973958bba04d9392b (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
from gaussian import Gaussian
from utils import quat2rot
from aabb import process_aabb, intersect, min_interval
import numpy as np

def similarity(gaussian: Gaussian, id1: int, id2: int):
    geometry_sim = geometry_similarity(gaussian, id1, id2)
    color_sim = color_similarity(gaussian.sh[id1], gaussian.sh[id2])
    color_max = np.max(np.abs(gaussian.sh))
    # return geometry_sim * geometry_coeff + color_sim * color_coeff
    return geometry_sim, color_sim / (color_max * color_max * 48)
    
def color_similarity(c1: np.ndarray, c2: np.ndarray):
    return np.sum(c1 * c2)

def geometry_similarity(gaussian: Gaussian, id1: int, id2: int):
    def geometry_similarity_using_overlap(gaussian: Gaussian, id1: int, id2: int):
        aabb1 = process_aabb(gaussian.positions[id1], gaussian.scales[id1], gaussian.rotations[id1], scale_factor=2)
        aabb2 = process_aabb(gaussian.positions[id2], gaussian.scales[id2], gaussian.rotations[id2], scale_factor=2)
        # 在两个 aabb 里 stratified sample 点,对两个 Gaussian 的乘积做积分
        # 然后除以总sample数作为重叠程度的 metric

        intersected_aabb = intersect(aabb1, aabb2)

        if intersected_aabb is None:
            return 0

        x_stride = (intersected_aabb[1] - intersected_aabb[0]) / (4. + 1e-3)
        y_stride = (intersected_aabb[3] - intersected_aabb[2]) / (4. + 1e-3)
        z_stride = (intersected_aabb[5] - intersected_aabb[4]) / (4. + 1e-3)
        
        score = 0
        for i in range(int(np.floor((intersected_aabb[1] - intersected_aabb[0]) / x_stride))):
            x = intersected_aabb[0] + i * x_stride
            for j in range(int(np.floor((intersected_aabb[3] - intersected_aabb[2]) / y_stride))):
                y = intersected_aabb[2] + j * y_stride
                for k in range(int(np.floor((intersected_aabb[5] - intersected_aabb[4]) / z_stride))):
                    z = intersected_aabb[4] + k * z_stride
                    pos = np.array([x, y, z])
                    score += gaussian.calc(pos, id1, 10) * gaussian.calc(pos, id2, 10) * gaussian.opacity[id1] * gaussian.opacity[id2]

        scale1 = gaussian.scales[id1][0] * gaussian.scales[id1][1] * gaussian.scales[id1][2]
        scale2 = gaussian.scales[id2][0] * gaussian.scales[id2][1] * gaussian.scales[id2][2]

        # print(f"calculating pair ({id1},{id2}), used {64} samples.")
        return score / (scale1 * scale2)

    def geometry_similarity_using_position(gaussian: Gaussian, id1: int, id2: int):
        def position_similarity(p1: np.ndarray, p2: np.ndarray):
            return np.linalg.norm(p1 - p2)
        
        def scale_similarity(s1: np.ndarray, s2: np.ndarray):
            return np.linalg.norm(s1 - s2)

        def rotation_similarity(q1: np.ndarray, q2: np.ndarray):
            return 1 - np.dot(q1, q2)
            # r1 = quat2rot(q1)
            # r2 = quat2rot(q2)
            # eigenvalues, eigenvectors = np.linalg.eig(r1 @ r2.T)
            # return np.linalg.norm(eigenvectors @ np.diag(np.log(eigenvalues)) @ np.linalg.inv(eigenvectors)) 
        position_coeff = 1.
        scale_coeff = 1.
        rotation_coeff = 1.
        return position_similarity(gaussian.positions[id1], gaussian.positions[id2]) * position_coeff + \
            scale_similarity(gaussian.scales[id1], gaussian.scales[id2]) * scale_coeff + \
            rotation_similarity(gaussian.rotations[id1], gaussian.rotations[id2]) * rotation_coeff

    return geometry_similarity_using_overlap(gaussian, id1, id2)