項目地址: https://github.com/Evilran/add-mask-and-goggle
武漢爆發了2020新型冠狀病毒肺炎,你們都紛紛戴上了口罩以預防被傳染。朋友圈也不例外,許多用戶都爲本身的頭像戴上了口罩,可是p圖調整口罩的位置浪費了你們不少時間。那麼咱們如何經過人臉識別自動給頭像添加口罩及護目鏡呢?html
此項目使用人臉識別自動給頭像添加口罩及護目鏡,僅爲呼籲你們積極佩戴口罩及護目鏡,爲武漢及奮鬥在第一線的醫護人員加油!python
在開始前,咱們須要在python3上安裝如下幾個包:git
Flask爲咱們的項目提供了一個簡單的Web服務器,dlib用以識別人臉及嘴脣和眼睛的部位(提供了口罩所在的位置),opencv庫能夠把口罩素材添加到人臉的嘴脣部位上,護目鏡添加到人臉的眼部。github
首先,引入flask庫並構造主頁面: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 項目。app
好了,到這裏咱們已經成功配置好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地址,另一種是直接上傳圖片:
目前口罩支持如下幾種類型:
原圖:
添加口罩及護目鏡:
原圖:
添加口罩:
感謝奮鬥在第一線的醫護人員,感謝春運中的逆行者!
口罩及護目鏡素材來自:[maskon-wuhan]@izumiwing