【项目实战】vue-springboot-pytorch前后端结合pytorch深度学习 html打开本地摄像头 监控人脸和记录时间

是一个项目的一个功能之一,调试了两小时,终于能够
javascript设置开始计和暂停计时 监控人脸 记录时间了
效果图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
离开页面之后回到页面会从0计时(不是关闭页面,而是页面失去焦点)
在这里插入图片描述
离开摄像头时会弹出提示。
在这里插入图片描述
离开摄像头反馈给后端的时间。

全部代码:


<template>
  <div class="camera_outer">
   
    <video src="../assets/shu.mp4" style="width: 600px;height: 600px;margin-left: 150px" controls="controls"></video>
<hr>
    <el-button type="warning" @click.native="gettime()" style="margin-left: 300px"><i class="el-icon-video-camera-solid"></i> 开始听课</el-button>

    <el-button type="primary" @click="computetime()"><i class="el-icon-price-tag"></i> 结束听课</el-button>
    <el-button type="success" @click="out()"><i class="el-icon-loading
"></i> 暂时离开</el-button>


    <div style="width: 130px;background: #00eeee;margin-left: 350px" v-if="this.set==true">

      <i class="el-icon-alarm-clock">
      </i>您上课的时间:<div ref="startTimer"></div></div>

    <video
        id="videoCamera"
        :width="videoWidth"
        :height="videoHeight"
        autoplay
    ></video>
    <br>
    <canvas

        id="canvasCamera"
        :width="videoWidth"
        :height="videoHeight"
    ></canvas>
  </div>

</template>
<script>

