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

Update web-demos/hugging_face/app.py

Browse files
Files changed (1) hide show
  1. web-demos/hugging_face/app.py +59 -54
web-demos/hugging_face/app.py CHANGED
@@ -16,6 +16,7 @@ import numpy as np
16
  import gradio as gr
17
  from gradio import Brush
18
  import tempfile
 
19
  import ffmpeg
20
  from PIL import Image
21
  from tools.painter import mask_painter
@@ -66,91 +67,95 @@ def get_prompt(click_state, click_input):
66
 
67
  # extract frames from upload video
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
 
 
16
  import gradio as gr
17
  from gradio import Brush
18
  import tempfile
19
+ import glob
20
  import ffmpeg
21
  from PIL import Image
22
  from tools.painter import mask_painter
 
67
 
68
  # extract frames from upload video
69
 
70
+ import os
71
+ import time
72
+ import subprocess
73
+ import glob
74
+ import numpy as np
75
+ from PIL import Image
76
+ import gradio as gr
77
+
78
  def get_frames_from_video(video_input, video_state):
79
  """
80
+ Извлечение кадров из видео без потерь (16-битный RGB).
81
  """
 
82
  frames = []
83
  user_name = time.time()
84
  status_ok = True
85
  operation_log = [("[Must Do]", "Click image"), (": Video uploaded! Try to click the image shown in step2 to add masks.\n", None)]
86
 
 
 
 
 
87
  try:
88
+ # Папка под кадры
89
+ temp_output_dir = f"/tmp/frames_{user_name}"
90
+ os.makedirs(temp_output_dir, exist_ok=True)
91
+
92
+ # Извлечение кадров без сжатия (TIFF 16 бит, RGB)
93
+ command = [
94
+ "ffmpeg", "-i", video_input,
95
+ "-pix_fmt", "rgb48le",
96
+ os.path.join(temp_output_dir, "frame_%05d.tiff")
97
  ]
98
+ subprocess.run(command, check=True)
99
+
100
+ # Получаем пути к кадрам
101
+ frame_paths = sorted(glob.glob(os.path.join(temp_output_dir, "frame_*.tiff")))
102
+ if len(frame_paths) == 0:
103
+ raise RuntimeError("ffmpeg failed to extract frames or no frames found.")
104
 
105
+ for path in frame_paths:
106
+ image = Image.open(path)
 
 
107
  frames.append(np.array(image))
108
 
109
+ # Получение FPS через ffprobe
110
+ fps_cmd = [
111
+ "ffprobe", "-v", "error", "-select_streams", "v:0",
112
+ "-show_entries", "stream=r_frame_rate",
113
+ "-of", "default=noprint_wrappers=1:nokey=1", video_input
114
+ ]
115
+ fps_raw = subprocess.check_output(fps_cmd).decode().strip()
116
+ num, den = map(int, fps_raw.split("/")) if "/" in fps_raw else (int(fps_raw), 1)
117
+ fps = num / den
118
 
119
  original_h, original_w = frames[0].shape[:2]
120
+ length = len(frames)
121
 
122
+ if length >= 600:
123
+ 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.", "Error")]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  status_ok = False
125
 
126
  except Exception as e:
127
+ print(f"[FFmpeg ERROR]: {e}")
128
  status_ok = False
129
+ return None
 
 
 
 
130
 
131
+ # Собираем состояние
132
  video_state = {
133
  "user_name": user_name,
134
+ "video_name": os.path.basename(video_input),
135
  "origin_images": frames,
136
  "painted_images": frames.copy(),
137
+ "masks": [np.zeros((original_h, original_w), np.uint8)] * length,
138
+ "logits": [None] * length,
139
  "select_frame_number": 0,
140
  "fps": fps
141
  }
142
 
143
+ video_info = f"Video Name: {video_state['video_name']},\nFPS: {round(video_state['fps'], 0)},\nTotal Frames: {length},\nImage Size: {(original_w, original_h)}"
144
 
 
145
  model.samcontroler.sam_controler.reset_image()
146
+ model.samcontroler.sam_controler.set_image(video_state["origin_images"][0])
147
+
148
+ return video_state, video_info, video_state["origin_images"][0], \
149
+ gr.update(visible=status_ok, maximum=length, value=1), \
150
+ gr.update(visible=status_ok, maximum=length, value=length), \
151
+ gr.update(visible=status_ok), gr.update(visible=status_ok), \
152
+ gr.update(visible=status_ok), gr.update(visible=status_ok), \
153
+ gr.update(visible=status_ok), gr.update(visible=status_ok), \
154
+ gr.update(visible=status_ok), gr.update(visible=status_ok), \
155
+ gr.update(visible=status_ok), gr.update(visible=status_ok), \
156
+ gr.update(visible=status_ok), gr.update(visible=status_ok, choices=[], value=[]), \
157
+ gr.update(visible=True, value=operation_log), \
158
+ gr.update(visible=status_ok, value=operation_log)
159
 
160
  def select_template(image_selection_slider, video_state, interactive_state, mask_dropdown):
161