sharifIslam commited on
Commit
e3d6629
·
1 Parent(s): 8c49342

Add initial project files including assets, styles, and utility functions

Browse files
Files changed (8) hide show
  1. .gitignore +5 -0
  2. assets/fullscreen.js +12 -0
  3. assets/style.css +53 -0
  4. gradio_ui.py +57 -0
  5. model.py +18 -0
  6. pipeline.py +49 -0
  7. setup.sh +2 -0
  8. utils.py +14 -0
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ venv/
3
+ dust3r/checkpoints/
4
+ dust3r/dust3r.egg-info/
5
+ __pycache__/
assets/fullscreen.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ () => {
2
+ const el = document.getElementById("model-container");
3
+ if (!el) return;
4
+
5
+ if (el.requestFullscreen) {
6
+ el.requestFullscreen();
7
+ } else if (el.webkitRequestFullscreen) {
8
+ el.webkitRequestFullscreen();
9
+ } else if (el.msRequestFullscreen) {
10
+ el.msRequestFullscreen();
11
+ }
12
+ }
assets/style.css ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ footer {display: none !important;}
2
+ #gradio-menu, .built-with, .api-link, #settings-button {display: none !important;}
3
+
4
+ :root {
5
+ --primary-500: #FFFFFF !important;
6
+ --body-background-fill: #000000 !important;
7
+ --block-background-fill: #000000 !important;
8
+ --input-background-fill: #000000 !important;
9
+ --border-color-primary: #333333 !important;
10
+ --background-fill-secondary: #000000 !important;
11
+ }
12
+
13
+ .gradio-container {
14
+ background-color: #000000 !important;
15
+ color: #FFFFFF !important;
16
+ font-family: 'Inter', system-ui, sans-serif !important;
17
+ }
18
+
19
+ button.primary {
20
+ background-color: #FFFFFF !important;
21
+ color: #000000 !important;
22
+ border-radius: 0px !important;
23
+ font-weight: 600 !important;
24
+ text-transform: uppercase;
25
+ letter-spacing: 1px;
26
+ }
27
+
28
+ button.primary:hover {
29
+ background-color: #B2B2B2 !important;
30
+ }
31
+
32
+ .label {
33
+ color: #808080 !important;
34
+ text-transform: uppercase;
35
+ font-size: 11px !important;
36
+ }
37
+
38
+ #model-container:fullscreen {
39
+ background-color: black;
40
+ width: 100vw;
41
+ height: 100vh;
42
+ }
43
+
44
+ .generating::after {
45
+ color: #808080;
46
+ font-size: 10px;
47
+ letter-spacing: 2px;
48
+ animation: blink 1.2s infinite;
49
+ }
50
+
51
+ @keyframes blink {
52
+ 50% { opacity: 0; }
53
+ }
gradio_ui.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import functools
3
+ from pathlib import Path
4
+ from pipeline import run_pipeline
5
+
6
+ ASSETS = Path(__file__).parent / "assets"
7
+ CSS = (ASSETS / "style.css").read_text()
8
+ FULLSCREEN_JS = (ASSETS / "fullscreen.js").read_text()
9
+
10
+
11
+ def build_ui(outdir, model, device):
12
+
13
+ pipeline = functools.partial(run_pipeline, outdir, model, device, 512)
14
+
15
+ with gr.Blocks(
16
+ title="3D Object Reconstruction",
17
+ css=CSS,
18
+ theme=gr.themes.Base(),
19
+ fill_width=True,
20
+ ) as app:
21
+
22
+ gr.Markdown("# 3D Object Reconstruction")
23
+
24
+ with gr.Row():
25
+
26
+ with gr.Column(scale=1):
27
+ files = gr.File(file_count="multiple", label="Images")
28
+ run_btn = gr.Button("Run Inference", variant="primary")
29
+
30
+ with gr.Accordion("Settings", open=False):
31
+ iters = gr.Slider(100, 1000, 300, step=50, label="Alignment Iteration")
32
+ as_pc = gr.Checkbox(True, label="Render as Point Cloud")
33
+ refine = gr.Checkbox(True, label="Filter Background Points")
34
+ clean = gr.Checkbox(True, label="Clean-up depthmaps")
35
+
36
+ with gr.Column(scale=2):
37
+ model3d = gr.Model3D(
38
+ label="3D Output",
39
+ height=600,
40
+ elem_id="model-container",
41
+ )
42
+ fs_btn = gr.Button("Toggle Full Screen ⛶", size="sm")
43
+
44
+ gr.Markdown("---")
45
+ gallery = gr.Gallery(columns=3, label="RGB | DEPTH | CONFIDENCE")
46
+
47
+ fs_btn.click(None, None, None, js=FULLSCREEN_JS)
48
+
49
+ state = gr.State()
50
+ run_btn.click(
51
+ fn=pipeline,
52
+ inputs=[files, iters, as_pc, refine, clean],
53
+ outputs=[state, model3d, gallery],
54
+ show_progress="minimal",
55
+ )
56
+
57
+ return app
model.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+ def initialize(model_path, device):
4
+ ckpt = torch.load(model_path, map_location="cpu", weights_only=False)
5
+ args = ckpt["args"].model.replace(
6
+ "ManyAR_PatchEmbed", "PatchEmbedDust3R"
7
+ )
8
+
9
+ if "landscape_only" not in args:
10
+ args = args[:-1] + ", landscape_only=False)"
11
+ else:
12
+ args = args.replace(" ", "").replace(
13
+ "landscape_only=True", "landscape_only=False"
14
+ )
15
+
16
+ net = eval(args)
17
+ net.load_state_dict(ckpt["model"], strict=False)
18
+ return net.to(device)
pipeline.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch, copy, numpy as np, trimesh, matplotlib.pyplot as plt
2
+ from dust3r.image_pairs import make_pairs
3
+ from dust3r.utils.image import load_images, rgb
4
+ from dust3r.utils.device import to_numpy, to_cpu, collate_with_cat as collate
5
+ from dust3r.viz import pts3d_to_trimesh, cat_meshes
6
+ from dust3r.cloud_opt import global_aligner, GlobalAlignerMode
7
+ from utils import preprocess
8
+
9
+ BATCH_SIZE = 1
10
+
11
+ def interleave(img1, img2):
12
+ out = {}
13
+ for k, v1 in img1.items():
14
+ v2 = img2[k]
15
+ if isinstance(v1, torch.Tensor):
16
+ out[k] = torch.stack((v1, v2), dim=1).flatten(0, 1)
17
+ else:
18
+ out[k] = [x for p in zip(v1, v2) for x in p]
19
+ return out
20
+
21
+ def inference(pairs, model, device):
22
+ results = []
23
+ for i in range(0, len(pairs), BATCH_SIZE):
24
+ batch = collate(pairs[i:i+BATCH_SIZE])
25
+ for view in batch:
26
+ for k in ["img", "pts3d", "valid_mask", "camera_pose", "camera_intrinsics"]:
27
+ if k in view:
28
+ view[k] = view[k].to(device)
29
+ v1, v2 = batch
30
+ v1, v2 = interleave(v1, v2), interleave(v2, v1)
31
+
32
+ with torch.cuda.amp.autocast():
33
+ p1, p2 = model(v1, v2)
34
+ results.append(to_cpu(dict(view1=v1, view2=v2, pred1=p1, pred2=p2)))
35
+
36
+ return collate(results, lists=True)
37
+
38
+ def create_glb(outdir, scene):
39
+ meshes = [
40
+ pts3d_to_trimesh(scene.imgs[i], scene.get_pts3d()[i], scene.get_masks()[i])
41
+ for i in range(len(scene.imgs))
42
+ ]
43
+ mesh = trimesh.Trimesh(**cat_meshes(meshes))
44
+ mesh.apply_translation(-mesh.centroid)
45
+
46
+ scene_out = trimesh.Scene(mesh)
47
+ out = f"{outdir}/object.glb"
48
+ scene_out.export(out)
49
+ return out
setup.sh CHANGED
@@ -10,6 +10,8 @@ fi
10
 
11
  pip install -r requirements.txt
12
 
 
 
13
  mkdir -p dust3r/checkpoints
14
 
15
  WEIGHTS=dust3r/checkpoints/DUSt3R_ViTLarge_BaseDecoder_512_dpt.pth
 
10
 
11
  pip install -r requirements.txt
12
 
13
+ pip install https://github.com/camenduru/wheels/releases/download/colab/curope-0.0.0-cp310-cp310-linux_x86_64.whl
14
+
15
  mkdir -p dust3r/checkpoints
16
 
17
  WEIGHTS=dust3r/checkpoints/DUSt3R_ViTLarge_BaseDecoder_512_dpt.pth
utils.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, tempfile
2
+ from PIL import Image, ImageEnhance
3
+
4
+ def preprocess(image_paths):
5
+ cleaned = []
6
+ for i, path in enumerate(image_paths):
7
+ img = Image.open(path).convert("RGB")
8
+ img = ImageEnhance.Contrast(img).enhance(1.2)
9
+ img = ImageEnhance.Sharpness(img).enhance(1.5)
10
+
11
+ out = os.path.join(tempfile.gettempdir(), f"input_refined_{i}.png")
12
+ img.save(out)
13
+ cleaned.append(out)
14
+ return cleaned