goryhon commited on
Commit
666d1b2
·
verified ·
1 Parent(s): 57e7ee5

Update web-demos/hugging_face/app.py

Browse files
Files changed (1) hide show
  1. web-demos/hugging_face/app.py +67 -49
web-demos/hugging_face/app.py CHANGED
@@ -2,6 +2,7 @@ import sys
2
  sys.path.append("../../")
3
 
4
  import os
 
5
  os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
6
  import json
7
  import time
@@ -67,72 +68,89 @@ def get_prompt(click_state, click_input):
67
 
68
  def get_frames_from_video(video_input, video_state):
69
  """
70
- Args:
71
- video_path:str
72
- timestamp:float64
73
- Return
74
- [[0:nearest_frame], [nearest_frame:], nearest_frame]
75
  """
76
  video_path = video_input
77
  frames = []
78
  user_name = time.time()
79
  status_ok = True
80
  operation_log = [("[Must Do]", "Click image"), (": Video uploaded! Try to click the image shown in step2 to add masks.\n", None)]
 
 
 
 
 
81
  try:
82
- cap = cv2.VideoCapture(video_path)
83
- fps = cap.get(cv2.CAP_PROP_FPS)
84
- length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
85
-
86
- if length >= 600:
87
- operation_log = [("You uploaded a video with more than 500 frames. Stop the video extraction. Kindly lower the video frame rate to a value below 500. We highly recommend deploying the demo locally for long video processing.", "Error")]
88
- ret, frame = cap.read()
89
- if ret == True:
90
- original_h, original_w = frame.shape[:2]
91
- frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  status_ok = False
93
- else:
94
- while cap.isOpened():
95
- ret, frame = cap.read()
96
- if ret == True:
97
- # resize input image
98
- original_h, original_w = frame.shape[:2]
99
- frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
100
- else:
101
- break
102
- t = len(frames)
103
- if t > 0:
104
- print(f'Inp video shape: t_{t}, s_{original_h}x{original_w}')
105
- else:
106
- print(f'Inp video shape: t_{t}, no input video!!!')
107
- except (OSError, TypeError, ValueError, KeyError, SyntaxError) as e:
108
  status_ok = False
109
- print("read_frame_source:{} error. {}\n".format(video_path, str(e)))
110
-
111
- # initialize video_state
112
  if frames[0].shape[0] > 720 or frames[0].shape[1] > 720:
113
- operation_log = [(f"Video uploaded! Try to click the image shown in step2 to add masks. (You uploaded a video with a size of {original_w}x{original_h}, and the length of its longest edge exceeds 720 pixels. We may resize the input video during processing.)", "Normal")]
114
 
115
  video_state = {
116
  "user_name": user_name,
117
- "video_name": os.path.split(video_path)[-1],
118
  "origin_images": frames,
119
  "painted_images": frames.copy(),
120
- "masks": [np.zeros((original_h, original_w), np.uint8)]*len(frames),
121
- "logits": [None]*len(frames),
122
  "select_frame_number": 0,
123
  "fps": fps
124
- }
125
- video_info = "Video Name: {},\nFPS: {},\nTotal Frames: {},\nImage Size:{}".format(video_state["video_name"], round(video_state["fps"], 0), length, (original_w, original_h))
126
- model.samcontroler.sam_controler.reset_image()
127
- model.samcontroler.sam_controler.set_image(video_state["origin_images"][0])
128
- return video_state, video_info, video_state["origin_images"][0], gr.update(visible=status_ok, maximum=len(frames), value=1), gr.update(visible=status_ok, maximum=len(frames), value=len(frames)), \
129
- gr.update(visible=status_ok), gr.update(visible=status_ok), \
130
- gr.update(visible=status_ok), gr.update(visible=status_ok),\
131
- gr.update(visible=status_ok), gr.update(visible=status_ok), \
132
- gr.update(visible=status_ok), gr.update(visible=status_ok), \
133
- gr.update(visible=status_ok), gr.update(visible=status_ok), \
134
- gr.update(visible=status_ok), gr.update(visible=status_ok, choices=[], value=[]), \
135
- gr.update(visible=True, value=operation_log), gr.update(visible=status_ok, value=operation_log)
 
 
 
 
136
 
137
  def select_template(image_selection_slider, video_state, interactive_state, mask_dropdown):
138
 
 
2
  sys.path.append("../../")
