ysdede commited on
Commit
e1f2ae7
·
1 Parent(s): 77b7c2e

Port to ZeroGPU: lazy model loading and @spaces.GPU decorators

Browse files
README.md CHANGED
@@ -4,7 +4,8 @@ emoji: 🤡
4
  colorFrom: red
5
  colorTo: green
6
  sdk: gradio
7
- sdk_version: 5.16.0
 
8
  app_file: hugging_face/app.py
9
  pinned: false
10
  license: other
 
4
  colorFrom: red
5
  colorTo: green
6
  sdk: gradio
7
+ sdk_version: 4.31.0
8
+ python_version: 3.10.13
9
  app_file: hugging_face/app.py
10
  pinned: false
11
  license: other
hugging_face/app.py CHANGED
@@ -15,10 +15,11 @@ import cv2
15
  import torch
16
  import numpy as np
17
  import gradio as gr
 
18
 
19
  from tools.painter import mask_painter
20
  from tools.interact_tools import SamControler
21
- from tools.misc import get_device
22
  from tools.download_util import load_file_from_url
23
 
24
  from matanyone2_wrapper import matanyone2
@@ -37,10 +38,13 @@ def parse_augment():
37
  parser.add_argument('--mask_save', default=False)
38
  args = parser.parse_args()
39
 
 
 
 
40
  if not args.device:
41
- args.device = str(get_device())
42
 
43
- return args
44
 
45
  # SAM generator
46
  class MaskGenerator():
@@ -94,8 +98,7 @@ def get_frames_from_image(image_input, image_state):
94
  "fps": None
95
  }
96
  image_info = "Image Name: N/A,\nFPS: N/A,\nTotal Frames: {},\nImage Size:{}".format(len(frames), image_size)
97
- model.samcontroler.sam_controler.reset_image()
98
- model.samcontroler.sam_controler.set_image(image_state["origin_images"][0])
99
  return image_state, image_info, image_state["origin_images"][0], \
100
  gr.update(visible=True, maximum=10, value=10), gr.update(visible=False, maximum=len(frames), value=len(frames)), \
101
  gr.update(visible=True), gr.update(visible=True), \
@@ -166,8 +169,7 @@ def get_frames_from_video(video_input, video_state):
166
  "audio": audio_path
167
  }
168
  video_info = "Video Name: {},\nFPS: {},\nTotal Frames: {},\nImage Size:{}".format(video_state["video_name"], round(video_state["fps"], 0), len(frames), image_size)
169
- model.samcontroler.sam_controler.reset_image()
170
- model.samcontroler.sam_controler.set_image(video_state["origin_images"][0])
171
  return video_state, video_info, video_state["origin_images"][0], gr.update(visible=True, maximum=len(frames), value=1), gr.update(visible=False, maximum=len(frames), value=len(frames)), \
172
  gr.update(visible=True), gr.update(visible=True), \
173
  gr.update(visible=True), gr.update(visible=True),\
