File size: 4,057 Bytes
91fb4ef
 
 
 
64a70c0
91fb4ef
64a70c0
 
91fb4ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import cv2
import numpy as np
from pathlib import Path
import subprocess
from typing import Any, Optional, Dict, List, Union, Tuple


def detect_black_bars(video_path: Path) -> Tuple[int, int, int, int]:
    """Detect black bars in video by analyzing first few frames
    
    Args:
        video_path: Path to video file
        
    Returns:
        Tuple of (top, bottom, left, right) crop values
    """
    cap = cv2.VideoCapture(str(video_path))
    if not cap.isOpened():
        raise ValueError(f"Could not open video: {video_path}")
    
    # Read first few frames to get stable detection
    frames_to_check = 5
    frames = []
    
    for _ in range(frames_to_check):
        ret, frame = cap.read()
        if not ret:
            break
        frames.append(frame)
    
    cap.release()
    
    if not frames:
        raise ValueError("Could not read any frames from video")
    
    # Convert frames to grayscale and find average
    gray_frames = [cv2.cvtColor(f, cv2.COLOR_BGR2GRAY) for f in frames]
    avg_frame = np.mean(gray_frames, axis=0)
    
    # Threshold to detect black regions (adjust sensitivity if needed)
    threshold = 20
    black_mask = avg_frame < threshold
    
    # Find black bars by analyzing row/column means
    row_means = np.mean(black_mask, axis=1)
    col_means = np.mean(black_mask, axis=0)
    
    # Detect edges where black bars end (using high threshold to avoid false positives)
    black_threshold = 0.95  # 95% of pixels in row/col must be black
    
    # Find top and bottom crops
    top_crop = 0
    bottom_crop = black_mask.shape[0]
    
    for i, mean in enumerate(row_means):
        if mean > black_threshold:
            top_crop = i + 1
        else:
            break
            
    for i, mean in enumerate(reversed(row_means)):
        if mean > black_threshold:
            bottom_crop = black_mask.shape[0] - i - 1
        else:
            break
    
    # Find left and right crops
    left_crop = 0
    right_crop = black_mask.shape[1]
    
    for i, mean in enumerate(col_means):
        if mean > black_threshold:
            left_crop = i + 1
        else:
            break
            
    for i, mean in enumerate(reversed(col_means)):
        if mean > black_threshold:
            right_crop = black_mask.shape[1] - i - 1
        else:
            break
    
    return top_crop, bottom_crop, left_crop, right_crop

def remove_black_bars(input_path: Path, output_path: Path) -> bool:
    """Remove black bars from video using FFmpeg
    
    Args:
        input_path: Path to input video
        output_path: Path to save processed video
        
    Returns:
        bool: True if successful, False if no cropping needed
    """
    try:
        # Detect black bars
        top, bottom, left, right = detect_black_bars(input_path)
        
        # Get video dimensions using OpenCV
        cap = cv2.VideoCapture(str(input_path))
        if not cap.isOpened():
            raise ValueError(f"Could not open video: {input_path}")
        
        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        cap.release()
        
        # If no significant black bars detected, return False
        if top < 10 and bottom > height - 10 and \
           left < 10 and right > width - 10:
            return False
        
        # Calculate crop dimensions
        crop_height = bottom - top
        crop_width = right - left
        
        if crop_height <= 0 or crop_width <= 0:
            return False
        
        # Use FFmpeg to crop and save video
        cmd = [
            'ffmpeg', '-i', str(input_path),
            '-vf', f'crop={crop_width}:{crop_height}:{left}:{top}',
            '-c:a', 'copy',  # Copy audio stream
            '-y',  # Overwrite output
            str(output_path)
        ]
        
        subprocess.run(cmd, check=True, capture_output=True)
        return True
        
    except Exception as e:
        print(f"Error removing black bars: {e}")
        return False