80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
import subprocess
|
|
import re
|
|
import sys
|
|
import json
|
|
from collections import Counter
|
|
|
|
def detect_crop(file_path):
|
|
cmd = [
|
|
'ffmpeg',
|
|
'-skip_frame', 'nokey',
|
|
'-i', file_path,
|
|
'-vf', 'cropdetect=limit=24/255:round=16:reset=0',
|
|
'-f', 'null',
|
|
'-'
|
|
]
|
|
|
|
process = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
|
|
crop_pattern = re.compile(r'crop=([0-9]+):([0-9]+):([0-9]+):([0-9]+)')
|
|
|
|
crops = []
|
|
|
|
for line in process.stderr:
|
|
match = crop_pattern.search(line)
|
|
if match:
|
|
w, h, x, y = map(int, match.groups())
|
|
# ignorujemy calkowicie ciemne klatki (gdzie cropdetect ucina z kazdej strony)
|
|
# interesuje nas glownie format wideo (np proporcje)
|
|
crops.append((w, h, x, y))
|
|
|
|
process.wait()
|
|
|
|
if not crops:
|
|
return {"error": "No crop detected"}
|
|
|
|
# Policz jak często występuje dany crop
|
|
crop_counts = Counter(crops)
|
|
total_frames = len(crops)
|
|
|
|
# Filtrujemy losowe błędy i czarne plansze (szukamy cropów które występują co najmniej w 5% klatek kluczowych)
|
|
valid_crops = [c for c, count in crop_counts.items() if count / total_frames > 0.05]
|
|
|
|
if not valid_crops:
|
|
# Jeśli nic nie przekracza 5%, bierzemy po prostu najczęstszy
|
|
valid_crops = [crop_counts.most_common(1)[0][0]]
|
|
|
|
# Z valid_crops wybieramy taki "safe crop", który jest obwiednią (bounding box)
|
|
# dla wszystkich ISTOTNYCH proporcji w filmie.
|
|
# To pozwoli na zachowanie scen IMAX, a odcięcie stałych czarnych pasów.
|
|
|
|
min_x = min(c[2] for c in valid_crops)
|
|
min_y = min(c[3] for c in valid_crops)
|
|
max_xw = max(c[2] + c[0] for c in valid_crops)
|
|
max_yh = max(c[3] + c[1] for c in valid_crops)
|
|
|
|
safe_crop = {
|
|
"w": max_xw - min_x,
|
|
"h": max_yh - min_y,
|
|
"x": min_x,
|
|
"y": min_y
|
|
}
|
|
|
|
most_common_tuple = crop_counts.most_common(1)[0][0]
|
|
most_common = f"{most_common_tuple[0]}:{most_common_tuple[1]}:{most_common_tuple[2]}:{most_common_tuple[3]}"
|
|
|
|
return {
|
|
"safe_crop": safe_crop,
|
|
"most_common": most_common,
|
|
"valid_crops_considered": len(valid_crops),
|
|
"raw_crops_count": total_frames
|
|
}
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python detect_crop.py <video_file>")
|
|
sys.exit(1)
|
|
|
|
file_path = sys.argv[1]
|
|
result = detect_crop(file_path)
|
|
print(json.dumps(result, indent=2))
|