Browse Source

人脸采集的视频

y595705120 5 months ago
parent
commit
9f35a5411d
2 changed files with 108 additions and 130 deletions
  1. 18 25
      src/components/face/icollect.vue
  2. 90 105
      src/containers/center/play/components/iMedia.vue

+ 18 - 25
src/components/face/icollect.vue

@@ -1,21 +1,19 @@
 <template>
   <div>
     <div class="video-box">
-      <video id="video" width="240" height="180" preload autoplay loop muted></video>
-      <canvas id="canvas" width="240" height="180"></canvas>
+      <video id="video" width="480" height="360" autoplay ></video>
+      <canvas id="canvas"  width="480" height="360"></canvas>
     </div>
-    <canvas id="screenshotCanvas" width="240" height="180" @click="init"></canvas>
-   <div class="switch-button">
+    <canvas id="screenshotCanvas" width="480" height="360" @click="init"></canvas>
+
+    <div class="switch-button">
       <el-row>
         <el-col :span="12">
-          <el-button type="text" style="color: red;" size="mini" @click="destroyed">关闭摄像头</el-button>
+          <el-button type="primary"  size="mini" @click="destroyed">关闭摄像头</el-button>
         </el-col>
-
         <el-col :span="12">
-          <el-button type="text" style="color: red;" size="mini" @click="init">开始识别</el-button>
+          <el-button type="primary" size="small" @click="init">开始识别</el-button>
         </el-col>
-
-
       </el-row>
     </div>
   </div>