export default {
  beforeRouteLeave (to, from, next) {
    // 这里需要elementui的支持,如果使用其他界面组件自行替换即可
    this.$confirm('正在离开本页面,本页面时间将从零开始计时', '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }).then(() => {
      // 正常跳转
      next()
    }).catch(() => {
      // 如果取消跳转地址栏会变化,这时保持地址栏不变
      window.history.go(1)
    })
  },
  data() {
    return {
      activeIndex2: '1',
      timer: "",
      content: "",
      hour: 0,
      minutes: 0,
      seconds: 0,
      videoWidth: 150,
      videoHeight: 150,
      imgSrc: "",
      thisCancas: null,
      thisContext: null,
      thisVideo: null,
      total:0,
      nowtime:[],
      set:true,
      yes:true,
      begintime:''
    };
  },
  created() {

    document.addEventListener('visibilitychange', this.startStopVideo)
  },
  mounted() {

      this.getCompetence();

      //this.gettime()

      var _this = this;
      this.thisCancas = document.getElementById("canvasCamera");
      this.thisContext = this.thisCancas.getContext("2d");
      this.thisVideo = document.getElementById("videoCamera");
      window.setInterval(
          this.setImage
          , 2000);

  },
  methods: {

       startStopVideo() {
  if (document.visibilityState === 'hidden') {

    if(this.yes==true){
      var stop1 = clearInterval(this.startTimer);
      this.yes = false;
    }
    else if(this.yes==false) {
      var stop2 = clearInterval(this.startTimer);
      this.yes = true

    }
window.location.reload()
  } else if (document.visibilityState === 'visible') {
    this.$message({
      message: '您刚刚离开了观看页面,将从零开始计时!',
      type: 'warning'
    });

  
    this.getCompetence();
    var _this = this;
    this.thisCancas = document.getElementById("canvasCamera");
    this.thisContext = this.thisCancas.getContext("2d");
    this.thisVideo = document.getElementById("videoCamera");
    window.setInterval(
        this.setImage
        , 2000);
  }
},
    out(){
      var stop1 = clearInterval(this.timer);
    },
    startTimer () {

        this.seconds += 1;
        if (this.seconds >= 60) {
          this.seconds = 0;
          this.minutes = this.minutes + 1;
        }

        if (this.minutes >= 60) {
          this.minutes = 0;
          this.hour = this.hour + 1;
        }
        this.total = this.minutes + this.hour * 60
        this.$refs.startTimer.innerHTML = (this.minutes < 10 ? '0' + this.minutes : this.minutes) + ':' + (this.seconds < 10 ? '0' + this.seconds : this.seconds) + '  total:' + this.total;

    },
    computetime(){

         var that = this
    this.set = false;
      this.$axios.post(
          "/gettime",
          {

            timenot: this.nowtime,
            total: this.total + '分',
            begintime: this.begintime

          }
      ).then(resp => {
        if (resp && resp.status === 200) {
          //
          that.$message({
                type: 'success',
                message: '您有一条新的学习记录生成!'}
            )
        }
        })
    },
    gettime(){
         this.begintime=new Date().toLocaleTimeString();
      this.timer = setInterval(this.startTimer, 1000);
    },
    // 调用权限(打开摄像头功能)
    getCompetence() {
      var _this = this;
      this.thisCancas = document.getElementById("canvasCamera");
      this.thisContext = this.thisCancas.getContext("2d");
      this.thisVideo = document.getElementById("videoCamera");
      // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {};
      }
      // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
      // 使用getUserMedia,因为它会覆盖现有的属性。
      // 这里,如果缺少getUserMedia属性,就添加它。
      if (navigator.mediaDevices.getUserMedia === undefined) {
        navigator.mediaDevices.getUserMedia = function (constraints) {
          // 首先获取现存的getUserMedia(如果存在)
          var getUserMedia =
              navigator.webkitGetUserMedia ||
              navigator.mozGetUserMedia ||
              navigator.getUserMedia;
          // 有些浏览器不支持,会返回错误信息
          // 保持接口一致
          if (!getUserMedia) {
            return Promise.reject(
                new Error("getUserMedia is not implemented in this browser")
            );
          }
          // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
          return new Promise(function (resolve, reject) {
            getUserMedia.call(navigator, constraints, resolve, reject);
          });
        };
      }
      var constraints = {
        audio: false,
        video: {
          width: this.videoWidth,
          height: this.videoHeight,
          transform: "scaleX(-1)",
        },
      };
      navigator.mediaDevices
          .getUserMedia(constraints)
          .then(function (stream) {
            // 旧的浏览器可能没有srcObject
            if ("srcObject" in _this.thisVideo) {
              _this.thisVideo.srcObject = stream;
            } else {
              // 避免在新的浏览器中使用它,因为它正在被弃用。
              _this.thisVideo.src = window.URL.createObjectURL(stream);
            }
            _this.thisVideo.onloadedmetadata = function (e) {
              _this.thisVideo.play();
            };
          })
          .catch((err) => {
            console.log(err);
          });
    },
    //  绘制图片(拍照功能)
    setImage() {
      var date = new Date();

      date .getYear(); //获取当前年份(2位)

      date .getFullYear(); //获取完整的年份(4位)

      date .getMonth(); //获取当前月份(0-11,0代表1月)

      date .getDate(); //获取当前日(1-31)

      date.getDay(); //获取当前星期X(0-6,0代表星期天)

      date.getTime(); //获取当前时间(从1970.1.1开始的毫秒数)

      date.getHours(); //获取当前小时数(0-23)

      date.getMinutes(); //获取当前分钟数(0-59)

      date.getSeconds(); //获取当前秒数(0-59)
      var _this = this;
   


      _this.thisContext.drawImage(
          _this.thisVideo,
          0,
          0,
          _this.videoWidth,
          _this.videoHeight
      );
      // 获取图片base64链接
      var image = this.thisCancas.toDataURL("image/png").split('base64,')[1];
      _this.imgSrc = image;
      console.log(_this.imgSrc)
      this.$axios.post('http://localhost:5000/getpic', {data: _this.imgSrc}).then(resp => {
        if (resp && resp.status === 200) {
          //状态码为200为请求成功
          //手动构造base64路径:前缀+返回码
          this.base64code = 'data:image/png;base64,' + resp.data.base64code
          if(resp.data == 'b')

          {  this.$message.error( date.getHours()+':'+date.getMinutes()+':'+date.getSeconds()+"请您勿离开摄像头视野!")
            let thistime =date.getHours()+':'+date.getMinutes()+':'+date.getSeconds()
            this.nowtime.push(thistime)
          }

          _this.thisContext.clearRect(0,0, _this.videoWidth,_this.videoHeight);
          // location.reload();
          //console.log(this.base64code)
        }
      })
    }
  }, beforeDestroy() {
    document.removeEventListener('visibilitychange', this.startStopVideo)

  }

};
</script>

其中包含了图片解码编码,打开摄像头,获取后端结果。
服务器有两个,一个是python的pytorch深度学习处理图片 在flask框架下,一个是java的springboot来获得离开摄像头的时间。
java部分:
实体类:

package com.naughty.userlogin02.bean;

import lombok.Data;

@Data
public class Nowtime {
    int id;
     String timenot;
   String total;
  String  nowtime;
  String begintime;

}

跨域请求:

@RestController
public class Timecontroller {
    @Autowired
    TimeDao timeDao;

