首页 > 编程语言 >Python: faces Swap

Python: faces Swap

时间:2024-06-13 20:12:15浏览次数:23  
标签:triangle point Python destination face source points Swap faces

 

# encoding: utf-8
# 版权所有 2024 ©涂聚文有限公司
# 许可信息查看: 两个头像图片之间换脸
# 描述: https://stackoverflow.com/questions/902761/saving-a-numpy-array-as-an-image?answertab=votes
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2023.1 python 311
# Datetime  : 2024/6/13 10:25
# User      : geovindu
# Product   : PyCharm
# Project   : EssentialAlgorithms
# File      : imageFaceSwapFun.py
# explain   : 学习
import cv2
import numpy as np
import dlib
from PIL import Image as im

class FaceSwaFun(object):
    """
    换脸类
    """
    def __init__(self,SOURCEPATH,DESTPATH):
        """
        实例化
        :param SOURCEPATH: 需要用脸的图片
        :param DESTPATH: 用脸目标图片
        """
        self.SOURCE_PATH=SOURCEPATH
        self.DEST_PATH=DESTPATH


    def index_from_array(self,numpyarray):
        """

        :param numpyarray:
        :return:
        """
        index = None
        for n in numpyarray[0]:
            index = n
            break
        return index

    def getImage(self)-> tuple:
        """

        :return: 返回 (图片的数组,保存的文件名)
        """
        frontal_face_detector = dlib.get_frontal_face_detector()
        frontal_face_predictor = dlib.shape_predictor("dataset/shape_predictor_68_face_landmarks.dat")

        source_image = cv2.imread(self.SOURCE_PATH)
        source_image_grayscale = cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY)
        #
        destination_image = cv2.imread(self.DEST_PATH)
        destination_image_grayscale = cv2.cvtColor(destination_image, cv2.COLOR_BGR2GRAY)

        source_image_canvas = np.zeros_like(source_image_grayscale)
        height, width, no_of_channels = destination_image.shape
        destination_image_canvas = np.zeros((height, width, no_of_channels), np.uint8)

        source_faces = frontal_face_detector(source_image_grayscale)

        # Obtaining source face landmark points, convex hull, creating mask and also getting delaunay triangle face landmark indices for every face
        for source_face in source_faces:
            source_face_landmarks = frontal_face_predictor(source_image_grayscale, source_face)
            source_face_landmark_points = []
            for landmark_no in range(68):
                x_point = source_face_landmarks.part(landmark_no).x
                y_point = source_face_landmarks.part(landmark_no).y
                source_face_landmark_points.append((x_point, y_point))

            source_face_landmark_points_array = np.array(source_face_landmark_points, np.int32)
            source_face_convexhull = cv2.convexHull(source_face_landmark_points_array)

            cv2.fillConvexPoly(source_image_canvas, source_face_convexhull, 255)
            source_face_image = cv2.bitwise_and(source_image, source_image, mask=source_image_canvas)

            # DELAUNAY TRIANGULATION

            bounding_rectangle = cv2.boundingRect(source_face_convexhull)
            subdivisions = cv2.Subdiv2D(bounding_rectangle)
            subdivisions.insert(source_face_landmark_points)
            triangles_vector = subdivisions.getTriangleList()
            triangles_array = np.array(triangles_vector, dtype=np.int32)

            triangle_landmark_points_list = []
            source_face_image_copy = source_face_image.copy()

            for triangle in triangles_array:
                index_point_1 = (triangle[0], triangle[1])
                index_point_2 = (triangle[2], triangle[3])
                index_point_3 = (triangle[4], triangle[5])

                index_1 = np.where((source_face_landmark_points_array == index_point_1).all(axis=1))
                index_1 = self.index_from_array(index_1)
                index_2 = np.where((source_face_landmark_points_array == index_point_2).all(axis=1))
                index_2 = self.index_from_array(index_2)
                index_3 = np.where((source_face_landmark_points_array == index_point_3).all(axis=1))
                index_3 = self.index_from_array(index_3)

                triangle = [index_1, index_2, index_3]
                triangle_landmark_points_list.append(triangle)

        destination_faces = frontal_face_detector(destination_image_grayscale)

        # Obtaining destination face landmark points and also convex hull for every face
        for destination_face in destination_faces:
            destination_face_landmarks = frontal_face_predictor(destination_image_grayscale, destination_face)
            destination_face_landmark_points = []
            for landmark_no in range(68):
                x_point = destination_face_landmarks.part(landmark_no).x
                y_point = destination_face_landmarks.part(landmark_no).y
                destination_face_landmark_points.append((x_point, y_point))

            destination_face_landmark_points_array = np.array(destination_face_landmark_points, np.int32)
            destination_face_convexhull = cv2.convexHull(destination_face_landmark_points_array)

        # Iterating through all source delaunay triangle and superimposing source triangles in empty destination canvas after warping to same size as destination triangles' shape
        for i, triangle_index_points in enumerate(triangle_landmark_points_list):
            # Cropping source triangle's bounding rectangle

            source_triangle_point_1 = source_face_landmark_points[triangle_index_points[0]]
            source_triangle_point_2 = source_face_landmark_points[triangle_index_points[1]]
            source_triangle_point_3 = source_face_landmark_points[triangle_index_points[2]]
            source_triangle = np.array([source_triangle_point_1, source_triangle_point_2, source_triangle_point_3],
                                       np.int32)

            source_rectangle = cv2.boundingRect(source_triangle)
            (x, y, w, h) = source_rectangle
            cropped_source_rectangle = source_image[y:y + h, x:x + w]

            source_triangle_points = np.array([[source_triangle_point_1[0] - x, source_triangle_point_1[1] - y],
                                               [source_triangle_point_2[0] - x, source_triangle_point_2[1] - y],
                                               [source_triangle_point_3[0] - x, source_triangle_point_3[1] - y]],
                                              np.int32)

            # Create a mask using cropped destination triangle's bounding rectangle(for same landmark points as used for source triangle)

            destination_triangle_point_1 = destination_face_landmark_points[triangle_index_points[0]]
            destination_triangle_point_2 = destination_face_landmark_points[triangle_index_points[1]]
            destination_triangle_point_3 = destination_face_landmark_points[triangle_index_points[2]]
            destination_triangle = np.array(
                [destination_triangle_point_1, destination_triangle_point_2, destination_triangle_point_3], np.int32)

            destination_rectangle = cv2.boundingRect(destination_triangle)
            (x, y, w, h) = destination_rectangle

            cropped_destination_rectangle_mask = np.zeros((h, w), np.uint8)

            destination_triangle_points = np.array(
                [[destination_triangle_point_1[0] - x, destination_triangle_point_1[1] - y],
                 [destination_triangle_point_2[0] - x, destination_triangle_point_2[1] - y],
                 [destination_triangle_point_3[0] - x, destination_triangle_point_3[1] - y]],
                np.int32)

            cv2.fillConvexPoly(cropped_destination_rectangle_mask, destination_triangle_points, 255)

            # Warp source triangle to match shape of destination triangle and put it over destination triangle mask

            source_triangle_points = np.float32(source_triangle_points)
            destination_triangle_points = np.float32(destination_triangle_points)

            matrix = cv2.getAffineTransform(source_triangle_points, destination_triangle_points)
            warped_rectangle = cv2.warpAffine(cropped_source_rectangle, matrix, (w, h))

            warped_triangle = cv2.bitwise_and(warped_rectangle, warped_rectangle,
                                              mask=cropped_destination_rectangle_mask)

            # Reconstructing destination face in empty canvas of destination image

            # removing white lines in triangle using masking
            new_dest_face_canvas_area = destination_image_canvas[y:y + h, x:x + w]
            new_dest_face_canvas_area_gray = cv2.cvtColor(new_dest_face_canvas_area, cv2.COLOR_BGR2GRAY)
            _, mask_created_triangle = cv2.threshold(new_dest_face_canvas_area_gray, 1, 255, cv2.THRESH_BINARY_INV)

            warped_triangle = cv2.bitwise_and(warped_triangle, warped_triangle, mask=mask_created_triangle)
            new_dest_face_canvas_area = cv2.add(new_dest_face_canvas_area, warped_triangle)
            destination_image_canvas[y:y + h, x:x + w] = new_dest_face_canvas_area

        # Put reconstructed face on the destination image
        final_destination_canvas = np.zeros_like(destination_image_grayscale)
        final_destination_face_mask = cv2.fillConvexPoly(final_destination_canvas, destination_face_convexhull, 255)
        final_destination_canvas = cv2.bitwise_not(final_destination_face_mask)
        destination_face_masked = cv2.bitwise_and(destination_image, destination_image, mask=final_destination_canvas)
        destination_with_face = cv2.add(destination_face_masked, destination_image_canvas)

        # Seamless cloning to make attachment blend with surrounding pixels

        # we have to find center point of reconstructed convex hull to pass into seamlessClone()
        (x, y, w, h) = cv2.boundingRect(destination_face_convexhull)
        destination_face_center_point = (int((x + x + w) / 2), int((y + y + h) / 2))
        seamless_cloned_face = cv2.seamlessClone(destination_with_face, destination_image, final_destination_face_mask,
                                                 destination_face_center_point, cv2.NORMAL_CLONE)

        data = im.fromarray(seamless_cloned_face)

        # saving the final output
        # as a PNG file
        file='geovindu.png'
        data.save(file)

        #cv2.imshow("Destination image with source face 2", seamless_cloned_face)
        #cv2.waitKey(0)
        #cv2.destroyAllWindows()
        print(type(seamless_cloned_face))
        return (seamless_cloned_face,file)

        '''
        1.
        import cv2
        cv2.imwrite("geovindu.jpg", seamless_cloned_face)
        2.
        from PIL import Image
        im = Image.fromarray(seamless_cloned_face)
        im.save("geovindu.jpg")
        3.
        import scipy.misc
        scipy.misc.imsave('geovindu.jpg', seamless_cloned_face)
        4.
        import scipy.misc
        scipy.misc.toimage(seamless_cloned_face, cmin=0.0, cmax=...).save('geovindu.jpg')
        5.
        import matplotlib
        matplotlib.image.imsave('geovindu.png', seamless_cloned_face)

        '''

  

