Spaces:
Running on Zero
Running on Zero
Does it work for you?
#6
by federic29 - opened
- README.md +2 -2
- requirements.txt +8 -1
- web-demos/hugging_face/app.py +20 -85
- web-demos/hugging_face/requirements.txt +1 -0
README.md
CHANGED
|
@@ -4,10 +4,10 @@ emoji: 👨🎨
|
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: red
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
app_file: web-demos/hugging_face/app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
| 11 |
---
|
| 12 |
|
| 13 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: red
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 3.50.2
|
| 8 |
app_file: web-demos/hugging_face/app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
| 11 |
---
|
| 12 |
|
| 13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
requirements.txt
CHANGED
|
@@ -6,6 +6,8 @@ numpy
|
|
| 6 |
scipy
|
| 7 |
matplotlib
|
| 8 |
scikit-image
|
|
|
|
|
|
|
| 9 |
imageio-ffmpeg
|
| 10 |
pyyaml
|
| 11 |
requests
|
|
@@ -17,9 +19,14 @@ gitpython
|
|
| 17 |
git+https://github.com/cheind/py-thin-plate-spline
|
| 18 |
hickle
|
| 19 |
tensorboard
|
|
|
|
| 20 |
git+https://github.com/facebookresearch/segment-anything.git
|
|
|
|
| 21 |
opencv-python
|
|
|
|
|
|
|
|
|
|
| 22 |
openmim
|
| 23 |
tqdm
|
| 24 |
psutil
|
| 25 |
-
omegaconf
|
|
|
|
| 6 |
scipy
|
| 7 |
matplotlib
|
| 8 |
scikit-image
|
| 9 |
+
torch>=1.7.1
|
| 10 |
+
torchvision>=0.8.2
|
| 11 |
imageio-ffmpeg
|
| 12 |
pyyaml
|
| 13 |
requests
|
|
|
|
| 19 |
git+https://github.com/cheind/py-thin-plate-spline
|
| 20 |
hickle
|
| 21 |
tensorboard
|
| 22 |
+
numpy
|
| 23 |
git+https://github.com/facebookresearch/segment-anything.git
|
| 24 |
+
gradio
|
| 25 |
opencv-python
|
| 26 |
+
matplotlib
|
| 27 |
+
pyyaml
|
| 28 |
+
av
|
| 29 |
openmim
|
| 30 |
tqdm
|
| 31 |
psutil
|
| 32 |
+
omegaconf
|
web-demos/hugging_face/app.py
CHANGED
|
@@ -12,8 +12,6 @@ import torch
|
|
| 12 |
import torchvision
|
| 13 |
import numpy as np
|
| 14 |
import gradio as gr
|
| 15 |
-
import spaces
|
| 16 |
-
import av
|
| 17 |
|
| 18 |
from tools.painter import mask_painter
|
| 19 |
from track_anything import TrackingAnything
|
|
@@ -62,7 +60,6 @@ def get_prompt(click_state, click_input):
|
|
| 62 |
return prompt
|
| 63 |
|
| 64 |
# extract frames from upload video
|
| 65 |
-
@spaces.GPU
|
| 66 |
def get_frames_from_video(video_input, video_state):
|
| 67 |
"""
|
| 68 |
Args:
|
|
@@ -139,7 +136,6 @@ def get_frames_from_video(video_input, video_state):
|
|
| 139 |
gr.update(visible=True, value=operation_log), gr.update(visible=status_ok, value=operation_log)
|
| 140 |
|
| 141 |
# get the select frame from gradio slider
|
| 142 |
-
@spaces.GPU
|
| 143 |
def select_template(image_selection_slider, video_state, interactive_state, mask_dropdown):
|
| 144 |
|
| 145 |
# images = video_state[1]
|
|
@@ -163,25 +159,6 @@ def get_end_number(track_pause_number_slider, video_state, interactive_state):
|
|
| 163 |
return video_state["painted_images"][track_pause_number_slider],interactive_state, operation_log, operation_log
|
| 164 |
|
| 165 |
# use sam to get the mask
|
| 166 |
-
@spaces.GPU
|
| 167 |
-
def _sam_refine_gpu(video_state, point_prompt, click_state, interactive_state, coordinate):
|
| 168 |
-
# prompt for sam model
|
| 169 |
-
model.samcontroler.sam_controler.reset_image()
|
| 170 |
-
model.samcontroler.sam_controler.set_image(video_state["origin_images"][video_state["select_frame_number"]])
|
| 171 |
-
prompt = get_prompt(click_state=click_state, click_input=coordinate)
|
| 172 |
-
|
| 173 |
-
mask, logit, painted_image = model.first_frame_click(
|
| 174 |
-
image=video_state["origin_images"][video_state["select_frame_number"]],
|
| 175 |
-
points=np.array(prompt["input_point"]),
|
| 176 |
-
labels=np.array(prompt["input_label"]),
|
| 177 |
-
multimask=prompt["multimask_output"],
|
| 178 |
-
)
|
| 179 |
-
video_state["masks"][video_state["select_frame_number"]] = mask
|
| 180 |
-
video_state["logits"][video_state["select_frame_number"]] = logit
|
| 181 |
-
video_state["painted_images"][video_state["select_frame_number"]] = painted_image
|
| 182 |
-
return painted_image, video_state, interactive_state
|
| 183 |
-
|
| 184 |
-
|
| 185 |
def sam_refine(video_state, point_prompt, click_state, interactive_state, evt:gr.SelectData):
|
| 186 |
"""
|
| 187 |
Args:
|
|
@@ -189,18 +166,27 @@ def sam_refine(video_state, point_prompt, click_state, interactive_state, evt:gr
|
|
| 189 |
point_prompt: flag for positive or negative button click
|
| 190 |
click_state: [[points], [labels]]
|
| 191 |
"""
|
| 192 |
-
# Extract the click coordinate here (outside @spaces.GPU) because
|
| 193 |
-
# gr.SelectData does not pickle across the ZeroGPU fork boundary.
|
| 194 |
if point_prompt == "Positive":
|
| 195 |
coordinate = "[[{},{},1]]".format(evt.index[0], evt.index[1])
|
| 196 |
interactive_state["positive_click_times"] += 1
|
| 197 |
else:
|
| 198 |
coordinate = "[[{},{},0]]".format(evt.index[0], evt.index[1])
|
| 199 |
interactive_state["negative_click_times"] += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
|
| 205 |
operation_log = [("[Must Do]", "Add mask"), (": add the current displayed mask for video segmentation.\n", None),
|
| 206 |
("[Optional]", "Remove mask"), (": remove all added masks.\n", None),
|
|
@@ -245,20 +231,6 @@ def show_mask(video_state, interactive_state, mask_dropdown):
|
|
| 245 |
return select_frame, operation_log, operation_log
|
| 246 |
|
| 247 |
# tracking vos
|
| 248 |
-
def _tracking_duration(video_state, interactive_state, mask_dropdown):
|
| 249 |
-
try:
|
| 250 |
-
origin = video_state.get("origin_images") if isinstance(video_state, dict) else None
|
| 251 |
-
start = video_state.get("select_frame_number", 0) if isinstance(video_state, dict) else 0
|
| 252 |
-
end = interactive_state.get("track_end_number") if isinstance(interactive_state, dict) else None
|
| 253 |
-
total = len(origin) if origin is not None else 60
|
| 254 |
-
n = (end if end else total) - start
|
| 255 |
-
n = max(1, int(n))
|
| 256 |
-
except Exception:
|
| 257 |
-
n = 60
|
| 258 |
-
return min(300, max(60, int(0.4 * n + 30)))
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
@spaces.GPU(duration=_tracking_duration)
|
| 262 |
def vos_tracking_video(video_state, interactive_state, mask_dropdown):
|
| 263 |
operation_log = [("",""), ("Tracking finished! Try to click the Inpainting button to get the inpainting result.","Normal")]
|
| 264 |
model.cutie.clear_memory()
|
|
@@ -319,18 +291,7 @@ def vos_tracking_video(video_state, interactive_state, mask_dropdown):
|
|
| 319 |
#### shanggao code for mask save
|
| 320 |
return video_output, video_state, interactive_state, operation_log, operation_log
|
| 321 |
|
| 322 |
-
# inpaint
|
| 323 |
-
def _inpaint_duration(video_state, resize_ratio_number, dilate_radius_number, raft_iter_number, subvideo_length_number, neighbor_length_number, ref_stride_number, mask_dropdown):
|
| 324 |
-
try:
|
| 325 |
-
origin = video_state.get("origin_images") if isinstance(video_state, dict) else None
|
| 326 |
-
n = len(origin) if origin is not None else 60
|
| 327 |
-
ratio = float(resize_ratio_number) if resize_ratio_number else 1.0
|
| 328 |
-
except Exception:
|
| 329 |
-
n, ratio = 60, 1.0
|
| 330 |
-
return min(420, max(90, int(n * ratio * 1.3 + 45)))
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
@spaces.GPU(duration=_inpaint_duration)
|
| 334 |
def inpaint_video(video_state, resize_ratio_number, dilate_radius_number, raft_iter_number, subvideo_length_number, neighbor_length_number, ref_stride_number, mask_dropdown):
|
| 335 |
operation_log = [("",""), ("Inpainting finished!","Normal")]
|
| 336 |
|
|
@@ -368,42 +329,16 @@ def inpaint_video(video_state, resize_ratio_number, dilate_radius_number, raft_i
|
|
| 368 |
def generate_video_from_frames(frames, output_path, fps=30):
|
| 369 |
"""
|
| 370 |
Generates a video from a list of frames.
|
| 371 |
-
|
| 372 |
Args:
|
| 373 |
frames (list of numpy arrays): The frames to include in the video.
|
| 374 |
output_path (str): The path to save the generated video.
|
| 375 |
fps (int, optional): The frame rate of the output video. Defaults to 30.
|
| 376 |
"""
|
| 377 |
-
frames = np.asarray(frames)
|
| 378 |
-
if frames.ndim != 4:
|
| 379 |
-
raise ValueError(f"Expected frames of shape (T, H, W, 3); got {frames.shape}")
|
| 380 |
if not os.path.exists(os.path.dirname(output_path)):
|
| 381 |
os.makedirs(os.path.dirname(output_path))
|
| 382 |
-
|
| 383 |
-
# torchvision.io.write_video was removed in newer torchvision; encode via PyAV.
|
| 384 |
-
height, width = frames.shape[1], frames.shape[2]
|
| 385 |
-
# libx264 requires even dimensions.
|
| 386 |
-
pad_h = height % 2
|
| 387 |
-
pad_w = width % 2
|
| 388 |
-
if pad_h or pad_w:
|
| 389 |
-
frames = np.pad(frames, ((0, 0), (0, pad_h), (0, pad_w), (0, 0)), mode="edge")
|
| 390 |
-
height += pad_h
|
| 391 |
-
width += pad_w
|
| 392 |
-
|
| 393 |
-
container = av.open(output_path, mode="w")
|
| 394 |
-
try:
|
| 395 |
-
stream = container.add_stream("libx264", rate=int(round(fps)) or 1)
|
| 396 |
-
stream.width = width
|
| 397 |
-
stream.height = height
|
| 398 |
-
stream.pix_fmt = "yuv420p"
|
| 399 |
-
for img in frames:
|
| 400 |
-
frame = av.VideoFrame.from_ndarray(np.ascontiguousarray(img.astype(np.uint8)), format="rgb24")
|
| 401 |
-
for packet in stream.encode(frame):
|
| 402 |
-
container.mux(packet)
|
| 403 |
-
for packet in stream.encode():
|
| 404 |
-
container.mux(packet)
|
| 405 |
-
finally:
|
| 406 |
-
container.close()
|
| 407 |
return output_path
|
| 408 |
|
| 409 |
def restart():
|
|
@@ -619,7 +554,7 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as iface:
|
|
| 619 |
visible=False,
|
| 620 |
min_width=100,
|
| 621 |
scale=1,)
|
| 622 |
-
with gr.Row(elem_classes="mask_button_group"):
|
| 623 |
Add_mask_button = gr.Button(value="Add mask", interactive=True, visible=False, elem_classes="add_button")
|
| 624 |
remove_mask_button = gr.Button(value="Remove mask", interactive=True, visible=False, elem_classes="remove_button")
|
| 625 |
clear_button_click = gr.Button(value="Clear clicks", interactive=True, visible=False, elem_classes="clear_button")
|
|
@@ -741,5 +676,5 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as iface:
|
|
| 741 |
)
|
| 742 |
gr.Markdown(article)
|
| 743 |
|
| 744 |
-
iface.queue()
|
| 745 |
iface.launch(debug=True)
|
|
|
|
| 12 |
import torchvision
|
| 13 |
import numpy as np
|
| 14 |
import gradio as gr
|
|
|
|
|
|
|
| 15 |
|
| 16 |
from tools.painter import mask_painter
|
| 17 |
from track_anything import TrackingAnything
|
|
|
|
| 60 |
return prompt
|
| 61 |
|
| 62 |
# extract frames from upload video
|
|
|
|
| 63 |
def get_frames_from_video(video_input, video_state):
|
| 64 |
"""
|
| 65 |
Args:
|
|
|
|
| 136 |
gr.update(visible=True, value=operation_log), gr.update(visible=status_ok, value=operation_log)
|
| 137 |
|
| 138 |
# get the select frame from gradio slider
|
|
|
|
| 139 |
def select_template(image_selection_slider, video_state, interactive_state, mask_dropdown):
|
| 140 |
|
| 141 |
# images = video_state[1]
|
|
|
|
| 159 |
return video_state["painted_images"][track_pause_number_slider],interactive_state, operation_log, operation_log
|
| 160 |
|
| 161 |
# use sam to get the mask
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
def sam_refine(video_state, point_prompt, click_state, interactive_state, evt:gr.SelectData):
|
| 163 |
"""
|
| 164 |
Args:
|
|
|
|
| 166 |
point_prompt: flag for positive or negative button click
|
| 167 |
click_state: [[points], [labels]]
|
| 168 |
"""
|
|
|
|
|
|
|
| 169 |
if point_prompt == "Positive":
|
| 170 |
coordinate = "[[{},{},1]]".format(evt.index[0], evt.index[1])
|
| 171 |
interactive_state["positive_click_times"] += 1
|
| 172 |
else:
|
| 173 |
coordinate = "[[{},{},0]]".format(evt.index[0], evt.index[1])
|
| 174 |
interactive_state["negative_click_times"] += 1
|
| 175 |
+
|
| 176 |
+
# prompt for sam model
|
| 177 |
+
model.samcontroler.sam_controler.reset_image()
|
| 178 |
+
model.samcontroler.sam_controler.set_image(video_state["origin_images"][video_state["select_frame_number"]])
|
| 179 |
+
prompt = get_prompt(click_state=click_state, click_input=coordinate)
|
| 180 |
|
| 181 |
+
mask, logit, painted_image = model.first_frame_click(
|
| 182 |
+
image=video_state["origin_images"][video_state["select_frame_number"]],
|
| 183 |
+
points=np.array(prompt["input_point"]),
|
| 184 |
+
labels=np.array(prompt["input_label"]),
|
| 185 |
+
multimask=prompt["multimask_output"],
|
| 186 |
+
)
|
| 187 |
+
video_state["masks"][video_state["select_frame_number"]] = mask
|
| 188 |
+
video_state["logits"][video_state["select_frame_number"]] = logit
|
| 189 |
+
video_state["painted_images"][video_state["select_frame_number"]] = painted_image
|
| 190 |
|
| 191 |
operation_log = [("[Must Do]", "Add mask"), (": add the current displayed mask for video segmentation.\n", None),
|
| 192 |
("[Optional]", "Remove mask"), (": remove all added masks.\n", None),
|
|
|
|
| 231 |
return select_frame, operation_log, operation_log
|
| 232 |
|
| 233 |
# tracking vos
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
def vos_tracking_video(video_state, interactive_state, mask_dropdown):
|
| 235 |
operation_log = [("",""), ("Tracking finished! Try to click the Inpainting button to get the inpainting result.","Normal")]
|
| 236 |
model.cutie.clear_memory()
|
|
|
|
| 291 |
#### shanggao code for mask save
|
| 292 |
return video_output, video_state, interactive_state, operation_log, operation_log
|
| 293 |
|
| 294 |
+
# inpaint
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
def inpaint_video(video_state, resize_ratio_number, dilate_radius_number, raft_iter_number, subvideo_length_number, neighbor_length_number, ref_stride_number, mask_dropdown):
|
| 296 |
operation_log = [("",""), ("Inpainting finished!","Normal")]
|
| 297 |
|
|
|
|
| 329 |
def generate_video_from_frames(frames, output_path, fps=30):
|
| 330 |
"""
|
| 331 |
Generates a video from a list of frames.
|
| 332 |
+
|
| 333 |
Args:
|
| 334 |
frames (list of numpy arrays): The frames to include in the video.
|
| 335 |
output_path (str): The path to save the generated video.
|
| 336 |
fps (int, optional): The frame rate of the output video. Defaults to 30.
|
| 337 |
"""
|
| 338 |
+
frames = torch.from_numpy(np.asarray(frames))
|
|
|
|
|
|
|
| 339 |
if not os.path.exists(os.path.dirname(output_path)):
|
| 340 |
os.makedirs(os.path.dirname(output_path))
|
| 341 |
+
torchvision.io.write_video(output_path, frames, fps=fps, video_codec="libx264")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
return output_path
|
| 343 |
|
| 344 |
def restart():
|
|
|
|
| 554 |
visible=False,
|
| 555 |
min_width=100,
|
| 556 |
scale=1,)
|
| 557 |
+
with gr.Row(scale=2, elem_classes="mask_button_group"):
|
| 558 |
Add_mask_button = gr.Button(value="Add mask", interactive=True, visible=False, elem_classes="add_button")
|
| 559 |
remove_mask_button = gr.Button(value="Remove mask", interactive=True, visible=False, elem_classes="remove_button")
|
| 560 |
clear_button_click = gr.Button(value="Clear clicks", interactive=True, visible=False, elem_classes="clear_button")
|
|
|
|
| 676 |
)
|
| 677 |
gr.Markdown(article)
|
| 678 |
|
| 679 |
+
iface.queue(concurrency_count=1)
|
| 680 |
iface.launch(debug=True)
|
web-demos/hugging_face/requirements.txt
CHANGED
|
@@ -6,6 +6,7 @@ hickle
|
|
| 6 |
tensorboard
|
| 7 |
numpy
|
| 8 |
git+https://github.com/facebookresearch/segment-anything.git
|
|
|
|
| 9 |
opencv-python
|
| 10 |
matplotlib
|
| 11 |
pyyaml
|
|
|
|
| 6 |
tensorboard
|
| 7 |
numpy
|
| 8 |
git+https://github.com/facebookresearch/segment-anything.git
|
| 9 |
+
gradio
|
| 10 |
opencv-python
|
| 11 |
matplotlib
|
| 12 |
pyyaml
|