Python 实现人脸融合与虚拟人物生成

Python 实现人脸融合与虚拟人物生成,只需要准备两张人脸图片,最好是大头照,这样融合效果才会更好。

实现步骤:

(1)准备两张图片(人脸)

(2)准备好如下过程Python利用paddlehub实现批量抠图和更换证件照背景底色_SmartGridequation的博客-优快云博客

(3)利用OpenCV去除图的单一颜色

Python 去除图片中多种颜色或者单一颜色_SmartGridequation的博客-优快云博客

融合人脸函数代码如下:

import numpy as np
import cv2
import dlib
from scipy.spatial import Delaunay
predictor_model = 'shape_predictor_68_face_landmarks.dat'

#-i https://mirrors.aliyun.com/pypi/simple/

def get_points(image):  # 用 dlib 来得到人脸的特征点
    global detected_face
    face_detector = dlib.get_frontal_face_detector()  # 正向人脸检测器,进行人脸检测,提取人脸外部矩形框
    face_pose_predictor = dlib.shape_predictor(predictor_model)
    try:
        detected_face = face_detector(image, 1)[0]
    except:
        print('No face detected in image {}'.format(image))
    pose_landmarks = face_pose_predictor(image, detected_face)  # 获取landmark
    points = []
    for p in pose_landmarks.parts():
        points.append([p.x, p.y])

    # 加入四个顶点和四条边的中点
    x = image.shape[1] - 1
    y = image.shape[0] - 1
    points.append([0, 0])
    points.append([x // 2, 0])
    points.append([x, 0])
    points.append([x, y // 2])
    points.append([x, y])
    points.append([x // 2, y])
    points.append([0, y])
    points.append([0, y // 2])

    return np.array(points)


def get_triangles(points):  #  在特征点上使用 Delaunay 三角剖分,将点集连接成一定大小的三角形,且分配要相对合理,才能呈现出漂亮的三角化
    return Delaunay(points).simplices


def affine_transform(input_image, input_triangle, output_triangle, size):  # 对人脸进行仿射变换,确定位置
    warp_matrix = cv2.getAffineTransform(
        np.float32(input_triangle), np.float32(output_triangle))
    output_image = cv2.warpAffine(input_image, warp_matrix, (size[0], size[1]), None,
                                  flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
    return output_image


def morph_triangle(img1, img2, img, tri1, tri2, tri, alpha):  # 三角形变形,Alpha 混合
    # 计算三角形的边界框
    rect1 = cv2.boundingRect(np.float32([tri1]))  # 寻找tri1的左上角坐标,和tri1的长和宽
    rect2 = cv2.boundingRect(np.float32([tri2]))
    rect = cv2.boundingRect(np.float32([tri]))

    tri_rect1 = []
    tri_rect2 = []
    tri_rect_warped = []

    for i in range(0, 3):
        tri_rect_warped.append(
            ((tri[i][0] - rect[0]), (tri[i][1] - rect[1])))
        tri_rect1.append(
            ((tri1[i][0] - rect1[0]), (tri1[i][1] - rect1[1])))
        tri_rect2.append(
            ((tri2[i][0] - rect2[0]), (tri2[i][1] - rect2[1])))

    # 在边界框内进行仿射变换
    img1_rect = img1[rect1[1]:rect1[1] +
                     rect1[3], rect1[0]:rect1[0] + rect1[2]]
    img2_rect = img2[rect2[1]:rect2[1] +
                     rect2[3], rect2[0]:rect2[0] + rect2[2]]

    size = (rect[2], rect[3])
    warped_img1 = affine_transform(
        img1_rect, tri_rect1, tri_rect_warped, size)
    warped_img2 = affine_transform(
        img2_rect, tri_rect2, tri_rect_warped, size)

    # 加权求和
    img_rect = (1.0 - alpha) * warped_img1 + alpha * warped_img2

    # 生成模板
    mask = np.zeros((rect[3], rect[2], 3), dtype=np.float32)
    cv2.fillConvexPoly(mask, np.int32(tri_rect_warped), (1.0, 1.0, 1.0), 16, 0)

    # 应用模板
    img[rect[1]:rect[1] + rect[3], rect[0]:rect[0] + rect[2]] = \
        img[rect[1]:rect[1] + rect[3], rect[0]:rect[0] +
            rect[2]] * (1 - mask) + img_rect * mask


def morph_faces(filename1, filename2, alpha=0.5):  # 融合图片
    img1 = cv2.imread(filename1)
    img2 = cv2.imread(filename2)
    img2 = cv2.resize(img2,(img1.shape[1],img1.shape[0]),interpolation=cv2.INTER_CUBIC)
    print('img1.shape',img1.shape)
    print('img2.shape',img2.shape)

    points1 = get_points(img1)
    print('pionts1:',len(points1),points1)
    points2 = get_points(img2)
    points = (1 - alpha) * np.array(points1) + alpha * np.array(points2)
    import pandas as pd
    p = pd.DataFrame(points)
    p.to_csv('./1.csv')

    img1 = np.float32(img1)
    img2 = np.float32(img2)
    img_morphed = np.zeros(img1.shape, dtype=img1.dtype)

    triangles = get_triangles(points)
    for i in triangles:
        x = i[0]
        y = i[1]
        z = i[2]

        tri1 = [points1[x], points1[y], points1[z]]
        tri2 = [points2[x], points2[y], points2[z]]
        tri = [points[x], points[y], points[z]]
        morph_triangle(img1, img2, img_morphed, tri1, tri2, tri, alpha)

    return np.uint8(img_morphed)


def main(file1,file2,alpha):
    try:
     alpha = float(alpha)
    except:
        alpha = 0.5
    img_morphed = morph_faces(file1, file2, alpha)
    output_file = '{}_{}_{}.jpg'.format(
        file1.split('.')[0][-2:], file2.split('.')[0][-2:], alpha)
    cv2.imwrite(output_file, img_morphed)
    return output_file

界面函数如下:

from PIL import Image, ImageTk
from tkinter.filedialog import askopenfilename
from tkinter import *
import PIL
from face_morhper import main

root = Tk()
root.title('人脸融合软件')
root.geometry('1200x500')

decoration = PIL.Image.open('background.jpeg').resize((1200, 500))
render = ImageTk.PhotoImage(decoration)
img = Label(image=render)
img.image = render
img.place(x=0, y=0)

global path1_, path2_, rate, seg_img_path


# 原图1展示
def show_original1_pic():
    global path1_
    path1_ = askopenfilename(title='选择文件')
    print(path1_)
    Img = PIL.Image.open(r'{}'.format(path1_))
    Img = Img.resize((270,270),PIL.Image.ANTIALIAS)   # 调整图片大小至256x256
    img_png_original = ImageTk.PhotoImage(Img)
    label_Img_original1.config(image=img_png_original)
    label_Img_original1.image = img_png_original  # keep a reference
    cv_orinial1.create_image(5, 5,anchor='nw', image=img_png_original)


# 原图2展示
def show_original2_pic():
    global path2_
    path2_ = askopenfilename(title='选择文件')
    print(path2_)
    Img = PIL.Image.open(r'{}'.format(path2_))
    Img = Img.resize((270,270),PIL.Image.ANTIALIAS)   # 调整图片大小至256x256
    img_png_original = ImageTk.PhotoImage(Img)
    label_Img_original2.config(image=img_png_original)
    label_Img_original2.image = img_png_original  # keep a reference
    cv_orinial2.create_image(5, 5,anchor='nw', image=img_png_original)


# 人脸融合效果展示
def show_morpher_pic():
    global path1_,seg_img_path,path2_
    print(entry.get())
    mor_img_path = main(path1_,path2_,entry.get())
    Img = PIL.Image.open(r'{}'.format(mor_img_path))
    Img = Img.resize((270, 270), PIL.Image.ANTIALIAS)  # 调整图片大小至256x256
    img_png_seg = ImageTk.PhotoImage(Img)
    label_Img_seg.config(image=img_png_seg)
    label_Img_seg.image = img_png_seg  # keep a reference


def quit():
    root.destroy()


# 原图1的展示
Button(root, text = "打开图片1", command = show_original1_pic).place(x=50,y=120)
# 原图2的展示
Button(root, text = "打开图片2", command = show_original2_pic).place(x=50,y=200)
# 进行提取结果的展示
Button(root, text = "人脸融合", command = show_morpher_pic).place(x=50,y=280)

Button(root, text = "退出软件", command = quit).place(x=900,y=40)

Label(root,text = "融合系数",font=10).place(x=50,y=10)
entry = Entry(root)
entry.place(x=130,y=10)


Label(root,text = "图片1",font=10).place(x=280,y=120)
cv_orinial1 = Canvas(root,bg = 'white',width=270,height=270)
cv_orinial1.create_rectangle(8,8,260,260,width=1,outline='red')
cv_orinial1.place(x=180,y=150)
label_Img_original1 = Label(root)
label_Img_original1.place(x=180,y=150)


Label(root,text="图片2",font=10).place(x=600,y=120)
cv_orinial2 = Canvas(root,bg = 'white',width=270,height=270)
cv_orinial2.create_rectangle(8,8,260,260,width=1,outline='red')
cv_orinial2.place(x=500,y=150)
label_Img_original2 = Label(root)
label_Img_original2.place(x=500,y=150)

Label(root, text="融合效果", font=10).place(x=920,y=120)
cv_seg = Canvas(root, bg='white', width=270,height=270)
cv_seg.create_rectangle(8,8,260,260,width=1,outline='red')
cv_seg.place(x=820,y=150)
label_Img_seg = Label(root)
label_Img_seg.place(x=820,y=150)


root.mainloop()

生成效果分别如下: 

 

利用抠图代码软件进行处理后的图片如下: 

 利用颜色消除代码最后得到的融合虚拟人物图像是:

至此完成虚拟人物的人脸融合。如有侵权,请私信告知,侵权必删。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值