调用:

# 调用
    du= BLL.imageFaceSwapFun.FaceSwaFun("media/images/modi.jpg","media/images/viplav.jpeg")
    #du.SOURCE_PATH="media/images/modi.jpg"
    # du.DEST_PATH="media/images/viplav.jpeg"
    geovindu=du.getImage()
    print(geovindu)
    cv2.imwrite("geovindu20.png", geovindu[0])

  

标签:triangle,point,Python,destination,face,source,points,Swap,faces
From: https://www.cnblogs.com/geovindu/p/18246680

相关文章

  • Python简单实现:读取文件夹并数字排序
    python中os.listdir()方法用于返回指定的文件夹包含的文件或文件夹的名字的列表importospath="../data/materials/test/"path_list=os.listdir(path)print(path_list)输出['1.jpg','10.jpg','11.jpg','12.jpg','13.jpg',......
  • Python中 sys.argv[]的用法解释
    sys.argv就是一个从程序外部获取参数的桥梁,这个“外部”很关键,因为我们从外部取得的参数可以是多个,所以获得的是一个列表(list),也就是说sys.argv其实可以看作是一个列表,所以才能用[]提取其中的元素。其第一个元素是程序本身,随后才依次是外部给予的参数。下面我们通过一个极简单......
  • Python中常用的几个内置方法(max()/min()、filter()、map()、sorted、reduce())
    1.max()/min()传入一个参数(可迭代对象),返回这个可迭代对象中最大的元素可以设置default关键字参数,当这个可迭代对象为空时,返回default的值传入多个参数,返回这些参数中最大的参数多个参数必须是同类型的两种方法都可以设置key关键字参数(传入函数)"""max(it......
  • Python实现:查找文本文件中重复的汉字
    查找文本文件中重复的汉字,找到在所在行号文本文件格式大小多少前后左……text.pyimportosimportrelist=[]same=0total=0index=[]withopen("1.txt","r",encoding="utf-8")asf:forlineinf.readlines():line=line.strip('\n......
  • python爬虫
    What's爬虫?简单来说:爬虫,即网络蜘蛛,是伪装成客户端与服务器进行数据交互的程序。代码frombs4importBeautifulSoup#网页解析importurllib.request,urllib.error#制定URL,获取网页数据importre#正则表达式进行文字匹配importx......
  • Python 如何将Latex转换成Word公式?
    好久没写博客啦!最近帮女朋友(数学老师)搞了个题目转成Word的小工具。情景就是,我们在一些图片里获取到数学题目时通常会使用到ocr技术,但是呢通过ocr给到的数学公式是Latex表达式,这也就是为什么我们用识图软件或者手机微信等自带的识别不了数学公式,识别了粘贴到word中又变成了......
  • 量化交易:miniQMT的可转债与正股折价套利策略python代码
    哈喽,大家好,我是木头左!套利是一种艺术,一种利用市场的价格差异来获取无风险利润的艺术。而可转债与正股之间的折价套利,更是量化交易者眼中的香饽饽。今天,我们将一起揭开这层神秘的面纱,探索如何使用miniQMT和Python来实现这一策略。......
  • 流畅的python--第十三章 接口、协议和抽象基类
    面向对象编程全靠接口。在Python中,支撑一个类型的是它提供的方法,也就是接口。在不同的编程语言中,接口的定义和使用方式不尽相同。从Python3.8开始,有4种方式,如图13-1中的类型图所示。这4种方式概述如下。鸭子类型自Python诞生以来默认使用的类型实现方式。从第1......
  • 如何利用ChatGPT辅助下处理:ENVI、GEE、Python等遥感数据
    遥感技术主要通过卫星和飞机从远处观察和测量我们的环境,是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型,在理解和生成人类语言方面表现出了非凡的能力。重点介绍ChatGPT在遥感中的应用,人工智能在解释复杂数据、提供见解和帮助决策过程方......
  • Python typing 的使用总结
    1. 类型提示(TypeHints):Python3.5引入了类型提示,这是一种新的语法特性,允许在函数声明中指定参数和返回值的预期类型。这些类型注解对Python解释器没有任何影响,但是可以被类型检查器、IDE、linter等工具用来捕获类型错误。defgreet(name:str)->str:return'Hello,'+......