FaceTracking.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <template>
  2. <div></div>
  3. </template>
  4. <script>
  5. import * as faceapi from "face-api.js";
  6. import { FACE_API_MODEL_PATH } from "@/constants/constants";
  7. function getFaceDetectorOptions() {
  8. window.____hideMe =
  9. window.____hideMe ||
  10. new faceapi.TinyFaceDetectorOptions({
  11. inputSize: 320,
  12. scoreThreshold: 0.5,
  13. });
  14. return window.____hideMe;
  15. // return new faceapi.SsdMobilenetv1Options({ minConfidence: 0.8 });
  16. // return new faceapi.MtcnnOptions({ minFaceSize: 200, scaleFactor: 0.8 });
  17. }
  18. const detectTimeArray = [];
  19. export default {
  20. name: "FaceTracking",
  21. async created() {
  22. await faceapi.nets.tinyFaceDetector.load(FACE_API_MODEL_PATH);
  23. // faceapi.nets.faceRecognitionNet.load(modelsPath);
  24. await faceapi.loadFaceLandmarkModel(FACE_API_MODEL_PATH);
  25. faceapi.tf.ENV.set("WEBGL_PACK", false);
  26. },
  27. async mounted() {
  28. let trackStarted = false;
  29. const that = this;
  30. async function trackHead() {
  31. const video = document.getElementById("video");
  32. if (
  33. video &&
  34. video.readyState === 4 &&
  35. faceapi.nets.tinyFaceDetector.params
  36. ) {
  37. trackStarted = true;
  38. } else {
  39. return;
  40. }
  41. console.log("start tracking ... ");
  42. await that.detectFaces();
  43. }
  44. this.trackHeadInterval = setInterval(() => {
  45. if (trackStarted) {
  46. clearInterval(this.trackHeadInterval);
  47. } else {
  48. trackHead();
  49. }
  50. }, 1000);
  51. },
  52. beforeDestroy() {
  53. clearInterval(this.trackHeadInterval);
  54. clearTimeout(this.warningTimeout);
  55. clearTimeout(this.detectFacesTimeout);
  56. },
  57. methods: {
  58. async detectFaces() {
  59. const detectStartTime = performance.now();
  60. const videoEl = document.getElementById("video");
  61. // this.___vWidth =
  62. // this.___vWidth ||
  63. // document.getElementById("video-container").clientWidth;
  64. const options = getFaceDetectorOptions();
  65. let result;
  66. try {
  67. result = await faceapi
  68. // .detectSingleFace(videoEl, options)
  69. .detectAllFaces(videoEl, options);
  70. } catch (e) {
  71. window._hmt.push(["_trackEvent", "正在考试页面", "实时人脸检测失败"]);
  72. throw e;
  73. }
  74. // console.log(result);
  75. const detectEndTime = performance.now();
  76. // console.log("WebGL: ", faceapi.tf.ENV.get("WEBGL_PACK"));
  77. console.log(
  78. "WebGL: ",
  79. faceapi.tf.ENV.get("WEBGL_PACK"),
  80. " single detect time: ",
  81. detectEndTime - detectStartTime,
  82. " result: ",
  83. result.length
  84. );
  85. if (detectTimeArray.length < 31) {
  86. // 仅捕获一部分检测次数
  87. detectTimeArray.push(detectEndTime - detectStartTime);
  88. }
  89. if (detectTimeArray.length === 31) {
  90. detectTimeArray.shift();
  91. const avg =
  92. detectTimeArray.reduce((a, b) => a + b, 0) / detectTimeArray.length;
  93. const roundAvg = Math.round(avg / 10) * 10;
  94. window._hmt.push([
  95. "_trackEvent",
  96. "正在考试页面",
  97. "实时人脸检测平均时长",
  98. roundAvg + "ms",
  99. ]);
  100. console.log(detectTimeArray);
  101. detectTimeArray.push(0, 0); // 避免再次达到push条件和上传条件
  102. }
  103. if (result.length >= 2) {
  104. this.$Message.warning({
  105. content: "请独立完成考试",
  106. duration: 5,
  107. closable: true,
  108. });
  109. }
  110. if (result.length === 0) {
  111. this.findFirst = !this.findFirst; // 两次才告警
  112. if (!this.findFirst) {
  113. this.$Message.warning({
  114. content: "请调整坐姿,诚信考试",
  115. duration: 5,
  116. closable: true,
  117. });
  118. }
  119. }
  120. if (
  121. (!result || result.length !== 1) &&
  122. !videoEl.classList.contains("video-warning")
  123. ) {
  124. videoEl.classList.add("video-warning");
  125. this.warningTimeout = setTimeout(function() {
  126. videoEl.classList.remove("video-warning");
  127. }, 3000);
  128. }
  129. this.detectFacesTimeout = setTimeout(() => this.detectFaces(), 5000);
  130. },
  131. },
  132. };
  133. </script>
  134. <style>
  135. @keyframes warning-people {
  136. 0% {
  137. /* border: solid 5px white; */
  138. box-shadow: 0 0 100px white;
  139. }
  140. 100% {
  141. /* border: solid 5px red; */
  142. box-shadow: 0 0 100px gold;
  143. }
  144. }
  145. .video-warning {
  146. animation: warning-people 3s infinite;
  147. }
  148. </style>