Prechádzať zdrojové kódy

添加bodyPix模型文件结合tensorflow人像背景虚化处理

fbw 1 týždeň pred
rodič
commit
9ca33bbdc1

BIN
public/js/model/bodypix/group1-shard1of2.bin


BIN
public/js/model/bodypix/group1-shard2of2.bin


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
public/js/model/bodypix/model-stride16.json


+ 112 - 68
src/views/recognize/components/VideoLocalWindow.vue

@@ -1,9 +1,18 @@
 <template>
   <div class="videoContainer">
-    <video ref="video" autoplay muted playsinline></video>
+    <video
+      ref="video"
+      id="video"
+      :width="1280"
+      :height="800"
+      autoplay
+      muted
+      playsinline
+    ></video>
     <div id="timestamp" v-show="false">
       {{ datetimeData.date + " " + datetimeData.time }}
     </div>
+    <canvas id="blurred-canvas" :width="1280" :height="800"></canvas>
     <!-- <el-button @click="startCamera">开启摄像头</el-button>
     <el-button @click="stopCamera" :disabled="!isCameraActive"
       >关闭摄像头</el-button
@@ -13,6 +22,9 @@
 
 
 <script>
+/* eslint-disable */
+import * as tf from "@tensorflow/tfjs";
+import * as bodyPix from "@tensorflow-models/body-pix";
 import { GetPersonByFace, GetPersonByFaceBase64 } from "@/API/custom";
 import Dayjs from "dayjs";
 
