gaussian-splatting 1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. gaussian_splatting-1.0/LICENSE.md +91 -0
  2. gaussian_splatting-1.0/PKG-INFO +11 -0
  3. gaussian_splatting-1.0/README.md +196 -0
  4. gaussian_splatting-1.0/gaussian_splatting/__init__.py +3 -0
  5. gaussian_splatting-1.0/gaussian_splatting/camera.py +106 -0
  6. gaussian_splatting-1.0/gaussian_splatting/camera_trainable.py +95 -0
  7. gaussian_splatting-1.0/gaussian_splatting/dataset/__init__.py +2 -0
  8. gaussian_splatting-1.0/gaussian_splatting/dataset/camera_trainable.py +70 -0
  9. gaussian_splatting-1.0/gaussian_splatting/dataset/colmap/__init__.py +5 -0
  10. gaussian_splatting-1.0/gaussian_splatting/dataset/colmap/dataset.py +106 -0
  11. gaussian_splatting-1.0/gaussian_splatting/dataset/colmap/params_init.py +120 -0
  12. gaussian_splatting-1.0/gaussian_splatting/dataset/colmap/utils.py +299 -0
  13. gaussian_splatting-1.0/gaussian_splatting/dataset/dataset.py +71 -0
  14. gaussian_splatting-1.0/gaussian_splatting/gaussian_model.py +254 -0
  15. gaussian_splatting-1.0/gaussian_splatting/render.py +61 -0
  16. gaussian_splatting-1.0/gaussian_splatting/train.py +112 -0
  17. gaussian_splatting-1.0/gaussian_splatting/trainer/__init__.py +3 -0
  18. gaussian_splatting-1.0/gaussian_splatting/trainer/camera_trainable.py +72 -0
  19. gaussian_splatting-1.0/gaussian_splatting/trainer/densifier.py +233 -0
  20. gaussian_splatting-1.0/gaussian_splatting/trainer/trainer.py +177 -0
  21. gaussian_splatting-1.0/gaussian_splatting/utils/__init__.py +7 -0
  22. gaussian_splatting-1.0/gaussian_splatting/utils/general.py +66 -0
  23. gaussian_splatting-1.0/gaussian_splatting/utils/graphics.py +67 -0
  24. gaussian_splatting-1.0/gaussian_splatting/utils/loss.py +64 -0
  25. gaussian_splatting-1.0/gaussian_splatting/utils/lpipsPyTorch/__init__.py +21 -0
  26. gaussian_splatting-1.0/gaussian_splatting/utils/lpipsPyTorch/modules/__init__.py +0 -0
  27. gaussian_splatting-1.0/gaussian_splatting/utils/lpipsPyTorch/modules/lpips.py +36 -0
  28. gaussian_splatting-1.0/gaussian_splatting/utils/lpipsPyTorch/modules/networks.py +96 -0
  29. gaussian_splatting-1.0/gaussian_splatting/utils/lpipsPyTorch/modules/utils.py +30 -0
  30. gaussian_splatting-1.0/gaussian_splatting/utils/metrics.py +19 -0
  31. gaussian_splatting-1.0/gaussian_splatting/utils/pose.py +160 -0
  32. gaussian_splatting-1.0/gaussian_splatting/utils/schedular.py +38 -0
  33. gaussian_splatting-1.0/gaussian_splatting/utils/shs.py +119 -0
  34. gaussian_splatting-1.0/gaussian_splatting.egg-info/PKG-INFO +11 -0
  35. gaussian_splatting-1.0/gaussian_splatting.egg-info/SOURCES.txt +55 -0
  36. gaussian_splatting-1.0/gaussian_splatting.egg-info/dependency_links.txt +1 -0
  37. gaussian_splatting-1.0/gaussian_splatting.egg-info/requires.txt +2 -0
  38. gaussian_splatting-1.0/gaussian_splatting.egg-info/top_level.txt +1 -0
  39. gaussian_splatting-1.0/setup.cfg +4 -0
  40. gaussian_splatting-1.0/setup.py +68 -0
  41. gaussian_splatting-1.0/submodules/diff-gaussian-rasterization/cuda_rasterizer/backward.cu +753 -0
  42. gaussian_splatting-1.0/submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.cu +484 -0
  43. gaussian_splatting-1.0/submodules/diff-gaussian-rasterization/cuda_rasterizer/rasterizer_impl.cu +450 -0
  44. gaussian_splatting-1.0/submodules/diff-gaussian-rasterization/diff_gaussian_rasterization/__init__.py +208 -0
  45. gaussian_splatting-1.0/submodules/diff-gaussian-rasterization/ext.cpp +19 -0
  46. gaussian_splatting-1.0/submodules/diff-gaussian-rasterization/rasterize_points.cu +243 -0
  47. gaussian_splatting-1.0/submodules/simple-knn/ext.cpp +17 -0
  48. gaussian_splatting-1.0/submodules/simple-knn/simple_knn.cu +222 -0
  49. gaussian_splatting-1.0/submodules/simple-knn/spatial.cu +26 -0
