ethanweber commited on
Commit
aa1677f
1 Parent(s): 8908918

gradio demo updates

Browse files
Files changed (3) hide show
  1. README.md +6 -0
  2. app.py +243 -37
  3. requirements.txt +1 -2
README.md CHANGED
@@ -11,3 +11,9 @@ license: apache-2.0
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
14
+
15
+ Here is the instructions we are following:
16
+
17
+ https://huggingface.co/docs/hub/en/spaces-sdks-gradio
18
+
19
+ Referencing this code https://huggingface.co/spaces/TencentARC/InstantMesh/blob/main/app.py
app.py CHANGED
@@ -1,59 +1,253 @@
1
  import spaces
2
  import gradio as gr
3
- from transformers import pipeline
 
 
 
 
 
 
4
 
5
- pipeline = pipeline(task="image-classification", model="julien-c/hotdog-not-hotdog")
6
-
7
- @spaces.GPU
8
- def predict(input_img):
9
- predictions = pipeline(input_img)
10
- return input_img, {p["label"]: p["score"] for p in predictions}
11
 
12
  _HEADER_ = '''
13
  <h2>Toon3D: Seeing Cartoons from a New Perspective</h2>
14
- Toon3D lifts cartoons into 3D via aligning and warping backprojected monocular depth predictions.<br>
15
- Project page @ <a href='https://toon3d.studio/' target='_blank'>https://toon3d.studio/</a>
16
 
17
- **Important Notes:**
18
- - TODO 1
19
- - TODO 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  '''
21
 
22
  def check_input_images(input_images):
23
  if input_images is None:
24
  raise gr.Error("No images uploaded!")
25
-
 
26
  def process_images(input_images):
27
 
28
- for image in input_images:
29
- print(image)
30
 
31
- return input_images
 
 
32
 
33
- gradio_app = gr.Interface(
34
- predict,
35
- inputs=gr.Image(label="Select hot dog candidate", sources=['upload', 'webcam'], type="pil"),
36
- outputs=[gr.Image(label="Processed Image"), gr.Label(label="Result", num_top_classes=2)],
37
- title="Toon3D",
38
- )
39
 
