Spaces:
Running
on
Zero
Running
on
Zero
Add some instruction. Delete unnesessary ui components.
Browse files- app.py +17 -20
- demo/gs_demo.py +28 -29
- demo/gs_train.py +10 -53
- demo/mast3r_demo.py +59 -128
- requirements.txt +5 -5
- wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl +2 -2
app.py
CHANGED
@@ -11,28 +11,25 @@ from gs_demo import gs_demo_tab
|
|
11 |
torch.backends.cuda.matmul.allow_tf32 = True
|
12 |
|
13 |
if __name__ == '__main__':
|
14 |
-
# parser = get_args_parser()
|
15 |
-
# args = parser.parse_args()
|
16 |
-
|
17 |
-
# if args.server_name is not None:
|
18 |
-
# server_name = args.server_name
|
19 |
-
# else:
|
20 |
-
# server_name = '0.0.0.0'# if args.local_network else '127.0.0.1'
|
21 |
-
|
22 |
-
# weights_path = '/app/wild-gaussian-splatting/mast3r/checkpoints/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric.pth'
|
23 |
-
# weights_path = "naver/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric"#args.weights if args.weights is not None else + MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric
|
24 |
-
# device = device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
25 |
-
# chkpt_tag = hash_md5(weights_path)
|
26 |
-
|
27 |
-
|
28 |
with gr.Blocks() as demo:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
with gr.Tabs():
|
30 |
-
with gr.Tab("MASt3R
|
31 |
mast3r_demo_tab()
|
32 |
-
with gr.Tab("
|
33 |
gs_demo_tab()
|
34 |
|
35 |
-
demo.launch(show_error=True, share=None, server_name=None, server_port=None)
|
36 |
-
# demo.launch(show_error=True, share=None, server_name='0.0.0.0', server_port=5555)
|
37 |
-
|
38 |
-
# python3 demo.py --weights "/app/mast3r/checkpoints/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric.pth" --device "cuda" --server_port 3334 --local_network "$@"
|
|
|
11 |
torch.backends.cuda.matmul.allow_tf32 = True
|
12 |
|
13 |
if __name__ == '__main__':
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
with gr.Blocks() as demo:
|
15 |
+
gr.HTML('''
|
16 |
+
<div style="text-align: center; padding: 20px; background-color: #f9f9f9; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">
|
17 |
+
<h2 style="color: #333;">MASt3R and 3DGS Pipeline Demo</h2>
|
18 |
+
<p style="font-size: 16px; color: #555;">This pipeline is designed for 3D reconstruction using MASt3R and 3DGS.</p>
|
19 |
+
<p style="font-size: 16px; color: #555;">The process is divided into two stages:</p>
|
20 |
+
<ol style="text-align: left; display: inline-block; margin: 0 auto; color: #555;">
|
21 |
+
<li>MASt3R is used to obtain the initial point cloud and camera parameters.</li>
|
22 |
+
<li>3DGS is then trained on the results from MASt3R to refine the 3D scene representation.</li>
|
23 |
+
</ol>
|
24 |
+
<p style="font-size: 16px; color: #555;">For a full version of this pipeline, please visit the repository at:</p>
|
25 |
+
<a href="https://github.com/nerlfield/wild-gaussian-splatting" target="_blank" style="font-size: 16px; color: #007bff; text-decoration: none;">nerlfield/wild-gaussian-splatting</a>
|
26 |
+
</div>
|
27 |
+
''')
|
28 |
+
|
29 |
with gr.Tabs():
|
30 |
+
with gr.Tab("MASt3R"):
|
31 |
mast3r_demo_tab()
|
32 |
+
with gr.Tab("3DGS"):
|
33 |
gs_demo_tab()
|
34 |
|
35 |
+
demo.launch(show_error=True, share=None, server_name=None, server_port=None)
|
|
|
|
|
|
demo/gs_demo.py
CHANGED
@@ -30,7 +30,26 @@ def gs_demo_tab():
|
|
30 |
}
|
31 |
</style>
|
32 |
""")
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
refresh_button = gr.Button("Refresh Datasets", elem_classes="refresh-button")
|
36 |
dataset_dropdown = gr.Dropdown(label="Select Dataset", choices=[], value="")
|
@@ -47,33 +66,15 @@ def gs_demo_tab():
|
|
47 |
|
48 |
# Set the update function to be called when the refresh button is clicked
|
49 |
refresh_button.click(fn=update_dataset_dropdown, inputs=None, outputs=dataset_dropdown)
|
50 |
-
|
51 |
-
with gr.Accordion("Model Parameters", open=False):
|
52 |
-
with gr.Row():
|
53 |
-
with gr.Column():
|
54 |
-
sh_degree = gr.Number(label="SH Degree", value=3)
|
55 |
-
model_path = gr.Textbox(label="Model Path", value="")
|
56 |
-
images = gr.Textbox(label="Images", value="images")
|
57 |
-
resolution = gr.Number(label="Resolution", value=-1)
|
58 |
-
white_background = gr.Checkbox(label="White Background", value=True)
|
59 |
-
data_device = gr.Dropdown(label="Data Device", choices=["cuda", "cpu"], value="cuda")
|
60 |
-
eval = gr.Checkbox(label="Eval", value=False)
|
61 |
-
|
62 |
-
with gr.Accordion("Pipeline Parameters", open=False):
|
63 |
-
with gr.Row():
|
64 |
-
with gr.Column():
|
65 |
-
convert_SHs_python = gr.Checkbox(label="Convert SHs Python", value=False)
|
66 |
-
compute_cov3D_python = gr.Checkbox(label="Compute Cov3D Python", value=False)
|
67 |
-
debug = gr.Checkbox(label="Debug", value=False)
|
68 |
|
69 |
with gr.Accordion("Optimization Parameters", open=False):
|
70 |
with gr.Row():
|
71 |
with gr.Column():
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
with gr.Column():
|
78 |
feature_lr = gr.Number(label="Feature LR", value=0.0025)
|
79 |
opacity_lr = gr.Number(label="Opacity LR", value=0.05)
|
@@ -87,7 +88,7 @@ def gs_demo_tab():
|
|
87 |
densify_from_iter = gr.Number(label="Densify From Iter", value=500)
|
88 |
densify_until_iter = gr.Number(label="Densify Until Iter", value=15000)
|
89 |
densify_grad_threshold = gr.Number(label="Densify Grad Threshold", value=0.0002)
|
90 |
-
|
91 |
|
92 |
start_button = gr.Button("Start Training")
|
93 |
|
@@ -129,12 +130,10 @@ def gs_demo_tab():
|
|
129 |
start_button.click(
|
130 |
fn=handle_training_complete,
|
131 |
inputs=[
|
132 |
-
dataset_dropdown,
|
133 |
-
convert_SHs_python, compute_cov3D_python, debug,
|
134 |
-
iterations, position_lr_init, position_lr_final, position_lr_delay_mult,
|
135 |
position_lr_max_steps, feature_lr, opacity_lr, scaling_lr, rotation_lr,
|
136 |
percent_dense, lambda_dssim, densification_interval, opacity_reset_interval,
|
137 |
-
densify_from_iter, densify_until_iter, densify_grad_threshold
|
138 |
],
|
139 |
outputs=[video_output, load_model_button, output, model_path_state]
|
140 |
)
|
|
|
30 |
}
|
31 |
</style>
|
32 |
""")
|
33 |
+
|
34 |
+
# Centered title
|
35 |
+
gr.Markdown("""
|
36 |
+
<h2 style="text-align: center;">3D Gaussian Splatting Reconstruction</h2>
|
37 |
+
""")
|
38 |
+
|
39 |
+
# Instructions
|
40 |
+
gr.Markdown('''
|
41 |
+
<div style="padding: 10px; background-color: #e9f7ef; border-radius: 5px; margin-bottom: 10px;">
|
42 |
+
<h3>Instructions for 3DGS Demo</h3>
|
43 |
+
<ul style="text-align: left; color: #333;">
|
44 |
+
<li>Make sure to press "Refresh Datasets" to obtain an updated list of datasets from Stage 1. They are in the format run_0, run_1, run_...</li>
|
45 |
+
<li>Adjust optimization parameters if needed, and press "Start Training".</li>
|
46 |
+
<li>It is recommended to use 7k iterations to avoid exceeding the 3-minute limit. If you still exceed the limit, reduce the number of iterations.</li>
|
47 |
+
<li>After reconstruction is finished, you can view it as a small video generated or download the full 3DGS reconstruction below the video.</li>
|
48 |
+
<li>Press "Load 3D Model" to view the full 3DGS reconstruction.</li>
|
49 |
+
</ul>
|
50 |
+
<p><b>Note: 3DGS '.ply' models could be heavy, so it may take some time to download and view them in the 3D model section.</b></p>
|
51 |
+
</div>
|
52 |
+
''')
|
53 |
|
54 |
refresh_button = gr.Button("Refresh Datasets", elem_classes="refresh-button")
|
55 |
dataset_dropdown = gr.Dropdown(label="Select Dataset", choices=[], value="")
|
|
|
66 |
|
67 |
# Set the update function to be called when the refresh button is clicked
|
68 |
refresh_button.click(fn=update_dataset_dropdown, inputs=None, outputs=dataset_dropdown)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
with gr.Accordion("Optimization Parameters", open=False):
|
71 |
with gr.Row():
|
72 |
with gr.Column():
|
73 |
+
position_lr_init = gr.Number(label="Position LR Init", value=0.00032)
|
74 |
+
position_lr_final = gr.Number(label="Position LR Final", value=0.0000032)
|
75 |
+
position_lr_delay_mult = gr.Number(label="Position LR Delay Mult", value=0.02)
|
76 |
+
position_lr_max_steps = gr.Number(label="Position LR Max Steps", value=15000)
|
77 |
+
feature_lr = gr.Number(label="Feature LR", value=0.005)
|
78 |
with gr.Column():
|
79 |
feature_lr = gr.Number(label="Feature LR", value=0.0025)
|
80 |
opacity_lr = gr.Number(label="Opacity LR", value=0.05)
|
|
|
88 |
densify_from_iter = gr.Number(label="Densify From Iter", value=500)
|
89 |
densify_until_iter = gr.Number(label="Densify Until Iter", value=15000)
|
90 |
densify_grad_threshold = gr.Number(label="Densify Grad Threshold", value=0.0002)
|
91 |
+
iterations = gr.Slider(label="Iterations", value=7000, minimum=1, maximum=15000, step=5)
|
92 |
|
93 |
start_button = gr.Button("Start Training")
|
94 |
|
|
|
130 |
start_button.click(
|
131 |
fn=handle_training_complete,
|
132 |
inputs=[
|
133 |
+
dataset_dropdown, iterations, position_lr_init, position_lr_final, position_lr_delay_mult,
|
|
|
|
|
134 |
position_lr_max_steps, feature_lr, opacity_lr, scaling_lr, rotation_lr,
|
135 |
percent_dense, lambda_dssim, densification_interval, opacity_reset_interval,
|
136 |
+
densify_from_iter, densify_until_iter, densify_grad_threshold
|
137 |
],
|
138 |
outputs=[video_output, load_model_button, output, model_path_state]
|
139 |
)
|
demo/gs_train.py
CHANGED
@@ -21,7 +21,8 @@ class PipelineParams:
|
|
21 |
|
22 |
@dataclass
|
23 |
class OptimizationParams:
|
24 |
-
|
|
|
25 |
position_lr_init: float = 0.00016
|
26 |
position_lr_final: float = 0.0000016
|
27 |
position_lr_delay_mult: float = 0.01
|
@@ -50,26 +51,12 @@ class ModelParams:
|
|
50 |
data_device: str = "cuda"
|
51 |
eval: bool = False
|
52 |
|
53 |
-
@dataclass
|
54 |
-
class TrainingArgs:
|
55 |
-
ip: str = "0.0.0.0"
|
56 |
-
port: int = 6007
|
57 |
-
debug_from: int = -1
|
58 |
-
detect_anomaly: bool = False
|
59 |
-
test_iterations: list[int] = field(default_factory=lambda: [7_000, 30_000])
|
60 |
-
save_iterations: list[int] = field(default_factory=lambda: [7_000, 30_000])
|
61 |
-
quiet: bool = False
|
62 |
-
checkpoint_iterations: list[int] = field(default_factory=lambda: [7_000, 15_000, 30_000])
|
63 |
-
start_checkpoint: str = None
|
64 |
-
|
65 |
@spaces.GPU(duration=20)
|
66 |
def train(
|
67 |
-
data_source_path,
|
68 |
-
convert_SHs_python, compute_cov3D_python, debug,
|
69 |
-
iterations, position_lr_init, position_lr_final, position_lr_delay_mult,
|
70 |
position_lr_max_steps, feature_lr, opacity_lr, scaling_lr, rotation_lr,
|
71 |
percent_dense, lambda_dssim, densification_interval, opacity_reset_interval,
|
72 |
-
densify_from_iter, densify_until_iter, densify_grad_threshold
|
73 |
):
|
74 |
|
75 |
# Add the path to the gaussian-splatting repository
|
@@ -96,22 +83,9 @@ def train(
|
|
96 |
|
97 |
print(data_source_path)
|
98 |
# Create instances of the parameter dataclasses
|
99 |
-
dataset = ModelParams(
|
100 |
-
sh_degree=sh_degree,
|
101 |
-
source_path=data_source_path,
|
102 |
-
model_path=model_path,
|
103 |
-
images=images,
|
104 |
-
resolution=resolution,
|
105 |
-
white_background=white_background,
|
106 |
-
data_device=data_device,
|
107 |
-
eval=eval
|
108 |
-
)
|
109 |
|
110 |
-
pipe = PipelineParams(
|
111 |
-
convert_SHs_python=convert_SHs_python,
|
112 |
-
compute_cov3D_python=compute_cov3D_python,
|
113 |
-
debug=debug
|
114 |
-
)
|
115 |
|
116 |
opt = OptimizationParams(
|
117 |
iterations=iterations,
|
@@ -130,20 +104,7 @@ def train(
|
|
130 |
densify_from_iter=densify_from_iter,
|
131 |
densify_until_iter=densify_until_iter,
|
132 |
densify_grad_threshold=densify_grad_threshold,
|
133 |
-
|
134 |
-
)
|
135 |
-
|
136 |
-
print("local_renderer")
|
137 |
-
|
138 |
-
args = TrainingArgs()
|
139 |
-
|
140 |
-
testing_iterations = args.test_iterations
|
141 |
-
saving_iterations = args.save_iterations
|
142 |
-
checkpoint_iterations = args.checkpoint_iterations
|
143 |
-
debug_from = args.debug_from
|
144 |
-
|
145 |
-
tb_writer = prepare_output_and_logger(dataset)
|
146 |
-
|
147 |
gaussians = GaussianModel(dataset.sh_degree)
|
148 |
scene = Scene(dataset, gaussians)
|
149 |
gaussians.training_setup(opt)
|
@@ -175,9 +136,6 @@ def train(
|
|
175 |
viewpoint_stack = scene.getTrainCameras().copy()
|
176 |
viewpoint_cam = viewpoint_stack.pop(randint(0, len(viewpoint_stack)-1))
|
177 |
|
178 |
-
# Render
|
179 |
-
if (iteration - 1) == debug_from:
|
180 |
-
pipe.debug = True
|
181 |
bg = torch.rand((3), device=DEVICE) if opt.random_background else background
|
182 |
|
183 |
render_pkg = render(viewpoint_cam, gaussians, pipe, bg)
|
@@ -201,7 +159,6 @@ def train(
|
|
201 |
progress_bar.close()
|
202 |
|
203 |
# Log and save
|
204 |
-
training_report(tb_writer, iteration, Ll1, loss, l1_loss, iter_start.elapsed_time(iter_end), testing_iterations, scene, render, (pipe, background))
|
205 |
if (iteration == opt.iterations):
|
206 |
point_cloud_path = os.path.join(os.path.join(dataset.model_path, "point_cloud/iteration_{}".format(iteration)), "point_cloud.ply")
|
207 |
print("\n[ITER {}] Saving Gaussians to {}".format(iteration, point_cloud_path))
|
@@ -225,9 +182,9 @@ def train(
|
|
225 |
gaussians.optimizer.step()
|
226 |
gaussians.optimizer.zero_grad(set_to_none = True)
|
227 |
|
228 |
-
if (iteration == opt.iterations):
|
229 |
-
|
230 |
-
|
231 |
|
232 |
|
233 |
from os import makedirs
|
|
|
21 |
|
22 |
@dataclass
|
23 |
class OptimizationParams:
|
24 |
+
# DEFAULT PARAMETERS
|
25 |
+
iterations: int = 30_000
|
26 |
position_lr_init: float = 0.00016
|
27 |
position_lr_final: float = 0.0000016
|
28 |
position_lr_delay_mult: float = 0.01
|
|
|
51 |
data_device: str = "cuda"
|
52 |
eval: bool = False
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
@spaces.GPU(duration=20)
|
55 |
def train(
|
56 |
+
data_source_path, iterations, position_lr_init, position_lr_final, position_lr_delay_mult,
|
|
|
|
|
57 |
position_lr_max_steps, feature_lr, opacity_lr, scaling_lr, rotation_lr,
|
58 |
percent_dense, lambda_dssim, densification_interval, opacity_reset_interval,
|
59 |
+
densify_from_iter, densify_until_iter, densify_grad_threshold
|
60 |
):
|
61 |
|
62 |
# Add the path to the gaussian-splatting repository
|
|
|
83 |
|
84 |
print(data_source_path)
|
85 |
# Create instances of the parameter dataclasses
|
86 |
+
dataset = ModelParams(source_path=data_source_path,)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
|
88 |
+
pipe = PipelineParams()
|
|
|
|
|
|
|
|
|
89 |
|
90 |
opt = OptimizationParams(
|
91 |
iterations=iterations,
|
|
|
104 |
densify_from_iter=densify_from_iter,
|
105 |
densify_until_iter=densify_until_iter,
|
106 |
densify_grad_threshold=densify_grad_threshold,
|
107 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
gaussians = GaussianModel(dataset.sh_degree)
|
109 |
scene = Scene(dataset, gaussians)
|
110 |
gaussians.training_setup(opt)
|
|
|
136 |
viewpoint_stack = scene.getTrainCameras().copy()
|
137 |
viewpoint_cam = viewpoint_stack.pop(randint(0, len(viewpoint_stack)-1))
|
138 |
|
|
|
|
|
|
|
139 |
bg = torch.rand((3), device=DEVICE) if opt.random_background else background
|
140 |
|
141 |
render_pkg = render(viewpoint_cam, gaussians, pipe, bg)
|
|
|
159 |
progress_bar.close()
|
160 |
|
161 |
# Log and save
|
|
|
162 |
if (iteration == opt.iterations):
|
163 |
point_cloud_path = os.path.join(os.path.join(dataset.model_path, "point_cloud/iteration_{}".format(iteration)), "point_cloud.ply")
|
164 |
print("\n[ITER {}] Saving Gaussians to {}".format(iteration, point_cloud_path))
|
|
|
182 |
gaussians.optimizer.step()
|
183 |
gaussians.optimizer.zero_grad(set_to_none = True)
|
184 |
|
185 |
+
# if (iteration == opt.iterations):
|
186 |
+
# print("\n[ITER {}] Saving Checkpoint".format(iteration))
|
187 |
+
# torch.save((gaussians.capture(), iteration), scene.model_path + "/chkpnt" + str(iteration) + ".pth")
|
188 |
|
189 |
|
190 |
from os import makedirs
|
demo/mast3r_demo.py
CHANGED
@@ -33,7 +33,6 @@ import matplotlib.pyplot as pl
|
|
33 |
|
34 |
import torch
|
35 |
|
36 |
-
|
37 |
from demo_globals import CACHE_PATH, MODEL, DEVICE, SILENT, DATASET_DIR
|
38 |
|
39 |
class SparseGAState():
|
@@ -175,20 +174,38 @@ def save_colmap_scene(scene, save_dir, min_conf_thr=2, clean_depth=False):
|
|
175 |
return save_path
|
176 |
|
177 |
@spaces.GPU(duration=10)
|
178 |
-
def get_reconstructed_scene(
|
179 |
-
filelist,
|
180 |
-
as_pointcloud,
|
181 |
-
win_cyclic, refid, TSDF_thresh, shared_intrinsics, **kw):
|
182 |
"""
|
183 |
from a list of images, run mast3r inference, sparse global aligner.
|
184 |
then run get_3D_model_from_scene
|
185 |
"""
|
|
|
186 |
imgs = load_images(filelist, size=image_size, verbose=not SILENT)
|
187 |
if len(imgs) == 1:
|
188 |
imgs = [imgs[0], copy.deepcopy(imgs[0])]
|
189 |
imgs[1]['idx'] = 1
|
190 |
filelist = [filelist[0], filelist[0] + '_2']
|
191 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
scene_graph_params = [scenegraph_type]
|
193 |
if scenegraph_type in ["swin", "logwin"]:
|
194 |
scene_graph_params.append(str(winsize))
|
@@ -198,8 +215,6 @@ def get_reconstructed_scene(image_size, current_scene_state,
|
|
198 |
scene_graph_params.append('noncyclic')
|
199 |
scene_graph = '-'.join(scene_graph_params)
|
200 |
pairs = make_pairs(imgs, scene_graph=scene_graph, prefilter=None, symmetrize=True)
|
201 |
-
if optim_level == 'coarse':
|
202 |
-
niter2 = 0
|
203 |
|
204 |
base_cache_dir = os.path.join(CACHE_PATH, 'cache')
|
205 |
os.makedirs(base_cache_dir, exist_ok=True)
|
@@ -214,7 +229,6 @@ def get_reconstructed_scene(image_size, current_scene_state,
|
|
214 |
return run_cache_dir
|
215 |
|
216 |
|
217 |
-
ten = torch.zeros((1024)).cuda()
|
218 |
cache_dir = get_next_dir(base_cache_dir)
|
219 |
scene = sparse_global_alignment(filelist, pairs, cache_dir,
|
220 |
MODEL, lr1=lr1, niter1=niter1, lr2=lr2, niter2=niter2, device=DEVICE,
|
@@ -243,34 +257,7 @@ def get_reconstructed_scene(image_size, current_scene_state,
|
|
243 |
return scene_state, outfile
|
244 |
|
245 |
|
246 |
-
def set_scenegraph_options(inputfiles, win_cyclic, refid, scenegraph_type):
|
247 |
-
num_files = len(inputfiles) if inputfiles is not None else 1
|
248 |
-
show_win_controls = scenegraph_type in ["swin", "logwin"]
|
249 |
-
show_winsize = scenegraph_type in ["swin", "logwin"]
|
250 |
-
show_cyclic = scenegraph_type in ["swin", "logwin"]
|
251 |
-
max_winsize, min_winsize = 1, 1
|
252 |
-
if scenegraph_type == "swin":
|
253 |
-
if win_cyclic:
|
254 |
-
max_winsize = max(1, math.ceil((num_files - 1) / 2))
|
255 |
-
else:
|
256 |
-
max_winsize = num_files - 1
|
257 |
-
elif scenegraph_type == "logwin":
|
258 |
-
if win_cyclic:
|
259 |
-
half_size = math.ceil((num_files - 1) / 2)
|
260 |
-
max_winsize = max(1, math.ceil(math.log(half_size, 2)))
|
261 |
-
else:
|
262 |
-
max_winsize = max(1, math.ceil(math.log(num_files, 2)))
|
263 |
-
winsize = gradio.Slider(label="Scene Graph: Window Size", value=max_winsize,
|
264 |
-
minimum=min_winsize, maximum=max_winsize, step=1, visible=show_winsize)
|
265 |
-
win_cyclic = gradio.Checkbox(value=win_cyclic, label="Cyclic sequence", visible=show_cyclic)
|
266 |
-
win_col = gradio.Column(visible=show_win_controls)
|
267 |
-
refid = gradio.Slider(label="Scene Graph: Id", value=0, minimum=0,
|
268 |
-
maximum=num_files - 1, step=1, visible=scenegraph_type == 'oneref')
|
269 |
-
return win_col, winsize, win_cyclic, refid
|
270 |
-
|
271 |
-
|
272 |
def mast3r_demo_tab():
|
273 |
-
|
274 |
if not SILENT:
|
275 |
print('Outputing stuff in', CACHE_PATH)
|
276 |
|
@@ -281,100 +268,44 @@ def mast3r_demo_tab():
|
|
281 |
|
282 |
with get_context() as demo:
|
283 |
scene = gradio.State(None)
|
|
|
|
|
284 |
gradio.HTML('<h2 style="text-align: center;">MASt3R Demo</h2>')
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
with gradio.Row():
|
322 |
-
min_conf_thr = gradio.Slider(label="min_conf_thr", value=1.5, minimum=0.0, maximum=10, step=0.1)
|
323 |
-
cam_size = gradio.Slider(label="cam_size", value=0.2, minimum=0.001, maximum=1.0, step=0.001)
|
324 |
-
TSDF_thresh = gradio.Slider(label="TSDF Threshold", value=0., minimum=0., maximum=1., step=0.01)
|
325 |
-
with gradio.Row():
|
326 |
-
as_pointcloud = gradio.Checkbox(value=True, label="As pointcloud")
|
327 |
-
mask_sky = gradio.Checkbox(value=False, label="Mask sky")
|
328 |
-
clean_depth = gradio.Checkbox(value=True, label="Clean-up depthmaps")
|
329 |
-
transparent_cams = gradio.Checkbox(value=False, label="Transparent cameras")
|
330 |
-
|
331 |
-
outmodel = gradio.Model3D()
|
332 |
-
|
333 |
-
scenegraph_type.change(set_scenegraph_options,
|
334 |
-
inputs=[inputfiles, win_cyclic, refid, scenegraph_type],
|
335 |
-
outputs=[win_col, winsize, win_cyclic, refid])
|
336 |
-
inputfiles.change(set_scenegraph_options,
|
337 |
-
inputs=[inputfiles, win_cyclic, refid, scenegraph_type],
|
338 |
-
outputs=[win_col, winsize, win_cyclic, refid])
|
339 |
-
win_cyclic.change(set_scenegraph_options,
|
340 |
-
inputs=[inputfiles, win_cyclic, refid, scenegraph_type],
|
341 |
-
outputs=[win_col, winsize, win_cyclic, refid])
|
342 |
-
run_btn.click(
|
343 |
-
fn=get_reconstructed_scene,
|
344 |
-
inputs=[image_size, scene, inputfiles, optim_level, lr1, niter1, lr2, niter2, min_conf_thr, matching_conf_thr,
|
345 |
-
as_pointcloud, mask_sky, clean_depth, transparent_cams, cam_size, scenegraph_type, winsize,
|
346 |
-
win_cyclic, refid, TSDF_thresh, shared_intrinsics],
|
347 |
-
outputs=[scene, outmodel]
|
348 |
-
)
|
349 |
-
# min_conf_thr.release(
|
350 |
-
# fn=get_3D_model_from_scene,
|
351 |
-
# inputs=[scene, min_conf_thr, as_pointcloud, mask_sky, clean_depth, transparent_cams, cam_size, TSDF_thresh],
|
352 |
-
# outputs=outmodel
|
353 |
-
# )
|
354 |
-
# cam_size.change(fn=get_3D_model_from_scene,
|
355 |
-
# inputs=[scene, min_conf_thr, as_pointcloud, mask_sky,
|
356 |
-
# clean_depth, transparent_cams, cam_size, TSDF_thresh],
|
357 |
-
# outputs=outmodel)
|
358 |
-
# TSDF_thresh.change(fn=get_3D_model_from_scene,
|
359 |
-
# inputs=[scene, min_conf_thr, as_pointcloud, mask_sky,
|
360 |
-
# clean_depth, transparent_cams, cam_size, TSDF_thresh],
|
361 |
-
# outputs=outmodel)
|
362 |
-
# as_pointcloud.change(fn=get_3D_model_from_scene,
|
363 |
-
# inputs=[scene, min_conf_thr, as_pointcloud, mask_sky,
|
364 |
-
# clean_depth, transparent_cams, cam_size, TSDF_thresh],
|
365 |
-
# outputs=outmodel)
|
366 |
-
# mask_sky.change(fn=get_3D_model_from_scene,
|
367 |
-
# inputs=[scene, min_conf_thr, as_pointcloud, mask_sky,
|
368 |
-
# clean_depth, transparent_cams, cam_size, TSDF_thresh],
|
369 |
-
# outputs=outmodel)
|
370 |
-
# clean_depth.change(fn=get_3D_model_from_scene,
|
371 |
-
# inputs=[scene, min_conf_thr, as_pointcloud, mask_sky,
|
372 |
-
# clean_depth, transparent_cams, cam_size, TSDF_thresh],
|
373 |
-
# outputs=outmodel)
|
374 |
-
# transparent_cams.change(fn=get_3D_model_from_scene,
|
375 |
-
# inputs=[scene, min_conf_thr, as_pointcloud, mask_sky,
|
376 |
-
# clean_depth, transparent_cams, cam_size, TSDF_thresh],
|
377 |
-
# outputs=outmodel)
|
378 |
|
379 |
return demo
|
380 |
|
|
|
33 |
|
34 |
import torch
|
35 |
|
|
|
36 |
from demo_globals import CACHE_PATH, MODEL, DEVICE, SILENT, DATASET_DIR
|
37 |
|
38 |
class SparseGAState():
|
|
|
174 |
return save_path
|
175 |
|
176 |
@spaces.GPU(duration=10)
|
177 |
+
def get_reconstructed_scene(current_scene_state,
|
178 |
+
filelist, min_conf_thr, matching_conf_thr,
|
179 |
+
as_pointcloud, cam_size, shared_intrinsics, **kw):
|
|
|
180 |
"""
|
181 |
from a list of images, run mast3r inference, sparse global aligner.
|
182 |
then run get_3D_model_from_scene
|
183 |
"""
|
184 |
+
image_size = 512
|
185 |
imgs = load_images(filelist, size=image_size, verbose=not SILENT)
|
186 |
if len(imgs) == 1:
|
187 |
imgs = [imgs[0], copy.deepcopy(imgs[0])]
|
188 |
imgs[1]['idx'] = 1
|
189 |
filelist = [filelist[0], filelist[0] + '_2']
|
190 |
|
191 |
+
lr1 = 0.07
|
192 |
+
niter1 = 500
|
193 |
+
lr2 = 0.014
|
194 |
+
niter2 = 200
|
195 |
+
optim_level = 'refine'
|
196 |
+
mask_sky, clean_depth, transparent_cams = False, True, False
|
197 |
+
if len(filelist) < 13:
|
198 |
+
scenegraph_type = 'complete'
|
199 |
+
winsize = 1
|
200 |
+
else:
|
201 |
+
scenegraph_type = 'logwin'
|
202 |
+
half_size = math.ceil((len(filelist) - 1) / 2)
|
203 |
+
max_winsize = max(1, math.ceil(math.log(half_size, 2)))
|
204 |
+
winsize = min(5, max_winsize)
|
205 |
+
refid = 0
|
206 |
+
win_cyclic = False
|
207 |
+
TSDF_thresh = 0
|
208 |
+
|
209 |
scene_graph_params = [scenegraph_type]
|
210 |
if scenegraph_type in ["swin", "logwin"]:
|
211 |
scene_graph_params.append(str(winsize))
|
|
|
215 |
scene_graph_params.append('noncyclic')
|
216 |
scene_graph = '-'.join(scene_graph_params)
|
217 |
pairs = make_pairs(imgs, scene_graph=scene_graph, prefilter=None, symmetrize=True)
|
|
|
|
|
218 |
|
219 |
base_cache_dir = os.path.join(CACHE_PATH, 'cache')
|
220 |
os.makedirs(base_cache_dir, exist_ok=True)
|
|
|
229 |
return run_cache_dir
|
230 |
|
231 |
|
|
|
232 |
cache_dir = get_next_dir(base_cache_dir)
|
233 |
scene = sparse_global_alignment(filelist, pairs, cache_dir,
|
234 |
MODEL, lr1=lr1, niter1=niter1, lr2=lr2, niter2=niter2, device=DEVICE,
|
|
|
257 |
return scene_state, outfile
|
258 |
|
259 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
def mast3r_demo_tab():
|
|
|
261 |
if not SILENT:
|
262 |
print('Outputing stuff in', CACHE_PATH)
|
263 |
|
|
|
268 |
|
269 |
with get_context() as demo:
|
270 |
scene = gradio.State(None)
|
271 |
+
|
272 |
+
# Title for the MASt3R demo
|
273 |
gradio.HTML('<h2 style="text-align: center;">MASt3R Demo</h2>')
|
274 |
+
|
275 |
+
# Add instructions for the MASt3R demo
|
276 |
+
gradio.HTML('''
|
277 |
+
<div style="padding: 10px; background-color: #e9f7ef; border-radius: 5px; margin-bottom: 10px;">
|
278 |
+
<h3>Instructions for MASt3R Demo</h3>
|
279 |
+
<ul style="text-align: left; color: #333;">
|
280 |
+
<li>Upload images. It is recommended to use no more than 10-12 images to avoid exceeding the 3-minute runtime limit for zeroGPU dynamic resources.</li>
|
281 |
+
<li>Press the "Run" button to start the process.</li>
|
282 |
+
<li>Once the stage is finished and the point cloud with cameras is visible below, switch to the 3DGS tab and follow the instructions there.</li>
|
283 |
+
</ul>
|
284 |
+
</div>
|
285 |
+
''')
|
286 |
+
|
287 |
+
inputfiles = gradio.File(file_count="multiple")
|
288 |
+
|
289 |
+
run_btn = gradio.Button("Run")
|
290 |
+
|
291 |
+
with gradio.Row():
|
292 |
+
matching_conf_thr = gradio.Slider(label="Matching Confidence Thr", value=5.,
|
293 |
+
minimum=0., maximum=30., step=0.1,
|
294 |
+
info="Before Fallback to Regr3D!")
|
295 |
+
min_conf_thr = gradio.Slider(label="min_conf_thr", value=1.5, minimum=0.0, maximum=10, step=0.1)
|
296 |
+
cam_size = gradio.Slider(label="cam_size", value=0.2, minimum=0.001, maximum=1.0, step=0.001)
|
297 |
+
with gradio.Row():
|
298 |
+
as_pointcloud = gradio.Checkbox(value=True, label="As pointcloud")
|
299 |
+
shared_intrinsics = gradio.Checkbox(value=False, label="Shared intrinsics",
|
300 |
+
info="Only optimize one set of intrinsics for all views")
|
301 |
+
|
302 |
+
outmodel = gradio.Model3D()
|
303 |
+
run_btn.click(
|
304 |
+
fn=get_reconstructed_scene,
|
305 |
+
inputs=[scene, inputfiles, min_conf_thr, matching_conf_thr,
|
306 |
+
as_pointcloud, cam_size, shared_intrinsics],
|
307 |
+
outputs=[scene, outmodel]
|
308 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
|
310 |
return demo
|
311 |
|
requirements.txt
CHANGED
@@ -4,6 +4,10 @@
|
|
4 |
torch==2.4.0
|
5 |
torchvision==0.19.0
|
6 |
|
|
|
|
|
|
|
|
|
7 |
gradio
|
8 |
matplotlib
|
9 |
tqdm
|
@@ -28,8 +32,4 @@ pytorch-lightning==2.1.0
|
|
28 |
PyYAML==6.0.1
|
29 |
ipywidgets
|
30 |
jupyterlab
|
31 |
-
sql
|
32 |
-
|
33 |
-
https://huggingface.co/spaces/ostapagon/mast3r-3dgs/resolve/main/wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl?download=true
|
34 |
-
https://huggingface.co/spaces/JeffreyXiang/TRELLIS/resolve/main/wheels/nvdiffrast-0.3.3-cp310-cp310-linux_x86_64.whl?download=true
|
35 |
-
https://huggingface.co/spaces/ostapagon/mast3r-3dgs/resolve/main/wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl?download=true
|
|
|
4 |
torch==2.4.0
|
5 |
torchvision==0.19.0
|
6 |
|
7 |
+
https://huggingface.co/spaces/ostapagon/mast3r-3dgs/resolve/main/wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl?download=true
|
8 |
+
https://huggingface.co/spaces/JeffreyXiang/TRELLIS/resolve/main/wheels/nvdiffrast-0.3.3-cp310-cp310-linux_x86_64.whl?download=true
|
9 |
+
https://huggingface.co/spaces/ostapagon/mast3r-3dgs/resolve/main/wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl?download=true
|
10 |
+
|
11 |
gradio
|
12 |
matplotlib
|
13 |
tqdm
|
|
|
32 |
PyYAML==6.0.1
|
33 |
ipywidgets
|
34 |
jupyterlab
|
35 |
+
sql
|
|
|
|
|
|
|
|
wheels/simple_knn-0.0.0-cp310-cp310-linux_x86_64.whl
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:bdbf04f4682c8dcd5d28b6c83755be96e46e6f5d5afb85e9cf0a0e49119e092e
|
3 |
+
size 3043536
|