@@ -0,0 +1,91 @@
1
+ Gaussian-Splatting License
2
+ ===========================
3
+
4
+ **Inria** and **the Max Planck Institut for Informatik (MPII)** hold all the ownership rights on the *Software* named **gaussian-splatting**.
5
+ The *Software* is in the process of being registered with the Agence pour la Protection des
6
+ Programmes (APP).
7
+
8
+ The *Software* is still being developed by the *Licensor*.
9
+
10
+ *Licensor*'s goal is to allow the research community to use, test and evaluate
11
+ the *Software*.
12
+
13
+ ## 1. Definitions
14
+
15
+ *Licensee* means any person or entity that uses the *Software* and distributes
16
+ its *Work*.
17
+
18
+ *Licensor* means the owners of the *Software*, i.e Inria and MPII
19
+
20
+ *Software* means the original work of authorship made available under this
21
+ License ie gaussian-splatting.
22
+
23
+ *Work* means the *Software* and any additions to or derivative works of the
24
+ *Software* that are made available under this License.
25
+
26
+
27
+ ## 2. Purpose
28
+ This license is intended to define the rights granted to the *Licensee* by
29
+ Licensors under the *Software*.
30
+
31
+ ## 3. Rights granted
32
+
33
+ For the above reasons Licensors have decided to distribute the *Software*.
34
+ Licensors grant non-exclusive rights to use the *Software* for research purposes
35
+ to research users (both academic and industrial), free of charge, without right
36
+ to sublicense.. The *Software* may be used "non-commercially", i.e., for research
37
+ and/or evaluation purposes only.
38
+
39
+ Subject to the terms and conditions of this License, you are granted a
40
+ non-exclusive, royalty-free, license to reproduce, prepare derivative works of,
41
+ publicly display, publicly perform and distribute its *Work* and any resulting
42
+ derivative works in any form.
43
+
44
+ ## 4. Limitations
45
+
46
+ **4.1 Redistribution.** You may reproduce or distribute the *Work* only if (a) you do
47
+ so under this License, (b) you include a complete copy of this License with
48
+ your distribution, and (c) you retain without modification any copyright,
49
+ patent, trademark, or attribution notices that are present in the *Work*.
50
+
51
+ **4.2 Derivative Works.** You may specify that additional or different terms apply
52
+ to the use, reproduction, and distribution of your derivative works of the *Work*
53
+ ("Your Terms") only if (a) Your Terms provide that the use limitation in
54
+ Section 2 applies to your derivative works, and (b) you identify the specific
55
+ derivative works that are subject to Your Terms. Notwithstanding Your Terms,
56
+ this License (including the redistribution requirements in Section 3.1) will
57
+ continue to apply to the *Work* itself.
58
+
59
+ **4.3** Any other use without of prior consent of Licensors is prohibited. Research
60
+ users explicitly acknowledge having received from Licensors all information
61
+ allowing to appreciate the adequacy between of the *Software* and their needs and
62
+ to undertake all necessary precautions for its execution and use.
63
+
64
+ **4.4** The *Software* is provided both as a compiled library file and as source
65
+ code. In case of using the *Software* for a publication or other results obtained
66
+ through the use of the *Software*, users are strongly encouraged to cite the
67
+ corresponding publications as explained in the documentation of the *Software*.
68
+
69
+ ## 5. Disclaimer
70
+
71
+ THE USER CANNOT USE, EXPLOIT OR DISTRIBUTE THE *SOFTWARE* FOR COMMERCIAL PURPOSES
72
+ WITHOUT PRIOR AND EXPLICIT CONSENT OF LICENSORS. YOU MUST CONTACT INRIA FOR ANY
73
+ UNAUTHORIZED USE: stip-sophia.transfert@inria.fr . ANY SUCH ACTION WILL
74
+ CONSTITUTE A FORGERY. THIS *SOFTWARE* IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES
75
+ OF ANY NATURE AND ANY EXPRESS OR IMPLIED WARRANTIES, WITH REGARDS TO COMMERCIAL
76
+ USE, PROFESSIONNAL USE, LEGAL OR NOT, OR OTHER, OR COMMERCIALISATION OR
77
+ ADAPTATION. UNLESS EXPLICITLY PROVIDED BY LAW, IN NO EVENT, SHALL INRIA OR THE
78
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
79
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
80
+ GOODS OR SERVICES, LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION)
81
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING FROM, OUT OF OR
83
+ IN CONNECTION WITH THE *SOFTWARE* OR THE USE OR OTHER DEALINGS IN THE *SOFTWARE*.
84
+
85
+ ## 6. Files subject to permissive licenses
86
+ The contents of the file ```utils/loss_utils.py``` are based on publicly available code authored by Evan Su, which falls under the permissive MIT license.
87
+
88
+ Title: pytorch-ssim\
89
+ Project code: https://github.com/Po-Hsun-Su/pytorch-ssim\
90
+ Copyright Evan Su, 2017\
91
+ License: https://github.com/Po-Hsun-Su/pytorch-ssim/blob/master/LICENSE.txt (MIT)
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.1
2
+ Name: gaussian_splatting
3
+ Version: 1.0
4
+ Summary: UNKNOWN
5
+ Home-page: UNKNOWN
6
+ License: UNKNOWN
7
+ Platform: UNKNOWN
8
+ License-File: LICENSE.md
9
+
10
+ UNKNOWN
11
+
@@ -0,0 +1,196 @@
1
+ # packaged 3D Gaussian Splatting
2
+
3
+ This repo is the **refactored python training and inference code for [3D Gaussian Splatting](https://github.com/graphdeco-inria/gaussian-splatting)**.
4
+ Forked from commit [a2a91d9093fd791fb01f556fa717f8d9f2cfbdd7](https://github.com/graphdeco-inria/gaussian-splatting/tree/a2a91d9093fd791fb01f556fa717f8d9f2cfbdd7).
5
+ We **refactored the original code following the standard Python package structure**, while **keeping the algorithms used in the code identical to the original version**.
6
+
7
+ ## Features
8
+
9
+ * [x] organize the code as a standard Python package
10
+ * [x] exposure compensation
11
+ * [x] camera and 3DGS parameters joint training
12
+ * [ ] depth regularization
13
+ * [ ] integrated 2DGS (integrated [gsplat](https://github.com/nerfstudio-project/gsplat) backend)
14
+
15
+ ## Install
16
+
17
+ ### Requirements
18
+
19
+ Install Pytorch and torchvision following the official guideline: [pytorch.org](https://pytorch.org/)
20
+
21
+ ### Local Install
22
+
23
+ ```shell
24
+ git clone https://github.com/yindaheng98/gaussian-splatting --recursive
25
+ cd gaussian-splatting
26
+ pip install tqdm plyfile
27
+ pip install --target . --upgrade . --no-deps
28
+ ```
29
+
30
+ ### Pip Install
31
+
32
+ You can download wheel from [Releases](https://github.com/yindaheng98/gaussian-splatting/releases), or
33
+ install latest from source:
34
+ ```shell
35
+ pip install --upgrade git+https://github.com/yindaheng98/gaussian-splatting.git@master
36
+ ```
37
+
38
+ ## Running
39
+
40
+ Download dataset [T&T+DB COLMAP (650MB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/datasets/input/tandt_db.zip) and extract to `./data` directory.
41
+
42
+ 1. Train 3DGS with densification (same with original 3DGS)
43
+ ```shell
44
+ python -m gaussian_splatting.train -s data/truck -d output/truck -i 30000 --mode densify
45
+ ```
46
+
47
+ 2. Render it
48
+ ```shell
49
+ python -m gaussian_splatting.render -s data/truck -d output/truck -i 30000 --mode densify
50
+ ```
51
+
52
+ 3. Joint training 3DGS and camera (load the trained 3DGS)
53
+ ```shell
54
+ python -m gaussian_splatting.train -s data/truck -d output/truck-camera -i 30000 --mode camera -l output/truck/point_cloud/iteration_30000/point_cloud.ply
55
+ ```
56
+
57
+ 4. Render it with trained 3DGS
58
+ ```shell
59
+ python -m gaussian_splatting.render -s data/truck -d output/truck-camera -i 30000 --mode camera --load_camera output/truck-camera/cameras.json
60
+ ```
61
+
62
+ This repo do not contrains code for initialization.
63
+ If you want to create your own scene, please refer to [InstantSplat](https://github.com/yindaheng98/InstantSplat) or use [convert.py](https://github.com/graphdeco-inria/gaussian-splatting/blob/main/convert.py).
64
+
65
+ ## Usage
66
+
67
+ **See [.vscode/launch.json](.vscode/launch.json) for more example.**
68
+
69
+ **See [gaussian_splatting.train](gaussian_splatting/train.py) and [gaussian_splatting.render](gaussian_splatting/render.py) for full options.**
70
+
71
+ ### Gaussian models
72
+
73
+ `GaussianModel` is the basic 3DGS model.
74
+ ```python
75
+ from gaussian_splatting import GaussianModel
76
+ gaussians = GaussianModel(sh_degree).to(device)
77
+ ```
78
+
79
+ If you want cameras-3DGS joint training, use `CameraTrainableGaussianModel`, the rendering process is different.
80
+ ```python
81
+ from gaussian_splatting import CameraTrainableGaussianModel
82
+ gaussians = CameraTrainableGaussianModel(sh_degree).to(device)
83
+ ```
84
+
85
+ save and load params:
86
+ ```python
87
+ gaussians.save_ply("output/truck/point_cloud/iteration_30000/point_cloud.ply")
88
+ gaussians.load_ply("output/truck/point_cloud/iteration_30000/point_cloud.ply")
89
+ ```
90
+
91
+ init 3DGS with sparse point cloud extracted by colmap:
92
+ ```python
93
+ from gaussian_splatting.dataset.colmap import colmap_init
94
+ colmap_init(gaussians, "data/truck")
95
+ ```
96
+
97
+ ### Dataset
98
+
99
+ Basic colmap dataset:
100
+ ```python
101
+ from gaussian_splatting.dataset.colmap import ColmapCameraDataset, colmap_init
102
+ dataset = ColmapCameraDataset("data/truck")
103
+ ```
104
+
105
+ save to JSON and load JSON dataset:
106
+ ```python
107
+ dataset.save_cameras("output/truck/cameras.json")
108
+ from gaussian_splatting import JSONCameraDataset
109
+ dataset = JSONCameraDataset("output/truck/cameras.json")
110
+ ```
111
+
112
+ Dataset with trainable cameras:
113
+ ```python
114
+ from gaussian_splatting import TrainableCameraDataset
115
+ dataset = TrainableCameraDataset("data/truck") # init cameras from colmap
116
+ dataset = TrainableCameraDataset.from_json("output/truck/cameras.json") # init cameras from saved json
117
+ ```
118
+
119
+ ### Inference
120
+
121
+ ```python
122
+ for camera in dataset:
123
+ out = gaussians(camera)
124
+ image = out["render"]
125
+ ... # compute loss, save image or others
126
+ ```
127
+
128
+ ### Training
129
+
130
+ `BaseTrainer` only optimize the 3DGS parameters, without densification or joint training with cameras.
131
+ ```python
132
+ from gaussian_splatting.trainer import BaseTrainer
133
+ trainer = BaseTrainer(
134
+ gaussians,
135
+ spatial_lr_scale=dataset.scene_extent(),
136
+ ... # see gaussian_splatting/trainer/trainer.py for full options
137
+ )
138
+ ```
139
+
140
+ `DensificationTrainer` optimize the 3DGS parameters and densify it.
141
+ ```python
142
+ from gaussian_splatting.trainer import DensificationTrainer
143
+ trainer = DensificationTrainer(
144
+ gaussians,
145
+ scene_extent=dataset.scene_extent(),
146
+ ... # see gaussian_splatting/trainer/densifier.py for full options
147
+ )
148
+ ```
149
+
150
+ `CameraTrainer` jointly optimize the 3DGS parameters and cameras, without densification
151
+ ```python
152
+ from gaussian_splatting.trainer import CameraTrainer
153
+ trainer = CameraTrainer(
154
+ gaussians,
155
+ scene_extent=dataset.scene_extent(),
156
+ dataset=dataset,
157
+ ... # see gaussian_splatting/trainer/camera_trainable.py for full options
158
+ )
159
+ ```
160
+
161
+ Train it:
162
+ ```python
163
+ for camera in dataset:
164
+ loss, out = trainer.step(camera)
165
+ ```
166
+
167
+ # 3D Gaussian Splatting for Real-Time Radiance Field Rendering
168
+ Bernhard Kerbl*, Georgios Kopanas*, Thomas Leimkühler, George Drettakis (* indicates equal contribution)<br>
169
+ | [Webpage](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/) | [Full Paper](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/3d_gaussian_splatting_high.pdf) | [Video](https://youtu.be/T_kXY43VZnk) | [Other GRAPHDECO Publications](http://www-sop.inria.fr/reves/publis/gdindex.php) | [FUNGRAPH project page](https://fungraph.inria.fr) |<br>
170
+ | [T&T+DB COLMAP (650MB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/datasets/input/tandt_db.zip) | [Pre-trained Models (14 GB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/datasets/pretrained/models.zip) | [Viewers for Windows (60MB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/binaries/viewers.zip) | [Evaluation Images (7 GB)](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/evaluation/images.zip) |<br>
171
+ ![Teaser image](assets/teaser.png)
172
+
173
+ This repository contains the official authors implementation associated with the paper "3D Gaussian Splatting for Real-Time Radiance Field Rendering", which can be found [here](https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/). We further provide the reference images used to create the error metrics reported in the paper, as well as recently created, pre-trained models.
174
+
175
+ <a href="https://www.inria.fr/"><img height="100" src="assets/logo_inria.png"> </a>
176
+ <a href="https://univ-cotedazur.eu/"><img height="100" src="assets/logo_uca.png"> </a>
177
+ <a href="https://www.mpi-inf.mpg.de"><img height="100" src="assets/logo_mpi.png"> </a>
178
+ <a href="https://team.inria.fr/graphdeco/"> <img style="width:100%;" src="assets/logo_graphdeco.png"></a>
179
+
180
+ Abstract: *Radiance Field methods have recently revolutionized novel-view synthesis of scenes captured with multiple photos or videos. However, achieving high visual quality still requires neural networks that are costly to train and render, while recent faster methods inevitably trade off speed for quality. For unbounded and complete scenes (rather than isolated objects) and 1080p resolution rendering, no current method can achieve real-time display rates. We introduce three key elements that allow us to achieve state-of-the-art visual quality while maintaining competitive training times and importantly allow high-quality real-time (≥ 30 fps) novel-view synthesis at 1080p resolution. First, starting from sparse points produced during camera calibration, we represent the scene with 3D Gaussians that preserve desirable properties of continuous volumetric radiance fields for scene optimization while avoiding unnecessary computation in empty space; Second, we perform interleaved optimization/density control of the 3D Gaussians, notably optimizing anisotropic covariance to achieve an accurate representation of the scene; Third, we develop a fast visibility-aware rendering algorithm that supports anisotropic splatting and both accelerates training and allows realtime rendering. We demonstrate state-of-the-art visual quality and real-time rendering on several established datasets.*
181
+
182
+ <section class="section" id="BibTeX">
183
+ <div class="container is-max-desktop content">
184
+ <h2 class="title">BibTeX</h2>
185
+ <pre><code>@Article{kerbl3Dgaussians,
186
+ author = {Kerbl, Bernhard and Kopanas, Georgios and Leimk{\"u}hler, Thomas and Drettakis, George},
187
+ title = {3D Gaussian Splatting for Real-Time Radiance Field Rendering},
188
+ journal = {ACM Transactions on Graphics},
189
+ number = {4},
190
+ volume = {42},
191
+ month = {July},
192
+ year = {2023},
193
+ url = {https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/}
194
+ }</code></pre>
195
+ </div>
196
+ </section>
@@ -0,0 +1,3 @@
1
+ from .camera import Camera
2
+ from .gaussian_model import GaussianModel
3
+ from .camera_trainable import CameraTrainableGaussianModel
@@ -0,0 +1,106 @@
1
+ import os
2
+ from typing import NamedTuple, Callable
3
+ import torch
4
+ from PIL import Image
5
+ from .utils import fov2focal, focal2fov, getProjectionMatrix, getWorld2View2, PILtoTorch, matrix_to_quaternion
6
+
7
+
8
+ class Camera(NamedTuple):
9
+ image_height: int
10
+ image_width: int
11
+ FoVx: float
12
+ FoVy: float
13
+ R: torch.Tensor
14
+ T: torch.Tensor
15
+ world_view_transform: torch.Tensor
16
+ projection_matrix: torch.Tensor
17
+ full_proj_transform: torch.Tensor
18
+ camera_center: torch.Tensor
19
+ quaternion: torch.Tensor
20
+ ground_truth_image_path: str
21
+ ground_truth_image: torch.Tensor = None
22
+ postprocess: Callable[['Camera', torch.Tensor], torch.Tensor] = lambda camera, x: x
23
+ bg_color: torch.Tensor = torch.tensor([0., 0., 0.])
24
+ custom_data: dict = {}
25
+
26
+
27
+ def camera2dict(camera: Camera, id):
28
+ Rt = torch.zeros((4, 4))
29
+ Rt[:3, :3] = camera.R
30
+ Rt[:3, 3] = camera.T
31
+ Rt[3, 3] = 1.0
32
+
33
+ W2C = torch.linalg.inv(Rt)
34
+ pos = W2C[:3, 3]
35
+ rot = W2C[:3, :3]
36
+ serializable_array_2d = [x.tolist() for x in rot]
37
+ camera_entry = {
38
+ 'id': id,
39
+ 'width': camera.image_width,
40
+ 'height': camera.image_height,
41
+ 'position': pos.tolist(),
42
+ 'rotation': serializable_array_2d,
43
+ 'fy': fov2focal(camera.FoVx, camera.image_height),
44
+ 'fx': fov2focal(camera.FoVy, camera.image_width),
45
+ 'ground_truth_image_path': camera.ground_truth_image_path.replace("\\", "/"),
46
+ "img_name": os.path.basename(camera.ground_truth_image_path),
47
+ }
48
+ return camera_entry
49
+
50
+
51
+ def build_camera(
52
+ image_height: int, image_width: int,
53
+ FoVx: float, FoVy: float,
54
+ R: torch.Tensor, T: torch.Tensor,
55
+ image_path: str = None, device="cuda"
56
+ ):
57
+ zfar = 100.0
58
+ znear = 0.01
59
+ trans = torch.zeros(3)
60
+ scale = 1.0
61
+ world_view_transform = getWorld2View2(R, T, trans, scale).to(device).transpose(0, 1)
62
+ projection_matrix = getProjectionMatrix(znear=znear, zfar=zfar, fovX=FoVx, fovY=FoVy).to(device).transpose(0, 1)
63
+ full_proj_transform = (world_view_transform.unsqueeze(0).bmm(projection_matrix.unsqueeze(0))).squeeze(0)
64
+ camera_center = world_view_transform.inverse()[3, :3]
65
+ quaternion = matrix_to_quaternion(R)
66
+ gt_image = None
67
+ if image_path is not None:
68
+ pil_image = Image.open(image_path)
69
+ torch_image = PILtoTorch(pil_image)
70
+ gt_image = torch_image[:3, ...].clamp(0.0, 1.0).to(device)
71
+ image_height = gt_image.shape[1]
72
+ image_width = gt_image.shape[2]
73
+ return Camera(
74
+ # image_height=colmap_camera.image_height, # colmap_camera.image_height is read from cameras.bin, maybe dfferent from the actual image size
75
+ # image_width=colmap_camera.image_width, # colmap_camera.image_width is read from cameras.bin, maybe dfferent from the actual image size
76
+ image_height=image_height, image_width=image_width,
77
+ FoVx=FoVx, FoVy=FoVy,
78
+ R=R.to(device), T=T.to(device),
79
+ world_view_transform=world_view_transform,
80
+ projection_matrix=projection_matrix,
81
+ full_proj_transform=full_proj_transform,
82
+ camera_center=camera_center,
83
+ quaternion=quaternion.to(device),
84
+ ground_truth_image_path=image_path,
85
+ ground_truth_image=gt_image
86
+ )
87
+
88
+
89
+ def dict2camera(camera_dict, device="cuda"):
90
+ W2C = torch.zeros((4, 4))
91
+ W2C[:3, 3] = torch.tensor(camera_dict['position'])
92
+ W2C[:3, :3] = torch.tensor(camera_dict['rotation'])
93
+ W2C[3, 3] = 1.0
94
+ Rt = torch.linalg.inv(W2C)
95
+ T = Rt[:3, 3]
96
+ R = Rt[:3, :3]
97
+ return build_camera(
98
+ image_width=camera_dict['width'],
99
+ image_height=camera_dict['height'],
100
+ FoVx=focal2fov(camera_dict['fy'], camera_dict['height']),
101
+ FoVy=focal2fov(camera_dict['fx'], camera_dict['width']),
102
+ R=R,
103
+ T=T,
104
+ image_path=camera_dict['ground_truth_image_path'],
105
+ device=device
106
+ )
@@ -0,0 +1,95 @@
1
+ import torch
2
+ import math
3
+ from .gaussian_model import GaussianModel, Camera
4
+ from .utils import normalize_quaternion, quaternion_to_matrix, quaternion_raw_multiply
5
+
6
+ from gaussian_splatting.diff_gaussian_rasterization import GaussianRasterizationSettings, GaussianRasterizer
7
+ from gaussian_splatting.simple_knn._C import distCUDA2
8
+
9
+
10
+ class CameraTrainableGaussianModel(GaussianModel):
11
+
12
+ def forward(self, viewpoint_camera: Camera):
13
+ # Create zero tensor. We will use it to make pytorch return gradients of the 2D (screen-space) means
14
+ screenspace_points = torch.zeros_like(self.get_xyz, dtype=self.get_xyz.dtype, requires_grad=True, device=self._xyz.device) + 0
15
+ try:
16
+ screenspace_points.retain_grad()
17
+ except:
18
+ pass
19
+
20
+ # Set up rasterization configuration
21
+ tanfovx = math.tan(viewpoint_camera.FoVx * 0.5)
22
+ tanfovy = math.tan(viewpoint_camera.FoVy * 0.5)
23
+
24
+ # Set camera pose as identity. Then, we will transform the Gaussians around camera_pose
25
+ w2c = torch.eye(4, device=self._xyz.device)
26
+ projmatrix = (
27
+ w2c.unsqueeze(0).bmm(viewpoint_camera.projection_matrix.unsqueeze(0))
28
+ ).squeeze(0)
29
+ campos = w2c.inverse()[3, :3]
30
+ raster_settings = GaussianRasterizationSettings(
31
+ image_height=int(viewpoint_camera.image_height),
32
+ image_width=int(viewpoint_camera.image_width),
33
+ tanfovx=tanfovx,
34
+ tanfovy=tanfovy,
35
+ bg=viewpoint_camera.bg_color.to(self._xyz.device),
36
+ scale_modifier=self.scale_modifier,
37
+ # viewmatrix=viewpoint_camera.world_view_transform,
38
+ # projmatrix=viewpoint_camera.full_proj_transform,
39
+ viewmatrix=w2c,
40
+ projmatrix=projmatrix,
41
+ sh_degree=self.active_sh_degree,
42
+ # campos=viewpoint_camera.camera_center,
43
+ campos=campos,
44
+ prefiltered=False,
45
+ debug=self.debug,
46
+ antialiasing=self.antialiasing
47
+ )
48
+
49
+ rasterizer = GaussianRasterizer(raster_settings=raster_settings)
50
+
51
+ # means3D = pc.get_xyz
52
+ rel_w2c = torch.eye(4, device=self._xyz.device)
53
+ quaternion = viewpoint_camera.quaternion
54
+ rel_w2c[:3, :3] = quaternion_to_matrix(normalize_quaternion(quaternion.unsqueeze(0))).squeeze(0)
55
+ rel_w2c[:3, 3] = viewpoint_camera.T
56
+ # Transform mean and rot of Gaussians to camera frame
57
+ gaussians_xyz = self._xyz.clone()
58
+ gaussians_rot = self._rotation.clone()
59
+
60
+ xyz_ones = torch.ones(gaussians_xyz.shape[0], 1).cuda().float()
61
+ xyz_homo = torch.cat((gaussians_xyz, xyz_ones), dim=1)
62
+ gaussians_xyz_trans = (rel_w2c @ xyz_homo.T).T[:, :3]
63
+ gaussians_rot_trans = quaternion_raw_multiply(quaternion, gaussians_rot)
64
+ means3D = gaussians_xyz_trans
65
+ means2D = screenspace_points
66
+ opacity = self.get_opacity
67
+
68
+ scales = self.get_scaling
69
+ rotations = gaussians_rot_trans # pc.get_rotation
70
+
71
+ shs = self.get_features
72
+
73
+ # Rasterize visible Gaussians to image, obtain their radii (on screen).
74
+ rendered_image, radii, depth_image = rasterizer(
75
+ means3D=means3D,
76
+ means2D=means2D,
77
+ shs=shs,
78
+ colors_precomp=None,
79
+ opacities=opacity,
80
+ scales=scales,
81
+ rotations=rotations,
82
+ cov3D_precomp=None)
83
+ rendered_image = viewpoint_camera.postprocess(viewpoint_camera, rendered_image)
84
+
85
+ # Those Gaussians that were frustum culled or had a radius of 0 were not visible.
86
+ # They will be excluded from value updates used in the splitting criteria.
87
+ rendered_image = rendered_image.clamp(0, 1)
88
+ out = {
89
+ "render": rendered_image,
90
+ "viewspace_points": screenspace_points,
91
+ "visibility_filter": (radii > 0).nonzero(),
92
+ "radii": radii,
93
+ "depth": depth_image
94
+ }
95
+ return out
@@ -0,0 +1,2 @@
1
+ from .dataset import CameraDataset, JSONCameraDataset
2
+ from .camera_trainable import TrainableCameraDataset
@@ -0,0 +1,70 @@
1
+ import json
2
+ from typing import List
3
+ from gaussian_splatting import Camera
4
+ import torch
5
+ import torch.nn as nn
6
+
7
+ from gaussian_splatting.camera import camera2dict
8
+ from gaussian_splatting.utils import quaternion_to_matrix
9
+ from .dataset import CameraDataset, JSONCameraDataset
10
+
11
+
12
+ def exposure_postprocess(camera: Camera, x: torch.Tensor):
13
+ exposure = camera.custom_data['exposures']
14
+ return torch.matmul(x.permute(1, 2, 0), exposure[:3, :3]).permute(2, 0, 1) + exposure[:3, 3, None, None]
15
+
16
+
17
+ class TrainableCameraDataset(CameraDataset):
18
+
19
+ def __init__(self, cameras: List[Camera], exposures: List[torch.Tensor] = []):
20
+ super().__init__()
21
+ self.cameras = cameras
22
+ self.quaternions = nn.Parameter(torch.stack([camera.quaternion for camera in cameras]))
23
+ self.Ts = nn.Parameter(torch.stack([camera.T for camera in cameras]))
24
+ self.exposures = nn.Parameter(torch.stack([torch.eye(3, 4, device=camera.T.device) for camera in cameras]))
25
+ if len(exposures) > 0:
26
+ assert len(exposures) == len(cameras), "Number of exposures must match number of cameras"
27
+ with torch.no_grad():
28
+ for idx, exposure in enumerate(exposures):
29
+ self.exposures[idx, ...] = exposure.to(self.exposures.device)
30
+
31
+ def __len__(self):
32
+ return len(self.cameras)
33
+
34
+ def __getitem__(self, idx) -> Camera:
35
+ return Camera(**{
36
+ **self.cameras[idx]._asdict(),
37
+ 'quaternion': self.quaternions[idx, ...],
38
+ 'T': self.Ts[idx, ...],
39
+ 'postprocess': exposure_postprocess,
40
+ 'custom_data': {
41
+ **self.cameras[idx].custom_data,
42
+ 'exposures': self.exposures[idx, ...]
43
+ }
44
+ })
45
+
46
+ def to(self, device):
47
+ self.quaternions.to(device)
48
+ self.Ts.to(device)
49
+ self.exposures.to(device)
50
+ return self
51
+
52
+ def save_cameras(self, path):
53
+ cameras = []
54
+ for idx, camera in enumerate(self):
55
+ cameras.append({
56
+ **camera2dict(Camera(**{
57
+ **camera._asdict(),
58
+ 'R': quaternion_to_matrix(self.quaternions[idx, ...]),
59
+ 'T': self.Ts[idx, ...],
60
+ }), idx),
61
+ "exposure": self.exposures[idx, ...].detach().tolist(),
62
+ })
63
+ with open(path, 'w') as f:
64
+ json.dump(cameras, f, indent=2)
65
+
66
+ @classmethod
67
+ def from_json(cls, path):
68
+ cameras = JSONCameraDataset(path)
69
+ exposures = [(torch.tensor(camera['exposure']) if 'exposure' in camera else torch.eye(3, 4)) for camera in cameras.json_cameras]
70
+ return cls(cameras, exposures)
@@ -0,0 +1,5 @@
1
+ from .dataset import ColmapCameraDataset, ColmapTrainableCameraDataset
2
+ from .params_init import colmap_init
3
+ from .dataset import ColmapCamera, read_colmap_cameras
4
+ from .params_init import read_colmap_points3D, read_points3D_binary, read_points3D_text
5
+ from .dataset import read_cameras_binary, read_cameras_text, parse_colmap_camera