123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <template>
- <div></div>
- </template>
- <script>
- import * as faceapi from "face-api.js";
- import { FACE_API_MODEL_PATH } from "@/constants/constants";
- window.faceapi = faceapi;
- const os = (function() {
- const ua = navigator.userAgent.toLowerCase();
- return {
- isWin2K: /windows nt 5.0/.test(ua),
- isXP: /windows nt 5.1/.test(ua),
- isVista: /windows nt 6.0/.test(ua),
- isWin7: /windows nt 6.1/.test(ua),
- isWin8: /windows nt 6.2/.test(ua),
- isWin81: /windows nt 6.3/.test(ua),
- isWin10: /windows nt 10.0/.test(ua),
- };
- })();
- let __cache4WebglAvailable = null;
- function webgl_available() {
- if (__cache4WebglAvailable) return __cache4WebglAvailable;
- var canvas = document.createElement("canvas");
- var gl = canvas.getContext("webgl");
- __cache4WebglAvailable = gl && gl instanceof WebGLRenderingContext;
- return __cache4WebglAvailable;
- }
- let __cache4TensorFlowWebPackStatus = null;
- function tensorFlowWebPackStatus() {
- if (__cache4TensorFlowWebPackStatus) return __cache4TensorFlowWebPackStatus;
- __cache4TensorFlowWebPackStatus = faceapi.tf.ENV.get("WEBGL_PACK");
- return __cache4TensorFlowWebPackStatus;
- }
- function getCPUModel() {
- if (typeof nodeRequire != "undefined") {
- var os = window.nodeRequire("os");
- const cpus = os.cpus();
- if (cpus.length > 0) {
- return cpus[0].model;
- }
- }
- return "null";
- }
- // if (os.isWin7) alert("是win7");
- // if (os.isWin10) alert("是win10");
- function getFaceDetectorOptions() {
- let inputSize = 320;
- if (os.isWin7) {
- inputSize = 256; // 在win7上无bug,速度快,效果较好
- } else if (os.isWin10) {
- inputSize = 320; // 在win10上,效果较好
- }
- window.____hideMe =
- window.____hideMe ||
- new faceapi.TinyFaceDetectorOptions({
- inputSize: inputSize,
- 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(FACE_API_MODEL_PATH);
- // faceapi.nets.faceRecognitionNet.load(modelsPath);
- await faceapi.loadFaceLandmarkModel(FACE_API_MODEL_PATH);
- 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() {
- this.singleTimeUsage = this.singleTimeUsage || 0;
- this.multipleTimeUsage = this.multipleTimeUsage || 0;
- if (
- this.singleTimeUsage > 10 * 1000 ||
- this.multipleTimeUsage > 3 * 1000
- ) {
- window._hmt.push([
- "_trackEvent",
- "正在考试页面",
- "关闭实时人脸检测,因为耗时过长",
- ]);
- return;
- }
- 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: ",
- webgl_available(),
- " WEBGL_PACK: ",
- tensorFlowWebPackStatus(),
- " single detect time: ",
- detectEndTime - detectStartTime,
- " result: ",
- result.length
- );
- this.singleTimeUsage = detectEndTime - detectStartTime;
- if (detectTimeArray.length < 11) {
- // 仅捕获一部分检测次数
- detectTimeArray.push(detectEndTime - detectStartTime);
- }
- if (detectTimeArray.length === 11) {
- detectTimeArray.shift();
- const avg =
- detectTimeArray.reduce((a, b) => a + b, 0) / detectTimeArray.length;
- const roundAvg = Math.round(avg / 100) * 100;
- window._hmt.push([
- "_trackEvent",
- "正在考试页面",
- "实时人脸检测平均时长",
- roundAvg + "ms",
- ]);
- console.log(detectTimeArray);
- detectTimeArray.push(0, 0); // 避免再次达到push条件和上传条件
- const roundAvg100 = Math.round(avg / 100) * 100;
- const osType = os.isWin7 ? "win7" : os.isWin10 ? "win10" : "other";
- const stats = `webgl: ${webgl_available()}; tf_backend: ${faceapi.tf.getBackend()}; os: ${osType}; cpu: ${getCPUModel()}`;
- window._hmt.push([
- "_trackEvent",
- "正在考试页面",
- "实时人脸检测统计" + roundAvg100 + "ms",
- stats,
- ]);
- this.multipleTimeUsage = roundAvg;
- }
- // init this.showWaringTime
- this.showWaringTime = this.showWaringTime || Date.now();
- if (result.length >= 2 && Date.now() - this.showWaringTime > 20 * 1000) {
- this.showWaringTime = Date.now();
- this.$Message.warning({
- content: "请独立完成考试",
- duration: 5,
- closable: true,
- });
- }
- if (result.length === 0 && Date.now() - this.showWaringTime > 20 * 1000) {
- this.showWaringTime = Date.now();
- 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(), 10 * 1000);
- },
- },
- };
- </script>
- <style>
- @keyframes warning-people {
- 0% {
- /* border: solid 5px white; */
- box-shadow: 0 0 20px white;
- }
- 100% {
- /* border: solid 5px red; */
- box-shadow: 0 0 20px gold;
- }
- }
- .video-warning {
- animation: warning-people 3s infinite;
- }
- </style>
|