Let there exist some function process_frame that takes in the current frame from a video and crops it to some new dimensions X2 x Y2. This can be accomplished by slicing the frame to the new dimensions:
frame[Y2:Y2+H, X2:X2+W]
I can return this value and blit it to the screen with SDL2, but I want to just export the cropped frames to a new mp4 file. This can be accomplished with cv2, but it is blurry, choppy, no audio, and the export is 2x slower than the FPS specified. I want to maintain as clean of a resolution as possible, maintain audio, speed, encoding (HEVC.265 preferably), but I have no clue how this is done iteratively with FFMPEG.
I've seen video exports done in one Terminal function, but the nuance here is that each cropped frame location will be different, so it is necessary to do this iteratively.
How is this done, and more specifically, how can I keep quality?
Code for reference:
import cv2
import sdl2
import sdl2.ext
import numpy as np
import time, sys, os
from display import Display
# auto-reframe new feature resolution
W, H = 1920//2, 1080//2
prev_x = 0
new_W_ratio = int((9*H) / 16)
cropped_frames = []
disp = Display(new_W_ratio, H)
def BlurValue(W, H):
""" The blur value is the dimension average divided by 10 """
avg = (W + H) // 2
return int(avg//10)
def process_frame(img, firstFrame=None):
global prev_x
img = cv2.resize(img, (W, H))
# take note of crop ratio (16:9)
new_W_ratio = int((9*H) / 16)
# ...
cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Loop through all contours and find the average nearest neighbor
for c in cnts:
(x, y, w, h) = cv2.boundingRect(c)
if prev_x == 0: prev_x = x
avg_x = (x+prev_x)/2
if prev_x == 0: prev_x = x
if abs(x - prev_x) < 25 and abs(prev_x - avg_x) < 50 and x != 0:
prev_x = x
cropped_frame = img[0:H, x:x+new_W_ratio]
cropped_frames.append(cropped_frame)
elif x != 0:
cropped_frame = img[0:H, prev_x:prev_x+new_W_ratio]
cropped_frames.append(cropped_frame)
else:
cropped_frame = img[0:H, prev_x:prev_x+new_W_ratio]
cropped_frames.append(cropped_frame)
disp.paint(cropped_frame)
if __name__ == "__main__":
cap = cv2.VideoCapture("TESTAUTOREFRAME.mov")
previousFrame = None
# save the auto reframe as a new file
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
output_video = cv2.VideoWriter('output_auto_reframe.mp4', fourcc, 120, (new_W_ratio, H))
while cap.isOpened():
ret, frame = cap.read()
if ret == True:
process_frame(frame)
else:
break
for f in cropped_frames:
output_video.write(f)
output_video.release()
cap.release()
cv2.destroyAllWindows()