利用摄像头每一秒截图一次图像。然后计算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。
体验地址文章来源:https://www.toymoban.com/news/detail-700397.html
不许动 文章来源地址https://www.toymoban.com/news/detail-700397.html
到了这里,关于js摄像头动态检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!