项目背景

公司最近客户要求做人脸验证,然后找了资料做了一个简单版,现在记录学习下。

实现原理

1,调用浏览器摄像头方法打开摄像头,然后利用canvas拍照转base64保存下来

2,利用websocket实时和后端通信, 每隔几秒向后端发送最新的拍的照片让后端对比,最后拿到返回的结果完成验证登录

<template>
  <el-dialog
    :visible.sync="dialogShow"
    width="70%"
    append-to-body
    @close="stopCamera"
    @open="openHeart"
  >
    <div class="compare-box">
      <div class="video-box">
        <div class="video-box1">
          <div class="video-title1">
            <video
              id="videoCamera"
              width="600"
              height="460"
              ref="videoElement"
              autoplay
            ></video>
          </div>
          <div class="botn-box">
            <el-button type="primary" @click="handleFile(1)"
              >打开摄像头</el-button
            >
            <el-button type="primary" @click="handleFile(2)">拍照</el-button>
          </div>
        </div>
        <div class="video-box2">
          <div class="video-title1">
            <canvas
              id="canvasCamera"
              width="600"
              height="460"
              ref="canvasElement"
            ></canvas>
          </div>
          <div class="botn-box">
            <el-button type="primary" @click="handleFile(3)"
              >确定上传</el-button
            >
            <el-button type="primary" @click="handleFile(4)">关闭</el-button>
          </div>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script>
export default {
  data() {
    return {
      dialogShow: false,
      photo: "", //拍照的
      Loading: false,
      videoElement: {
        srcObject: null,
      },
      urlBase: "http://xxxxx", //地址
      heartbeatInterval: null, // 保存心跳定时器的ID
      heartbeatTimeout: 3000, // 心跳间隔时间
      isConnected: false,
      ws: null, // WebSocket连接
      timerInter: null,
    };
  },
  components: {},
  computed: {},
  created() {},
  mounted() {
    // this.initConnect();
  },
  methods: {
    //按钮
    handleFile(e) {
      if (e == 1) {
        this.startCamera();
      } else if (e == 2) {
        this.sendFrame();
      } else if (e == 3) {
        this.sendPhoto();
      } else if (e == 4) {
        this.stopCamera();
      }
    },
    //打开摄像头
    startCamera() {
      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices
          .getUserMedia({ video: true })
          .then((stream) => {
            this.$refs.videoElement.srcObject = stream;
            this.videoElement.srcObject = stream;
            this.$refs.videoElement.play();

            // this.sendFrame();
          })
          .catch((error) => {
            console.error("获取摄像头失败:", error);
          });
      } else {
        window.alert("浏览器不支持getUserMedia");
      }
    },
    //关闭摄像头和心跳
    stopCamera() {
      if (this.videoElement.srcObject) {
        const tracks = this.$refs.videoElement.srcObject.getTracks();
        tracks.forEach((track) => track.stop());
        this.$refs.videoElement.srcObject = null;
        this.videoElement.srcObject = null;
      }
      this.dialogShow = false;
      const canvas = this.$refs.canvasCamera;
      const context = canvas.getContext("2d");
      context.clearRect(0, 0, canvas.width, canvas.height);
      this.photo = "";

      this.heartbeatInterval = null;
      // 清除心跳定时器
      clearInterval(this.heartbeatInterval);
      this.timerInter = null;
      // 定时器
      clearInterval(this.timerInter);
    },
    openHeart() {
      this.initConnect();
    },
    // 拍照
    handlePhotograph() {
      let canvas = this.$refs.canvasElement;
      const context = canvas.getContext("2d");
      context.drawImage(
        this.$refs.videoElement,
        0,
        0,
        canvas.width,
        canvas.height
      );
      this.photo = canvas.toDataURL("image/jpeg"); // 将canvas内容转换为DataURL,即base64编码的图片数据UR
      console.log(this.photo);
      // this.sendPhoto(this.photo);
    },
    //开始拍照
    sendFrame() {
      this.handlePhotograph();
    },
    // 发送图片
    sendPhoto(photo) {
      if (this.ws && this.ws.readyState === WebSocket.OPEN) {
        this.ws.send(photo);
      }
    },
    initConnect() {
      this.startCamera();
      var reqUrl = this.urlBase + "/camera";
      let url = reqUrl.replace("http", "ws");
      this.ws = new WebSocket(url); //websocket连接地址
      this.ws.onopen = () => {
        console.log("WebSocket连接已建立");
        this.isConnected = true;
        // 建立心跳定时器
        this.heartbeatInterval = setInterval(() => {
          if (this.ws.readyState === 1) {
            // console.log(this.photo);
            // this.ws.send(this.photo);
            console.log("心跳开启");
          }
        }, this.heartbeatTimeout);
      };
      this.ws.onmessage = (event) => {
        console.log(event.data, "接收到的信息");
        if (event.data == "0") {
          this.sendFrame();
        } else if (event.data !== "连接成功") {
          this.$emit("photoFile", event.data);
          this.stopCamera();
        } else {
        }
      };
      this.ws.onerror = () => {
        console.error("WebSocket连接发生错误");
        this.ws.close();
      };
      this.ws.onclose = () => {
        console.log("WebSocket连接已关闭");
        this.ws.send("close");
        this.isConnected = false;
        // 清除心跳定时器
        clearInterval(this.heartbeatInterval);
        this.handleReconnect();
      };
    },
    handleReconnect() {
      console.log("WebSocket 断开连接,尝试重连...");
      setTimeout(() => this.initConnect(), this.heartbeatTimeout);
    },
  },
  beforeDestroy() {
    if (this.heartbeatInterval !== null) {
      this.ws.close();
      this.heartbeatInterval = null;
      // 清除心跳定时器
      clearInterval(this.heartbeatInterval);
      this.timerInter = null;
      // 定时器
      clearInterval(this.timerInter);
    }
  },
};
</script>
<style lang="less" scoped>
.video-box {
  display: flex;
  width: 1220px;
  padding: 10px;
  height: 580px;
  margin: 0 auto;
  align-items: center;
  padding: 30px;
}

.video-box1 {
  width: 600px;
}
.video-title1 {
  width: 600px;
  height: 470px;
  border: 1px solid #409eff;
}
#videoCamera {
  width: 100%; /* 或者其他尺寸 */
  height: auto;
}
#canvasCamera {
  width: 100%; /* 或者其他尺寸 */
  height: auto;
}
.botn-box {
  text-align: center;
  margin-top: 20px;
}
.el-button {
  //   display: block;
  margin: 0px auto;
  text-align: center;
  color: #fff;
  background: #15bd9b;
  border: none;
  //   border-radius: 36px;
  cursor: pointer;
  box-shadow: 0px 5px 25px rgba(0, 0, 0, 0.1);
}
.el-button:hover {
  background-color: #088d72;
}
</style>

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