123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- <template>
- <div></div>
- </template>
- <script>
- import * as faceapi from "face-api.js";
- // models path
- const modelsPath = "/models/";
- function getFaceDetectorOptions() {
- window.____hideMe =
- window.____hideMe ||
- new faceapi.TinyFaceDetectorOptions({
- inputSize: 320,
- scoreThreshold: 0.5,
- });
- return window.____hideMe;
- // return new faceapi.SsdMobilenetv1Options({ minConfidence: 0.8 });
- // return new faceapi.MtcnnOptions({ minFaceSize: 200, scaleFactor: 0.8 });
- }
- const detectTimeArray = [];
- export default {
- name: "FaceTracking",
- async created() {
- await faceapi.nets.tinyFaceDetector.load(modelsPath);
- // faceapi.nets.faceRecognitionNet.load(modelsPath);
- await faceapi.loadFaceLandmarkModel(modelsPath);
- faceapi.tf.ENV.set("WEBGL_PACK", false);
- },
- async mounted() {
- let trackStarted = false;
- const that = this;
- async function trackHead() {
- const video = document.getElementById("video");
- if (
- video &&
- video.readyState === 4 &&
- faceapi.nets.tinyFaceDetector.params
- ) {
- trackStarted = true;
- } else {
- return;
- }
- console.log("start tracking ... ");
- await that.detectFaces();
- }
- this.trackHeadInterval = setInterval(() => {
- if (trackStarted) {
- clearInterval(this.trackHeadInterval);
- } else {
- trackHead();
- }
- }, 1000);
- },
- beforeDestroy() {
- clearInterval(this.trackHeadInterval);
- clearTimeout(this.warningTimeout);
- clearTimeout(this.detectFacesTimeout);
- },
- methods: {
- async detectFaces() {
- const detectStartTime = performance.now();
- const videoEl = document.getElementById("video");
- // this.___vWidth =
- // this.___vWidth ||
- // document.getElementById("video-container").clientWidth;
- const options = getFaceDetectorOptions();
- let result;
- try {
- result = await faceapi
- // .detectSingleFace(videoEl, options)
- .detectAllFaces(videoEl, options);
- } catch (e) {
- window._hmt.push(["_trackEvent", "正在考试页面", "实时人脸检测失败"]);
- throw e;
- }
- // console.log(result);
- const detectEndTime = performance.now();
- // console.log("WebGL: ", faceapi.tf.ENV.get("WEBGL_PACK"));
- console.log(
- "WebGL: ",
- faceapi.tf.ENV.get("WEBGL_PACK"),
- " single detect time: ",
- detectEndTime - detectStartTime,
- " result: ",
- result.length
- );
- if (detectTimeArray.length < 31) {
- // 仅捕获一部分检测次数
- detectTimeArray.push(detectEndTime - detectStartTime);
- }
- if (detectTimeArray.length === 31) {
- detectTimeArray.shift();
- const avg =
- detectTimeArray.reduce((a, b) => a + b, 0) / detectTimeArray.length;
- const roundAvg = Math.round(avg / 10) * 10;
- window._hmt.push([
- "_trackEvent",
- "正在考试页面",
- "实时人脸检测平均时长",
- roundAvg + "ms",
- ]);
- console.log(detectTimeArray);
- detectTimeArray.push(0, 0); // 避免再次达到push条件和上传条件
- }
- if (result.length >= 2) {
- this.$Message.warning({
- content: "请独立完成考试",
- duration: 5,
- closable: true,
- });
- }
- if (result.length === 0) {
- this.findFirst = !this.findFirst; // 两次才告警
- if (!this.findFirst) {
- this.$Message.warning({
- content: "请调整坐姿,诚信考试",
- duration: 5,
- closable: true,
- });
- }
- }
- if (
- (!result || result.length !== 1) &&
- !videoEl.classList.contains("video-warning")
- ) {
- videoEl.classList.add("video-warning");
- this.warningTimeout = setTimeout(function() {
- videoEl.classList.remove("video-warning");
- }, 3000);
- }
- this.detectFacesTimeout = setTimeout(() => this.detectFaces(), 5000);
- },
- },
- };
- </script>
- <style>
- @keyframes warning-people {
- 0% {
- /* border: solid 5px white; */
- box-shadow: 0 0 100px white;
- }
- 100% {
- /* border: solid 5px red; */
- box-shadow: 0 0 100px gold;
- }
- }
- .video-warning {
- animation: warning-people 3s infinite;
- }
- </style>
|