因为我本专业是光电信息科学与工程,最近课设要做一个人脸辨认。关于我这种半途转前端的on9仔,当然是不会做啦。经过查找材料发现,能够使用opencv这个开源的计算机视觉和机器学习软件库来实现,我就想着上网CTRL+CV一段代码交差啦哈哈哈

灵光一闪

居然能够做到人脸辨认,那岂不是能够在我的项目的登录体系中加入人脸登录,那样面试的时分又有东西可吹了

废话不多,直接开干。

思路

  1. 前端注册时上传自己的大头照,后端经过OpenCV练习
  2. 登录时前端经过tracking.js辨认出自己的人脸,再使用canvas转正base64的图片上传给后端,后端拿这张图片进行辨认

技能栈

  • 前端:Vue2 + tracking.js
  • 后端:Python + OpenCV + Flask

不会Python的小伙伴不要担心,我也不会哈哈哈,只用调用opencv的库就ok了

人脸辨认演示

我这儿用的是这篇文章的代码用Python进行人脸辨认[包含源代码],里面有源码和翻开教程(本来计划直接就用来交差的)

能够点我这儿下载源代码 人脸辨认代码,或许文章后边有我封装好的代码

翻开后,在终端运转以下指令,安装依赖

pip install numpy opencv-python

pip install dlib

pip install face_recognition

然后履行一下main.py文件,就能够看到运转的成果了,

这次真的成为CV程序猿了(人脸辨认登录)附代码

总结一下

经过Python使用OpenCV先练习train文件夹下的图片,然后咱们拿test文件夹下的图片用来测试,OpenCV会经过train下最像的图片,放回该图片的文件名(人名)

前端实践

注册

这一部分只要把用户名(最终辨认出来的姓名)和图片上传给后端

注意 照片一定要明晰的大头照,不然OpenCV练习不了会报错

这次真的成为CV程序猿了(人脸辨认登录)附代码

<form
      method="post"
      action="http://localhost:3000/register/"
      enctype="multipart/form-data"
      target="hideIframe1"
    >
      <h3>注册</h3>
      <input type="text" placeholder="账号" name="username" />
      <input type="file" name="photo" />
      <button style="margin-top: 10px" type="submit">注册账号</button>
</form>

tracking.js

tracking.js的安装网上说不建议用nmp,咱们能够到官网上下载tracking.js然后把文件放在src/assets 目录下文件夹更名为 tracking 方便引入

这次真的成为CV程序猿了(人脸辨认登录)附代码

之后咱们只要在需求的页面上引证

import "@/assets/tracking/build/data/face-min.js";

人脸登录

这一步,便是调用摄像头,辨认出人脸,把人脸图片上传到后端,后端会回来辨认后的成果

注意 我这儿仅仅本地调试,上线需求运用有https的域名 不然无法调用摄像头

    <div class="video-box">
      <video id="video" width="320" height="240" preload autoplay loop muted></video>
      <canvas id="canvas" width="320" height="240"></canvas>
    </div>
    <canvas id="screenshotCanvas" width="320" height="240"></canvas>
// 初始化设置
    async init() {
      this.video = document.getElementById("video");
      this.screenshotCanvas = document.getElementById("screenshotCanvas");
      let canvas = document.getElementById("canvas");
      let context = canvas.getContext("2d");
      // 固定写法
      let tracker = new window.tracking.ObjectTracker("face");
      tracker.setInitialScale(4);
      tracker.setStepSize(2);
      tracker.setEdgesDensity(0.1);
      window.tracking.track("#video", tracker, {
        camera: true,
      });
       // 我这儿写了个sleep函数等两秒再履行,避免还没反响过来,摄像头一翻开就辨认上传了
      await this.sleep(2000);
      let _this = this;
      tracker.on("track", function (event) {
        // 检测出人脸 绘画人脸方位
        context.clearRect(0, 0, canvas.width, canvas.height);
        event.data.forEach(function (rect) {
          context.strokeStyle = "#0764B7";
          context.strokeRect(rect.x, rect.y, rect.width, rect.height);
          // 上传图片
          _this.uploadLock && _this.screenshotAndUpload();
        });
      });
    },
    // 上传图片
    async screenshotAndUpload() {
      // 上锁避免重复发送恳求
      this.uploadLock = false;
      // 制作当前帧图片转换为base64格局
      let canvas = this.screenshotCanvas;
      let video = this.video;
      let ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
      console.log("camvas", canvas);
      // 将图片保存为png格局
      let base64Img = canvas.toDataURL("image/png");
      // 运用 base64Img 恳求接口即可
      // console.log("base64Img:", base64Img);
      //我后端地址是localhost:3000,我这儿用了webpack代理解决跨域
      axios.post("/api/check", {
          data: base64Img,
        }).then((res) => {
          。。。。。。
        });
      // 恳求接口成功今后翻开锁
      // await this.sleep(1500);
      // this.uploadLock = true;
    },

到这一步前端的工作就悉数完结了

后端实践

Flask敞开服务器

我真的不会Python,可是思路上后端要做的工作都一样,我先上网搜了下发现能够使用Flask敞开一个本地的服务器

from flask import Flask, request
app = Flask(__name__)
@app.route("/test/")
def test():
    return "hello world"
if __name__ == '__main__':
    app.run(host='127.0.0.1', port=3000)

运转起来,在浏览器拜访localhost:3000/tset/,就能够看到hello word

这样咱们只需求写两个接口注册和辨认

注册

咱们只需求把前端传来的图片存在本地的,并以username命名图片