@@ -59,6 +71,7 @@ export default {
   data() {
     return {
       isCameraActive: false,
+      video: null,
       stream: null,
       captureInterval: null, // 新增定时器变量
       datetimeData: {
@@ -66,6 +79,12 @@ export default {
         time: Dayjs(new Date()).format("HH:mm:ss"),
         week: Dayjs(new Date()).format("dddd"),
       },
+      // BodyPix模型加载
+      net: null,
+      localModelPath: "/js/model/bodypix/model-stride16.json",
+      // 修改默认值为 true,自动开启背景虚化
+      showBlurred: true,
+      loading: true,
     };
   },
   methods: {
@@ -84,18 +103,51 @@ export default {
         timer = null;
       });
     },
+    async loadBodyPix() {
+      this.net = await bodyPix.load({ modelUrl: this.localModelPath });
+      console.log("BodyPix模型加载返回", this.net);
+      this.processVideoFrame();
+    },
+    async processVideoFrame() {
+      // 确保 video 和 blurredCanvas 存在
+      if (this.showBlurred && this.video && this.blurredCanvas) {
+        try {
+          const segmentation = await this.net.segmentPerson(this.video);
+          const backgroundBlurAmount = 10;
+          const edgeBlurAmount = 3;
+          const flipHorizontal = false;
+
+          bodyPix.drawBokehEffect(
+            this.blurredCanvas,
+            this.video,
+            segmentation,
+            backgroundBlurAmount,
+            edgeBlurAmount,
+            flipHorizontal
+          );
+        } catch (err) {
+          console.error("处理视频帧时出错:", err);
+        }
+      }
+
+      requestAnimationFrame(() => this.processVideoFrame());
+    },
     async startCamera() {
       try {
-        const stream = await navigator.mediaDevices.getUserMedia({
-          video: {
-            width: { ideal: 1280 },
-            height: { ideal: 800 },
-            facingMode: "user",
-          },
+        this.stream = await navigator.mediaDevices.getUserMedia({
+          video: true,
         });
-        this.stream = stream;
+        this.video = document.getElementById("video");
         this.isCameraActive = true;
-        this.$refs.video.srcObject = stream;
+
+        if (this.video) {
+          this.video.srcObject = this.stream;
+          this.loading = false;
+          this.loadBodyPix();
+        } else {
+          this.error = "未能找到视频元素,请检查 HTML 结构。";
+          this.loading = false;
+        }
 
         if (this.isUpload) {
           setTimeout(() => {
@@ -111,13 +163,14 @@ export default {
       } catch (err) {
         console.error("摄像头访问错误:", err);
         alert(`摄像头访问失败: ${err.message}`);
+        this.loading = false;
       }
     },
     stopCamera() {
       if (this.stream) {
         this.stream.getTracks().forEach((track) => track.stop());
         this.isCameraActive = false;
-        this.$refs.video.srcObject = null;
+        this.video.srcObject = null;
         this.stream = null;
 
         // 停止定时器
@@ -127,65 +180,24 @@ export default {
         }
       }
     },
-    // 新增截图方法
-    // async captureImage() {
-    //   const video = this.$refs.video;
-    //   video.currentTime = 1;
-    //   const canvas = document.createElement("canvas");
-    //   canvas.width = video.videoWidth;
-    //   canvas.height = video.videoHeight;
-    //   canvas
-    //     .getContext("2d")
-    //     .drawImage(video, 0, 0, canvas.width, canvas.height);
-    //   // 下载到本地
-    //   // const link = document.createElement("a");
-    //   // link.download = `capture_${new Date()
-    //   //   .toISOString()
-    //   //   .replace(/[:.]/g, "-")}.png`;
-    //   // link.href = canvas.toDataURL("image/png");
-    //   // link.click();
-
-    //   // 将canvas转为Blob对象
-    //   canvas.toBlob(async (blob) => {
-    //     if (blob) {
-    //       console.log("blob数据", blob);
-    //       const formData = new FormData();
-    //       formData.append("timestamp", new Date().toISOString());
-    //       formData.append("file", blob, "screenshot.png");
-    //       console.log("上传数据", formData);
-    //       try {
-    //         // const res = await GetPersonByFace(formData);
-    //         // console.log("上传反馈", res);
-    //         // const response = await fetch("System/Person/GetPersonByFace", {
-    //         //   method: "POST",
-    //         //   body: formData,
-    //         // });
-    //       } catch (err) {
-    //         console.error("上传过程中出错:", err);
-    //       }
-    //     }
-    //   }, "image/png");
-    // },
-
     async captureImage() {
-      const video = this.$refs.video;
-      if (video.paused) return;
+      if (this.video.paused) return;
       const canvas = document.createElement("canvas");
 
-      const cropWidth = video.videoWidth * 0.5;
-      const cropHeight = video.videoHeight * 0.98;
+      const cropWidth = this.video.videoWidth * 0.5;
+      const cropHeight = this.video.videoHeight * 0.98;
 
       // 设置canvas尺寸为选择区域大小
       canvas.width = cropWidth;
       canvas.height = cropHeight;
 
-      const x = (video.videoWidth - cropWidth) / 2;
-      const y = (video.videoHeight - cropHeight) / 2;
+      const x = (this.video.videoWidth - cropWidth) / 2;
+      const y = (this.video.videoHeight - cropHeight) / 2;
 
       const ctx = canvas.getContext("2d");
       //中心60%区域
       ctx.drawImage(
-        video,
+        this.video,
         x,
         y,
         cropWidth,
@@ -232,27 +244,48 @@ export default {
       }
     },
     async uploadImage() {
-      const video = this.$refs.video;
       const canvas = document.createElement("canvas");
 
-      const cropWidth = video.videoWidth * 0.5;
-      const cropHeight = video.videoHeight * 0.98;
+      const cropWidth = this.video.videoWidth * 0.5;
+      const cropHeight = this.video.videoHeight * 0.98;
 
       // 设置canvas尺寸为选择区域大小
       canvas.width = cropWidth;
       canvas.height = cropHeight;
 
-      const x = (video.videoWidth - cropWidth) / 2;
-      const y = (video.videoHeight - cropHeight) / 2;
+      const x = (this.video.videoWidth - cropWidth) / 2;
+      const y = (this.video.videoHeight - cropHeight) / 2;
 
       const ctx = canvas.getContext("2d");
-      //中心60%区域
+      // console.log(
+      //   "???????????????????",
+      //   x,
+      //   y,
+      //   cropWidth,
+      //   cropHeight,
+      //   this.video,
+      //   this.blurredCanvas,
+      //   canvas
+      // );
+      //中心60%区域-原图
+      // ctx.drawImage(
+      //   this.video,
+      //   x,
+      //   y,
+      //   cropWidth,
+      //   cropHeight,
+      //   0,
+      //   0,
+      //   cropWidth,
+      //   cropHeight
+      // );
+      // 虚化背景处理绘制
       ctx.drawImage(
-        video,
-        x,
-        y,
-        cropWidth,
-        cropHeight,
+        this.showBlurred ? this.blurredCanvas : this.video,
+        this.blurredCanvas.width * 0.25,
+        this.blurredCanvas.height * 0.01,
+        this.blurredCanvas.width * 0.5,
+        this.blurredCanvas.height * 0.98,
         0,
         0,
         cropWidth,
@@ -294,6 +327,14 @@ export default {
       }
     },
   },
+  mounted() {
+    if (this.loading) {
+      this.blurredCanvas = document.getElementById("blurred-canvas");
+      if (this.blurredCanvas) {
+        this.ctx = this.blurredCanvas.getContext("2d");
+      }
+    }
+  },
   created() {
     this.startCamera();
     this.refreshTime();
@@ -329,4 +370,7 @@ video {
   background-color: rgba(0, 0, 0, 0.5);
   padding: 5px;
 }
+#blurred-video {
+  display: none;
+}
 </style>

+ 63 - 104
src/views/recognize/components/VideoLocalWindowTest.vue → src/views/recognize/components/VideoLocalWindowORI.vue

@@ -1,18 +1,9 @@
 <template>
   <div class="videoContainer">
-    <video
-      ref="video"
-      id="video"
-      :width="1280"
-      :height="800"
-      autoplay
-      muted
-      playsinline
-    ></video>
+    <video ref="video" autoplay muted playsinline></video>
     <div id="timestamp" v-show="false">
       {{ datetimeData.date + " " + datetimeData.time }}
     </div>
-    <canvas id="blurred-canvas" :width="1280" :height="800"></canvas>
     <!-- <el-button @click="startCamera">开启摄像头</el-button>
     <el-button @click="stopCamera" :disabled="!isCameraActive"
       >关闭摄像头</el-button
@@ -22,9 +13,6 @@
 
 
 <script>
-/* eslint-disable */
-import * as tf from "@tensorflow/tfjs";
-import * as bodyPix from "@tensorflow-models/body-pix";
 import { GetPersonByFace, GetPersonByFaceBase64 } from "@/API/custom";
 import Dayjs from "dayjs";
 
@@ -71,7 +59,6 @@ export default {
   data() {
     return {
       isCameraActive: false,
-      video: null,
       stream: null,
       captureInterval: null, // 新增定时器变量
       datetimeData: {
@@ -79,11 +66,6 @@ export default {
         time: Dayjs(new Date()).format("HH:mm:ss"),
         week: Dayjs(new Date()).format("dddd"),
       },
-      // BodyPix模型加载
-      net: null,
-      // 修改默认值为 true,自动开启背景虚化
-      showBlurred: true,
-      loading: true,
     };
   },
   methods: {
@@ -102,50 +84,18 @@ export default {
         timer = null;
       });
     },
-    async loadBodyPix() {
-      this.net = await bodyPix.load();
-      this.processVideoFrame();
-    },
-    async processVideoFrame() {
-      // 确保 video 和 blurredCanvas 存在
-      if (this.showBlurred && this.video && this.blurredCanvas) {
-        try {
-          const segmentation = await this.net.segmentPerson(this.video);
-          const backgroundBlurAmount = 5;
-          const edgeBlurAmount = 3;
-          const flipHorizontal = false;
-
-          bodyPix.drawBokehEffect(
-            this.blurredCanvas,
-            this.video,
-            segmentation,
-            backgroundBlurAmount,
-            edgeBlurAmount,
-            flipHorizontal
-          );
-        } catch (err) {
-          console.error("处理视频帧时出错:", err);
-        }
-      }
-
-      requestAnimationFrame(() => this.processVideoFrame());
-    },
     async startCamera() {
       try {
-        this.stream = await navigator.mediaDevices.getUserMedia({
-          video: true,
+        const stream = await navigator.mediaDevices.getUserMedia({
+          video: {
+            width: { ideal: 1280 },
+            height: { ideal: 800 },
+            facingMode: "user",
+          },
         });
-        this.video = document.getElementById("video");
+        this.stream = stream;
         this.isCameraActive = true;
-
-        if (this.video) {
-          this.video.srcObject = this.stream;
-          this.loading = false;
-          this.loadBodyPix();
-        } else {
-          this.error = "未能找到视频元素,请检查 HTML 结构。";
-          this.loading = false;
-        }
+        this.$refs.video.srcObject = stream;
 
         if (this.isUpload) {
           setTimeout(() => {
@@ -161,14 +111,13 @@ export default {
       } catch (err) {
         console.error("摄像头访问错误:", err);
         alert(`摄像头访问失败: ${err.message}`);
-        this.loading = false;
       }
     },
     stopCamera() {
       if (this.stream) {
         this.stream.getTracks().forEach((track) => track.stop());
         this.isCameraActive = false;
-        this.video.srcObject = null;
+        this.$refs.video.srcObject = null;
         this.stream = null;
 
         // 停止定时器
@@ -178,24 +127,65 @@ export default {
         }
       }
     },
+    // 新增截图方法
+    // async captureImage() {
+    //   const video = this.$refs.video;
+    //   video.currentTime = 1;
+    //   const canvas = document.createElement("canvas");
+    //   canvas.width = video.videoWidth;
+    //   canvas.height = video.videoHeight;
+    //   canvas
+    //     .getContext("2d")
+    //     .drawImage(video, 0, 0, canvas.width, canvas.height);
+    //   // 下载到本地
+    //   // const link = document.createElement("a");
+    //   // link.download = `capture_${new Date()
+    //   //   .toISOString()
+    //   //   .replace(/[:.]/g, "-")}.png`;
+    //   // link.href = canvas.toDataURL("image/png");
+    //   // link.click();
+
+    //   // 将canvas转为Blob对象
+    //   canvas.toBlob(async (blob) => {
+    //     if (blob) {
+    //       console.log("blob数据", blob);
+    //       const formData = new FormData();
+    //       formData.append("timestamp", new Date().toISOString());
+    //       formData.append("file", blob, "screenshot.png");
+    //       console.log("上传数据", formData);
+    //       try {
+    //         // const res = await GetPersonByFace(formData);
+    //         // console.log("上传反馈", res);
+    //         // const response = await fetch("System/Person/GetPersonByFace", {
+    //         //   method: "POST",
+    //         //   body: formData,
+    //         // });
+    //       } catch (err) {
+    //         console.error("上传过程中出错:", err);
+    //       }
+    //     }
+    //   }, "image/png");
+    // },
+
     async captureImage() {
-      if (this.video.paused) return;
+      const video = this.$refs.video;
+      if (video.paused) return;
       const canvas = document.createElement("canvas");
 
-      const cropWidth = this.video.videoWidth * 0.5;
-      const cropHeight = this.video.videoHeight * 0.98;
+      const cropWidth = video.videoWidth * 0.5;
+      const cropHeight = video.videoHeight * 0.98;
 
       // 设置canvas尺寸为选择区域大小
       canvas.width = cropWidth;
       canvas.height = cropHeight;
 
-      const x = (this.video.videoWidth - cropWidth) / 2;
-      const y = (this.video.videoHeight - cropHeight) / 2;
+      const x = (video.videoWidth - cropWidth) / 2;
+      const y = (video.videoHeight - cropHeight) / 2;
 
       const ctx = canvas.getContext("2d");
       //中心60%区域
       ctx.drawImage(
-        this.video,
+        video,
         x,
         y,
         cropWidth,
@@ -242,32 +232,23 @@ export default {
       }
     },
     async uploadImage() {
+      const video = this.$refs.video;
       const canvas = document.createElement("canvas");
 
-      const cropWidth = this.video.videoWidth * 0.5;
-      const cropHeight = this.video.videoHeight * 0.98;
+      const cropWidth = video.videoWidth * 0.5;
+      const cropHeight = video.videoHeight * 0.98;
 
       // 设置canvas尺寸为选择区域大小
       canvas.width = cropWidth;
       canvas.height = cropHeight;
 
-      const x = (this.video.videoWidth - cropWidth) / 2;
-      const y = (this.video.videoHeight - cropHeight) / 2;
+      const x = (video.videoWidth - cropWidth) / 2;
+      const y = (video.videoHeight - cropHeight) / 2;
 
       const ctx = canvas.getContext("2d");
-      console.log(
-        "???????????????????",
-        x,
-        y,
-        cropWidth,
-        cropHeight,
-        this.video,
-        this.blurredCanvas,
-        canvas
-      );
       //中心60%区域
       ctx.drawImage(
-        this.video,
+        video,
         x,
         y,
         cropWidth,
@@ -277,17 +258,6 @@ export default {
         cropWidth,
         cropHeight
       );
-      ctx.drawImage(
-        this.showBlurred ? this.blurredCanvas : this.video,
-        x,
-        y,
-        this.blurredCanvas.width,
-        this.blurredCanvas.height,
-        0,
-        0,
-        cropWidth,
-        cropHeight
-      );
       // ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
       const timestampDiv = document.getElementById("timestamp");
       // 在canvas上绘制时间戳
@@ -324,14 +294,6 @@ export default {
       }
     },
   },
-  mounted() {
-    if (this.loading) {
-      this.blurredCanvas = document.getElementById("blurred-canvas");
-      if (this.blurredCanvas) {
-        this.ctx = this.blurredCanvas.getContext("2d");
-      }
-    }
-  },
   created() {
     this.startCamera();
     this.refreshTime();
@@ -367,7 +329,4 @@ video {
   background-color: rgba(0, 0, 0, 0.5);
   padding: 5px;
 }
-#blurred-video {
-  display: none;
-}
 </style>

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov