John2J commited on
Commit
dd90a45
·
verified ·
1 Parent(s): 87692a7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -0
app.py CHANGED
@@ -156,6 +156,51 @@ def clear_clicks(video_state):
156
  video_state["painted_images"] = None
157
  return Image.fromarray(video_state["origin_images"][0]) if video_state["origin_images"] is not None else None
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
  def preprocess_for_removal(images, masks):
161
  out_images = []
@@ -402,6 +447,16 @@ with gr.Blocks() as demo:
402
  inputs=[dilation_slider, inference_steps_slider, video_state],
403
  outputs=remove_video
404
  )
 
 
 
 
 
 
 
 
 
 
405
  get_info_btn.click(get_video_info, inputs=[video_input, video_state], \
406
  outputs=image_output)
407
  image_output.select(fn=segment_frame, inputs=[point_prompt, video_state], outputs=image_output)
 
156
  video_state["painted_images"] = None
157
  return Image.fromarray(video_state["origin_images"][0]) if video_state["origin_images"] is not None else None
158
 
159
+
160
+ def load_uploaded_mask_video(video_path, mask_video_path, n_frames, video_state):
161
+ """Load a user-supplied mask video (white = object) and use it directly,
162
+ skipping click segmentation and SAM2 tracking."""
163
+ src = video_state["video_path"] or video_path
164
+ if mask_video_path is None or src is None:
165
+ return video_state, None
166
+
167
+ # --- load source frames (same logic as track_video) ---
168
+ vr = VideoReader(src, ctx=cpu(0))
169
+ images = [vr[i].asnumpy() for i in range(min(len(vr), int(n_frames)))]
170
+ del vr
171
+
172
+ if images[0].shape[0] > images[0].shape[1]:
173
+ W_ = W
174
+ H_ = int(W_ * images[0].shape[0] / images[0].shape[1])
175
+ else:
176
+ H_ = H
177
+ W_ = int(H_ * images[0].shape[1] / images[0].shape[0])
178
+ images = [cv2.resize(img, (W_, H_)) for img in images]
179
+ video_state["origin_images"] = images
180
+
181
+ # --- load mask frames ---
182
+ mvr = VideoReader(mask_video_path, ctx=cpu(0))
183
+ mask_frames = []
184
+ for i in range(min(len(mvr), len(images))):
185
+ m = mvr[i].asnumpy()
186
+ if m.ndim == 3:
187
+ m = cv2.cvtColor(m, cv2.COLOR_RGB2GRAY)
188
+ m = cv2.resize(m, (W_, H_), interpolation=cv2.INTER_NEAREST)
189
+ m = (m > 127).astype(np.float32)
190
+ # match the (H_, W_, 3) shape that track_video produces
191
+ mask_frames.append(np.repeat(m[..., None], 3, axis=2))
192
+ del mvr
193
+
194
+ while len(mask_frames) < len(images): # pad if mask video is shorter
195
+ mask_frames.append(mask_frames[-1].copy())
196
+ video_state["masks"] = mask_frames
197
+
198
+ # preview: overlay first mask on first frame
199
+ color = np.array(COLOR_PALETTE[0], dtype=np.float32) / 255.0
200
+ frame = images[0].astype(np.float32) / 255.0
201
+ painted = (1 - mask_frames[0] * 0.5) * frame + mask_frames[0] * 0.5 * color
202
+ preview = np.uint8(np.clip(painted * 255, 0, 255))
203
+ return video_state, Image.fromarray(preview)
204
 
205
  def preprocess_for_removal(images, masks):
206
  out_images = []
 
447
  inputs=[dilation_slider, inference_steps_slider, video_state],
448
  outputs=remove_video
449
  )
450
+
451
+ mask_video_input = gr.Video(label="(Optional) Upload Mask Video — white = object to remove")
452
+ use_mask_btn = gr.Button("Use Uploaded Mask (skips clicking & tracking)", elem_id="my-btn")
453
+
454
+ use_mask_btn.click(
455
+ load_uploaded_mask_video,
456
+ inputs=[video_input, mask_video_input, n_frames_slider, video_state],
457
+ outputs=[video_state, image_output],
458
+ )
459
+
460
  get_info_btn.click(get_video_info, inputs=[video_input, video_state], \
461
  outputs=image_output)
462
  image_output.select(fn=segment_frame, inputs=[point_prompt, video_state], outputs=image_output)