embed images

This commit is contained in:
Mariano Gabriel
2025-10-28 08:02:45 -03:00
parent b1e1daf278
commit 118ef04223
12 changed files with 1016 additions and 61 deletions

View File

@@ -16,17 +16,19 @@ logger = logging.getLogger(__name__)
class FrameExtractor:
"""Extract frames from video files."""
def __init__(self, video_path: str, output_dir: str = "frames"):
def __init__(self, video_path: str, output_dir: str = "frames", quality: int = 75):
"""
Initialize frame extractor.
Args:
video_path: Path to video file
output_dir: Directory to save extracted frames
quality: JPEG quality for saved frames (0-100)
"""
self.video_path = video_path
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.quality = quality
def extract_by_interval(self, interval_seconds: int = 5) -> List[Tuple[str, float]]:
"""
@@ -56,8 +58,16 @@ class FrameExtractor:
frame_filename = f"frame_{saved_count:05d}_{timestamp:.2f}s.jpg"
frame_path = self.output_dir / frame_filename
# Use high quality for text readability (95 = high quality JPEG)
cv2.imwrite(str(frame_path), frame, [cv2.IMWRITE_JPEG_QUALITY, 95])
# Downscale to 1600px width for smaller file size (but still readable)
height, width = frame.shape[:2]
if width > 1600:
ratio = 1600 / width
new_width = 1600
new_height = int(height * ratio)
frame = cv2.resize(frame, (new_width, new_height), interpolation=cv2.INTER_LANCZOS4)
# Save with configured quality (matches embed quality)
cv2.imwrite(str(frame_path), frame, [cv2.IMWRITE_JPEG_QUALITY, self.quality])
frames_info.append((str(frame_path), timestamp))
saved_count += 1
@@ -90,16 +100,24 @@ class FrameExtractor:
output_pattern = self.output_dir / f"{video_name}_%05d.jpg"
try:
# Use FFmpeg's scene detection filter with high quality output
# Use FFmpeg's scene detection filter with downscaling
stream = ffmpeg.input(self.video_path)
stream = ffmpeg.filter(stream, 'select', f'gt(scene,{threshold/100})')
stream = ffmpeg.filter(stream, 'showinfo')
# Scale to 1600px width (maintains aspect ratio, still readable)
# Use simple conditional: if width > 1600, scale to 1600, else keep original
stream = ffmpeg.filter(stream, 'scale', w='min(1600,iw)', h=-1)
# Convert JPEG quality (0-100) to FFmpeg qscale (2-31, lower=better)
# Rough mapping: qscale ≈ (100 - quality) / 10, clamped to 2-31
qscale = max(2, min(31, int((100 - self.quality) / 10 + 2)))
stream = ffmpeg.output(
stream,
str(output_pattern),
vsync='vfr',
frame_pts=1,
**{'q:v': '2'} # High quality JPEG
**{'q:v': str(qscale)} # Matches configured quality
)
# Run with stderr capture to get showinfo output