@@ -181,22 +183,14 @@ def select_video_template(image_selection_slider, video_state, interactive_state
181
 
182
  image_selection_slider -= 1
183
  video_state["select_frame_number"] = image_selection_slider
184
-
185
- # once select a new template frame, set the image in sam
186
- model.samcontroler.sam_controler.reset_image()
187
- model.samcontroler.sam_controler.set_image(video_state["origin_images"][image_selection_slider])
188
-
189
  return video_state["painted_images"][image_selection_slider], video_state, interactive_state
190
 
191
  def select_image_template(image_selection_slider, video_state, interactive_state):
192
 
193
  image_selection_slider = 0 # fixed for image
194
  video_state["select_frame_number"] = image_selection_slider
195
-
196
- # once select a new template frame, set the image in sam
197
- model.samcontroler.sam_controler.reset_image()
198
- model.samcontroler.sam_controler.set_image(video_state["origin_images"][image_selection_slider])
199
-
200
  return video_state["painted_images"][image_selection_slider], video_state, interactive_state
201
 
202
  # set the tracking end frame
@@ -206,6 +200,7 @@ def get_end_number(track_pause_number_slider, video_state, interactive_state):
206
  return video_state["painted_images"][track_pause_number_slider],interactive_state
207
 
208
  # use sam to get the mask
 
209
  def sam_refine(video_state, point_prompt, click_state, interactive_state, evt:gr.SelectData):
210
  """
211
  Args:
@@ -221,6 +216,7 @@ def sam_refine(video_state, point_prompt, click_state, interactive_state, evt:gr
221
  interactive_state["negative_click_times"] += 1
222
 
223
  # prompt for sam model
 
224
  model.samcontroler.sam_controler.reset_image()
225
  model.samcontroler.sam_controler.set_image(video_state["origin_images"][video_state["select_frame_number"]])
226
  prompt = get_prompt(click_state=click_state, click_input=coordinate)
@@ -269,6 +265,7 @@ def show_mask(video_state, interactive_state, mask_dropdown):
269
  return select_frame
270
 
271
  # image matting
 
272
  def image_matting(video_state, interactive_state, mask_dropdown, erode_kernel_size, dilate_kernel_size, refine_iter, model_selection):
273
  # Load model if not already loaded
274
  try:
@@ -308,6 +305,7 @@ def image_matting(video_state, interactive_state, mask_dropdown, erode_kernel_si
308
  return foreground_output, alpha_output
309
 
310
  # video matting
 
311
  def video_matting(video_state, interactive_state, mask_dropdown, erode_kernel_size, dilate_kernel_size, model_selection):
312
  # Load model if not already loaded
313
  try:
@@ -368,34 +366,40 @@ def add_audio_to_video(video_path, audio_path, output_path):
368
 
369
 
370
  def generate_video_from_frames(frames, output_path, fps=30, gray2rgb=False, audio_path=""):
371
- """
372
- Generates a video from a list of frames.
373
-
374
- Args:
375
- frames (list of numpy arrays): The frames to include in the video.
376
- output_path (str): The path to save the generated video.
377
- fps (int, optional): The frame rate of the output video. Defaults to 30.
378
- """
379
- frames = torch.from_numpy(np.asarray(frames))
380
- _, h, w, _ = frames.shape
381
  if gray2rgb:
382
  frames = np.repeat(frames, 3, axis=3)
383
 
 
 
 
 
 
 
 
 
 
 
384
  if not os.path.exists(os.path.dirname(output_path)):
385
  os.makedirs(os.path.dirname(output_path))
 
386
  video_temp_path = output_path.replace(".mp4", "_temp.mp4")
387
-
388
- # resize back to ensure input resolution
389
- imageio.mimwrite(video_temp_path, frames, fps=fps, quality=7,
390
- codec='libx264', ffmpeg_params=["-vf", f"scale={w}:{h}"])
391
-
392
- # add audio to video if audio path exists
 
 
 
 
393
  if audio_path != "" and os.path.exists(audio_path):
394
- output_path = add_audio_to_video(video_temp_path, audio_path, output_path)
395
  os.remove(video_temp_path)
396
  return output_path
397
- else:
398
- return video_temp_path
399
 
400
  # reset all states for a new input
401
  def restart():
@@ -434,11 +438,10 @@ sam_checkpoint_url_dict = {
434
  }
435
  checkpoint_folder = os.path.join('/home/user/app/', 'pretrained_models')
436
 
437
- sam_checkpoint = load_file_from_url(sam_checkpoint_url_dict[args.sam_model_type], checkpoint_folder)
438
- # initialize sams
439
- model = MaskGenerator(sam_checkpoint, args)
440
 
441
- # initialize matanyone - lazy loading
442
  # Model display names to file names mapping
443
  model_display_to_file = {
444
  "MatAnyone": "matanyone.pth",
@@ -451,71 +454,79 @@ model_urls = {
451
  "matanyone2.pth": "https://github.com/pq-yang/MatAnyone2/releases/download/v1.0.0/matanyone2.pth"
452
  }
453
 
454
- # Model paths - download models using load_file_from_url
455
- model_paths = {
456
- "matanyone.pth": load_file_from_url(model_urls["matanyone.pth"], checkpoint_folder),
457
- "matanyone2.pth": load_file_from_url(model_urls["matanyone2.pth"], checkpoint_folder)
458
- }
459
 
460
- # Cache for loaded models (lazy loading)
461
  loaded_models = {}
462
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  def load_model(display_name):
464
- """Load a model if not already loaded"""
465
- # Convert display name to file name
466
  if display_name in model_display_to_file:
467
  model_file = model_display_to_file[display_name]
468
- elif display_name in model_paths:
469
- # Also support direct file name for backward compatibility
470
  model_file = display_name
471
  else:
472
  raise ValueError(f"Unknown model: {display_name}")
473
-
474
  if model_file in loaded_models:
475
  return loaded_models[model_file]
476
-
477
- if model_file not in model_paths:
478
- raise ValueError(f"Unknown model file: {model_file}")
479
-
480
- ckpt_path = model_paths[model_file]
481
- if not os.path.exists(ckpt_path):
482
- raise FileNotFoundError(f"Model file not found: {ckpt_path}")
483
-
484
  # Clear Hydra instance if already initialized (to allow loading different models)
485
  try:
486
  GlobalHydra.instance().clear()
487
- except:
488
- pass # If Hydra is not initialized, this is fine
489
-
490
- print(f"Loading model: {display_name} ({model_file})...")
491
- model = get_matanyone2_model(ckpt_path, args.device)
492
- model = model.to(args.device).eval()
493
- loaded_models[model_file] = model
 
494
  print(f"Model {display_name} loaded successfully.")
495
- return model
496
-
497
- # Get available model choices for the UI (check if files exist)
498
- # Order: MatAnyone 2 first, then MatAnyone
499
- available_models = []
500
- # Check MatAnyone 2 first
501
- if "MatAnyone 2" in model_display_to_file:
502
- file_name = model_display_to_file["MatAnyone 2"]
503
- if file_name in model_paths and os.path.exists(model_paths[file_name]):
504
- available_models.append("MatAnyone 2")
505
- # Then check MatAnyone
506
- if "MatAnyone" in model_display_to_file:
507
- file_name = model_display_to_file["MatAnyone"]
508
- if file_name in model_paths and os.path.exists(model_paths[file_name]):
509
- available_models.append("MatAnyone")
510
-
511
- if not available_models:
512
- raise RuntimeError("No models are available! Please ensure at least one model file exists in ../pretrained_models/")
513
- default_model = "MatAnyone 2" if "MatAnyone 2" in available_models else available_models[0]
514
 
515
  # download test samples
516
  test_sample_path = os.path.join('/home/user/app/hugging_face/', "test_sample/")
517
- load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-0-1080p.mp4', test_sample_path)
518
- load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-1-1080p.mp4', test_sample_path)
519
  load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-2-720p.mp4', test_sample_path)
520
  load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-3-720p.mp4', test_sample_path)
521
  load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-4-720p.mp4', test_sample_path)
@@ -562,7 +573,7 @@ If our work is useful for your research, please consider citing:
562
  @InProceedings{yang2025matanyone,
563
  title = {{MatAnyone}: Stable Video Matting with Consistent Memory Propagation},
564
  author = {Yang, Peiqing and Zhou, Shangchen and Zhao, Jixin and Tao, Qingyi and Loy, Chen Change},
565
- booktitle = {arXiv preprint arXiv:2501.14677},
566
  year = {2025}
567
  }
568
  ```
@@ -632,7 +643,7 @@ body {
632
  text-align: center;
633
  padding: 0;
634
  margin: 0;
635
- height: 5vh;
636
  width: 80vw;
637
  font-family: "Sarpanch", sans-serif;
638
  font-weight: 60;
@@ -878,7 +889,7 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=my_custom_css) as demo:
878
  gr.Markdown("---")
879
  gr.Markdown("## Examples")
880
  gr.Examples(
881
- examples=[os.path.join(os.path.dirname(__file__), "./test_sample/", test_sample) for test_sample in ["test-sample-0-1080p.mp4", "test-sample-1-1080p.mp4", "test-sample-2-720p.mp4", "test-sample-3-720p.mp4", "test-sample-4-720p.mp4", "test-sample-5-720p.mp4"]],
882
  inputs=[video_input],
883
  )
884
 
 
15
  import torch
16
  import numpy as np
17
  import gradio as gr
18
+ import spaces
19
 
20
  from tools.painter import mask_painter
21
  from tools.interact_tools import SamControler
22
+ # get_device is NOT imported at module level to avoid CUDA init via torch.cuda.is_available()
23
  from tools.download_util import load_file_from_url
24
 
25
  from matanyone2_wrapper import matanyone2
 
38
  parser.add_argument('--mask_save', default=False)
39
  args = parser.parse_args()
40
 
41
+ # ZeroGPU: do NOT call get_device() (which calls torch.cuda.is_available()) at module level.
42
+ # It can trigger CUDA init in the main process. Default to 'cpu'; GPU functions
43
+ # determine the actual device at runtime inside @spaces.GPU-decorated functions.
44
  if not args.device:
45
+ args.device = "cpu"
46
 
47
+ return args
48
 
49
  # SAM generator
50
  class MaskGenerator():
 
98
  "fps": None
99
  }
100
  image_info = "Image Name: N/A,\nFPS: N/A,\nTotal Frames: {},\nImage Size:{}".format(len(frames), image_size)
101
+ # SAM loading and set_image are deferred to sam_refine() which runs under @spaces.GPU
 
102
  return image_state, image_info, image_state["origin_images"][0], \
103
  gr.update(visible=True, maximum=10, value=10), gr.update(visible=False, maximum=len(frames), value=len(frames)), \
104
  gr.update(visible=True), gr.update(visible=True), \
 
169
  "audio": audio_path
170
  }
171
  video_info = "Video Name: {},\nFPS: {},\nTotal Frames: {},\nImage Size:{}".format(video_state["video_name"], round(video_state["fps"], 0), len(frames), image_size)
172
+ # SAM loading and set_image are deferred to sam_refine() which runs under @spaces.GPU
 
173
  return video_state, video_info, video_state["origin_images"][0], gr.update(visible=True, maximum=len(frames), value=1), gr.update(visible=False, maximum=len(frames), value=len(frames)), \
174
  gr.update(visible=True), gr.update(visible=True), \
175
  gr.update(visible=True), gr.update(visible=True),\
 
183
 
184
  image_selection_slider -= 1
185
  video_state["select_frame_number"] = image_selection_slider
186
+ # SAM set_image is deferred to sam_refine() which runs under @spaces.GPU
 
 
 
 
187
  return video_state["painted_images"][image_selection_slider], video_state, interactive_state
188
 
189
  def select_image_template(image_selection_slider, video_state, interactive_state):
190
 
191
  image_selection_slider = 0 # fixed for image
192
  video_state["select_frame_number"] = image_selection_slider
193
+ # SAM set_image is deferred to sam_refine() which runs under @spaces.GPU
 
 
 
 
194
  return video_state["painted_images"][image_selection_slider], video_state, interactive_state
195
 
196
  # set the tracking end frame
 
200
  return video_state["painted_images"][track_pause_number_slider],interactive_state
201
 
202
  # use sam to get the mask
203
+ @spaces.GPU(duration=60)
204
  def sam_refine(video_state, point_prompt, click_state, interactive_state, evt:gr.SelectData):
205
  """
206
  Args:
 
216
  interactive_state["negative_click_times"] += 1
217
 
218
  # prompt for sam model
219
+ ensure_sam_on_cuda()
220
  model.samcontroler.sam_controler.reset_image()
221
  model.samcontroler.sam_controler.set_image(video_state["origin_images"][video_state["select_frame_number"]])
222
  prompt = get_prompt(click_state=click_state, click_input=coordinate)
 
265
  return select_frame
266
 
267
  # image matting
268
+ @spaces.GPU(duration=120)
269
  def image_matting(video_state, interactive_state, mask_dropdown, erode_kernel_size, dilate_kernel_size, refine_iter, model_selection):
270
  # Load model if not already loaded
271
  try:
 
305
  return foreground_output, alpha_output
306
 
307
  # video matting
308
+ @spaces.GPU(duration=300)
309
  def video_matting(video_state, interactive_state, mask_dropdown, erode_kernel_size, dilate_kernel_size, model_selection):
310
  # Load model if not already loaded
311
  try:
 
366
 
367
 
368
  def generate_video_from_frames(frames, output_path, fps=30, gray2rgb=False, audio_path=""):
369
+ frames = np.asarray(frames)
370
+
 
 
 
 
 
 
 
 
371
  if gray2rgb:
372
  frames = np.repeat(frames, 3, axis=3)
373
 
374
+ _, h, w, _ = frames.shape
375
+ h = h // 2 * 2
376
+ w = w // 2 * 2
377
+
378
+ if frames.shape[1] != h or frames.shape[2] != w:
379
+ frames = np.asarray([
380
+ cv2.resize(frame, (w, h), interpolation=cv2.INTER_LINEAR)
381
+ for frame in frames
382
+ ])
383
+
384
  if not os.path.exists(os.path.dirname(output_path)):
385
  os.makedirs(os.path.dirname(output_path))
386
+
387
  video_temp_path = output_path.replace(".mp4", "_temp.mp4")
388
+
389
+ imageio.mimwrite(
390
+ video_temp_path,
391
+ frames,
392
+ fps=fps,
393
+ quality=7,
394
+ codec="libx264",
395
+ macro_block_size=1
396
+ )
397
+
398
  if audio_path != "" and os.path.exists(audio_path):
399
+ output_path = add_audio_to_video(video_temp_path, audio_path, output_path)
400
  os.remove(video_temp_path)
401
  return output_path
402
+ return video_temp_path
 
403
 
404
  # reset all states for a new input
405
  def restart():
 
438
  }
439
  checkpoint_folder = os.path.join('/home/user/app/', 'pretrained_models')
440
 
441
+ # ZeroGPU: do NOT download or load models at module level.
442
+ # All model loading is deferred to the first GPU function call.
443
+ model = None # SAM MaskGenerator — lazily initialized
444
 
 
445
  # Model display names to file names mapping
446
  model_display_to_file = {
447
  "MatAnyone": "matanyone.pth",
 
454
  "matanyone2.pth": "https://github.com/pq-yang/MatAnyone2/releases/download/v1.0.0/matanyone2.pth"
455
  }
456
 
457
+ # MatAnyone model file paths — filled lazily on first download
458
+ model_paths = {}
 
 
 
459
 
460
+ # Cache for loaded MatAnyone models (lazy loading)
461
  loaded_models = {}
462
 
463
+ # All supported models (for the UI) — always show both options
464
+ available_models = ["MatAnyone 2", "MatAnyone"]
465
+ default_model = "MatAnyone 2"
466
+
467
+
468
+ def ensure_sam_loaded():
469
+ """Download SAM checkpoint and init MaskGenerator on CPU (safe to call outside GPU context)."""
470
+ global model
471
+ if model is None:
472
+ sam_checkpoint = load_file_from_url(sam_checkpoint_url_dict[args.sam_model_type], checkpoint_folder)
473
+ # Always load on CPU here — CUDA placement happens in ensure_sam_on_cuda(),
474
+ # which is only ever called from within a @spaces.GPU-decorated function.
475
+ import copy
476
+ cpu_args = copy.copy(args)
477
+ cpu_args.device = "cpu"
478
+ model = MaskGenerator(sam_checkpoint, cpu_args)
479
+
480
+
481
+ def ensure_sam_on_cuda():
482
+ """Move SAM to CUDA. Must only be called inside a @spaces.GPU-decorated function."""
483
+ ensure_sam_loaded()
484
+ cuda_device = "cuda" if torch.cuda.is_available() else "cpu"
485
+ model.samcontroler.sam_controler.predictor.model.to(cuda_device)
486
+ model.samcontroler.sam_controler.device = cuda_device
487
+ model.samcontroler.sam_controler.torch_dtype = torch.float16 if cuda_device == "cuda" else torch.float32
488
+
489
+
490
+ def _ensure_matanyone_downloaded(model_file):
491
+ """Download the MatAnyone checkpoint if not already present."""
492
+ if model_file not in model_paths:
493
+ model_paths[model_file] = load_file_from_url(model_urls[model_file], checkpoint_folder)
494
+ return model_paths[model_file]
495
+
496
+
497
  def load_model(display_name):
