# -*- coding: utf-8 -*-
|
import logging
|
import subprocess
|
from typing import Optional, Tuple
|
|
import cv2
|
import numpy as np
|
|
from app.video_io import get_ffmpeg_cmd
|
|
logger = logging.getLogger(__name__)
|
|
|
def laplacian_score(image_path: str) -> float:
|
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
|
if img is None:
|
return 0.0
|
return float(cv2.Laplacian(img, cv2.CV_64F).var())
|
|
|
def refine_time_in_window(
|
video_path: str,
|
center_sec: float,
|
window_sec: float = 2.0,
|
step: float = 0.5,
|
) -> Tuple[float, float]:
|
"""在 [center-window, center+window] 内选清晰度最高帧,返回 (best_sec, score)。"""
|
import os
|
import tempfile
|
|
best_t = center_sec
|
best_score = 0.0
|
ffmpeg = get_ffmpeg_cmd("ffmpeg")
|
t = max(0.0, center_sec - window_sec)
|
end = center_sec + window_sec
|
tmp = tempfile.NamedTemporaryFile(suffix=".jpg", delete=False)
|
tmp.close()
|
try:
|
while t <= end:
|
cmd = [
|
ffmpeg, "-y", "-ss", f"{t:.3f}", "-i", video_path,
|
"-frames:v", "1", "-q:v", "2", tmp.name,
|
]
|
subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
if os.path.isfile(tmp.name) and os.path.getsize(tmp.name) > 0:
|
score = laplacian_score(tmp.name)
|
if score > best_score:
|
best_score = score
|
best_t = t
|
t += step
|
finally:
|
if os.path.isfile(tmp.name):
|
os.remove(tmp.name)
|
return round(best_t, 2), best_score
|