资讯专栏INFORMATION COLUMN

媒体流数据获取和人脸检测

chadLi / 2404人阅读

摘要:入参是一个对象是判断是否启动摄像头和录音,返回一个对象。这个包可以把你想要检测的图片视频以及摄像头上面的内容都是支持捕捉人脸和检测面部特征。我这里主要实现的是摄像头捕捉人脸和检测面部特征。

背景

由于最近这些年互联网面向的受众面越来越光,有了更多的人和设备访问互联网,这也就意味着我们要做的就越来越多, 不在是像以前那样只需要调整页面样式和切图就可以了。所以就有了这篇文章的诞生,本次讲的如何在本地唤醒相机然后进行拍照,同时对拍照的照片进行修改,还可以对摄像头所捕捉的数据进行一个转发,同时还可以检测摄像头中是否存在人。

关键字API以及兼容性

唤醒摄像头主要用的API是 navigator.mediaDevices.getUserMedia。入参是一个对象{ audio: true, video: true } 是判断是否启动摄像头和录音,返回一个promise对象。以前的navigator.getUserMedia已经被废弃。如果video没有设置自动播放 需要在成功回调函数那里手动调用执行,只有这样摄像头才会被执行,不然就不会正确显示。

目前 IOS 设备的微信和 Safari 均不支持,较新的安卓和桌面端浏览器均支持。另外,出于安全问题考虑,Chrome 只支持 HTTPS 页面启用摄像头。

开启本地相机

test是用vue来的。因为考虑到到时候直接复制就好,所以在用的时候需要考虑自己的环境来进行部分修改和调整

  HTML部分
  
  
CSS部分 #photo { border: 1px solid black; width: 320px; height: 240px; } #canvas { display: none; } .camera { width: 340px; display: inline-block; } .output { width: 340px; display: inline-block; } #startbutton { display: block; position: relative; margin-left: auto; margin-right: auto; bottom: 32px; background-color: rgba(0, 150, 0, 0.5); border: 1px solid rgba(255, 255, 255, 0.7); box-shadow: 0px 0px 1px 2px rgba(0, 0, 0, 0.2); font-size: 14px; font-family: "Lucida Grande", "Arial", sans-serif; color: rgba(255, 255, 255, 1); } .contentarea { font-size: 16px; font-family: "Lucida Grande", "Arial", sans-serif; width: 760px; } JS部分 // 监听摄像头是否启动成功并且按照4:3的比例初始化摄像头和画布 canplay () { let { video, canvas } = this.$refs if (!this.streaming) { this.height = video.videoHeight / (video.videoWidth / this.width); console.log(this.height) if (isNaN(this.height)) { this.height = this.width / (4 / 3); } video.setAttribute("width", this.width); video.setAttribute("height", this.height); canvas.setAttribute("width", this.width); canvas.setAttribute("height", this.height); this.streaming = true; } }, // 获取摄像头被点击的那一刻的数据并且存到canvas里面以便进行修改 然后在存储在img标签显示在页面 takepicture () { let { video, canvas, photo } = this.$refs let context = canvas.getContext("2d") if (this.width && this.height) { canvas.width = this.width; canvas.height = this.height; context.drawImage(video, 0, 0, this.width, this.height); let data = canvas.toDataURL("image/png"); photo.setAttribute("src", data); } else { this.clearphoto(); } }, // 清除canvas信息 clearphoto () { let { canvas, photo } = this.$refs var context = canvas.getContext("2d"); context.fillStyle = "#AAA"; context.fillRect(0, 0, canvas.width, canvas.height); var data = canvas.toDataURL("image/png"); photo.setAttribute("src", data); }, // 初始化摄像头调用 startup() { let { video } = this.$refs this.width = 320 this.height = 0 this.streaming = false navigator.mediaDevices .getUserMedia({ video: true, audio: false }) .then((stream) => { video.srcObject = stream; video.play(); }) .catch((err) => { console.log("An error occurred: " + err); }) }

autoplay 需要开启自动播放不然需要在成功的回调里面手动执行,不然不会显示内容. 如果只是开启摄像头部分我们不需要声音,所以关闭掉了

 
 

我们需要等页面加载之后手动开启摄像头方法。

mounted() {
   this.startup()
}

startup() {
  let { video } = this.$refs // 获取页面上面的视频元素
  this.width = 320 // 初始化宽度
  this.height = 0 // 初始化高度
  this.streaming = false // 初始化是否进行中
  navigator.mediaDevices
    .getUserMedia({ video: true, audio: false }) // 这里我们只开启摄像头
    .then((stream) => { // 成功的执行
      video.srcObject = stream;
    })
    .catch((err) => { // 失败的执行
      console.error("An error occurred: " + err);
    })
},

当摄像头被成功启动之后, 就会执行 canplay 方法

 canplay () {
  let { video, canvas } = this.$refs // 获取节点 
  if (!this.streaming) { // 是否是在运行中 如果是
    this.height = video.videoHeight / (video.videoWidth / this.width); // 初始化高度
    console.log(this.height)
    if (isNaN(this.height)) { // 这里初始化高度是为了和宽度进行一个响应 初始成一个4:3的比例
      this.height = this.width / (4 / 3);
    }
    video.setAttribute("width", this.width); // 这个时候开始设置节点的宽度和高度
    video.setAttribute("height", this.height);
    canvas.setAttribute("width", this.width);
    canvas.setAttribute("height", this.height);
    this.streaming = true;
  }
}

这个时候摄像头的基本也就已经操作完毕了 如果没有一场的时候就可以在页面上看到你摄像头所捕捉到的内容 这个时候我们需要把你想要捕捉的内容转成图片显示到页面上

