图片换脸、视频换脸早几年就出现了,也一直活跃在各大视频媒体。今天我也自己动手来实现下图片和视频换脸。
模型使用的是insightface开源的模型文件,
其中buffalo_l是人脸检测模型,inswapper_128.onnx是执行换脸的核心模型文件,128是换脸后的像素。分辨率比较低。后续我们可以使用超分辨率模型进行分辨率提升。
使用opencv将视频文件转换为系列图片
def video2imgs(input_video_path, output_dir, interval=1):
"""
:param ipnut_video_path:
:param output_dir:
:param interval:
:return: 视频的帧率,用于视频合成
"""
if not os.path.exists(output_dir):
os.makedirs(output_dir) # 目标文件夹不存在,则创建
cap = cv2.VideoCapture(input_video_path) # 获取视频
judge = cap.isOpened() # 判断是否能打开成功
print(judge)
fps = cap.get(cv2.CAP_PROP_FPS)
# global fps # 帧率,视频每秒展示多少张图片
print("该视频的fps:", fps)
frames = 1 # 用于统计所有帧数
count = 1 # 用于统计保存的图片数量
while judge:
flag, frame = cap.read() # 读取每一张图片 flag表示是否读取成功,frame是图片
if not flag:
print(flag)
print("Process finished!")
break
else:
if (frames + 1) % interval == 0: # 每隔 interval 帧抽一张
imgname = "pngs_" + str(count).rjust(3, "0") + ".png"
newPath = os.path.join(output_dir, imgname)
# print(imgname)
cv2.imwrite(newPath, frame, [cv2.IMWRITE_JPEG_QUALITY, 100])
# cv2.imencode('.jpg', frame)[1].tofile(newPath)
count += 1
frames += 1
cap.release()
print("共有 %d 张图片,%d 帧" % (count - 1, frames - 1))
return fps
def image2video_2(images_dir: str, video_saved_path: str, fps: int = 30):
videoWriter = VideoWriter(video_saved_path, fps)
image_files = os.listdir(images_dir)
image_files = [
image_name
for image_name in image_files
if image_name.split(".")[-1] in ["png", "jpg", "jpeg"]
]
image_list = []
for image in tqdm(sorted(image_files)):
if image.lower().split(".")[-1] in ["jpg", "png", "jpeg"]:
image_path = os.path.join(images_dir, image)
img = cv2.imread(image_path)
# videoWriter.write(img)
image_list.append(img)
videoWriter.write(image_list)
videoWriter.close()
def swapface(
input_video_path: str,
target_face_path: str,
swapper: insightface.model_zoo.inswapper.INSwapper,
app: FaceAnalysis,
):
"""
单人的视频换脸
1.视频抽取帧
2.每张图片进行人脸转换
3.对人脸转换后的图片进行视频合成
:param input_video_path:输入视频路径
:param target_face_path:包含目标face的图片
:return: 换脸后的视频路径
"""
video_name = os.path.splitext(os.path.basename(input_video_path))[0]
output_frames_dir = os.path.join(BASE_DIR, video_name, "output_frames")
swap_image_dir = os.path.join(BASE_DIR, video_name, "swapped_frames")
if not os.path.exists(output_frames_dir):
os.makedirs(output_frames_dir)
if not os.path.exists(swap_image_dir):
os.makedirs(swap_image_dir)
interval = 1
fps = 30
fps = video_images.video2imgs(
input_video_path, output_frames_dir, interval=interval
)
faceswap_insightface.swap_faces_batch(
output_frames_dir, target_face_path, swap_image_dir, swapper, app
)
output_video_path = os.path.join(
BASE_DIR,
target_face_path.split(".")[0].split("/")[-1]
+ "_"
+ video_name
+ "_swapped.mp4",
)
video_images.image2video_2(swap_image_dir, output_video_path, fps=fps / interval)
# 删除中间目录
shutil.rmtree(os.path.join(BASE_DIR, video_name))
print(f"换脸后的视频保存在:{output_video_path}")
return output_video_path
def gradio_interface(input_video, target_image):
# 初始化FaceAnalysis和Swapper
app = FaceAnalysis(
name="buffalo_l",
root="checkpoints",
providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
provider_options=[{"device_id": 0}, {}],
)
app.prepare(ctx_id=0, det_size=(640, 640))
swapper = insightface.model_zoo.get_model(
"./checkpoints/models/inswapper_128.onnx", download=True, download_zip=True
)
# 进行换脸操作
output_video_path = swapface(input_video, target_image, swapper, app)
# 返回换脸后的视频路径
return output_video_path
# Gradio界面
iface = gr.Interface(
fn=gradio_interface,
inputs=[
gr.Video(label="Input Video"),
gr.Image(type="filepath", label="Target Face Image"),
],
outputs=gr.Video(label="Swapped Video"),
title="Video Face Swap",
description="Upload a video and a target face image to swap faces.",
)
# 启动Gradio界面
iface.launch(server_name="0.0.0.0", debug=True)
- 刘亦菲视频换脸
github代码: https://github.com/chongzicbo/ai-master/tree/main
github文章合集:https://github.com/chongzicbo/ReadWriteThink