python实现AI换脸

  • 思路
  • 找到人脸
  • 拼接人脸
  • 全部代码


思路

AI换脸要求把两张人脸的面部内容进行交替,并且能够尽量地进行拟合。

我们首先在互联网上下载两张图片:(妹子证件照不好找,用下面两位哥的图片凑合一下😂)

python换脸表情 gif python换脸算法_python


python换脸表情 gif python换脸算法_人工智能_02

换脸技术在现在看来已经不是那么热门了,已经有很多应用软件都实现了换脸技术。

但是我不建议使用它们的软件,它们前期开发的这些软件,目的就是收集你的人脸信息,帮助训练他们的数据模型。

所谓的搞人工智能相关的人才,一类是专门做学术研究的,研究这些算法的;还有一类是专门应用这些算法的。而大家所了解的一些换脸这些应用,它是免费开放给你用的。但你要知道,它也是有研发成本的,不是无缘无故就免费给你用的。它需要去收集大量的用户人脸数据,方便训练他自己的模型。如果你去了解一些谷歌开源的一些人工智能框架,或者其他公司给你开源的人工智能框架,你会发现框架的东西,包括有一些算法,其实已经有人提出来了,也有些人的是能够理解掌握的。但关键的是支撑这些算法的数据,它没有给你开放。

我们今天实现的内容是:实现两张图片中人脸面部信息的交换。

需要用到的工具

import json
import base64
import requests

其中json和base64是python自带的,requests是第三方的包。

换脸的思路很简单,我们甚至可以使用截图工具,把一张脸截取替换另一张脸上。但是,使用python操作图像并不是那么简单,我们要考虑的东西有很多。

首先,需要识别图像当中脸部的轮廓。

人类可以很轻松的识别什么是脸,什么是肩膀,什么是背景,而计算机并不知道。

它需要有一系列的算法,以及建立所谓的模型来识别人脸。

利用这些算法可以智能的实现人脸面部信息的识别。当然也可以去GitHub上找一些现成的,别人训练好的模型。

如果要自己训练,就需要通过爬虫在互联网上下载大量的人脸图片数据,通过这些数据来训练模型,使其达到人工智能的要求。

这对于我这样一个新手小白来说是短期内无法完成的,我们没有人工智能的理论基础和实践经验,更没有海量的数据。算法我们尚且可以学习,原理不难,但操作起来难以理解。但大量的数据我们却没有。谷歌公司的强大之处很大程度就在于它真正掌握了那些我们想都不敢想的海量数据。

为了实现功能,我们需要站在巨人的肩膀上,调用已有的工具,即已经训练好的模型。(使用轮子)

实现步骤:

  1. 找到人脸数据,不光光是脸部的轮廓,还有脸部的大小,眼睛鼻子的大小。
  2. 拟合,拼接人脸
# 找到人脸数据
def find_face():
    pass
# 拟合,拼接人脸
def merge_face():
    pass

找到人脸

注册旷视:https://console.faceplusplus.com.cn/login

它可以提供人脸识别,人体识别,证件识别,图像识别等api,前提是需要注册。

API接口:

https://api-cn.faceplusplus.com/facepp/v3/detect

这个接口的作用就是帮助我们找到人脸相关的数据,你只需要把图像传给它,就就可以通过调用后台服务器的运算,对图像进行处理,并把处理后的结果返回。

注册完成以后,点击创建我的应用,即可生成试用版的 api_key 和 api_secret

因为要携带数据,所以使用post请求,携带的数据不仅包含api_key 和 api_secret,同时也包含img_url和return_landmark。

img_url表示图片的路径,return_landmark则表示返回的人脸区域坐标。

除了携带参数的请求,也可以携带一个文件去请求,就好比上传一个文件。

files = {'image_file':open(imgpath)}

拼接人脸

拼接人脸的第一个,先获取两张图片的脸部轮廓数据。

然后进行换脸,需要用到用到一个接口:

https://api-cn.faceplusplus.com/imagepp/v1/mergeface

我们说调用别人的接口,就必须别人的规范,传递的参数类型,参数值都要符合人家的要求。

