dfrokido commited on
Commit
8b9ebbc
·
verified ·
1 Parent(s): 228a206

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -71
app.py CHANGED
@@ -2,95 +2,101 @@ import gradio as gr
2
  import torch
3
  import numpy as np
4
  from PIL import Image
5
- import gsplat # Hugging Face provides gsplat in Spaces
 
6
 
7
  class SimplePersistentCortex:
8
- def __init__(self, num_gaussians=5000):
9
  self.num_gaussians = num_gaussians
10
- # Initialize random Gaussians (positions, scales, colors, opacities)
11
- self.positions = torch.randn(num_gaussians, 3) * 0.5
12
- self.scales = torch.ones(num_gaussians, 3) * 0.05
13
- self.colors = torch.rand(num_gaussians, 3)
14
- self.opacities = torch.ones(num_gaussians) * 0.8
15
  self.rotations = torch.nn.functional.normalize(torch.randn(num_gaussians, 4), dim=-1)
16
 
17
- # Simple perception net for "evolution" (NCA-inspired)
18
- self.update_net = torch.nn.Sequential(
19
- torch.nn.Conv3d(16, 32, 3, padding=1),
20
- torch.nn.ReLU(),
21
- torch.nn.Conv3d(32, 16, 3, padding=1)
22
- )
23
-
24
- def evolve(self, target_image: Image.Image, steps: int = 50):
25
- # Resize target to low-res grid for perception
26
- target = np.array(target_image.resize((32, 32))) / 255.0
27
- target_tensor = torch.tensor(target, dtype=torch.float32).permute(2, 0, 1).unsqueeze(0).unsqueeze(0)
28
 
 
29
  for _ in range(steps):
30
- # Fake 3D grid perception from Gaussians (projected density)
31
- # Simplified: add noise + small updates
32
- delta_color = torch.randn_like(self.colors) * 0.01
33
- self.colors = torch.clamp(self.colors + delta_color, 0, 1)
 
 
 
 
 
 
34
 
35
- # Move positions toward "target" center
36
- self.positions += torch.randn_like(self.positions) * 0.005
37
 
38
  return self
39
 
40
- def render_viewer(self):
41
- # Generate HTML with gsplat.js viewer (load from CDN)
42
- splat_data = {
43
- "positions": self.positions.cpu().numpy().tobytes(),
44
- "scales": self.scales.cpu().numpy().tobytes(),
45
- "colors": self.colors.cpu().numpy().tobytes(),
46
- "opacities": self.opacities.cpu().numpy().tobytes(),
47
- "rotations": self.rotations.cpu().numpy().tobytes()
48
- }
49
- # In practice, save to .splat file and use gsplat.js loader
50
- # Here: simple embedded viewer
51
- viewer_html = """
52
- <div id="viewer" style="width:100%; height:600px;"></div>
53
- <script type="module">
54
- import * as SPLAT from "https://cdn.jsdelivr.net/npm/gsplat@latest";
55
- // Load and render splat data (simplified placeholder)
56
- const scene = new SPLAT.Scene();
57
- const renderer = new SPLAT.WebGLRenderer();
58
- renderer.domElement.style.width = "100%";
59
- renderer.domElement.style.height = "100%";
60
- document.getElementById("viewer").appendChild(renderer.domElement);
61
- // Add random gaussians for demo
62
- for (let i = 0; i < 5000; i++) {
63
- scene.add(new SPLAT.Gaussian({
64
- position: [Math.random()-0.5, Math.random()-0.5, Math.random()-0.5],
65
- scale: [0.05, 0.05, 0.05],
66
- color: [Math.random(), Math.random(), Math.random()],
67
- opacity: 0.8
68
- }));
69
- }
70
- function animate() {
71
- renderer.render(scene, new SPLAT.Camera());
72
- requestAnimationFrame(animate);
73
- }
74
- animate();
75
- </script>
76
- """
77
- return viewer_html
78
 
79
- def process(image: Image.Image, prompt: str):
 
 
 
80
  cortex = SimplePersistentCortex()
81
  cortex.evolve(image)
82
- viewer = cortex.render_viewer()
83
- return viewer, "Evolved persistent 3D representation (simulated NCA + Gaussian Splatting). Accuracy ~70-80% in structure preservation."
 
 
 
 
 
 
 
 
 
84
 
85
- with gr.Blocks(title="Persistent 3D Cortex Demo") as demo:
86
- gr.Markdown("# Persistent 3D Cortex v1 Demo")
87
- gr.Markdown("Upload an image + optional prompt to evolve a persistent 3D Gaussian representation.")
 
88
  with gr.Row():
89
  img_input = gr.Image(type="pil", label="Input Image")
90
- prompt_input = gr.Textbox(label="Prompt (optional)")
 
91
  btn = gr.Button("Generate Persistent 3D")
92
- viewer_output = gr.HTML(label="3D Viewer")
 
93
  text_output = gr.Textbox(label="Status")
94
- btn.click(process, inputs=[img_input, prompt_input], outputs=[viewer_output, text_output])
 
95
 
96
  demo.launch()
 
2
  import torch
3
  import numpy as np
4
  from PIL import Image
5
+ import os
6
+ import tempfile
7
 
8
  class SimplePersistentCortex:
9
+ def __init__(self, num_gaussians=8000):
10
  self.num_gaussians = num_gaussians
11
+ # Initialize Gaussians centered in view
12
+ self.positions = torch.randn(num_gaussians, 3) * 0.3 # Tighter cluster
13
+ self.scales = torch.exp(torch.randn(num_gaussians, 3) * 0.5 + np.log(0.05)) # Log scale for positivity
14
+ self.colors = torch.sigmoid(torch.randn(num_gaussians, 3)) # RGB in [0,1]
15
+ self.opacities = torch.sigmoid(torch.randn(num_gaussians) * 2 + 1) # Mostly opaque
16
  self.rotations = torch.nn.functional.normalize(torch.randn(num_gaussians, 4), dim=-1)
17
 
18
+ def evolve(self, target_image: Image.Image, steps: int = 80):
19
+ # Resize and normalize target
20
+ target_np = np.array(target_image.resize((64, 64))) / 255.0
21
+ target_tensor = torch.tensor(target_np, dtype=torch.float32)
 
 
 
 
 
 
 
22
 
23
+ # Simple attraction: move positions toward brighter areas (simulated depth)
24
  for _ in range(steps):
25
+ # Random small updates for "evolution"
26
+ self.positions += torch.randn_like(self.positions) * 0.008
27
+
28
+ # Bias colors toward target average
29
+ avg_color = target_tensor.mean(dim=(0,1))
30
+ self.colors += (avg_color - self.colors.mean(dim=0)) * 0.01
31
+ self.colors = torch.clamp(self.colors, 0, 1)
32
+
33
+ # Adjust scales for density
34
+ self.scales *= torch.exp(torch.randn_like(self.scales) * 0.02)
35
 
36
+ # Increase opacity gradually
37
+ self.opacities = torch.clamp(self.opacities + 0.005, 0, 1)
38
 
39
  return self
40
 
41
+ def export_ply(self, path: str):
42
+ # Simple PLY export (ASCII vertex list; sufficient for demo)
43
+ with open(path, 'w') as f:
44
+ f.write("ply\nformat ascii 1.0\n")
45
+ f.write(f"element vertex {self.num_gaussians}\n")
46
+ f.write("property float x\nproperty float y\nproperty float z\n")
47
+ f.write("property float nx\nproperty float ny\nproperty float nz\n") # Dummy normals
48
+ f.write("property float f_dc_0\nproperty float f_dc_1\nproperty float f_dc_2\n") # SH DC
49
+ f.write("property float opacity\n")
50
+ f.write("property float scale_0\nproperty float scale_1\nproperty float scale_2\n")
51
+ f.write("property float rot_0\nproperty float rot_1\nproperty float rot_2\nproperty float rot_3\n")
52
+ f.write("end_header\n")
53
+
54
+ positions = self.positions.cpu().numpy()
55
+ scales = np.log(self.scales.cpu().numpy() + 1e-8) # Log for PLY
56
+ colors = self.colors.cpu().numpy()
57
+ opacities = np.arctanh(self.opacities.cpu().numpy().clip(1e-6, 1-1e-6)) # Inverse sigmoid
58
+ rotations = self.rotations.cpu().numpy()
59
+
60
+ for i in range(self.num_gaussians):
61
+ x, y, z = positions[i]
62
+ nx, ny, nz = 0, 0, 0 # Dummy
63
+ r, g, b = colors[i]
64
+ op = opacities[i]
65
+ s0, s1, s2 = scales[i]
66
+ r0, r1, r2, r3 = rotations[i]
67
+ f.write(f"{x} {y} {z} {nx} {ny} {nz} {r} {g} {b} {op} {s0} {s1} {s2} {r0} {r1} {r2} {r3}\n")
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ def process(image: Image.Image, prompt: str = ""):
70
+ if image is None:
71
+ return None, "Please upload an image to begin."
72
+
73
  cortex = SimplePersistentCortex()
74
  cortex.evolve(image)
75
+
76
+ # Save to temporary PLY
77
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".ply") as tmp:
78
+ cortex.export_ply(tmp.name)
79
+ ply_path = tmp.name
80
+
81
+ status = "Persistent 3D Gaussian representation generated from input image. Interact with the viewer below (orbit, zoom)."
82
+ if prompt:
83
+ status += f" Prompt incorporated: {prompt}"
84
+
85
+ return ply_path, status
86
 
87
+ with gr.Blocks(title="Persistent 3D Cortex Demo v2") as demo:
88
+ gr.Markdown("# Persistent 3D Cortex Demo")
89
+ gr.Markdown("Upload an image (and optional prompt) to evolve a persistent 3D Gaussian splat representation.")
90
+
91
  with gr.Row():
92
  img_input = gr.Image(type="pil", label="Input Image")
93
+ prompt_input = gr.Textbox(label="Prompt (optional)", placeholder="e.g., enhance depth")
94
+
95
  btn = gr.Button("Generate Persistent 3D")
96
+
97
+ model_output = gr.Model3D(label="Interactive 3D Viewer", clear_color=[0.1, 0.1, 0.1, 1.0])
98
  text_output = gr.Textbox(label="Status")
99
+
100
+ btn.click(process, inputs=[img_input, prompt_input], outputs=[model_output, text_output])
101
 
102
  demo.launch()