John2J commited on
Commit
3a7187f
·
verified ·
1 Parent(s): 0ea1fc6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -13
app.py CHANGED
@@ -36,6 +36,57 @@ def filter_kwargs(cls, kwargs):
36
  valid_params = set(sig.parameters.keys()) - {'self', 'cls'}
37
  return {k: v for k, v in kwargs.items() if k in valid_params}
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  from huggingface_hub import snapshot_download
40
 
41
  def download_component_subfolder(repo_id, subfolder):
@@ -128,7 +179,7 @@ def get_prompt(click_state, click_input):
128
 
129
  @spaces.GPU
130
  # extract frames from upload video
131
- def get_frames_from_video(video_input, video_state):
132
  """
133
  Args:
134
  video_path:str
@@ -348,9 +399,11 @@ def inpaint_video(video_state, *_):
348
  # import pdb;pdb.set_trace()
349
  frames = video_state["origin_images"]
350
  masks = video_state["masks"]
351
- # masks = masks * 255
352
  fps = int(video_state["fps"])
353
 
 
 
 
354
  total_frames = len(frames)
355
  target_frame_count = (total_frames - 1) // 16 * 16 + 1
356
  frames = frames[:target_frame_count]
@@ -456,7 +509,7 @@ description = r"""
456
  <center></center>
457
  <b>Official Gradio demo</b> for <a href='https://github.com/Kunbyte-AI/ROSE' target='_blank'><b>Remove Objects with Side Effects in Videos</b></a>.<br>
458
  🔥 ROSE is a robust inpainting algorithm.<br>
459
- 🤗 Try to drop your video, add the masks and get the the inpainting results!<br>
460
  """
461
 
462
  css = """
@@ -518,9 +571,21 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as iface:
518
  # input video
519
  gr.Markdown("## Step1: Upload video")
520
  with gr.Row(equal_height=True):
