js摄像头动态检测

news2024/9/24 11:31:54

利用摄像头每一秒截图一次图像。然后计算2次图像之间的相似度。

如果相似度低于98%就会报警。

var video = document.getElementsByClassName('inputvideo')[0];
video.innerHTML = "<video class='input_video' id='camera' autoplay width='640px' height='380px'></video>";

const videoElement = document.getElementById('camera');

// 获取用户媒体设备(摄像头)
navigator.mediaDevices.getUserMedia({ video: true })
  .then(function (stream) {
    videoElement.srcObject = stream;
  })
  .catch(function (error) {
    console.error('获取摄像头失败:', error);
  });

var canvas = document.getElementsByClassName('outputcanvas')[0];
canvas.innerHTML = "<canvas class='output_canvas' width='640px' height='480px'></canvas>";

var canvasElement = document.getElementsByClassName('output_canvas')[0];
var canvasCtx = canvasElement.getContext('2d');

// 设置 canvas 尺寸与视频流尺寸一致
canvasElement.width = 64;
canvasElement.height = 64;
var last = 0

function captureFrame() {
  // 捕获图像并绘制到画布
  canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
  // 获取绘制后的图像数据
  const imageData = canvasCtx.getImageData(0, 0, canvasElement.width, canvasElement.height);

  // 压缩图像并将其绘制到目标画布上
  const compressedImageDataPromise = compressImgFromImageData(imageData);

  // 处理压缩后的图像数据
  compressedImageDataPromise.then(function (compressedData) {
    // 在这里可以使用 compressedData 进行进一步的操作,例如上传或显示在页面上

    // 清空画布
    canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);

    // 转换为灰度图像
    const grayscaleImageData = createGrayscale(compressedData);

    // 获取哈希指纹
    const hashFingerprint = getHashFingerprint(grayscaleImageData);
    // 判断 last 是否等于 hashFingerprint
    if (last !== 0) {
      if (last === hashFingerprint) {
        console.log('你没动');
      } else {
        // console.log('你动了' + last);// 计算汉明距离
        const distance = hammingDistance(last, hashFingerprint);
        // 计算相似度百分比
        const similarityPercentage = (1 - distance / (hashFingerprint.length * 2)) * 100;
        // console.log('汉明距离:', distance);
        const baifenbi=similarityPercentage.toFixed(2);
        console.log('相似度百分比:', baifenbi + '%');
        if (baifenbi<98){
       _funcCb (true, {param1: true})
          }
       _funcCb (true, {param2: baifenbi})
      }
    }
    last = hashFingerprint
    // console.log('哈希指纹:', hashFingerprint);

    // 在画布上绘制灰度图像
    canvasCtx.putImageData(grayscaleImageData, 0, 0);
  });
}

// 每隔一段时间捕获一帧
setInterval(captureFrame, 1000); // 1 帧每秒

// 定义压缩图像的函数
function compressImgFromImageData(imageData) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const imgWidth = 64; // 设置压缩后的宽度

  canvas.width = imgWidth;
  canvas.height = imgWidth;

  // 将图像数据绘制到临时 canvas 上
  ctx.putImageData(imageData, 0, 0);

  // 获取压缩后的图像数据
  return new Promise((resolve, reject) => {
    const imgData = ctx.getImageData(0, 0, imgWidth, imgWidth);
    resolve(imgData);
  });
}

// createGrayscale 函数已经在之前的代码中定义
// 根据 RGBA 数组生成 ImageData
function createImgData(dataDetail) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const imgWidth = Math.sqrt(dataDetail.length / 4);
  const newImageData = ctx.createImageData(imgWidth, imgWidth);
  for (let i = 0; i < dataDetail.length; i += 4) {
    let R = dataDetail[i];
    let G = dataDetail[i + 1];
    let B = dataDetail[i + 2];
    let Alpha = dataDetail[i + 3];

    newImageData.data[i] = R;
    newImageData.data[i + 1] = G;
    newImageData.data[i + 2] = B;
    newImageData.data[i + 3] = Alpha;
  }
  return newImageData;
}

// 创建灰度图像
function createGrayscale(imgData) {
  const newData = Array(imgData.data.length).fill(0);
  imgData.data.forEach((_data, index) => {
    if ((index + 1) % 4 === 0) {
      const R = imgData.data[index - 3];
      const G = imgData.data[index - 2];
      const B = imgData.data[index - 1];

      const gray = ~~((R + G + B) / 3);
      newData[index - 3] = gray;
      newData[index - 2] = gray;
      newData[index - 1] = gray;
      newData[index] = 255; // Alpha 值固定为255
    }
  });
  return createImgData(newData);
}