    static int id = 0;
    @CrossOrigin
    @PostMapping("/gettime")
    public String getteacherList(@RequestBody String time){

        id++;
        System.out.println(time);
    //    System.out.println(nowtime.getId());
     Map<String, Object> jsonMap = JSON.parseObject(time);
        System.out.println(jsonMap.get("total"));
        LocalDate date = LocalDate.now();
        System.out.println(date);
        Nowtime nowtime = new Nowtime();
        nowtime.setNowtime(date.toString());
        String ns=jsonMap.get("timenot").toString();
        String totaltime=jsonMap.get("total").toString();
        String begintime = jsonMap.get("begintime").toString();
        nowtime.setTimenot(ns);
        nowtime.setTotal(totaltime);
        nowtime.setId(id);
        nowtime.setBegintime(begintime);
        timeDao.addtime(nowtime);
        return "ok";


        //return timenot;
    }
    @GetMapping("/gettime")
    public String getalltime(){
        System.out.println("time!");
     List<Nowtime> nowtimes = timeDao.getall();
        HashMap<String, Object> res = new HashMap<>();
        res.put("data",nowtimes);
        String users_json = JSON.toJSONString(res);
        return users_json;
    }

}

xml语句:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.naughty.userlogin02.dao.TimeDao">

    <insert id="addtime" parameterType="com.naughty.userlogin02.bean.Nowtime">
        insert into data1.gettime(timenot,total,nowtime,begintime) values (#{timenot},#{total},#{nowtime},#{begintime});
    </insert>
    <select id="getall" resultType="com.naughty.userlogin02.bean.Nowtime">
        SELECT * FROM gettime
        <if test="nowtime !=null">
            WHERE nowtime like #{nowtime}
        </if>

    </select>
</mapper>

python的主程序:

import base64
from predict import class_names
import torch
from torchvision import datasets, models, transforms
import cv2
import numpy as np
import requests
from flask import Flask,make_response, jsonify
import flask
from flask_cors import CORS
import socket
import threading
import json
import os
from io import BytesIO
from multiprocessing import Process
import io
from PIL import Image
# 配置全局app
app = Flask(__name__)
# 导入index中定义的所有函数
#from autotrade.server.index import *

def run_index():
    # 启动web服务器,使用多线程方式,接收所有http请求
    app.run(host='0.0.0.0', port=5000, threaded=True)

def make_new_response(data):
    res = make_response(jsonify({'code': 0, 'data': data}))
    res.headers['Access-Control-Allow-Origin'] = '*'
    res.headers['Access-Control-Allow-Method'] = '*'
    res.headers['Access-Control-Allow-Headers'] = '*'

    return res


def decode_base64(data):
    """Decode base64, padding being optional.

    :param data: Base64 data as an ASCII byte string
    :returns: The decoded byte string.

    """
    missing_padding = len(data) % 4
    if missing_padding != 0:
        data += b'='* (4 - missing_padding)
    # return base64.decodestring(data)
    return base64.b64decode(data)


@app.route("/test")
def test():
    res = "{'no':'dddd'}"
    return make_new_response(res)

CORS(app, resources=r'/*', supports_credentials=True)


basedir = os.path.abspath(os.path.dirname(__file__))


transform=transforms.Compose([
            transforms.Resize(224),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485,0.456,0.406],
                                 std=[0.229,0.224,0.225])
                            ])
@app.route('/getpic', methods=['POST'])
def getpic():
    data = json.loads(flask.request.get_data("data"))
    data_64 = str.encode(data['data'])
    print(type(data_64))

    #print(data_64)
    print('------------------------')
    print(str(data_64, 'utf8'))
    imgdata = decode_base64(data_64)
    file = open('1.jpg', 'wb')
    file.write(imgdata)
    file.close()
    image = Image.open(r"1.jpg").convert('RGB')
    image = transform(image).unsqueeze(0)
    modelme = torch.load('modefresnet.pkl')
    modelme.eval()
    outputs = modelme(image)
    _, predict = torch.max(outputs.data, 1)
    for j in range(image.size()[0]):
        print('predicted: {}'.format(class_names[predict[j]]))

    return class_names[predict[j]]
 
if __name__ == "__main__":
    app.run(debug=True)


深度学习的处理图片的网络模型就不贴了,需要的可以留言
用的是Resnet残差网络。识别速度还是很快的,判断的正确率也比较高。(训练的数据集很少,只有六百多张)

##Y1BCojf69##4;1%yBNfY3ne6a!/
下例为从指定的层提取ResNet50的特征。

import torch
from torch import nn
import torchvision.models as models
import torchvision.transforms as transforms
import cv2

class FeatureExtractor(nn.Module): # 提取特征工具
    def __init__(self, submodule, extracted_layers):
        super(FeatureExtractor, self).__init__()
        self.submodule = submodule
        self.extracted_layers = extracted_layers
 
    def forward(self, x):
        outputs = []
        for name, module in self.submodule._modules.items():
            if name is "fc": 
                x = x.view(x.size(0), -1)
            x = module(x)
            if name in self.extracted_layers:
                outputs.append(x)
        return outputs

model = models.resnet50(pretrained=True) # 加载resnet50工具
model = model.cuda()
model.eval()

img=cv2.imread('test.jpg') # 加载图片
img=cv2.resize(img,(224,224));
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
img=transform(img).cuda()
img=img.unsqueeze(0)

