dfrokido commited on
Commit
28fc630
·
verified ·
1 Parent(s): 43e9ff5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -0
app.py CHANGED
@@ -72,6 +72,101 @@ class PersistentCortex:
72
  self.colors = torch.clamp(self.colors + color_shift.repeat(self.num, 1) * 0.3, 0, 1)
73
  return self
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  def export_ply(self, path="output.ply"):
76
  # Prepare vertex data matching gsplat.js expected properties
77
  zeros = np.zeros((self.num, 3), dtype=np.float32)
 
72
  self.colors = torch.clamp(self.colors + color_shift.repeat(self.num, 1) * 0.3, 0, 1)
73
  return self
74
 
75
+ def export_ply(self, path="output.ply"):
76
+ # Prepare vertex data matching gsplat.js expected properties
77
+ zeros = np.zeros((self.num, 3), dtype=np.float32)
78
+ log_scales = np.log(self.scales.cpu().numpy()).astype(np.float32)
79
+
80
+ vertex_data = np.core.records.fromarrays([
81
+ self.positions.cpu().numpy().astype(np.float32).T,
82
+ zeros.T, # normals (unused)
83
+ self.colors.cpu().numpy().T,
84
+ self.opacities.cpu().numpy().reshape(1, -1).T,
85
+ log_scales.T,
86
+ self.rotations.cpu().numpy().T
87
+ ], names='x,y,z,nx,ny,nz,f_dc_0,f_dc_1,f_dc_2,opacity,scale_0,scale_1,scale_2,rot_0,rot_1,rot_2,rot_3')
88
+
89
+ el = plyfile.PlyElement.describe(vertex_data, 'vertex')
90
+ plyfile.PlyData([el], text=True).write(path)
91
+ return os.path.abspath(path)
92
+
93
+ def process(image: Image.Image, prompt: str = ""):
94
+ if image is None:
95
+ raise ValueError("Please upload an image to proceed.")
96
+
97
+ cortex = PersistentCortex(num_gaussians=8000)
98
+ cortex.evolve_from_image(image, steps=800)
99
+ if prompt:
100
+ cortex.condition_on_prompt(prompt)
101
+
102
+ ply_path = cortex.export_ply("/tmp/output.ply")
103
+
104
+ # In Hugging Face Spaces, /tmp files are automatically served under /files/
105
+ viewer_html = f"""
106
+ <div id="viewer" style="width:100%; height:600px; background:#000;"></div>
107
+ <script type="module">
108
+ import * as SPLAT from "https://cdn.jsdelivr.net/npm/gsplat@latest";
109
+
110
+ const container = document.getElementById('viewer');
111
+ const canvas = document.createElement('canvas');
112
+ canvas.style.width = '100%';
113
+ canvas.style.height = '100%';
114
+ container.appendChild(canvas);
115
+
116
+ const scene = new SPLAT.Scene();
117
+ const camera = new SPLAT.Camera();
118
+ const renderer = new SPLAT.WebGLRenderer({{ canvas }});
119
+ const controls = new SPLAT.OrbitControls(camera, canvas);
120
+
121
+ controls.autoRotate = false;
122
+ controls.enableDamping = true;
123
+ controls.dampingFactor = 0.05;
124
+ controls.rotateSpeed = 1.0;
125
+ controls.zoomSpeed = 1.2;
126
+ controls.panSpeed = 0.8;
127
+
128
+ await SPLAT.Loader.LoadAsync("/files/output.ply", scene);
129
+
130
+ function animate() {{
131
+ controls.update();
132
+ renderer.render(scene, camera);
133
+ requestAnimationFrame(animate);
134
+ }}
135
+ animate();
136
+ </script>
137
+ """
138
+
139
+ status = "3D Gaussian splat generated and evolved from your image"
140
+ if prompt:
141
+ status += f" with prompt conditioning: '{prompt}'."
142
+ else:
143
+ status += "."
144
+
145
+ return viewer_html, status
146
+
147
+ with gr.Blocks(title="Persistent 3D Cortex Demo") as demo:
148
+ gr.Markdown("# Persistent 3D Cortex – Interactive Demo")
149
+ gr.Markdown("""
150
+ Upload an image and optionally add a text prompt.
151
+ The system evolves a persistent 3D Gaussian splat representation influenced by the image content and prompt.
152
+ """)
153
+
154
+ with gr.Row():
155
+ img_input = gr.Image(type="pil", label="Input Image")
156
+ prompt_input = gr.Textbox(label="Prompt (e.g., 'shiny red apple', 'futuristic city')", placeholder="Optional text prompt")
157
+
158
+ generate_btn = gr.Button("Generate & Evolve 3D", variant="primary")
159
+
160
+ viewer_output = gr.HTML(label="Interactive 3D Viewer")
161
+ status_output = gr.Textbox(label="Status")
162
+
163
+ generate_btn.click(
164
+ fn=process,
165
+ inputs=[img_input, prompt_input],
166
+ outputs=[viewer_output, status_output]
167
+ )
168
+
169
+ demo.launch()
170
  def export_ply(self, path="output.ply"):
171
  # Prepare vertex data matching gsplat.js expected properties
172
  zeros = np.zeros((self.num, 3), dtype=np.float32)