dfrokido commited on
Commit
0c12567
·
verified ·
1 Parent(s): 6c163ca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -55
app.py CHANGED
@@ -2,99 +2,93 @@ import gradio as gr
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])
 
2
  import torch
3
  import numpy as np
4
  from PIL import Image
 
5
  import tempfile
6
+ import plyfile # Add to requirements.txt
7
 
8
  class SimplePersistentCortex:
9
+ def __init__(self, num_gaussians=10000):
10
  self.num_gaussians = num_gaussians
11
+ # Initialize clustered Gaussians
12
+ self.positions = torch.randn(num_gaussians, 3) * 0.4
13
+ self.scales = torch.exp(torch.randn(num_gaussians, 3) * 0.6 - 1.0) # Positive scales
14
+ self.colors_dc = torch.rand(num_gaussians, 3) * 0.5 + 0.25 # Base colors (SH degree 0)
15
+ self.opacities = torch.sigmoid(torch.randn(num_gaussians) * 1.5 + 2.0) # Mostly visible
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 = 100):
19
+ target_np = np.array(target_image.resize((128, 128))) / 255.0
20
+ target_tensor = torch.tensor(target_np, dtype=torch.float32).mean(dim=(0,1)) # Average color
 
21
 
 
22
  for _ in range(steps):
23
+ # Attract positions to center with noise
24
+ self.positions += torch.randn_like(self.positions) * 0.01
25
+ self.positions *= 0.99 # Dampen spread
26
 
27
+ # Adapt colors toward target
28
+ self.colors_dc += (target_tensor - self.colors_dc.mean(dim=0)) * 0.02
29
+ self.colors_dc = torch.clamp(self.colors_dc, 0, 1)
 
30
 
31
+ # Vary scales for density
32
+ self.scales *= torch.exp(torch.randn_like(self.scales) * 0.03)
33
 
34
+ # Boost opacity
35
+ self.opacities = torch.clamp(self.opacities + 0.01, 0, 1)
36
 
37
  return self
38
 
39
  def export_ply(self, path: str):
40
+ positions = self.positions.cpu().numpy()
41
+ scales = np.log(self.scales.cpu().numpy() + 1e-9)
42
+ opacities = np.arctanh(self.opacities.cpu().numpy().clip(1e-6, 1-1e-6))
43
+ rot = self.rotations.cpu().numpy()
44
+ sh_dc = self.colors_dc.cpu().numpy().reshape(-1, 3) # Simplified SH
 
 
 
 
 
 
45
 
46
+ # Create vertex data
47
+ vertex_data = np.empty(self.num_gaussians, dtype=[
48
+ ('x', 'f4'), ('y', 'f4'), ('z', 'f4'),
49
+ ('f_dc_0', 'f4'), ('f_dc_1', 'f4'), ('f_dc_2', 'f4'),
50
+ ('opacity', 'f4'),
51
+ ('scale_0', 'f4'), ('scale_1', 'f4'), ('scale_2', 'f4'),
52
+ ('rot_0', 'f4'), ('rot_1', 'f4'), ('rot_2', 'f4'), ('rot_3', 'f4')
53
+ ])
54
 
55
+ vertex_data['x'], vertex_data['y'], vertex_data['z'] = positions[:, 0], positions[:, 1], positions[:, 2]
56
+ vertex_data['f_dc_0'], vertex_data['f_dc_1'], vertex_data['f_dc_2'] = sh_dc[:, 0], sh_dc[:, 1], sh_dc[:, 2]
57
+ vertex_data['opacity'] = opacities
58
+ vertex_data['scale_0'], vertex_data['scale_1'], vertex_data['scale_2'] = scales[:, 0], scales[:, 1], scales[:, 2]
59
+ vertex_data['rot_0'], vertex_data['rot_1'], vertex_data['rot_2'], vertex_data['rot_3'] = rot[:, 0], rot[:, 1], rot[:, 2], rot[:, 3]
60
+
61
+ el = plyfile.PlyElement.describe(vertex_data, 'vertex')
62
+ plyfile.PlyData([el]).write(path)
63
 
64
  def process(image: Image.Image, prompt: str = ""):
65
  if image is None:
66
+ return None, "Error: Please upload an image."
67
 
68
  cortex = SimplePersistentCortex()
69
  cortex.evolve(image)
70
 
 
71
  with tempfile.NamedTemporaryFile(delete=False, suffix=".ply") as tmp:
72
  cortex.export_ply(tmp.name)
73
  ply_path = tmp.name
74
 
75
+ status = "Persistent 3D Gaussian splat generated. Use mouse to orbit/zoom in viewer."
76
  if prompt:
77
+ status += f" (Prompt: {prompt})"
78
 
79
  return ply_path, status
80
 
81
+ with gr.Blocks(title="Persistent 3D Cortex Demo v3") as demo:
82
  gr.Markdown("# Persistent 3D Cortex Demo")
83
+ gr.Markdown("Upload an image to generate an evolving 3D Gaussian representation.")
84
 
85
  with gr.Row():
86
  img_input = gr.Image(type="pil", label="Input Image")
87
+ prompt_input = gr.Textbox(label="Prompt (optional)")
88
 
89
+ btn = gr.Button("Generate 3D")
90
 
91
+ model_output = gr.Model3D(label="Interactive Gaussian Splat Viewer", clear_color=[0.0, 0.0, 0.0, 1.0])
92
  text_output = gr.Textbox(label="Status")
93
 
94
  btn.click(process, inputs=[img_input, prompt_input], outputs=[model_output, text_output])