3
 
4
  import os
5
+ import subprocess
6
  os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
7
  import json
8
  import time
 
68
 
69
  def get_frames_from_video(video_input, video_state):
70
  """
71
+ Извлечение кадров без потерь через ffmpeg (16-битные RGB кадры).
 
 
 
 
72
  """
73
  video_path = video_input
74
  frames = []
75
  user_name = time.time()
76
  status_ok = True
77
  operation_log = [("[Must Do]", "Click image"), (": Video uploaded! Try to click the image shown in step2 to add masks.\n", None)]
78
+
79
+ output_dir = f"/tmp/frames_{user_name}"
80
+ os.makedirs(output_dir, exist_ok=True)
81
+ output_pattern = os.path.join(output_dir, "frame_%05d.tiff")
82
+
83
  try:
84
+ # Извлекаем 16-битные RGB кадры
85
+ cmd = [
86
+ "ffmpeg", "-y", "-i", video_path,
87
+ "-pix_fmt", "rgb48le", # 16-бит на канал
88
+ output_pattern
89
+ ]
90
+ subprocess.run(cmd, check=True)
91
+
92
+ # Загружаем изображения
93
+ frame_files = sorted(f for f in os.listdir(output_dir) if f.endswith(".tiff"))
94
+ for frame_name in frame_files:
95
+ image = Image.open(os.path.join(output_dir, frame_name))
96
+ frames.append(np.array(image))
97
+
98
+ if not frames:
99
+ raise RuntimeError("Не удалось извлечь кадры.")
100
+
101
+ original_h, original_w = frames[0].shape[:2]
102
+
103
+ # Определим fps через ffprobe
104
+ try:
105
+ result = subprocess.run(
106
+ ["ffprobe", "-v", "error", "-select_streams", "v:0",
107
+ "-show_entries", "stream=r_frame_rate", "-of", "default=noprint_wrappers=1:nokey=1",
108
+ video_path],
109
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT
110
+ )
111
+ fps_expr = result.stdout.decode().strip()
112
+ num, denom = map(int, fps_expr.split('/'))
113
+ fps = num / denom
114
+ except:
115
+ fps = 24 # fallback
116
+
117
+ if len(frames) >= 600:
118
+ operation_log = [("Видео содержит более 500 кадров. Обработка остановлена. Запустите локально.", "Error")]
119
  status_ok = False
120
+
121
+ except Exception as e:
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  status_ok = False
123
+ operation_log = [(f"[Ошибка] Не удалось извлечь кадры: {e}", "Error")]
124
+ return None, None, None, *[gr.update(visible=False)] * 16, gr.update(visible=True, value=operation_log), gr.update(visible=False, value=operation_log)
125
+
126
  if frames[0].shape[0] > 720 or frames[0].shape[1] > 720:
127
+ operation_log = [(f"Видео размером {original_w}x{original_h}. Возможно будет ресайз при обработке.", "Normal")]
128
 
129
  video_state = {
130
  "user_name": user_name,
131
+ "video_name": os.path.basename(video_path),
132
  "origin_images": frames,
133
  "painted_images": frames.copy(),
134
+ "masks": [np.zeros((original_h, original_w), np.uint8)] * len(frames),
135
+ "logits": [None] * len(frames),
136
  "select_frame_number": 0,
137
  "fps": fps
138
+ }
139
+
140
+ video_info = f"Video Name: {video_state['video_name']},\nFPS: {round(fps, 0)},\nTotal Frames: {len(frames)},\nImage Size: {original_w}x{original_h}"
141
+
142
+ # SAM-подгрузка не удаляй, если используется
143
+ model.samcontroler.sam_controler.reset_image()
144
+ model.samcontroler.sam_controler.set_image(frames[0])
145
+
146
+ return video_state, video_info, frames[0], \
147
+ gr.update(visible=status_ok, maximum=len(frames), value=1), \
148
+ gr.update(visible=status_ok, maximum=len(frames), value=len(frames)), \
149
+ *[gr.update(visible=status_ok) for _ in range(14)], \
150
+ gr.update(visible=status_ok, choices=[], value=[]), \
151
+ gr.update(visible=True, value=operation_log), \
152
+ gr.update(visible=status_ok, value=operation_log)
153
+
154
 
155
  def select_template(image_selection_slider, video_state, interactive_state, mask_dropdown):
156