renderer.py 3.61 KB
Newer Older
Nianchen Deng's avatar
sync    
Nianchen Deng committed
1
2
from .__common__ import *
import torch.nn.functional as F
Nianchen Deng's avatar
sync    
Nianchen Deng committed
3

Nianchen Deng's avatar
sync    
Nianchen Deng committed
4
__all__ = ["density2energy", "density2alpha", "VolumnRenderer"]
Nianchen Deng's avatar
sync    
Nianchen Deng committed
5
6


Nianchen Deng's avatar
sync    
Nianchen Deng committed
7
def density2energy(densities: torch.Tensor, dists: torch.Tensor, raw_noise_std: float = 0) -> torch.Tensor:
Nianchen Deng's avatar
sync    
Nianchen Deng committed
8
9
10
    """
    Calculate energies from densities inferred by model.

Nianchen Deng's avatar
sync    
Nianchen Deng committed
11
    :param densities `Tensor(N...)`: model's output densities
Nianchen Deng's avatar
sync    
Nianchen Deng committed
12
13
14
    :param dists `Tensor(N...)`: integration times
    :param raw_noise_std `float`: the noise std used to egularize network during training (prevents 
                                  floater artifacts), defaults to 0, means no noise is added
Nianchen Deng's avatar
sync    
Nianchen Deng committed
15
    :return `Tensor(N...)`: energies which block light rays
Nianchen Deng's avatar
sync    
Nianchen Deng committed
16
17
18
19
    """
    if raw_noise_std > 0:
        # Add noise to model's predictions for density. Can be used to
        # regularize network during training (prevents floater artifacts).
Nianchen Deng's avatar
sync    
Nianchen Deng committed
20
21
22
        densities = densities + torch.normal(0.0, raw_noise_std, densities.shape,
                                             device=densities.device)
    return F.relu(densities) * dists
Nianchen Deng's avatar
sync    
Nianchen Deng committed
23
24


Nianchen Deng's avatar
sync    
Nianchen Deng committed
25
def energy2alpha(energies: torch.Tensor) -> torch.Tensor:
Nianchen Deng's avatar
sync    
Nianchen Deng committed
26
    """
Nianchen Deng's avatar
sync    
Nianchen Deng committed
27
    Convert energies to alphas.
Nianchen Deng's avatar
sync    
Nianchen Deng committed
28

Nianchen Deng's avatar
sync    
Nianchen Deng committed
29
30
    :param energies `Tensor(N...)`: energies (calculated from densities)
    :return `Tensor(N...)`: alphas
Nianchen Deng's avatar
sync    
Nianchen Deng committed
31
32
    """
    return 1.0 - torch.exp(-energies)
Nianchen Deng's avatar
Nianchen Deng committed
33
34


Nianchen Deng's avatar
sync    
Nianchen Deng committed
35
36
37
def density2alpha(densities: torch.Tensor, dists: torch.Tensor, raw_noise_std: float = 0) -> torch.Tensor:
    """
    Calculate alphas from densities inferred by model.
Nianchen Deng's avatar
sync    
Nianchen Deng committed
38

Nianchen Deng's avatar
sync    
Nianchen Deng committed
39
40
41
42
43
44
45
    :param densities `Tensor(N...)`: model's output densities
    :param dists `Tensor(N...)`: integration times
    :param raw_noise_std `float`: the noise std used to regularize network during training (prevents 
                                  floater artifacts), defaults to 0, means no noise is added
    :return `Tensor(N...)`: alphas
    """
    return energy2alpha(density2energy(densities, dists, raw_noise_std))
Nianchen Deng's avatar
sync    
Nianchen Deng committed
46
47


Nianchen Deng's avatar
sync    
Nianchen Deng committed
48
class VolumnRenderer(nn.Module):
Nianchen Deng's avatar
sync    
Nianchen Deng committed
49

Nianchen Deng's avatar
sync    
Nianchen Deng committed
50
    def __init__(self):
Nianchen Deng's avatar
Nianchen Deng committed
51
        super().__init__()
Nianchen Deng's avatar
sync    
Nianchen Deng committed
52

Nianchen Deng's avatar
sync    
Nianchen Deng committed
53
54
55
    # stub method
    def __call__(self, samples: Samples, densities: torch.Tensor, colors: torch.Tensor, *outputs: str,
                 white_bg: bool, raw_noise_std: float) -> ReturnData:
Nianchen Deng's avatar
sync    
Nianchen Deng committed
56
57
58
        """
        Perform volumn rendering.

Nianchen Deng's avatar
sync    
Nianchen Deng committed
59
60
        :param samples `Samples(B, P)`: samples
        :param rgbd `Tensor(B, P, C+1)`: colors and densities
Nianchen Deng's avatar
sync    
Nianchen Deng committed
61
62
        :param outputs `str...`: items should be contained in the result dict.
                Optional values include 'color', 'depth', 'layers', 'states' and attribute names in class `States` (e.g. 'weights'). Defaults to []
Nianchen Deng's avatar
sync    
Nianchen Deng committed
63
        :return `ReturnData`: render result { 'color'[, 'depth', 'layers', 'states', ...] }
Nianchen Deng's avatar
Nianchen Deng committed
64
        """
Nianchen Deng's avatar
sync    
Nianchen Deng committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
        ...

    @profile
    def forward(self, samples: Samples, rgbd: torch.Tensor, *outputs: str,
                white_bg: bool, raw_noise_std: float) -> ReturnData:
        energies = density2energy(rgbd[..., -1], samples.dists, raw_noise_std)  # (B, P)
        alphas = energy2alpha(energies)  # (B, P)
        weights = (alphas * torch.cumprod(union(1, 1. - alphas + 1e-10), -1)[..., :-1])[..., None]
        output_fn = {
            "color": lambda: torch.sum(weights * rgbd[..., :-1], -2) + (1. - torch.sum(weights, -2)
                                                                        if white_bg else 0.),
            "depth": lambda: torch.sum(weights * samples.depths[..., None], -2),
            "colors": lambda: rgbd[..., :-1],
            "densities": lambda: rgbd[..., -1:],
            "alphas": lambda: alphas[..., None],
            "energies": lambda: energies[..., None],
            "weights": lambda: weights
        }
        return ReturnData({key: output_fn[key]() for key in outputs if key in output_fn})