QQ头像加口罩PHP,如何用人脸识别自动给头像添加口罩及护目镜

给头像添加口罩及护目镜

写在前面

武汉爆发了2020新型冠狀病毒肺炎,大家都纷纷戴上了口罩以预防被传染。朋友圈也不例外,许多用户都为自己的头像戴上了口罩,但是p图调整口罩的位置浪费了大家很多时间。那么我们如何通过人脸识别自动给头像添加口罩及护目镜呢?

此项目使用人脸识别自动给头像添加口罩及护目镜,仅为呼吁大家积极佩戴口罩及护目镜,为武汉及奋斗在第一线的医护人员加油!

依赖🐍

在开始前,我们需要在python3上安装以下几个包:

numpy==1.17.4

Flask>=1.0.0

requests==2.22.0

opencv-python==4.0.0.21

dlib==19.17.99

Flask为我们的项目提供了一个简单的Web服务器,dlib用以识别人脸及嘴唇和眼睛的部位(提供了口罩所在的位置),opencv库可以把口罩素材添加到人脸的嘴唇部位上,护目镜添加到人脸的眼部。

搭建Web服务器

首先,引入flask库并构造主页面:

from flask import Flask

from flask import request

from flask import render_template

@app.route('/', methods=['GET', 'POST'])

def index():

return render_template('index.html')

----------------------

if __name__ == '__main__':

app.run()

需要注意的是,我们的服务器上只允许上传图片类型的文件,并且不缓存图片(用户可以选择其他的口罩重新制作),所以我们要进行如下配置:

app = Flask(__name__)

# 取消图片缓存

app.config['SEND_FILE_MAX_AGE_DEFAULT'] = timedelta(seconds=1)

ALLOWED_EXTENSIONS = set(['bmp', 'png', 'jpg', 'jpeg'])

UPLOAD_FOLDER=r'./cache/'

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):

return '.' in filename and \

filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

我们的Web服务器上包含有两个路由:

/url /add

url 是粘贴图片的地址,服务器会自动下载图片,add 则为用户手动上传图片 (如果只需用户手动上传图片,不需要引入requests库)

add 路由的函数代码如下:

@app.route('/add', methods=['GET', 'POST'])

def search():

if request.method == 'POST':

file = request.files['image']

mode = (int)(request.form['mask'])

isGoggle = request.form.get('goggle')

if file and allowed_file(file.filename):

path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)

file.save(path)

output = add(path, file.filename, mode, isGoggle)

return render_template('index.html', output = output)

else:

return render_template('index.html', alert = '文件类型必须是图片!')

else:

return render_template('index.html')

接着我们配置好 templates 里的 index.html 文件,详细代码请移步 Github 项目。

人脸识别

好了,到这里我们已经成功配置好Web服务器了,接着我们开始写后端处理图片的代码。我们引入 dlib 和 opencv 库:

import cv2

import dlib

import numpy as np

import os

利用已经训练好的 Dlib 正向人脸检测器 detector = dlib.get_frontal_face_detector() 进行人脸检测,并用 'models/shapepredictor68facelandmarks.dat' 进行 人脸嘴部 20 个特征点坐标( 40 维特征)的提取:

def get_mouth(img):

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor('models/shape_predictor_68_face_landmarks.dat')

faces = detector(img_gray, 0)

for k, d in enumerate(faces):

x = []

y = []

# 人脸大小的高度

height = d.bottom() - d.top()

# 人脸大小的宽度

width = d.right() - d.left()

shape = predictor(img_gray, d)

# 49-68 为嘴唇部分

for i in range(48, 68):

x.append(shape.part(i).x)

y.append(shape.part(i).y)

# 根据人脸的大小扩大嘴唇对应口罩的区域

y_max = (int)(max(y) + height / 3)

y_min = (int)(min(y) - height / 3)

x_max = (int)(max(x) + width / 3)

x_min = (int)(min(x) - width / 3)

size = ((x_max-x_min),(y_max-y_min))

return x_min, x_max, y_min, y_max, size

同样的道理,我们进行 人脸眼部特征 的提取:

def get_eye(img):

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor('models/shape_predictor_68_face_landmarks.dat')

faces = detector(img_gray, 0)

for k, d in enumerate(faces):

x = []

y = []

height = d.bottom() - d.top()

width = d.right() - d.left()

shape = predictor(img_gray, d)

for i in range(36, 48):

x.append(shape.part(i).x)

y.append(shape.part(i).y)

y_max = (int)(max(y) + height / 3)

y_min = (int)(min(y) - height / 3)

x_max = (int)(max(x) + width / 3)

x_min = (int)(min(x) - width / 3)

size = ((x_max-x_min),(y_max-y_min))

return x_min, x_max, y_min, y_max, size

识别出嘴唇和眼睛的位置后,我们通过 opencv 处理背景透明的口罩和护目镜素材 ,把背景变成白色:

img2 = cv2.imread('masks/goggle.png', cv2.IMREAD_UNCHANGED)

img2 = cv2.resize(img2,size)

alpha_channel = img2[:, :, 3]

_, mask = cv2.threshold(alpha_channel, 220, 255, cv2.THRESH_BINARY)

color = img2[:, :, :3]

img2 = cv2.bitwise_not(cv2.bitwise_not(color, mask=mask))

然后进行图像融合,把口罩及护目镜添加到我们刚刚得到的嘴唇位置和眼睛位置:

x_min, x_max, y_min, y_max, size = get_eye(img1)

rows,cols,channels = img2.shape

roi = img1[y_min: y_min + rows, x_min:x_min + cols]

img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

ret, mask = cv2.threshold(img2gray, 254, 255, cv2.THRESH_BINARY)

mask_inv = cv2.bitwise_not(mask)

img1_bg = cv2.bitwise_and(roi,roi,mask = mask)

img2_fg = cv2.bitwise_and(img2,img2,mask = mask_inv)

dst = cv2.add(img1_bg,img2_fg)

img1[y_min: y_min + rows, x_min:x_min + cols] = dst

到这里,我们人脸识别添加口罩及护目镜的代码就已经成功完成了。

演示😷

项目完成后,

仅需一个命令即可简单地运行Web服务器:

$ python3 server.py

然后访问:127.0.0.1:5000(端口 5000).

这里支持两种模式,一种是输入URL地址,另外一种是直接上传图片:

1460000021647490

1460000021647491

目前口罩支持以下几种类型:

1460000021647494

举个栗子🌰

原图:

1460000021647492

添加口罩及护目镜:

1460000021647495

原图:

1460000021647496

添加口罩:

1460000021647493

感谢🙏

感谢奋斗在第一线的医护人员,感谢春运中的逆行者!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值