// 获取图像的哈希指纹
function getHashFingerprint(imgData) {
  const grayList = imgData.data.reduce((pre, cur, index) => {
    if ((index + 1) % 4 === 0) {
      pre.push(imgData.data[index - 1]);
    }
    return pre;
  }, []);
  const length = grayList.length;
  const grayAverage = grayList.reduce((pre, next) => pre + next, 0) / length;
  return grayList.map(gray => (gray >= grayAverage ? 1 : 0)).join('');
}

// 计算汉明距离
function hammingDistance(hash1, hash2) {
  if (hash1.length !== hash2.length) {
    throw new Error('Hashes must have the same length');
  }

  let distance = 0;
  for (let i = 0; i < hash1.length; i++) {
    if (hash1[i] !== hash2[i]) {
      distance++;
    }
  }

  return distance;
}

原理是看了有一篇文章

利用 JS 实现多种图片相似度算法

首先降低图片分辨率

然后使用指纹提取

在“平均哈希算法”中,若灰度图的某个像素的灰度值大于平均值,则视为1,否则为0。把这部分信息组合起来就是图片的指纹。由于我们已经拿到了灰度图的 ImageData 对象,要提取指纹也就变得很容易了:

最后用汉明距离计算相似度

摘一段维基百科关于“汉明距离”的描述:

在信息论中,两个等长字符串之间的汉明距离(英语:Hamming distance)是两个字符串对应位置的不同字符的个数。换句话说,它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。

例如:

  • 1011101与1001001之间的汉明距离是2。
  • 2143896与2233796之间的汉明距离是3。
  • "toned"与"roses"之间的汉明距离是3。

体验地址

不许动 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/986024.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode 1123. Lowest Common Ancestor of Deepest Leaves【树,DFS,BFS,哈希表】1607

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

2023高教社杯数学建模C题思路模型 - 蔬菜类商品的自动定价与补货决策

# 1 赛题 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c; 大部分品种如当日未售出&#xff0c;隔日就无法再售。因此&#xff0c; 商超通常会根据各商品的历史销售和需 求情况每天进行补货。 由于商超销售的蔬菜…

X86_64函数调用汇编程序分析

X86_64函数调用汇编程序分析 1 X86_64寄存器使用标准2 对应代码的分析2.1 main函数及其对应的汇编程序2.1.1 main的C代码实现2.1.2 main函数对应汇编及其分析2.1.3 执行完成之后栈的存放情况 2.2 test_fun_a函数及其对应的汇编程序2.2.1 test_fun_a函数的C实现2.2.2 test_fun_a…

【工作技术栈】【源码解读】一次springboot注入bean失败问题的排查过程

目录 前言现象分析原因解决方法思考感悟 前言 对这次的过程排查如果要形容的话&#xff0c;我觉得更像是悬疑剧&#xff0c;bean not found 这种错误&#xff0c;已经看腻了&#xff0c;甚至有时候都看不起这种错误&#xff0c;但是似乎这个想法被springboot听见了&#xff0c…

spring-security-源码解析+自定义拓展

1.参考文档 https://docs.spring.io/spring-security/reference/5.7/servlet/architecture.html 1.1.各种filterchain 1.1.1.SecurityFilterChain 1.1.2.springSecurityFilterChain 1.1.3.Security Filters 2.几个重要的注解 2.1.EnableXXX EnableWebMvcSecurity–deprecate…

C语言之初阶总结篇

目录 NO.1 NO.2 NO.3 NO.4 NO.5 NO.6 NO.7 NO.8 NO.9 NO.10 NO.11 NO.12.概念tips NO.13.求最小公倍数 NO.14.最大公因数 NO.15.输入读取字符串 NO.16.倒置字符串 今天是一些C语言题目&#xff0c;最近天气炎热&#xff0c;多喝水。 NO.1 下面程序执行后&am…

浅谈泛在电力物联网、能源互联网与虚拟电厂

导读&#xff1a;从能源互联网推进受阻&#xff0c;到泛在电力物联网名噪一时&#xff0c;到虚拟电厂再次走向火爆&#xff0c;能源领域亟需更进一步的数智化发展。如今&#xff0c;随着新型电力系统建设推进&#xff0c;虚拟电厂有望迎来快速发展。除了国网和南网公司下属的电…

LLMs之Baichuan 2:《Baichuan 2: Open Large-scale Language Models》翻译与解读

