基于 Face Recognition 實(shí)現(xiàn)人臉識(shí)別服務(wù)

概述

之前的文章所述桑驱,筆者的項(xiàng)目需求是:公司預(yù)先將員工的照片錄入系統(tǒng)懂盐,此后員工訪問系統(tǒng)時(shí)褥赊,可以由前端的照相設(shè)備采集面孔,使用人臉識(shí)別技術(shù)莉恼,找到員工對(duì)應(yīng)的身份信息拌喉,實(shí)現(xiàn) 刷臉登錄 的功能,此外俐银,最好身份信息和照片都在系統(tǒng)內(nèi)尿背,盡量不使用互聯(lián)網(wǎng)服務(wù)。

Face Recognition 庫簡介

經(jīng)過前面對(duì) Face Recognition 庫的學(xué)習(xí)捶惜,實(shí)現(xiàn)了通過Python腳本實(shí)現(xiàn)命令行對(duì)2張人臉的比對(duì)與識(shí)別田藐。再次說明, Face Recognition 庫的主要接口API為:

  1. 人臉檢測:face_recognition.face_locations(img, number_of_times_to_upsample=1, model="hog")
  2. 檢測面部特征點(diǎn): face_landmarks(face_image, face_locations=None, model="large")
  3. 給臉部編碼:face_encodings(face_image, known_face_locations=None, num_jitters=1)
  4. 從編碼中找出人的名字:compare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6)

Face Recognition 庫簡單來說就是:給定一張照片吱七,它可以從中框出人臉汽久,并將人臉提取為特征向量

人臉特征提取

人臉查找

關(guān)鍵在于怎么實(shí)現(xiàn)人臉的比對(duì)陪捷。如果僅僅是2張照片回窘,庫中給出的examples 是通過對(duì)特征向量求距離實(shí)現(xiàn)的。

2張照片比對(duì)

在這個(gè)過程中市袖,根據(jù)照片求特征向量是較慢的啡直,而向量距離是很快的,因?yàn)樗皇菆?zhí)行了簡單矩陣計(jì)算苍碟,這步很快酒觅。

那么如何實(shí)現(xiàn)已有100名員工的照片,傳入一張新照片微峰,查找他是誰呢舷丹?
我也Google了網(wǎng)上其他網(wǎng)友實(shí)現(xiàn)的基于Face Recognition 庫的人臉查找,他們實(shí)現(xiàn)的方式大多擴(kuò)展了一下2張照片比對(duì)的情形蜓肆,比如face-recognition-service颜凯。它的邏輯就是:讀取圖片庫中的100張照片,逐照片分析得出特征向量1-100仗扬,形成特征向量矩陣M症概,然后對(duì)新照片,得出特征向量A早芭,計(jì)算矩陣M和A的距離彼城,選距離小于閾值的那個(gè)向量,反求對(duì)應(yīng)的人。

典型過程

人臉查找邏輯優(yōu)化

前面的邏輯是可以的募壕,唯一問題在于新增人臉后特征向量增加怎么處理调炬。有的項(xiàng)目是再次執(zhí)行預(yù)處理過程,求特征矩陣這步很耗時(shí)舱馅,求距離矩陣這步非崇峙荩快速。

所以我將特征向量存入redis數(shù)據(jù)庫代嗤,查找時(shí)匀谣,直接從數(shù)據(jù)庫取出人名和他對(duì)應(yīng)的特征向量,然后組成特征矩陣资溃,計(jì)算相似度(距離矩陣)

邏輯優(yōu)化

代碼實(shí)現(xiàn)

本代碼基于 Python3 ,使用的庫有 flask烈炭、redis溶锭、numpy 以及 face_recognition

#!/usr/bin/python
# -*- coding: utf-8 -*-

from flask import Flask, Response, request, jsonify
import redis
import face_recognition
import numpy as np

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False

pool = redis.ConnectionPool(host='127.0.0.1', port=6379)

# 首頁
@app.route('/', methods=['GET'])
def index():
    return '''
    <!doctype html>
    <title>人臉服務(wù)</title>
    <a href="upload">人臉錄入</a><br>
    <a href="search">人臉?biāo)阉?lt;/a>
    '''

