如何用人臉識別自動給頭像添加口罩及護目鏡
給頭像添加口罩及護目鏡
項目地址:https://github.com/Evilran/add-mask-and-goggle
寫在前面
武漢爆發(fā)了2020新型冠狀病毒肺炎,大家都紛紛戴上了口罩以預防被傳染。朋友圈也不例外,許多用戶都為自己的頭像戴上了口罩,但是p圖調整口罩的位置浪費了大家很多時間。那么我們如何通過人臉識別自動給頭像添加口罩及護目鏡呢?
此項目使用人臉識別自動給頭像添加口罩及護目鏡,僅為呼吁大家積極佩戴口罩及護目鏡,為武漢及奮斗在第一線的醫(yī)護人員加油!
依賴🐍
在開始前,我們需要在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', outputoutput = 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 維特征)的提?。?nbsp;
- 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)
- # 根據人臉的大小擴大嘴唇對應口罩的區(qū)域
- 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
同樣的道理,我們進行 人臉眼部特征 的提?。?nbsp;
- 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, maskmask=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,maskmask = 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地址,另外一種是直接上傳圖片:
目前口罩支持以下幾種類型:
舉個栗子🌰
原圖:
添加口罩及護目鏡:
原圖:
添加口罩:
感謝🙏
感謝奮斗在第一線的醫(yī)護人員,感謝春運中的逆行者!