@@ -37,8 +35,7 @@
     },
     props:['updateTime'],
     mounted() {
-      setTimeout( this.init, 2000 )
-      // this.init();
+      setTimeout( this.init, 1500 )
     },
     beforeDestroy(){
       this.destroyed()
@@ -53,10 +50,8 @@
       init() {
         this.video = this.mediaStreamTrack = document.getElementById('video');
         this.screenshotCanvas = document.getElementById('screenshotCanvas');
-
         let canvas = document.getElementById('canvas');
         let context = canvas.getContext('2d');
-
         // 固定写法
         let tracker = new window.tracking.ObjectTracker('face');
         tracker.setInitialScale(4);
@@ -69,7 +64,6 @@
 
         let _this = this;
         tracker.on('track', function(event) {
-
           // 检测出人脸 绘画人脸位置
           context.clearRect(0, 0, canvas.width, canvas.height);
           event.data.forEach(function(rect) {
@@ -87,7 +81,6 @@
       screenshotAndUpload() {
         // 上锁避免重复发送请求
         this.uploadLock = false;
-
         // 绘制当前帧图片转换为base64格式
         let canvas = this.screenshotCanvas;
         let video = this.video;
@@ -97,19 +90,17 @@
         let base64Img = canvas.toDataURL('image/jpeg', 1);
 
         this.$emit("getface", base64Img.replace("data:image/jpeg;base64,", "") )
-        // 打印出 base64Img
-        // console.log('base64Img', base64Img.replace("data:image/jpeg;base64,", ""))
 
         // 请求接口成功以后打开锁
         this.uploadLock = true;
       },
       //关闭摄像头
       destroyed(){
-        if(!this.mediaStreamTrack){
+        if(!this.mediaStreamTrack || !this.mediaStreamTrack.srcObject ){
           return
         }
-        this.mediaStreamTrack.srcObject.getTracks()[0].stop();
-        this.trackerTask.stop()
+        let getTracks =  this.mediaStreamTrack.srcObject.getTracks()
+        if( getTracks.length >0 ) getTracks[0].stop();
       }
     }
   }
@@ -124,21 +115,23 @@
   .video-box{
     position: relative;
     margin-left: 5px;
-    width: 240px;
-    height: 180px;
+    width: 480px;
+    height: 360px;
   }
 
   .switch-button{
     /* margin-top: -50px; */
-    margin: -28px auto;
-    margin-left: 30px;
+    margin: 28px auto;
+    text-align: center;
+    /* margin-left: 30px; */
     /* text-align: center; */
     /* margin-left: 30px; */
   }
   video,canvas{
+    border-radius: 10px;
     position: absolute;
     top: 0;
     left: 0;
-    border: #000000 5px solid;
+    /* border: #000000 5px solid; */
   }
 </style>

+ 90 - 105
src/containers/center/play/components/iMedia.vue

@@ -10,7 +10,6 @@
 
         <div style="height: 540px;">
         <video-player id="myVideo" class="video-player-box" ref="videoPlayer"
-
           @pause="onPlayerPause($event)"
           @play="onPlayerStart($event)"
           @ready="playerReadied"
@@ -21,7 +20,7 @@
         </div>
 
         <div class="tc">
-             <p  v-if="errMsg && identifyFace" style="font-size: 30px;color: red;"> {{errMsg}}</p>
+             <p  v-if="errMsg" style="font-size: 30px;color: red;"> {{errMsg}}</p>
         </div>
 
       </el-col>
@@ -91,30 +90,19 @@
       </el-col>
 
     </el-row>
-<!--   <div class="left-float" v-if="!closeFace" v-drag v-show="identifyFacePass">
-      <video ref="video"  width="240" height="180" autoplay></video>
-      <canvas ref="canvas" v-show="ontakebtn" width="240" height="180"></canvas>
-    </div> -->
-
-    <div class="left-float-dialog" v-drag v-show="identifyFace">
-      <i-collect :updateTime="updateTime" @getface="getface" />
-    </div>
 
-   <el-dialog  title="开始人脸认证" center :visible.sync="identifyFaceDialog" width="400px" :append-to-body="true" >
+   <el-dialog  title="开始人脸认证" center :visible.sync="identifyFaceDialog" width="540px" :append-to-body="true" >
       <div>
-        <p style="color: red;font-size: 24px;text-align: center;"> 请将人脸对准摄像头</p>
-        <canvas id="canvas" width="240" height="180"></canvas>
+        <i-collect :updateTime="updateTime" @getface="getface" />
         <div class="tc m20">
-          <p  v-if="errMsg && identifyFace" style="font-size: 30px;color: red;"> {{errMsg}}</p>
+          <p  v-if="errMsg" style="font-size: 30px;color: red;"> {{errMsg}}</p>
         </div>
       </div>
-    </el-dialog> 
+    </el-dialog>
   </div>
 </template>
 
 <script>
-  // import tracking from '@/assets/tracking/build/tracking-min.js';
-  // import '@/assets/tracking/build/data/face-min.js';
   import {
     httpServer
   } from "@/components/httpServer/httpServer.js";
@@ -125,7 +113,6 @@
   import IMessage from '@/components/message/iMessage.vue'
   import ICollect from '@/components/face/iCollect.vue'
   import 'video.js/dist/video-js.css'
-  // import html2canvas from "html2canvas";
   import {
     MessageBox
   } from "element-ui";
@@ -138,17 +125,18 @@
         tickNum: 0,
         prevTime: 0,
         isReady: false,
-        ontakebtn: false,
-        identifyFace: false,
-        identifyFacePass: false,
         identifyFaceDialog: false,
+        startPlay: false,     // 开始认证
+        nextFaceTime: 0,
+        faceInterval: 10,     // 打开人脸时间
+        closeDailogTime: 20,  // 关闭dialog时间
+        onIdentify: false,    // 同一时间一个认证
+        identifyDuration: 180*1000,
         activeChapter: '',
         activeName: '',
         curTimes: 0,
         errMsg: '',
-        errCount: 0,
         prevCollect: 0,
-        onIdentify: false,
         updateTime: 0,
         imgbase64: '',
         onPlay: false,
@@ -177,21 +165,6 @@
       this.stopTick()
       this.reportErr("play", 'destroy');
     },
-    directives: {
-      drag(el, bindings) {
-        el.onmousedown = function(e) {
-          var disx = e.pageX - el.offsetLeft
-          var disy = e.pageY - el.offsetTop
-          document.onmousemove = function(e) {
-            el.style.left = e.pageX - disx + 'px'
-            el.style.top = e.pageY - disy + 'px'
-          }
-          document.onmouseup = function() {
-            document.onmousemove = document.onmouseup = null
-          }
-        }
-      }
-    },
     computed: {
       player() {
         return this.$refs.videoPlayer.player
@@ -199,10 +172,8 @@
     },
     beforeDestroy() {
       this.destroyTimer()
-      // this.closeCamera( "video" )
     },
     created() {
-      this.startTick()
       this.startMonitor();
       this.activeChapter = this.media.chapterName;
       this.activeName = this.media.name
@@ -213,7 +184,6 @@
         this.activeName = this.media.name
         this.tickNum = 0
         this.errMsg = ''
-        this.errCount = 0
         this.prevCollect = 0;
         this.startIdentify()
         this.setposition( this.media.position )
@@ -223,33 +193,30 @@
       getface( val){
         this.imgbase64 = val;
         let now = parseInt( Date.now()/2000 );
-        if( !this.identifyFacePass && this.prevCollect != now ){
+        // 人脸认证期间, 一秒一次
+        if( !this.identifyFaceDialog && this.prevCollect != now ){
           this.prevCollect = now
-          this.photograph("video2")
+          this.photograph("video")
         }
       },
-      handler_msg(pause, identify, msg ){
+      handler_msg(pause, msg ){
         this.errMsg = msg || '';
-        if (msg) {
-          this.errCount++
-        } else {
-          if( identify ){
-            this.identifyPassAndPlay()
-          }
-          this.errCount = 0;
-        }
-        if (!identify && this.errCount > this.maxErrorCount) {
-          this.doPause();
+        if ( !msg ) {
+          this.identifyPassAndPlay()
         }
       },
       photograph( ref ) {
-        let identify = (ref=="video2");
-        this.ontakebtn = true
-        if( this.onIdentify ){
+        // 认证窗口关闭
+        if( !this.identifyFaceDialog  ){
           return;
         }
+        // 取不到base64
         if( !this.imgbase64 ){
-          this.handler_msg(false, identify, "人脸不在视频上" );
+          this.handler_msg(false, "人脸定位中...." );
+          return;
+        }
+        // 用户在认证中
+        if( this.onIdentify ){
           return;
         }
         this.onIdentify = true;
@@ -265,7 +232,7 @@
             pause
           } = res.data
           this.onIdentify = false;
-          this.handler_msg(pause, identify, msg )
+          this.handler_msg(pause, msg )
         })
       },
       destroyTimer() {
@@ -316,7 +283,6 @@
       onPlayerTimeupdate(player) {
         let curTimes = player.cache_.currentTime;
         if (curTimes > 30 && curTimes > this.curTimes + 2) {
-          console.log("return", curTimes, this.media.position)
           player.currentTime(this.curTimes);
           return;
         }
@@ -326,8 +292,7 @@
         if (position > this.media.duration) position = this.media.duration;
         let player = this.$refs.videoPlayer.player;
         let res = player.currentTime(position);
-        console.log("setposition", position)
-        // player.play()
+        // player.load();
         this.curTimes = position;
         if (this.media.isFinish) return;
         if (this.media.position >= this.media.duration - 2*this.heartbeat && !this.media.isFinish) {
@@ -346,26 +311,29 @@
         this.reportErr("play", 'close')
         this.doPause()
         this.$emit("close")
-        // this.closeCamera( "video")
       },
       doPause() {
         this.onPlay = false
-        let myPlayer = this.$refs.videoPlayer.player;
-        myPlayer && myPlayer.pause()
+        setTimeout( ()=>{
+          let myPlayer = this.$refs.videoPlayer.player;
+          myPlayer && myPlayer.pause()
+        }, 20);
+        // console.log( myPlayer )
+        // myPlayer&& myPlayer.controlBar.hide()
       },
       doPlay() {
         this.onPlay = true
         this.startTick();
         if (!this.$refs.videoPlayer || !this.$refs.videoPlayer.player) return;
-        // if (!this.dialog) return this.doPause();
         let myPlayer = this.$refs.videoPlayer.player;
         myPlayer && myPlayer.play()
         this.tickNum = 0
       },
       onPlayerStart( player ) {
-        console.log("onPlayerStart")
         this.onPlay = true
-        if( !this.identifyFacePass){
+        this.startPlay  = true;
+        let now = Date.now()
+        if(  now > this.nextFaceTime ){
           this.startIdentify()
           return
         }
@@ -373,19 +341,32 @@
         this.startTick();
       },
       startIdentify(){
+        // 清空上一次遗留
+        this.imgbase64 = '';
+        let isDebug = false
         if( !this.closeFace){
-          this.identifyFace = true
-          this.identifyFacePass = false
           this.identifyFaceDialog = true
           this.updateTime = Date.now()
+          // 人脸采集间隔时间
+          this.faceInterval = this.heartbeat * this.collectBeat*1000;
+          // 关闭时间
+          this.closeDailogTime = this.updateTime +  this.identifyDuration;
+          //
+          if( isDebug){
+            this.faceInterval = 30*1000;
+            this.closeDailogTime = this.updateTime + 30*1000;
+          }
         }
         this.startTick()
       },
-
       identifyPassAndPlay(){
-        this.identifyFacePass = true
+        //  认证通过 关闭dialog
         this.identifyFaceDialog = false
+        //  下一次人脸采集时间
+        this.nextFaceTime = Date.now() + this.faceInterval
+        // 通过 开始播放
         this.$message.successMsg("人脸认证通过", 2)
+        this.errMsg = ''
         this.doPlay()
       },
       reportErr(action, msg) {
@@ -407,56 +388,57 @@
           }
         });
       },
+
       tick(force = false) {
         let media = this.media;
         this.tickNum++
-        // 人脸认证期间
-        if( !this.closeFace && !this.identifyFacePass ) {
-          if( this.onPlay ){
-            this.doPause()
-          }
-          // 人脸认证
-          // if (this.tickNum % 3 == 1) {
-          //   this.photograph( "video2" );
-          // }
-          return;
-        };
+        let now = Date.now()
+        // 人脸认证期间 关闭播放
+        if( !this.closeFace ){
+          //
+            if( this.identifyFaceDialog  ) {
+              // 在播放中,关闭播放
+              if( this.onPlay ){
+                this.doPause()
+              }
+              // 主动关闭人脸认证
+              if( now > this.closeDailogTime ){
+                this.$message.errorMsg("人脸检测失败,暂停播放", 5);
+                this.errMsg = "人脸检测失败,暂停播放";
+                // 关闭定时器
+                this.startPlay = false;
+                //  认真失败,下一次播发需要人脸
+                this.nextFaceTime = now
+                this.stopTick();
+                this.identifyFaceDialog = false;
+              }else{
+                // 人脸认证
+                this.photograph("video")
+              }
+              return;
+            }else{
+              console.log("next",(now - this.nextFaceTime)/1000 )
+              if( this.startPlay && now > this.nextFaceTime  ){
+                this.startIdentify();
+                return;
+              }
+            }
+        }
         // 未开始
         if(!force && !this.onPlay ){
           return;
         }
-
         // 已经完成
         if (this.media.isFinish) {
           console.log("finish")
           return;
         }
+
         // 每5秒一次心跳
         if (this.tickNum % this.heartbeat != 0) {
           return;
         }
-        // if (!this.media.isFinish && this.onPlay && !this.closeFace) {
-        //   console.log(this.identifyFacePass , this.media.isFinish , this.onPlay, this.closeFace)
-        //   this.$message.errorMsg("需要安装摄像头才能学习", 2);
-        //   this.doPause()
-        //   return;
-        // }
-        if (this.errCount >= this.maxErrorCount) {
-          this.$message.errorMsg("人脸不在摄像头上", 5);
-          this.destroyTimer()
-          this.$emit("close");
-          return;
-        }
 
-        let heartBeat = parseInt(this.tickNum / this.heartbeat);
-        // 异常 10秒检查
-        if (!this.closeFace) {
-          if (this.errCount > 0) {
-            this.photograph("video")
-          } else if (heartBeat % this.collectBeat == 1) {
-            this.photograph("video")
-          }
-        }
         // 主动暂停
         let myPlayer = this.$refs.videoPlayer.player;
         let curTimes = parseInt(myPlayer.currentTime());
@@ -489,6 +471,9 @@
             } = res.data
             if (pause || closed) {
               this.doPause();
+              // 服务器关闭播放
+              this.startPlay = false;
+              this.stopTick()
               this.$emit("close")
               if (closed) {
                 this.$message.errorMsg("课程关闭学习", 5);