498
+ """Download (if needed) and load a MatAnyone model. Cached after first load."""
499
+ # Map display name to file name
500
  if display_name in model_display_to_file:
501
  model_file = model_display_to_file[display_name]
502
+ elif display_name in model_urls:
 
503
  model_file = display_name
504
  else:
505
  raise ValueError(f"Unknown model: {display_name}")
506
+
507
  if model_file in loaded_models:
508
  return loaded_models[model_file]
509
+
510
+ ckpt_path = _ensure_matanyone_downloaded(model_file)
511
+
 
 
 
 
 
512
  # Clear Hydra instance if already initialized (to allow loading different models)
513
  try:
514
  GlobalHydra.instance().clear()
515
+ except Exception:
516
+ pass
517
+
518
+ device = "cuda" if torch.cuda.is_available() else args.device
519
+ print(f"Loading model: {display_name} ({model_file}) on {device}...")
520
+ loaded_mat_model = get_matanyone2_model(ckpt_path, device)
521
+ loaded_mat_model = loaded_mat_model.to(device).eval()
522
+ loaded_models[model_file] = loaded_mat_model
523
  print(f"Model {display_name} loaded successfully.")
524
+ return loaded_mat_model
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
 
526
  # download test samples
527
  test_sample_path = os.path.join('/home/user/app/hugging_face/', "test_sample/")