521
- with gr.Column(scale=2):
522
- video_input = gr.Video(elem_classes="video")
523
- extract_frames_button = gr.Button(value="Get video info", interactive=True, variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
524
  with gr.Column(scale=2):
525
  run_status = gr.HighlightedText(value=[("",""), ("Try to upload your video and click the Get video info button to get started!", "Normal")],
526
  color_map={"Normal": "green", "Error": "red", "Clear clicks": "gray", "Add mask": "green", "Remove mask": "red"})
@@ -553,20 +618,20 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as iface:
553
  mask_dropdown = gr.Dropdown(multiselect=True, value=[], label="Mask selection", info=".", visible=False)
554
 
555
  # output video
556
- step3_title = gr.Markdown("---\n## Step3: Track masks and get the inpainting result", visible=False)
557
  with gr.Row(equal_height=True):
558
  with gr.Column(scale=2):
559
  tracking_video_output = gr.Video(visible=False, elem_classes="video")
560
- tracking_video_predict_button = gr.Button(value="1. Tracking", visible=False, elem_classes="margin_center")
561
  with gr.Column(scale=2):
562
  inpaiting_video_output = gr.Video(visible=False, elem_classes="video")
563
- inpaint_video_predict_button = gr.Button(value="2. Inpainting", visible=False, elem_classes="margin_center")
564
 
565
  # first step: get the video information
566
  extract_frames_button.click(
567
  fn=get_frames_from_video,
568
  inputs=[
569
- video_input, video_state
570
  ],
571
  outputs=[video_state, video_info, template_frame,
572
  image_selection_slider, track_pause_number_slider,point_prompt, clear_button_click, Add_mask_button, template_frame,
@@ -608,14 +673,14 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as iface:
608
  outputs=[tracking_video_output, video_state, interactive_state, run_status, run_status2]
609
  )
610
 
611
- # inpaint video from select image and mask
612
  inpaint_video_predict_button.click(
613
  fn=inpaint_video,
614
- #inputs=[video_state, resize_ratio_number, dilate_radius_number, raft_iter_number, subvideo_length_number, neighbor_length_number, ref_stride_number, mask_dropdown],
615
- inputs=[video_state, mask_dropdown],
616
  outputs=[inpaiting_video_output, run_status, run_status2]
617
  )
618
 
 
619
  # click to get mask
620
  mask_dropdown.change(
621
  fn=show_mask,
 
36
  valid_params = set(sig.parameters.keys()) - {'self', 'cls'}
37
  return {k: v for k, v in kwargs.items() if k in valid_params}
38
 
39
+
40
+ def load_mask_video(mask_video_path, target_frame_count, target_size, target_fps):
41
+ """
42
+ Load a user-supplied mask video.
43
+
44
+ Convention:
45
+ - white / bright pixels = area to inpaint
46
+ - black pixels = keep unchanged
47
+ - grayscale masks are supported
48
+ - the mask video is resized to the source video's resolution
49
+ - if the mask has fewer frames than the source, an error is raised
50
+ """
51
+ if not mask_video_path:
52
+ return None
53
+
54
+ cap = cv2.VideoCapture(mask_video_path)
55
+ if not cap.isOpened():
56
+ raise ValueError(f"Could not open mask video: {mask_video_path}")
57
+
58
+ masks = []
59
+ while True:
60
+ ret, frame = cap.read()
61
+ if not ret:
62
+ break
63
+
64
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
65
+ if (gray.shape[1], gray.shape[0]) != target_size:
66
+ gray = cv2.resize(
67
+ gray,
68
+ target_size,
69
+ interpolation=cv2.INTER_NEAREST
70
+ )
71
+
72
+ # Normalize to a binary mask. Any non-black pixel is treated as masked.
73
+ mask = (gray > 127).astype(np.uint8)
74
+ masks.append(mask)
75
+
76
+ cap.release()
77
+
78
+ if not masks:
79
+ raise ValueError("The supplied mask video contains no readable frames.")
80
+
81
+ if len(masks) < target_frame_count:
82
+ raise ValueError(
83
+ f"Mask video has {len(masks)} frames, but the source video has "
84
+ f"{target_frame_count} frames."
85
+ )
86
+
87
+ # Extra mask frames are ignored so both videos stay aligned.
88
+ return masks[:target_frame_count]
89
+
90
  from huggingface_hub import snapshot_download
91
 
92
  def download_component_subfolder(repo_id, subfolder):
 
179
 
180
  @spaces.GPU
181
  # extract frames from upload video
182
+ def get_frames_from_video(video_input, mask_video_input, video_state):
183
  """
184
  Args:
185
  video_path:str
 
399
  # import pdb;pdb.set_trace()
400
  frames = video_state["origin_images"]
401
  masks = video_state["masks"]
 
402
  fps = int(video_state["fps"])
403
 
404
+ if masks is None or len(masks) != len(frames):
405
+ raise gr.Error("Mask video is missing or does not match the source video frame count.")
406
+
407
  total_frames = len(frames)
408
  target_frame_count = (total_frames - 1) // 16 * 16 + 1
409
  frames = frames[:target_frame_count]
 
509
  <center></center>
510
  <b>Official Gradio demo</b> for <a href='https://github.com/Kunbyte-AI/ROSE' target='_blank'><b>Remove Objects with Side Effects in Videos</b></a>.<br>
511
  🔥 ROSE is a robust inpainting algorithm.<br>
512
+ 🤗 Drop your source video and, optionally, a pre-made mask video, then get the inpainting result!<br>
513
  """
514
 
515
  css = """
 
571
  # input video
572
  gr.Markdown("## Step1: Upload video")
573
  with gr.Row(equal_height=True):
574
+ with gr.Column(scale=2):
575
+ video_input = gr.Video(label="Source video", elem_classes="video")
576
+ mask_video_input = gr.Video(
577
+ label="Mask video (optional)",
578
+ elem_classes="video"
579
+ )
580
+ gr.Markdown(
581
+ "**Mask convention:** white = remove/inpaint, black = keep. "
582
+ "The mask video must be frame-aligned with the source video."
583
+ )
584
+ extract_frames_button = gr.Button(
585
+ value="Get video info",
586
+ interactive=True,
587
+ variant="primary"
588
+ )
589
  with gr.Column(scale=2):
590
  run_status = gr.HighlightedText(value=[("",""), ("Try to upload your video and click the Get video info button to get started!", "Normal")],
591
  color_map={"Normal": "green", "Error": "red", "Clear clicks": "gray", "Add mask": "green", "Remove mask": "red"})
 
618
  mask_dropdown = gr.Dropdown(multiselect=True, value=[], label="Mask selection", info=".", visible=False)
619
 
620
  # output video
621
+ step3_title = gr.Markdown("---\n## Step3: Get the inpainting result", visible=False)
622
  with gr.Row(equal_height=True):
623
  with gr.Column(scale=2):
624
  tracking_video_output = gr.Video(visible=False, elem_classes="video")
625
+ tracking_video_predict_button = gr.Button(value="1. Tracking (optional)", visible=False, elem_classes="margin_center")
626
  with gr.Column(scale=2):
627
  inpaiting_video_output = gr.Video(visible=False, elem_classes="video")
628
+ inpaint_video_predict_button = gr.Button(value="Inpainting", visible=False, elem_classes="margin_center")
629
 
630
  # first step: get the video information
631
  extract_frames_button.click(
632
  fn=get_frames_from_video,
633
  inputs=[
634
+ video_input, mask_video_input, video_state
635
  ],
636
  outputs=[video_state, video_info, template_frame,
637
  image_selection_slider, track_pause_number_slider,point_prompt, clear_button_click, Add_mask_button, template_frame,
 
673
  outputs=[tracking_video_output, video_state, interactive_state, run_status, run_status2]
674
  )
675
 
676
+ # inpaint directly from the supplied mask video
677
  inpaint_video_predict_button.click(
678
  fn=inpaint_video,
679
+ inputs=[video_state],
 
680
  outputs=[inpaiting_video_output, run_status, run_status2]
681
  )
682
 
683
+
684
  # click to get mask
685
  mask_dropdown.change(
686
  fn=show_mask,