model2 = FeatureExtractor(model, ['layer3']) # 指定提取 layer3 层特征
with torch.no_grad():
    out=model2(img)
    print(len(out), out[0].shape)
  • 4
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
### 回答1: 外卖项目的前后端分离是指将项目的前端部分和后端部分进行分离开发,前端使用Vue框架,后端使用Spring Boot框架。 前端使用Vue框架可以提供良好的用户界面和交互体验。Vue具有组件化的特点,使得前端开发更加模块化和可维护。同时,Vue的数据绑定和响应式设计可以帮助实现快速更新页面的功能。通过Vue,用户可以方便地浏览外卖项目的菜单、下单、支付等操作,提升用户的使用体验。 后端使用Spring Boot框架可以提供强大的后台支持。Spring Boot是一种轻量级的Java框架,可以快速搭建和部署项目,减少开发的复杂度。使用Spring Boot,开发人员可以方便地实现外卖项目的后台逻辑,例如订单的处理、菜单的管理、支付的接口等。同时,Spring Boot集成了许多常用且可靠的开源库,为项目提供了高效、稳定的基础设施。 前后端分离的优势在于前端和后端可以并行开发,提高开发效率。前端和后端之间通过定义接口进行通信,降低了耦合度,灵活性更强。同时,单独部署前端和后端也可以提高项目的可维护性和可扩展性。例如,当需要添加新的功能或修改现有功能时,只需要修改相应的前端或后端代码,而不会影响到整个项目。 总之,外卖项目的前后端分离以及使用Vue和Spring Boot框架的设计选择,可以帮助实现一个高效、稳定、可扩展的外卖平台。 ### 回答2: 外卖项目采用前后端分离的架构,前端使用Vue框架,后端采用Spring Boot框架。 前端使用Vue框架可以实现用户界面的可视化设计和交互体验。Vue框架具有简单易用、灵活可扩展、高效性能等特点,适用于构建复杂的单页面应用(SPA)。通过Vue框架,可以实现用户注册、登录、浏览菜单、购物车管理、订单处理等功能的前端设计和开发。前端通过调用后端接口,获取后端处理的数据,并将数据展示在用户界面上。 后端使用Spring Boot框架可以实现业务逻辑的处理和数据存储。Spring Boot框架提供了快速构建、简化配置和集成多种功能的特性,适用于快速开发和维护可靠的应用程序。通过Spring Boot框架,可以处理用户注册、登录验证、菜单管理、订单处理等业务逻辑,并与数据库进行交互,存储与外卖项目相关的数据。后端还需要提供RESTful接口,供前端调用和交互。 前后端分离架构的好处是可以实现前端与后端的解耦,提高开发效率和维护性。前端和后端可以同时进行开发,并可采用不同的技术栈,使得团队成员能够专注于自己的领域。前后端分离还可以实现多端复用,例如可以用同一组后端接口提供给Web端和移动端调用。 总的来说,外卖项目采用前后端分离的架构,借助Vue和Spring Boot框架实现了用户界面的展示和交互以及业务逻辑的处理和数据存储,从而使得项目开发更加高效和可维护。 ### 回答3: 外卖项目采用前后端分离的架构,前端使用Vue.js框架进行开发,后端使用Spring Boot框架进行开发。 前端使用Vue.js框架的原因是因为Vue.js具有简洁、高效、灵活的特点,能够轻松构建交互式的用户界面。Vue.js还拥有一套完整的生态系统,能够方便地进行组件化开发,并提供了强大的工具来处理数据和状态的变化。 后端使用Spring Boot框架的原因是因为Spring Boot是一个简化了Spring开发的微框架,能够快速构建可独立运行的、生产级的应用。Spring Boot提供了大量的开箱即用的特性,如自动配置、快速开发等,能够极大地提高开发效率。 在外卖项目中,前端负责用户界面的展示和交互逻辑的实现。前端通过Vue.js进行组件化开发,将页面拆分为多个可复用的组件,提高开发效率和代码维护性。前端还通过Vue.js提供的路由功能,实现不同页面之间的跳转和导航。同时,前端还与后端通过HTTP协议进行通信,获取后端提供的数据和服务,并将其展示给用户。 后端负责处理前端发送的请求,并根据业务逻辑进行相应的处理,最终返回数据给前端。后端还负责与数据库交互,对数据进行增删改查操作。后端使用Spring Boot提供的RESTful风格的API,能够轻松构建出符合规范的接口。同时,后端还可以利用Spring Security进行权限管理,确保只有具备相应权限的用户才能访问特定的接口。 综上所述,外卖项目采用前后端分离的架构,前端使用Vue.js框架进行开发,后端使用Spring Boot框架进行开发,能够提高开发效率和代码的可维护性,同时还能够满足用户对于界面交互和数据操作的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值