参数包含:

api_key
api_secret
template_base64:base64编码后的模板图片
template_rectangle:字符串格式的脸部数据
merge_base64:编码后的待合并图片
merge_rectangle:字符串格式的脸部数据
merge_rate:相似度

这里总结两种json格式转化为字典格式的方法:
1、

req_dict = json.loads(req_con)

2、

req_dict = json.JSONDecoder().decode(req_con)

文件读取:

f1 = open(img_url1,'rb')
    f1_64 = base64.b64encode(f1.read()) #编码
    f1.close()

文件写入:

file = open(img_url3,'wb')
    file.write(imgdata)
    file.close()

在相似度设置为100的情况下,合并后的图片效果对比:

python换脸表情 gif python换脸算法_python换脸表情 gif_03


改变两张图片的位置,效果:

python换脸表情 gif python换脸算法_python换脸表情 gif_04


相似度设置为30,也就是相当于没有100%换脸,只是换了30%,效果就不粘贴了。

全部代码

import json
import base64
import requests

# 算法
# 构建模型
# 训练模型  ---> 需要数据集

# 找到人脸数据
def find_face(imgpath):
    http_url = 'https://api-cn.faceplusplus.com/facepp/v3/detect'
    #参数
    data = {
        'api_key': '你自己的api_key',
        'api_secret': '你自己的api_secret',
        'img_url':imgpath,
        'return_landmark':1
    }
    #文件
    files = {'image_file':open(imgpath,'rb')}#rb表示二进制的读取
    # 携带数据的请求我们通常使用post请求
    resp = requests.post(http_url,data=data,files=files)
    #req_con是个json格式的数据
    req_con = resp.text
    #类型转换
    this_dict = json.loads(req_con)
    faces = this_dict['faces']
    list0 = faces[0]
    #得到人脸框的数据
    rectangle = list0['face_rectangle']
    print(rectangle)
    return rectangle
# 拟合,拼接人脸
def merge_face(img_url1,img_url2,img_url3,number):
    """
    :param img_url1: 第一张图像
    :param img_url2: 第二张图像
    :param img_url3: 合并后的效果图
    :param number:相似度
    :return:
    """
    #分别获取第一张图片和第二张图片的人脸数据
    ff1 = find_face(img_url1)
    ff2 = find_face(img_url2)
    #因为参数需要是字符串类型,而ff1和ff2都是字典,我们需要格式转换
    rectangle1 = str( str(ff1['top'])+","+str(ff1['left'])+","+str(ff1['width'])+","+str(ff1['height']) )
    rectangle2 = str( str(ff2['top'])+","+str(ff2['left'])+","+str(ff2['width'])+","+str(ff2['height']) )
    print(rectangle1)
    print(rectangle2)
    f1 = open(img_url1,'rb')
    f1_64 = base64.b64encode(f1.read()) #编码
    f1.close()
    f2 = open(img_url2, 'rb')
    f2_64 = base64.b64encode(f2.read())  # 编码
    f2.close()
    #合并,我们需要使用另一个接口
    url_add = 'https://api-cn.faceplusplus.com/imagepp/v1/mergeface'

    data = {
        'api_key': '你自己的api_key',
        'api_secret': '你自己的api_secret',
        'template_base64':f1_64,'template_rectangle':rectangle1,
        'merge_base64':f2_64,'merge_rectangle':rectangle2,
        'merge_rate':number
    }
    resp = requests.post(url_add,data=data)
    req_con = resp.text
    # req_dict = json.loads(req_con)
    # 把json转化为字典,作用和上面那个一样,殊途同归
    req_dict = json.JSONDecoder().decode(req_con)

    result = req_dict['result']
    imgdata = base64.b64decode(result)
    file = open(img_url3,'wb')#用wb写入这张图像
    file.write(imgdata)
    file.close()
if __name__=="__main__":
    img1 = r"E:\test\1.jpg"
    img2 = r"E:\test\2.jpg"
    img3 = r"E:\test\result.jpg"
    merge_face(img1,img2,img3,30)