Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -10,7 +10,16 @@ import cv2
|
|
10 |
from pathlib import Path
|
11 |
import tempfile
|
12 |
import imageio
|
13 |
-
from tqdm import tqdm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
# 从环境变量获取密码
|
16 |
APP_USERNAME = "admin" # 用户名保持固定
|
@@ -29,9 +38,12 @@ auth_state = AuthState()
|
|
29 |
|
30 |
def login(username, password):
|
31 |
"""登录验证"""
|
|
|
32 |
if username == APP_USERNAME and password == APP_PASSWORD:
|
33 |
auth_state.is_logged_in = True
|
|
|
34 |
return gr.update(visible=False), gr.update(visible=True), "登录成功"
|
|
|
35 |
return gr.update(visible=True), gr.update(visible=False), "用户名或密码错误"
|
36 |
|
37 |
@spaces.GPU(duration=300)
|
@@ -44,14 +56,20 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
44 |
conf_threshold: 置信度阈值(0-1)
|
45 |
max_det: 每帧最大检测数量
|
46 |
"""
|
|
|
|
|
|
|
47 |
if not auth_state.is_logged_in:
|
|
|
48 |
return None, "请先登录"
|
49 |
|
50 |
# 创建临时目录保存输出视频
|
|
|
51 |
with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp_file:
|
52 |
output_path = tmp_file.name
|
53 |
|
54 |
# 获取视频信息
|
|
|
55 |
cap = cv2.VideoCapture(video_path)
|
56 |
fps = int(cap.get(cv2.CAP_PROP_FPS))
|
57 |
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
@@ -59,6 +77,8 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
59 |
total_frames = int(process_seconds * fps) if process_seconds else int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
60 |
cap.release()
|
61 |
|
|
|
|
|
62 |
# 创建视频写入器
|
63 |
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
64 |
video_writer = cv2.VideoWriter(
|
@@ -72,7 +92,7 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
72 |
base_size = min(width, height)
|
73 |
line_thickness = max(1, int(base_size * 0.002)) # 0.2% 的最小边长
|
74 |
|
75 |
-
|
76 |
results = model.predict(
|
77 |
source=video_path,
|
78 |
device=device,
|
@@ -90,7 +110,7 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
90 |
verbose=False # 关闭YOLO默认日志输出
|
91 |
)
|
92 |
|
93 |
-
|
94 |
frame_count = 0
|
95 |
detection_info = []
|
96 |
all_positions = []
|
@@ -147,6 +167,7 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
147 |
|
148 |
pbar.close() # 关闭进度条
|
149 |
video_writer.release()
|
|
|
150 |
|
151 |
# 生成分析报告
|
152 |
confidences = [float(det['confidence'].strip('%'))/100 for info in detection_info for det in info['detections']]
|
@@ -180,7 +201,7 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
180 |
positions: 位置列表 [[x1,y1], [x2,y2],...]
|
181 |
width: 视频宽度
|
182 |
height: 视频高度
|
183 |
-
max_jump_distance:
|
184 |
"""
|
185 |
if len(positions) < 3:
|
186 |
return positions
|
@@ -315,6 +336,7 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
315 |
frame_heatmap_color = cv2.addWeighted(frame_heatmap_color, 0.7, np.full_like(frame_heatmap_color, 255), 0.3, 0)
|
316 |
heatmap_frames.append(frame_heatmap_color)
|
317 |
|
|
|
318 |
trajectory_gif_path = output_path.replace('.mp4', '_trajectory.gif')
|
319 |
heatmap_gif_path = output_path.replace('.mp4', '_heatmap.gif')
|
320 |
|
@@ -326,6 +348,13 @@ def process_video(video_path, process_seconds=20, conf_threshold=0.2, max_det=8)
|
|
326 |
cv2.imwrite(trajectory_path, trajectory_img)
|
327 |
cv2.imwrite(heatmap_path, heatmap_colored)
|
328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
return output_path, trajectory_path, heatmap_path, trajectory_gif_path, heatmap_gif_path, report
|
330 |
|
331 |
# 创建 Gradio 界面
|
|
|
10 |
from pathlib import Path
|
11 |
import tempfile
|
12 |
import imageio
|
13 |
+
from tqdm import tqdm
|
14 |
+
import logging
|
15 |
+
|
16 |
+
# 新增: 配置logging
|
17 |
+
logging.basicConfig(
|
18 |
+
level=logging.INFO,
|
19 |
+
format='%(asctime)s - %(levelname)s - %(message)s',
|
20 |
+
datefmt='%Y-%m-%d %H:%M:%S'
|
21 |
+
)
|
22 |
+
logger = logging.getLogger(__name__)
|
23 |
|
24 |
# 从环境变量获取密码
|
25 |
APP_USERNAME = "admin" # 用户名保持固定
|
|
|
38 |
|
39 |
def login(username, password):
|
40 |
"""登录验证"""
|
41 |
+
logger.info(f"用户尝试登录: {username}")
|
42 |
if username == APP_USERNAME and password == APP_PASSWORD:
|
43 |
auth_state.is_logged_in = True
|
44 |
+
logger.info("登录成功")
|
45 |
return gr.update(visible=False), gr.update(visible=True), "登录成功"
|
46 |
+
logger.warning("登录失败:用户名或密码错误")
|
47 |
return gr.update(visible=True), gr.update(visible=False), "用户名或密码错误"
|
48 |
|
49 |
@spaces.GPU(duration=300)
|
|
|
56 |
conf_threshold: 置信度阈值(0-1)
|
57 |
max_det: 每帧最大检测数量
|
58 |
"""
|
59 |
+
logger.info(f"开始处理视频: {video_path}")
|
60 |
+
logger.info(f"参数设置 - 处理时长: {process_seconds}秒, 置信度阈值: {conf_threshold}, 最大检测数: {max_det}")
|
61 |
+
|
62 |
if not auth_state.is_logged_in:
|
63 |
+
logger.warning("用户未登录,拒绝访问")
|
64 |
return None, "请先登录"
|
65 |
|
66 |
# 创建临时目录保存输出视频
|
67 |
+
logger.info("创建临时输出目录")
|
68 |
with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp_file:
|
69 |
output_path = tmp_file.name
|
70 |
|
71 |
# 获取视频信息
|
72 |
+
logger.info("读取视频信息")
|
73 |
cap = cv2.VideoCapture(video_path)
|
74 |
fps = int(cap.get(cv2.CAP_PROP_FPS))
|
75 |
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
|
|
77 |
total_frames = int(process_seconds * fps) if process_seconds else int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
78 |
cap.release()
|
79 |
|
80 |
+
logger.info(f"视频信息 - FPS: {fps}, 分辨率: {width}x{height}, 总帧数: {total_frames}")
|
81 |
+
|
82 |
# 创建视频写入器
|
83 |
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
84 |
video_writer = cv2.VideoWriter(
|
|
|
92 |
base_size = min(width, height)
|
93 |
line_thickness = max(1, int(base_size * 0.002)) # 0.2% 的最小边长
|
94 |
|
95 |
+
logger.info("开始YOLO模型推理")
|
96 |
results = model.predict(
|
97 |
source=video_path,
|
98 |
device=device,
|
|
|
110 |
verbose=False # 关闭YOLO默认日志输出
|
111 |
)
|
112 |
|
113 |
+
logger.info("开始处理检测结果")
|
114 |
frame_count = 0
|
115 |
detection_info = []
|
116 |
all_positions = []
|
|
|
167 |
|
168 |
pbar.close() # 关闭进度条
|
169 |
video_writer.release()
|
170 |
+
logger.info(f"视频处理完成,共处理 {frame_count} 帧")
|
171 |
|
172 |
# 生成分析报告
|
173 |
confidences = [float(det['confidence'].strip('%'))/100 for info in detection_info for det in info['detections']]
|
|
|
201 |
positions: 位置列表 [[x1,y1], [x2,y2],...]
|
202 |
width: 视频宽度
|
203 |
height: 视频高度
|
204 |
+
max_jump_distance: 允许��最大跳跃距离
|
205 |
"""
|
206 |
if len(positions) < 3:
|
207 |
return positions
|
|
|
336 |
frame_heatmap_color = cv2.addWeighted(frame_heatmap_color, 0.7, np.full_like(frame_heatmap_color, 255), 0.3, 0)
|
337 |
heatmap_frames.append(frame_heatmap_color)
|
338 |
|
339 |
+
logger.info("开始生成轨迹图和热力图")
|
340 |
trajectory_gif_path = output_path.replace('.mp4', '_trajectory.gif')
|
341 |
heatmap_gif_path = output_path.replace('.mp4', '_heatmap.gif')
|
342 |
|
|
|
348 |
cv2.imwrite(trajectory_path, trajectory_img)
|
349 |
cv2.imwrite(heatmap_path, heatmap_colored)
|
350 |
|
351 |
+
logger.info("轨迹图和热力图生成完成")
|
352 |
+
logger.info("开始生成GIF动画")
|
353 |
+
imageio.mimsave(trajectory_gif_path, trajectory_frames, duration=50)
|
354 |
+
imageio.mimsave(heatmap_gif_path, heatmap_frames, duration=50)
|
355 |
+
logger.info("GIF动画生成完成")
|
356 |
+
|
357 |
+
logger.info("所有处理完成,准备返回结果")
|
358 |
return output_path, trajectory_path, heatmap_path, trajectory_gif_path, heatmap_gif_path, report
|
359 |
|
360 |
# 创建 Gradio 界面
|