cropping for videos

This commit is contained in:
q
2024-12-12 20:15:37 +02:00
parent 6ffcaa257e
commit c5947d0d60
2 changed files with 125 additions and 4 deletions

View File

@@ -20,6 +20,8 @@ class Marker:
self.frame_visu = []
self.max_res = (1280, 720)
self.min_res = (512, None)
self.crop = [(None, None), (None, None), None]
self.crop_click = 0
self.forced_fps = opts.fps
try:
@@ -49,6 +51,10 @@ class Marker:
int(self.video_reader.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(self.video_reader.get(cv2.CAP_PROP_FRAME_HEIGHT)),
]
self.video_res_original = [
int(self.video_reader.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(self.video_reader.get(cv2.CAP_PROP_FRAME_HEIGHT)),
]
video_aspect = self.video_res[0] / self.video_res[1]
if self.video_res[0] > self.max_res[0]:
self.video_res[0] = int(self.max_res[0])
@@ -63,6 +69,20 @@ class Marker:
self.video_res[1] = int(self.video_res[0] / video_aspect)
self.video_res = tuple(self.video_res)
self.crop = [(0, 0), tuple(self.video_res), None]
if self.opts.crop:
w, h, x, y = [int(c) for c in self.opts.crop.split(":")]
self.crop = [
(
int(self.video_res[0] * x / self.video_res_original[0]),
int(self.video_res[1] * y / self.video_res_original[1]),
),
(
int(self.video_res[0] * w / self.video_res_original[0]),
int(self.video_res[1] * h / self.video_res_original[1]),
),
True,
]
self.bar_start = int(self.video_res[0] * 0.05)
self.bar_end = int(self.video_res[0] * 0.95)
self.bar_top = int(self.video_res[1] * 0.90)
@@ -147,6 +167,49 @@ class Marker:
(255, 255, 255),
)
def draw_crop(self, frame):
if self.crop[2] is None:
return
p2 = (self.crop[0][0] + self.crop[1][0], self.crop[0][1] + self.crop[1][1])
cv2.rectangle(
frame,
self.crop[0],
p2,
(0, 192, 192),
1,
)
if self.crop_click == 1:
x, y = [
int(self.video_res_original[0] * self.crop[0][0] / self.video_res[0]),
int(self.video_res_original[1] * self.crop[0][1] / self.video_res[1]),
]
self.shadow_text(
frame,
f"{x},{y}",
self.crop[0],
0.5,
1,
(0, 192, 192),
)
if self.crop_click == 2:
x, y = [
int(self.video_res_original[0] * self.crop[0][0] / self.video_res[0]),
int(self.video_res_original[1] * self.crop[0][1] / self.video_res[1]),
]
w, h = [
abs(int(self.video_res_original[0] * self.crop[1][0] / self.video_res[0])),
abs(int(self.video_res_original[1] * self.crop[1][1] / self.video_res[1])),
]
self.shadow_text(
frame,
f"{w}x{h}",
self.crop[0],
0.5,
1,
(0, 192, 192),
)
def draw_help(self, frame):
bottom = 80
@@ -195,6 +258,7 @@ class Marker:
mark frame
space or click video
pause
a and s modify crop offset or size
f toggle 0.5x 1x or 2x FPS
v toggle HUD
h toggle help
@@ -211,6 +275,17 @@ class Marker:
y > self.bar_top,
)
)
if self.crop_click == 1:
self.crop[0] = (x, y)
if event == cv2.EVENT_LBUTTONDOWN:
self.crop_click = 0
return
if self.crop_click == 2:
self.crop[1] = (x - self.crop[0][0], y - self.crop[0][1])
if event == cv2.EVENT_LBUTTONDOWN:
self.crop_click = 0
return
if event == cv2.EVENT_LBUTTONDOWN:
if in_bar:
click_relative = (x - self.bar_start) / (self.bar_end - self.bar_start)
@@ -271,17 +346,48 @@ class Marker:
print(self.get_help())
def print_timestamps(self):
if self.crop[2] is None:
cropstr = ""
else:
x, y = [
int(self.video_res_original[0] * self.crop[0][0] / self.video_res[0]),
int(self.video_res_original[1] * self.crop[0][1] / self.video_res[1]),
]
w, h = [
int(self.video_res_original[0] * self.crop[1][0] / self.video_res[0]),
int(self.video_res_original[1] * self.crop[1][1] / self.video_res[1]),
]
if w < 0:
x = x + w
w = -w
if h < 0:
y = y + h
h = -h
cropstr = f"-filter:v crop={w}:{h}:{x}:{y} "
self.stamps.sort()
print("# Timestamps:")
for i, ts in enumerate(self.stamps):
print("# {}: {} / {}".format(i + 1, self.format_time(ts), ts))
if len(self.stamps) == 0:
self.stamps.append(0)
self.stamps.append(self.frames)
if len(self.stamps) > 0:
print(
'ffmpeg -ss {} -to {} -i "{}" -c copy "{}.trimmed.mp4"'.format(
'ffmpeg -i "{}" {}-c:v mpeg2video -q:v 3 -g 1 -a copy -ss {} -to {} "{}.trimmed.mp4"'.format(
self.opts.video.replace('"', '\\"'),
cropstr,
self.format_time(self.stamps[0]),
self.format_time(self.stamps[-1]),
os.path.splitext(self.opts.video)[0].replace('"', '\\"'),
)
)
elif self.crop[0][0] is not None:
print(
'ffmpeg -i "{}" {}-c:v mpeg2video -q:v 3 -g 1 "{}.trimmed.mp4"'.format(
self.opts.video.replace('"', '\\"'),
self.opts.video.replace('"', '\\"'),
cropstr,
os.path.splitext(self.opts.video)[0].replace('"', '\\"'),
)
)
@@ -350,6 +456,7 @@ class Marker:
if (not self.paused) or self.read_next:
self.read_next = False
frame_visu = cv2.resize(frame.copy(), self.video_res)
self.draw_crop(frame_visu)
nr_time = self.nr / self.fps
if self.show_info:
self.draw_time(frame_visu)
@@ -436,7 +543,12 @@ class Marker:
elif k & 0xFF == ord("f"): # modify FPS
FPS_modifier = (FPS_modifier + 1) % len(FPS_modifiers)
elif k & 0xFF == ord("a"): # toggle crop offset
self.crop_click = 0 if self.crop_click == 1 else 1
self.crop[2] = True
elif k & 0xFF == ord("s"): # toggle crop size
self.crop_click = 0 if self.crop_click == 2 else 2
self.crop[2] = True
elif k & 0xFF == ord("x"): # toggle ts
self.toggle_stamp()