528
+ load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-0-720p.mp4', test_sample_path)
529
+ load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-1-720p.mp4', test_sample_path)
530
  load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-2-720p.mp4', test_sample_path)
531
  load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-3-720p.mp4', test_sample_path)
532
  load_file_from_url('https://github.com/pq-yang/MatAnyone2/releases/download/media/test-sample-4-720p.mp4', test_sample_path)
 
573
  @InProceedings{yang2025matanyone,
574
  title = {{MatAnyone}: Stable Video Matting with Consistent Memory Propagation},
575
  author = {Yang, Peiqing and Zhou, Shangchen and Zhao, Jixin and Tao, Qingyi and Loy, Chen Change},
576
+ booktitle = {CVPR},
577
  year = {2025}
578
  }
579
  ```
 
643
  text-align: center;
644
  padding: 0;
645
  margin: 0;
646
+ height: 2vh;
647
  width: 80vw;
648
  font-family: "Sarpanch", sans-serif;
649
  font-weight: 60;
 
889
  gr.Markdown("---")
890
  gr.Markdown("## Examples")
891
  gr.Examples(
892
+ examples=[os.path.join(os.path.dirname(__file__), "./test_sample/", test_sample) for test_sample in ["test-sample-0-720p.mp4", "test-sample-1-720p.mp4", "test-sample-2-720p.mp4", "test-sample-3-720p.mp4", "test-sample-4-720p.mp4", "test-sample-5-720p.mp4"]],
893
  inputs=[video_input],
894
  )
895
 
hugging_face/matanyone2_wrapper.py CHANGED
@@ -7,8 +7,6 @@ import random
7
  import cv2
8
  from matanyone2.utils.device import get_default_device, safe_autocast_decorator
9
 
10
- device = get_default_device()
11
-
12
  def gen_dilate(alpha, min_kernel_size, max_kernel_size):
13
  kernel_size = random.randint(min_kernel_size, max_kernel_size)
14
  kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size,kernel_size))
@@ -34,6 +32,7 @@ def matanyone2(processor, frames_np, mask, r_erode=0, r_dilate=0, n_warmup=10):
34
  com: [(H,W,C)]*n, uint8
35
  pha: [(H,W,C)]*n, uint8
36
  """
 
37
 
38
  # print(f'===== [r_erode] {r_erode}; [r_dilate] {r_dilate} =====')
39
  bgr = (np.array([120, 255, 155], dtype=np.float32)/255).reshape((1, 1, 3))
 
7
  import cv2
8
  from matanyone2.utils.device import get_default_device, safe_autocast_decorator
9
 
 
 
10
  def gen_dilate(alpha, min_kernel_size, max_kernel_size):
11
  kernel_size = random.randint(min_kernel_size, max_kernel_size)
12
  kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size,kernel_size))
 
32
  com: [(H,W,C)]*n, uint8
33
  pha: [(H,W,C)]*n, uint8
34
  """
35
+ device = get_default_device()
36
 
37
  # print(f'===== [r_erode] {r_erode}; [r_dilate] {r_dilate} =====')
38
  bgr = (np.array([120, 255, 155], dtype=np.float32)/255).reshape((1, 1, 3))
requirements.txt CHANGED
@@ -1,3 +1,4 @@
 
1
  progressbar2
2
  gdown >= 4.7.1
3
  gitpython >= 3.1
@@ -6,7 +7,7 @@ hickle >= 5.0
6
  tensorboard >= 2.11
7
  numpy >= 1.21
8
  git+https://github.com/facebookresearch/segment-anything.git
9
- gradio==4.31.0
10
  fastapi==0.111.0
11
  pydantic==2.7.1
12
  opencv-python >= 4.8
@@ -33,4 +34,5 @@ pyqtdarktheme
33
  imageio == 2.25.0
34
  imageio[ffmpeg]
35
  ffmpeg-python
36
- safetensors
 
 
1
+ spaces
2
  progressbar2
3
  gdown >= 4.7.1
4
  gitpython >= 3.1
 
7
  tensorboard >= 2.11
8
  numpy >= 1.21
9
  git+https://github.com/facebookresearch/segment-anything.git
10
+ # gradio==4.31.0
11
  fastapi==0.111.0
12
  pydantic==2.7.1
13
  opencv-python >= 4.8
 
34
  imageio == 2.25.0
35
  imageio[ffmpeg]
36
  ffmpeg-python
37
+ safetensors
38
+ huggingface_hub < 1.0