FaceTracking.vue 4.2 KB

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