takepicture () { // 点击方法 当我们点击 Take photo 按钮的时候 这个时候把这部分的信息转成图片
  let { video, canvas, photo } = this.$refs // 获取节点
  let context = canvas.getContext("2d")
  if (this.width && this.height) { // 把video的数据存入canvas以便我们进行其他操作 转成图片资源然后显示在页面上
    canvas.width = this.width;
    canvas.height = this.height;
    context.drawImage(video, 0, 0, this.width, this.height);
    let data = canvas.toDataURL("image/png");
    photo.setAttribute("src", data);
  } else { // 如果初始化的宽高不存在 这个时候说明有异常需要排除,同时清除掉画布上面的图片数据
    this.clearphoto();
  }
},
clearphoto () { // 清除画布图片数据 同时更新img
  let { canvas, photo } = this.$refs
  var context = canvas.getContext("2d");
  context.fillStyle = "#AAA";
  context.fillRect(0, 0, canvas.width, canvas.height);

  var data = canvas.toDataURL("image/png");
  photo.setAttribute("src", data);
},
对摄像头捕捉的画面进行获取和解析 应用场景

完成以上步骤之后,没有问题。我们就可以唤醒连接的摄像头设备,捕捉你想要的画面存到你想要存的地方。当我们把捕捉到的画面存到canvas里面去之后,我们可以进行很多操作,可以对你捕捉的画面增加你想要的特效,这个时候canvas能够实现的功能都可以在你捕捉到画面上面实现,并且转成图片。
此时,摄像头所捕捉到的内容还是单向的,无法与别人通讯。如果你想实现一种类似于视频聊天的功能。这个时候就要改一下我们的代码,参考一下webRTC即时通讯协议。需要搭建一个第三方的信令服务器,来进行双向通讯。

人脸检测工具的使用

我现在借助的是的face-api这款工具 有捕捉人脸,检测面部特征。这个包可以把你想要检测的图片视频以及摄像头上面的内容都是支持捕捉人脸和检测面部特征。我这里主要实现的是摄像头捕捉人脸和检测面部特征。

官网: https://github.com/justadudew...

HTML部分


JS部分

const video = document.getElementById("video"); // 获取节点
Promise.all([ // 加载我想要使用的模型 同时对应的josn文件和shard文件要处在同一目录 不然读取的时候可能读取不到。当你读取不到的时候你可能会报 SyntaxError: Unexpected token < in JSON at position 0。这点略坑
  faceapi.nets.tinyFaceDetector.loadFromUri("/models"),
  faceapi.nets.faceLandmark68Net.loadFromUri("/models"),
  faceapi.nets.faceRecognitionNet.loadFromUri("/models"),
  faceapi.nets.faceExpressionNet.loadFromUri("/models")
]).then(startVideo); // 载入成功之后唤醒摄像头

function startVideo() {
  navigator.getUserMedia(
    { video: {} },
    stream => (video.srcObject = stream),
    err => console.error(err)
  );
}

video.addEventListener("play", () => { // 当摄像头成功启动之后 开始执行这部分的方法
  const canvas = faceapi.createCanvasFromMedia(video); // 创建一个画布
  document.body.append(canvas);
  const displaySize = { width: 640, height: 480 }; // 这部分的大小是等同video的大小的
  faceapi.matchDimensions(canvas, displaySize); // 声明大小
  setInterval(async () => { // 我们需要持续传递摄像头的数据
    const detections = await faceapi
      .detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())
      .withFaceLandmarks()
      .withFaceExpressions();
    const resizedDetections = faceapi.resizeResults(
      detections,
      displaySize
    );
    canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
    faceapi.draw.drawDetections(canvas, resizedDetections);
    faceapi.draw.drawFaceLandmarks(canvas, resizedDetections);
    faceapi.draw.drawFaceExpressions(canvas, resizedDetections);
  }, 100);
});
场景

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104917.html

相关文章

  • 【名额有限】云开发AI拓展能力等你来体验!

    摘要:一键部署后端能力首先需要开通云开发的人脸特征分析与检测扩展能力,并完成授权。云开发与云开发和本没有特别大的关联,使用云开发可以化调用腾讯云的能力,然鹅来自官方的云开发扩展能力解决方案却让这两者发生了奇妙的化学反应。 这次来了个超厉害的新能力!人脸智能打马赛克、人脸智能裁剪……各种操作,都能一步到位!迫不及待想体验,戳链接:https://wj.qq.com/s2/3986990/......

    Simon 评论0 收藏0
  • 阿里巴巴直播内容风险防控中的AI力量

    摘要:阿里巴巴集团安全部今年在直播管控中的特色在于大量采用人工智能和深度学习等技术,配合优化后的高性能多媒体计算集群,大幅度降低人工审核成本的同时,提升了对内容风险的防控能力。 阿里巴巴直播内容风险防控中的AI力量 直播作为近来新兴的互动形态和今年阿里巴巴双十一的一大亮点,其内容风险监控是一个全新的课题,技术的挑战非常大,管控难点主要包括业界缺乏成熟方案和标准、主播行为、直播内容不可控、峰值...

    lvzishen 评论0 收藏0
  • 场景化封装,一站式使用,普惠AI集成 ——阿里云发布智能媒体管理产品

    摘要:摘要导语近日,阿里云发布了智能媒体管理服务,通过离线处理能力关联授权的云存储,提供便捷的海量多媒体数据一键分析,并通过该分析过程构建价值元数据,更好支撑内容检索。标准统一,访问接口统一为阿里云的标准。场景化一键式处理,提高易用性。 摘要: 导语 近日,阿里云发布了智能媒体管理(Intelligent Media Management)服务, 通过离线处理能力关联授权的云存储,提供便捷的...

    big_cat 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<