调整视频帧率、分辨率

时间:2024-07-17 20:46:54
import cv2 import os from tqdm import tqdm # 进度条 import subprocess # 加载人脸检测模型 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') def contains_face(frame): gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) return len(faces) > 0 def crop_center(frame, crop_width, crop_height): height, width = frame.shape[:2] start_x = width//2 - crop_width//2 start_y = height//2 - crop_height//2 return frame[start_y:start_y+crop_height, start_x:start_x+crop_width] def extract_audio(input_path, audio_path): subprocess.run(['ffmpeg', '-y', '-i', input_path, '-vn', '-acodec', 'copy', audio_path]) def merge_video_audio(video_path, audio_path, output_path): subprocess.run(['ffmpeg', '-y', '-i', video_path, '-i', audio_path, '-c:v', 'copy', '-c:a', 'aac', '-map', '0:v:0', '-map', '1:a:0', output_path]) def process_video(path, out_path, fps=25): print(f'[INFO] ===== process video from {path} to {out_path} =====') # 创建VideoCapture对象 cap = cv2.VideoCapture(path) # 检查是否成功打开视频 if not cap.isOpened(): print("Error opening video file") return frame_rate = cap.get(cv2.CAP_PROP_FPS) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 获取视频的总帧数 frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频的宽度 frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频的高度 print("原视频帧率=", frame_rate, "fps") print("原视频帧数=", total_frames) print("原视频尺寸=", frame_width, "x", frame_height) if frame_rate != fps: cap.set(cv2.CAP_PROP_FPS, fps) frame_rate = fps # 创建VideoWriter对象 fourcc = cv2.VideoWriter_fourcc(*'mp4v') out = cv2.VideoWriter(out_path, fourcc, fps, (512, 512)) frame_count = 0 # 创建一个tqdm进度条 pbar = tqdm(total=total_frames, ncols=70, unit='frame') while cap.isOpened(): ret, frame = cap.read() if ret: if contains_face(frame) and frame_count % (frame_rate // fps) == 0: frame = crop_center(frame, 512, 512) out.write(frame) frame_count += 1 pbar.update(1) # 更新进度条 else: break pbar.close() # 关闭进度条 cap.release() out.release() # 你的代码中存在一些可能影响最终视频与音频同步的潜在问题: # 当你使用cap.set(cv2.CAP_PROP_FPS, fps)尝试改变视频的帧率,这实际上并不会改变视频的内部帧率属性。CAP_PROP_FPS是一个读取属性,而不是写入属性。因此,你不能依靠这种方法来更改视频的帧率。 # 当你基于frame_rate // fps的模运算来决定是否抽取帧时,这假定了frame_rate可以被fps整除。如果frame_rate和fps不是整数倍的关系,那么视频的总时长可能会与原视频不完全匹配,这可能导致音频和视频的轻微不同步。 # 为了避免这些问题,你应该: # 不尝试设置CAP_PROP_FPS,而是通过抽取帧来实现目标帧率。 # 计算每个帧应该抽取的时间戳,确保与原始视频的帧持续时间一致。 # def process_video(path, out_path, target_fps=25): # print(f'[INFO] ===== process video from {path} to {out_path} =====') # # 创建VideoCapture对象 # cap = cv2.VideoCapture(path) # # 检查是否成功打开视频 # if not cap.isOpened(): # print("Error opening video file") # return # original_fps = cap.get(cv2.CAP_PROP_FPS) # total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # frame_duration = 1 / original_fps # 原始视频每帧的持续时间 # # 创建VideoWriter对象 # fourcc = cv2.VideoWriter_fourcc(*'mp4v') # out = cv2.VideoWriter(out_path, fourcc, target_fps, (512, 512)) # frame_count = 0 # target_frame_time = 0 # 目标帧的累积时间 # # 创建一个tqdm进度条 # pbar = tqdm(total=total_frames, ncols=70, unit='frame') # while cap.isOpened(): # ret, frame = cap.read() # if ret: # current_time = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000 # 当前帧的时间戳(秒) # # 如果当前时间等于或超过目标帧时间,则写入帧 # if current_time >= target_frame_time: # if contains_face(frame): # frame = crop_center(frame, 512, 512) # out.write(frame) # target_frame_time += frame_duration * (original_fps / target_fps) # 下一帧的目标时间 # frame_count += 1 # pbar.update(1) # 更新进度条 # else: # break # pbar.close() # 关闭进度条 # cap.release() # out.release() print(f'[INFO] ===== processed video =====') # 打开处理后的视频,获取总帧数、帧率和视频尺寸 cap_out = cv2.VideoCapture(out_path) total_frames_out = int(cap_out.get(cv2.CAP_PROP_FRAME_COUNT)) frame_rate_out = cap_out.get(cv2.CAP_PROP_FPS) frame_width = int(cap_out.get(cv2.CAP_PROP_FRAME_WIDTH)) frame_height = int(cap_out.get(cv2.CAP_PROP_FRAME_HEIGHT)) print(f'处理后的视频帧率: {frame_rate_out} fps') print(f'处理后的视频帧数: {total_frames_out}') print(f'处理后的视频尺寸: {frame_width}x{frame_height}') cap_out.release() def process_video_with_audio(input_path, output_path): audio_path = output_path.replace('.mp4', '_audio.aac') output_with_audio_path = output_path.replace('.mp4', '_with_audio.mp4') extract_audio(input_path, audio_path) process_video(input_path, output_path) merge_video_audio(output_path, audio_path, output_with_audio_path) # 删除临时文件 os.remove(output_path) os.remove(audio_path) return output_with_audio_path if __name__ == "__main__": for i in tqdm(range(1, 75), desc="Processing videos"): input_path = f"data/{i}/{i}.mp4" output_path = f"data/{i}/{i}_fc.mp4" if not os.path.isfile(input_path): print(f"文件 {input_path} 不存在.") continue final_output_path = process_video_with_audio(input_path, output_path) print(f"处理后的视频已保存至 {final_output_path}")