LLMs之Baichuan 2&#xff1a;《Baichuan 2: Open Large-scale Language Models》翻译与解读 导读&#xff1a;2023年9月6日&#xff0c;百川智能重磅发布Baichuan 2。科技论文主要介绍了Baichuan 2&#xff0c;一个开源的大规模语言模型&#xff0c;以及其在多个领域的性能表现…

与 vmx86 驱动程序的版本不匹配: 预期为 410.0,实际为 401.0

与 vmx86 驱动程序的版本不匹配: 预期为 410.0&#xff0c;实际为 401.0。 驱动程序“vmx86.sys”的版本不正确。请尝试重新安装 VMware Workstation。 我电脑历史上装过几个版本的vmware workstation: 怀疑是不兼容版本生成的vmx.86.sys 在系统中和该软件冲突&#xff0c;又没…

【完整代码】2023数学建模国赛C题代码--蔬菜类商品的自动定价与补货决策

C 题 蔬菜类商品的自动定价与补货决策 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c; 大部分品种如当日未售出&#xff0c;隔日就无法再售。因此&#xff0c;商超通常会根据各商品的历史销售和需 求情况每天进…

java+ssh+mysql智能化办公管理系统

项目介绍&#xff1a; 本系统为基于jspsshmysql的OA智能办公管理系统&#xff0c;包含管理员、领导、员工角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;公告信息&#xff1b;工作计划&#xff1b;公司资料&#xff1b;部门管理&#xff1b;员工管理&#xff1b;员…

软件测试/测试开发丨Linux进阶命令

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27139 一、Linux进阶命令学习 curljq 二、curl简介 curl 是一个发送请求数据给服务器的工具 curl支持的协议有&#xff1a;FTP、FTPS、HTTP、HTTP、SFTP…

深度学习推荐系统(七)NFM模型及其在Criteo数据集上的应用

深度学习推荐系统(七)NFM模型及其在Criteo数据集上的应用 1 NFM模型原理及其实现 1.1 NFM模型原理 无论是 FM&#xff0c;还是其改进模型FFM&#xff0c;归根结底是⼀个⼆阶特征交叉的模型。受组合爆炸问题的困扰&#xff0c;FM 几乎不可能扩展到三阶以上&#xff0c;这就不…

sonarqube的基本使用

操作截图 下载一个中文插件。 插件安装成功&#xff0c;提示需要重启sonarqube。 通过maven的命令对代码进行测试 找到maven。 修改apache-maven-3.6.1\setting.xml。 通过以下命令对当前代码进行质量检测。 检测完毕。 回到sonarqube&#xff0c;看到刚刚检测的结果…

【Unity3D赛车游戏优化篇】【十】汽车粒子特效和引擎咆哮打造极速漂移

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

Nginx 学习(十)高可用中间件的配置与实现

一 Keepalived热备 1 概述 调度器出现单点故障&#xff0c;如何解决?Keepalived实现了高可用集群Keepalived最初是为LVS设计的&#xff0c;专门监控各服务器节点的状态Keepalived后来加入了VRRP功能&#xff0c;防止单点故障 2 运行原理 Keepalived检测每个服务器节点状…

湖南省副省长秦国文一行调研考察亚信科技

9月5日&#xff0c;湖南省人民政府党组成员、副省长秦国文一行到亚信科技调研考察&#xff0c;亚信科技高级副总裁陈武主持接待。 图&#xff1a;双方合影 在亚信科技创新展示中心&#xff0c;秦国文了解了亚信科技在5G、算力网络、人工智能、大数据等前沿领域的创新探索&…

LeetCode 865. Smallest Subtree with all the Deepest Nodes【树,DFS,BFS,哈希表】1534

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

AVLTree模拟实现

一、常用的搜索逻辑 1、暴力搜索 O(N) 2、二分搜索 前提是有序&#xff0c;可以先用O(NlogN)排序一次&#xff0c;后续每次查找都是logN。 缺点&#xff1a;快排需要容器有随机访问功能&#xff0c;即为顺序表等。 如果不仅要搜索&#xff0c;还要插入删除&#xff0c;此时…

修复 ChatGPT 发生错误的问题

目录 ChatGPT 发生错误&#xff1f;请参阅如何修复连接错误&#xff01; 修复 ChatGPT 发生错误的问题 基本故障排除技巧 检查 ChatGPT 的服务器状态 检查 API 限制 检查输入格式 清除浏览数据 香港DSE是什么&#xff1f; 台湾指考是什么&#xff1f; 王湘浩 生平 …