用Python实现AI换脸

liftword6个月前 (01-08)技术文章99

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

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

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

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

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

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

需要用到的工具

import json
import base64
import requests

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

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

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

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

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

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

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

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

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

实现步骤:

找到人脸数据,不光光是脸部的轮廓,还有脸部的大小,眼睛鼻子的大小。

拟合,拼接人脸

# 找到人脸数据
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的情况下,合并后的图片效果对比:

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

相似度设置为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)

免责声明:
本案例使用到的图片来源于互联网,仅供个人学习使用,侵删。

相关文章

教你使用python编程绘制函数图像

函数公式很抽象,图像更直观,但聪明的我们总不会手画图像吧?来学习一下用Python怎么画函数图像吧。首先打开Visual Studio Code(后面简称VSCode),点击New File(中文版是...

Python中如何操作Surface对象绘制图形?

在Surface对象上绘制图形分为加载图片和绘制图片两个步骤。(1)加载图片加载图片即将图片读取到程序中,通过pygame中 image模块的load()方法可以向程序中加载图片,生成Surface对...

一篇带你实战的Python绘图Turtle库

Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x、纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行...

Python——如何写一个自动生成短视频的小工具

在如今这个短视频风靡的时代,大家都想在短视频领域分一杯羹。要是有个能自动生成短视频的小工具,那可就太实用啦!今天咱就来聊聊怎么写一个简易的自动生成短视频小工具代码,不管你是编程爱好者,还是想为自己的自...

Python大屏看板最全教程之Pyecharts图表

阅读本文大约需要3分钟主要内容:数据分析。适用人群:Python初学者,数据分析师,或有志从事数据分析工作的人员。准备软件:Anaconda(Spyder:代码编译)、Navicat Premium...

python编程:如何使用python代码绘制出哪些常见的机器学习图像?

专栏推荐绘图的变量单变量查看单变量最方便的无疑是displot()函数,默认绘制一个直方图,并你核密度估计(KDE)sns.set(color_codes=True)np.random.seed(su...