# 人臉錄入頁
@app.route('/upload', methods=['GET'])
def uploadHtml():
    return '''
    <!doctype html>
    <title>人臉錄入</title>
    <h1>人臉錄入</h1>
    <form method="POST" action="upload" enctype="multipart/form-data">
      姓名:<input type="text" name="name"><br>
      <input type="file" name="file">
      <input type="submit" value="提交">
    </form>
    '''

# 人臉錄入
@app.route('/upload', methods=['POST'])
def upload():
    if 'file' not in request.files:
        return jsonify({'code': 500, 'msg': '沒有文件'})
    file = request.files['file']
    name = request.form['name']
    image = face_recognition.load_image_file(file)
    face_locations = face_recognition.face_locations(image)
    if len(face_locations) != 1:
        return jsonify({'code': 500, 'msg': '人臉數(shù)量有誤'})
    face_encodings = face_recognition.face_encodings(image, face_locations)
    # 連數(shù)據(jù)庫
    r = redis.Redis(connection_pool=pool)
    # 錄入人名-對(duì)應(yīng)特征向量
    r.set(name, face_encodings[0].tobytes())
    return jsonify({'code': 0, 'msg': '錄入成功'})

# 人臉?biāo)阉黜?@app.route('/search', methods=['GET'])
def searchHtml():
    return '''
    <!doctype html>
    <title>人臉?biāo)阉?lt;/title>
    <h1>人臉?biāo)阉?lt;/h1>
    <form method="POST" enctype="multipart/form-data">
      <input type="file" name="file">
      <input type="submit" value="提交">
    </form>
    '''

# 人臉?biāo)阉?@app.route('/search', methods=['POST'])
def search():
    if 'file' not in request.files:
        return jsonify({'code': 500, 'msg': '沒有文件'})
    file = request.files['file']
    image = face_recognition.load_image_file(file)
    face_locations = face_recognition.face_locations(image)
    if len(face_locations) != 1:
        return jsonify({'code': 500, 'msg': '人臉數(shù)量有誤'})
    face_encodings = face_recognition.face_encodings(image, face_locations)
    # 連數(shù)據(jù)庫
    r = redis.Redis(connection_pool=pool)
    # 取出所有的人名和它對(duì)應(yīng)的特征向量
    names = r.keys()
    faces = r.mget(names)
    # 組成矩陣符隙,計(jì)算相似度(歐式距離)
    matches = face_recognition.compare_faces([np.frombuffer(x) for x in faces], face_encodings[0])
    return jsonify({'code': 0, 'names': [str(name, 'utf-8') for name, match in zip(names, matches) if match]})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001, debug=True)

測試

  1. 將代碼保存為 face.py
  2. 通過命令啟動(dòng)代碼 python3 face.py
  3. 通過瀏覽器訪問 http://127.0.0.1:5001 就可以訪問服務(wù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趴捅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子霹疫,更是在濱河造成了極大的恐慌拱绑,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丽蝎,死亡現(xiàn)場離奇詭異猎拨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)屠阻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門红省,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人国觉,你說我怎么就攤上這事吧恃。” “怎么了麻诀?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵痕寓,是天一觀的道長。 經(jīng)常有香客問我蝇闭,道長呻率,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任丁眼,我火速辦了婚禮筷凤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己藐守,他們只是感情好挪丢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卢厂,像睡著了一般乾蓬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上慎恒,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天任内,我揣著相機(jī)與錄音,去河邊找鬼融柬。 笑死死嗦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的粒氧。 我是一名探鬼主播越除,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼外盯!你這毒婦竟也來了摘盆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤饱苟,失蹤者是張志新(化名)和其女友劉穎孩擂,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箱熬,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡类垦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坦弟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片护锤。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酿傍,靈堂內(nèi)的尸體忽然破棺而出烙懦,到底是詐尸還是另有隱情,我是刑警寧澤赤炒,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布氯析,位于F島的核電站,受9級(jí)特大地震影響莺褒,放射性物質(zhì)發(fā)生泄漏掩缓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一遵岩、第九天 我趴在偏房一處隱蔽的房頂上張望你辣。 院中可真熱鬧巡通,春花似錦、人聲如沸舍哄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽表悬。三九已至弥锄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蟆沫,已是汗流浹背籽暇。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饭庞,地道東北人戒悠。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像舟山,于是被迫代替她去往敵國和親救崔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容