40
- with gr.Blocks() as demo:
41
- gr.Markdown(_HEADER_)
42
- with gr.Row(variant="panel"):
43
- with gr.Column():
44
- with gr.Row():
45
- input_images = gr.File(label="Upload Images", file_count="multiple", file_types=[".jpg", "jpeg", "png"])
46
- with gr.Row():
47
- process_data_button = gr.Button("Process Data", elem_id="process_data", variant="primary")
48
- with gr.Row():
49
- processed_data_zip = gr.File(label="Processed Data", file_count="single", file_types=[".zip"])
50
- with gr.Column():
51
- with gr.Row():
52
- labeled_data = gr.File(label="Labeled Points", file_count="single", file_types=[".json"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
 
 
54
 
 
 
 
 
55
 
56
- # mv_images = gr.State()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
  process_data_button.click(fn=check_input_images, inputs=[input_images]).success(
59
  fn=process_images,
@@ -61,5 +255,17 @@ with gr.Blocks() as demo:
61
  outputs=[processed_data_zip],
62
  )
63
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  if __name__ == "__main__":
65
- demo.launch()
 
1
  import spaces
2
  import gradio as gr
3
+ import os
4
+ import shutil
5
+ from pathlib import Path
6
+ from toon3d.scripts.viser_vis import main as viser_vis_main
7
+ import viser
8
+ import time
9
+ import threading
10
 
11
+ viewer_thread_instance = None
12
+ stop_event = threading.Event()
13
+ shared_url = None
 
 
 
14
 
15
  _HEADER_ = '''
16
  <h2>Toon3D: Seeing Cartoons from a New Perspective</h2>
17
+ Toon3D lifts cartoons into 3D via aligning and warping backprojected monocular depth predictions. The project page is at <a href='https://toon3d.studio/' target='_blank'>https://toon3d.studio/</a> and the Toon3D Labeler is at <a href='https://labeler.toon3d.studio/' target='_blank'>https://labeler.toon3d.studio/</a>. Follow the steps below to run Toon3D!
 
18
 
19
+ <div style="margin-top: 20px; font-size: 16px; line-height: 1.6;">
20
+ <div style="display: flex; justify-content: space-between;">
21
+ <div style="width: 49%;">
22
+ <ol>
23
+ <li><strong>Prepare and Process Data</strong>
24
+ <ul>
25
+ <li>Upload images and click on "Process Data" to generate processed data.</li>
26
+ <li>Download the processed data.</li>
27
+ </ul>
28
+ </li>
29
+ <li><strong>Label Data</strong>
30
+ <ul>
31
+ <li>Upload the processed data and label points using the labeler ("Upload ZIP").</li>
32
+ <li>Click export and upload the points.json to the "Labeled Points" section.</li>
33
+ </ul>
34
+ </li>
35
+ </ol>
36
+ </div>
37
+ <div style="width: 49%;">
38
+ <ol start="3">
39
+ <li><strong>Generate 3D Output</strong>
40
+ <ul>
41
+ <li>Click on "Run Toon3D" to run the structure from motion pipeline.</li>
42
+ <li>Download the output and inspect locally (point cloud, mesh, Nerfstudio dataset).</li>
43
+ </ul>
44
+ </li>
45
+ <li><strong>View in Web!</strong>
46
+ <ul>
47
+ <li>Click on "Open Viewer" to view the output in an interactive viewer powered by <a href="https://viser.studio/">Viser</a>.</li>
48
+ </ul>
49
+ <ul>
50
+ <li>Reach out if you have any questions!</li>
51
+ </ul>
52
+ </li>
53
+ </ol>
54
+ </div>
55
+ </div>
56
+ </div>
57
  '''
58
 
59
  def check_input_images(input_images):
60
  if input_images is None:
61
  raise gr.Error("No images uploaded!")
62
+
63
+ @spaces.GPU
64
  def process_images(input_images):
65
 
66
+ images_path = "/tmp/gradio/images"
67
+ processed_path = "/tmp/gradio/processed"
68
 
69
+ # remove the images_path folder
70
+ os.system(f"rm -rf {images_path}")
71
+ os.system(f"rm -rf {processed_path}")
72
 
73
+ # copy the uploaded images to the images_path folder
74
+ os.system(f"mkdir -p {images_path}")
75
+ os.system(f"mkdir -p {processed_path}")
 
 
 
76
 
77
+ for fileobj in input_images:
78
+ shutil.copyfile(fileobj.name, images_path + "/" + os.path.basename(fileobj.name))
79
+
80
+ # download SAM checkpoint
81
+ download_cmd = "tnd-download-data sam --save-dir /tmp/gradio"
82
+ os.system(download_cmd)
83
+
84
+ # process the data
85
+ process_data_cmd = f"tnd-process-data initialize --dataset toon3d-dataset --input_path {images_path} --data_prefix {processed_path} --sam_checkpoint_prefix /tmp/gradio/sam-checkpoints"
86
+ os.system(process_data_cmd)
87
+
88
+ zip_folder = "/tmp/gradio/processed/toon3d-dataset"
89
+ shutil.make_archive(zip_folder, 'zip', zip_folder)
90
+
91
+ return zip_folder + ".zip"
92
+
93
+ def toggle_labeler_visibility(visible):
94
+ if visible:
95
+ return '<iframe src="https://labeler.toon3d.studio/" style="display: block; margin: auto; width: 100%; height: 100vh;" frameborder="0"></iframe>'
96
+ else:
97
+ return ""
98
+
99
+ def check_input_toon3d(processed_data_zip, labeled_data):
100
+ if processed_data_zip is None:
101
+ raise gr.Error("No images uploaded!")
102
+
103
+ @spaces.GPU
104
+ def run_toon3d(processed_data_zip, labeled_data):
105
+
106
+ data_prefix = "/tmp/gradio/inputs"
107
+ processed_path = f"{data_prefix}/toon3d-dataset"
108
+ output_prefix = "/tmp/gradio/outputs"
109
+ nerfstudio_folder = "/tmp/gradio/nerfstudio"
110
+
111
+ os.system(f"rm -rf {processed_path}")
112
+ os.system(f"rm -rf {output_prefix}")
113
+ os.system(f"rm -rf {nerfstudio_folder}")
114
+
115
+ shutil.unpack_archive(processed_data_zip.name, processed_path)
116
+ shutil.copyfile(labeled_data.name, f"{processed_path}/points.json")
117
+
118
+ # run toon3d
119
+ toon3d_cmd = f"tnd-run --dataset toon3d-dataset --data_prefix {data_prefix} --output_prefix {output_prefix} --nerfstudio_folder {nerfstudio_folder} --no-view-point-cloud"
120
+ os.system(toon3d_cmd)
121
+
122
+ # get the last timestamped folder in output_prefix
123
+ # output_folder = sorted([f.path for f in os.scandir(output_prefix) if f.is_dir()])[-1]
124
+ output_dirs = Path(output_prefix) / "toon3d-dataset" / "run"
125
+ output_dir = Path(output_dirs / sorted(os.listdir(output_dirs))[-1])
126
+
127
+ zip_folder = str(output_dir)
128
+ shutil.make_archive(zip_folder, 'zip', zip_folder)
129
+
130
+ return zip_folder + ".zip"
131
+
132
+ # def open_viewer_fn(processed_data_zip, labeled_data, toon3d_output_zip):
133
+
134
+ # print(processed_data_zip)
135
+ # print(labeled_data)
136
+ # print(toon3d_output_zip)
137
 
138
+ # data_prefix = Path("/tmp/gradio/inputs")
139
+ # processed_path = f"{data_prefix}/toon3d-dataset"
140
 
141
+ # # extract the zip file
142
+ # viewer_folder = "/tmp/gradio/viewer/toon3d-dataset/run/temp"
143
+ # os.system(f"rm -rf {viewer_folder}")
144
+ # shutil.unpack_archive(toon3d_output_zip.name, viewer_folder)
145
 
146
+ # shutil.unpack_archive(processed_data_zip.name, processed_path)
147
+ # shutil.copyfile(labeled_data.name, f"{processed_path}/points.json")
148
+
149
+ # viser_server = viser.ViserServer()
150
+ # url = viser_server.request_share_url()
151
+ # print(url)
152
+
153
+ # # this is an infinite while loop so needs to be run in a separate thread
154
+ # # TODO:
155
+ # viser_vis_main(
156
+ # data_prefix=data_prefix,
157
+ # dataset="toon3d-dataset",
158
+ # output_prefix=Path("/tmp/gradio/viewer"),
159
+ # output_method=Path("run"),
160
+ # server=viser_server,
161
+ # visible=True,
162
+ # )
163
+
164
+ def viewer_thread(processed_data_zip, labeled_data, toon3d_output_zip):
165
+ global shared_url
166
+ data_prefix = Path("/tmp/gradio/inputs")
167
+ processed_path = f"{data_prefix}/toon3d-dataset"
168
+
169
+ viewer_folder = "/tmp/gradio/viewer/toon3d-dataset/run/temp"
170
+ os.system(f"rm -rf {viewer_folder}")
171
+ shutil.unpack_archive(toon3d_output_zip.name, viewer_folder)
172
+ shutil.unpack_archive(processed_data_zip.name, processed_path)
173
+ shutil.copyfile(labeled_data.name, f"{processed_path}/points.json")
174
+
175
+ viser_server = viser.ViserServer()
176
+ url = viser_server.request_share_url()
177
+ shared_url = url # Save the URL to the global variable
178
+ print(url)
179
+
180
+ viser_vis_main(
181
+ data_prefix=data_prefix,
182
+ dataset="toon3d-dataset",
183
+ output_prefix=Path("/tmp/gradio/viewer"),
184
+ output_method=Path("run"),
185
+ server=viser_server,
186
+ visible=True,
187
+ return_early=True
188
+ )
189
+ while not stop_event.is_set():
190
+ time.sleep(1)
191
+
192
+ viser_server.stop() # Ensure the server is stopped when the loop exits
193
+
194
+ def kill_viewer():
195
+ global viewer_thread_instance, stop_event
196
+ if viewer_thread_instance and viewer_thread_instance.is_alive():
197
+ stop_event.set() # Signal the thread to stop
198
+ viewer_thread_instance.join() # Wait for the thread to actually stop
199
+ viewer_thread_instance = None
200
+ print("Viewer has been stopped.")
201
+ else:
202
+ print("No viewer is running.")
203
+
204
+ def get_html_for_shared_url(url):
205
+ return f'<h1>Open <a href="{url}" target="_blank">{url}</a>!</h1>'
206
+
207
+ def check_input_open_viewer(processed_data_zip, labeled_data, toon3d_output_zip):
208
+ if processed_data_zip is None:
209
+ raise gr.Error("No processed data uploaded!")
210
+ if labeled_data is None:
211
+ raise gr.Error("No labeled points uploaded!")
212
+ if toon3d_output_zip is None:
213
+ raise gr.Error("No Toon3D output uploaded!")
214
+
215
+ def start_viewer(processed_data_zip, labeled_data, toon3d_output_zip):
216
+ kill_viewer() # Kill the existing viewer if it's running
217
+
218
+ global viewer_thread_instance, stop_event, shared_url
219
+ stop_event.clear() # Reset the stop event
220
+ shared_url = None # Reset the URL before starting
221
+ if viewer_thread_instance is None or not viewer_thread_instance.is_alive():
222
+ viewer_thread_instance = threading.Thread(target=viewer_thread, args=(processed_data_zip, labeled_data, toon3d_output_zip))
223
+ viewer_thread_instance.start()
224
+ while not shared_url:
225
+ # Wait for the URL to be set by the thread
226
+ time.sleep(0.1)
227
+ return get_html_for_shared_url(shared_url) # Return the URL after the thread has set it
228
+ else:
229
+ print("Viewer is already running.")
230
+ return get_html_for_shared_url(shared_url) # Return the current URL if the viewer is already running
231
+
232
+ with gr.Blocks(title="Toon3D") as demo:
233
+ gr.Markdown(_HEADER_)
234
+ with gr.Row(variant="panel"):
235
+ input_images = gr.File(label="Upload Images", file_count="multiple", file_types=[".jpg", "jpeg", "png"])
236
+ process_data_button = gr.Button("Process Data", elem_id="process_data_button", variant="primary")
237
+ processed_data_zip = gr.File(label="Processed Data", file_count="single", file_types=[".zip"], interactive=True)
238
+ with gr.Row(variant="panel"):
239
+ labeler_visible = gr.Checkbox(label="Show Labeler", value=False)
240
+ with gr.Row(variant="panel"):
241
+ labeler_frame = gr.HTML()
242
+ labeler_visible.change(toggle_labeler_visibility, inputs=[labeler_visible], outputs=[labeler_frame])
243
+ with gr.Row(variant="panel"):
244
+ labeled_data = gr.File(label="Labeled Points", file_count="single", file_types=[".json"])
245
+ run_toon3d_button = gr.Button("Run Toon3D", elem_id="run_toon3d_button", variant="primary")
246
+ toon3d_output_zip = gr.File(label="Toon3D Output", file_count="single", file_types=[".zip"], interactive=True)
247
+ with gr.Row(variant="panel"):
248
+ open_viewer_button = gr.Button("Open Viewer", elem_id="open_viser_button", variant="primary")
249
+ with gr.Row(variant="panel"):
250
+ viser_link = gr.HTML()
251
 
252
  process_data_button.click(fn=check_input_images, inputs=[input_images]).success(
253
  fn=process_images,
 
255
  outputs=[processed_data_zip],
256
  )
257
 
258
+ run_toon3d_button.click(fn=check_input_toon3d, inputs=[processed_data_zip, labeled_data]).success(
259
+ fn=run_toon3d,
260
+ inputs=[processed_data_zip, labeled_data],
261
+ outputs=[toon3d_output_zip],
262
+ )
263
+
264
+ open_viewer_button.click(fn=check_input_open_viewer, inputs=[processed_data_zip, labeled_data, toon3d_output_zip]).success(
265
+ fn=start_viewer,
266
+ inputs=[processed_data_zip, labeled_data, toon3d_output_zip],
267
+ outputs=[viser_link],
268
+ )
269
+
270
  if __name__ == "__main__":
271
+ demo.launch(server_port=7862)
requirements.txt CHANGED
@@ -1,2 +1 @@
1
- transformers
2
- torch
 
1
+ toon3d