@app.route('/register/', methods=['POST'])
def register():
    img = request.files.get('photo')  # 从post恳求中获取图片数据
    username = request.form.get('username', '')
    suffix = '.' + img.filename.split('.')[-1]  # 获取文件后缀名
    basedir = os.path.abspath(os.path.dirname(__file__))  # 获取当前文件途径
    photo = '/static/uploads/' + username + suffix  # 拼接相对途径,并把username作为图片姓名
    img_path = basedir + photo  # 拼接图片完好保存途径,
    img.save(img_path)  # 保存图片
    return {'msg': 'ok'}

辨认

这儿咱们拿到的是前端传来base64格局的图片,咱们要把它转成图片并保存在本地(temp.png)

@app.route('/check', methods=['POST'])
def check():
    src = request.data
    print(src)
    data = str(src).split(',')[1][:-3]
    img_data = base64.b64decode(data)
    with open("./test/temp.png", 'wb') as f:
        f.write(img_data)
    这儿使用OpenCV辨认这张图片,然后把成果回来
    return {'msg': 'ok'}

要点来了

因为我真的一点也不会Python,我的想法很简单,计划把main.py里的代码包装成一个函数最终把辨认出来的数组return,我在/check接口中接纳。

我咨询了一下我同学一些语法问题,他是视觉辨认这一块的大佬(10多个省奖),他听了后觉得代码写的十分的不高雅,于是乎他把一切main.py的代码封装成一个类,并把悉数代码写入一个文件中,代码如下

完好后端代码

  • face_distances这个值越小阐明精度越高,大于这个值就回来["no match"]
  • 辨认完放回一个的数组msg:['Chris]
import face_recognition as fr
import cv2
import numpy as np
import os, base64
from flask import Flask, request, Response, render_template
app=Flask(__name__)
class face:
    def __init__(self, train_path):
        self.known_names = []
        self.known_name_encodings = []
        self.train_path = train_path
    def init(self):
        images = os.listdir(self.train_path)
        for _ in images:
            image = fr.load_image_file(self.train_path + _)
            image_path = self.train_path + _
            encoding = fr.face_encodings(image)[0]
            self.known_name_encodings.append(encoding)
            self.known_names.append(os.path.splitext(os.path.basename(image_path))[0].capitalize())
    def add(self, img_path):
        image = fr.load_image_file(img_path)
        encoding = fr.face_encodings(image)[0]
        self.known_name_encodings.append(encoding)
        self.known_names.append(os.path.splitext(os.path.basename(img_path))[0].capitalize())
        # print(self.known_names)
    def compare(self, img_path):
        image = img_path
        image = cv2.imread(image)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        face_locations = fr.face_locations(image)
        face_encodings = fr.face_encodings(image, face_locations)
        names = []
        for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
            matches = fr.compare_faces(self.known_name_encodings, face_encoding)
            name = ""
            face_distances = fr.face_distance(self.known_name_encodings, face_encoding)
            print(face_distances)
            if min(face_distances) > 0.45:
            // face_distances这个值越小阐明精度越高,大于这个值就回来["no match"]
                return ["no match"]
            best_match = np.argmin(face_distances)
            if matches[best_match]:
                name = self.known_names[best_match]
                names.append(name)
            cv2.rectangle(image, (left, top), (right, bottom), (0, 0, 255), 2)
            cv2.rectangle(image, (left, bottom - 15), (right, bottom), (0, 0, 255), cv2.FILLED)
            font = cv2.FONT_HERSHEY_DUPLEX
            cv2.putText(image, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)
        print(names)
        return names
        # cv2.imshow("Result", image)
        # cv2.imwrite("./output.jpg", image)
        # cv2.waitKey(0)
        # cv2.destroyAllWindows()
@app.route('/register/', methods=['POST'])
def register():
    global recognition
    img = request.files.get('photo')  # 从post恳求中获取图片数据
    username = request.form.get('username', '')
    suffix = '.' + img.filename.split('.')[-1]  # 获取文件后缀名
    basedir = os.path.abspath(os.path.dirname(__file__))  # 获取当前文件途径
    photo = '/train/' + username + suffix  # 拼接相对途径
    img_path = basedir + photo  # 拼接图片完好保存途径,时刻戳命名文件防止重复
    img.save(img_path)  # 保存图片
    recognition.add(img_path)
    return {'msg': 'ok'}
@app.route('/check', methods=['POST'])
def check():
    global recognition
    src = request.data
    data = str(src).split(',')[1][:-3]
    img_data = base64.b64decode(data)
    with open("./test/temp.png", 'wb') as f:
        f.write(img_data)
    names = recognition.compare("./test/temp.png")
    // 放回一个辨认的数组
    return {'msg': names}
if __name__ == "__main__":
    recognition = face("./train/")
    recognition.init()
    app.run(host='127.0.0.1', port=3000)

到这一步后端一切的工作也做完啦

演示

登录

我英文名叫Chris,照片就放简历的大头照哈哈哈

这次真的成为CV程序猿了(人脸辨认登录)附代码

辨认

这次真的成为CV程序猿了(人脸辨认登录)附代码

成功后提示,接下来操作… (自由发挥)

这次真的成为CV程序猿了(人脸辨认登录)附代码

整个人脸登录已完结,恭喜自己成为CV程序猿哈哈哈

END

  • 感想

或许许多小伙伴会说,为什么不自己写一个人脸辨认的算法呀,你都根本不明白Python,这仅仅调库。我想说关于咱们这种小白,咱们能够站在伟人的膀子上,使用市面上各种开源的库,来结合自己的需求,完结公司的项目。咱们先锻炼自己的编码思维,再对自己感兴趣的范畴进行专研。✊✊

  • 谢谢我们的支持,希望这篇文章能够协助到有需求的小伙伴,有各种问题能够评论区留言或许私信我