python实现抠出绿幕视频中的人物,合成到另一个背景视频中。要求是如果如果背景视频过短是,循环播放。
上python代码:
# -*- coding: utf-8 -*-
import numpy as np
import cv2
from moviepy.editor import VideoFileClip, concatenate_videoclips, CompositeVideoClip
def generate_mask(frame):
frame_blurred = cv2.bilateralFilter(frame, d=9, sigmaColor=75, sigmaSpace=75)
hsv = cv2.cvtColor(frame_blurred, cv2.COLOR_RGB2HSV)
lower_green = np.array([40, 50, 50])
upper_green = np.array([80, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
mask_inv = cv2.bitwise_not(mask)
#使用腐蚀和膨胀操作来清除噪点
kernel = np.ones((3, 3), np.uint8)
mask_inv = cv2.erode(mask_inv, kernel, iterations=1)
mask_inv = cv2.dilate(mask_inv, kernel, iterations=1)
#闭操作填充对象内细小空洞,开操作去除小对象
mask_inv = cv2.morphologyEx(mask_inv, cv2.MORPH_CLOSE, kernel)
mask_inv = cv2.morphologyEx(mask_inv, cv2.MORPH_OPEN, kernel)
three_channel_mask = np.stack([mask_inv] * 3, axis=-1)
return three_channel_mask
def simple_color_balance(frame, r_factor=0.95, g_factor=0.85, b_factor=0.95):
frame_copy = frame.copy()
#微调RGB各通道的系数可以更好地融合前景和背景
frame_copy[:, :, 0] = np.clip(frame_copy[:, :, 0] * r_factor, 0, 255).astype(np.uint8)
frame_copy[:, :, 1] = np.clip(frame_copy[:, :, 1] * g_factor, 0, 255).astype(np.uint8)
frame_copy[:, :, 2] = np.clip(frame_copy[:, :, 2] * b_factor, 0, 255).astype(np.uint8)
return frame_copy
def process_videos(foreground_video_path, background_video_path, output_video_path, output_size=(1080, 1920)):
foreground_clip = VideoFileClip(foreground_video_path)
background_clip = VideoFileClip(background_video_path).set_duration(foreground_clip.duration)
num_loops = int(foreground_clip.duration / background_clip.duration + 1)
background_clip = concatenate_videoclips([background_clip] * num_loops).subclip(0, foreground_clip.duration)
background_clip = background_clip.resize(newsize=output_size)
mask_clip = foreground_clip.fl_image(generate_mask).to_mask()
masked_foreground = foreground_clip.set_mask(mask_clip).fl_image(simple_color_balance).resize(newsize=output_size)
composite_clip = CompositeVideoClip([background_clip, masked_foreground], use_bgclip=True)
composite_clip.set_duration(foreground_clip.duration).write_videofile(output_video_path, codec='libx264', fps=24)
# 调用函数开始处理视频 1.mov是绿幕视频,2.mp4背景视频,output.mp4输出合成视频
process_videos('F:\\shipin\\1.mov', 'F:\\shipin\\2.mp4', 'F:\\shipin\\output.mp4')
合成原理
在视频合成中,首先通过色键技术(绿幕技术)从前景视频中抠出主体。通过在HSV色彩空间中应用特定的色彩范围来生成一个掩模,这个掩模用于区分前景中的主体和背景。然后将主体与一个新的背景视频合成在一起。
最终的合成视频是通过将调整后的前景视频(已应用掩模和色彩平衡)放置在背景视频上形成的。使用MoviePy库中的CompositeVideoClip类来实现这一点,它允许你轻松地将多个视频层叠加在一起。
调整色键掩模参数
调整HSV阈值:
色键(Chroma Key)的HSV阈值对掩模的生成影响很大。调整这些阈值可以更精确地分离前景和背景,从而减少边缘的白点和亮点。
尝试缩小 lower_green 和 upper_green 之间的距离,使得绿色的选取更加严格。比如,可以尝试将 lower_green 改为 [45, 50, 50],upper_green 改为 [75, 255, 255]。
优化腐蚀和膨胀操作:
腐蚀(Erosion)可以帮助移除小白点,但如果过多可能会使前景边缘变得不平滑。
膨胀(Dilation)操作通常跟在腐蚀之后,用来恢复前景的形状,但过多的膨胀可能会引入额外的亮点。
可以尝试调整腐蚀和膨胀的迭代次数(iterations),或者更改核的大小(通过修改 kernel = np.ones((3, 3), np.uint8) 中的 (3, 3))。
调整色彩平衡参数
在 simple_color_balance 函数中,通过微调 r_factor, g_factor, b_factor 参数,可以帮助更好地融合前景和背景的色彩,减少因色彩不匹配产生的亮点。
小幅度调整这些因子,例如将 g_factor 从 0.90 调整到 0.85 或 0.95,观察效果。
这些是合成视频处理所需的Python库:
numpy 用于进行高效的数值计算。
cv2 (OpenCV) 提供强大的视频和图像处理功能。
moviepy 用于视频文件的读取、处理和合成。
以上代码改一下文件路径可以直接运行。有什么问题欢迎讨论学习。