运行时直接复制下方相应代码即可
html 代码部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>摄像头检测动态与静态物体</title>
</head>
<style>
.demo{
width: 100%;
display: flex;
justify-content: flex-start;
}
.demo>div{
width: 400px;
}
</style>
<body>
<video src="" id="payVideo"></video>
<canvas id="canvas" width='400' height='300'></canvas><br>
<div class="demo">
<div>
<h3>取景</h3>
<img src="" id="img1" alt="">
</div>
<div>
<h3>底片留存</h3>
<img src="" id="img2" alt="">
</div>
</div>
</body>
<script src="./index.js"></script>
</html>
js 部分
//下方方法为2帧对比判断,也可以3帧判断准确度更高
//可在下方基础上作优化,参数调整,优化为物体完全静止时才取景(未测试不同摄像头,不同环境下是否有影响)
let mediaStreamTrack = null;
let videoName=""; //存在多个摄像头时,此处放指定摄像头设备名称即可
let w = 400,
w_10=w/10,
h = 300,
h_10 =h/10;
window.navigator.getMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia; //获取媒体对象(这里指摄像头)
let payVideo = document.getElementById('payVideo'),
img1 = document.getElementById('img1'),
img2= document.getElementById('img2'),
canvas = document.getElementById('canvas');
window.dbData=null;
let qjState=false; //是否单次已采集图片
let ctx = canvas.getContext('2d'),
timer = null;
let constraints = { //设置摄像头长宽
width: {
min: w,ideal: 400
},
height: {
min: h,ideal: 300
},
advanced: [
{
width: w,height: h
},
{
aspectRatio: 1.333
}
]
};
getMenuVideo(videoName, (strem) => {
console.log(strem)
if (!strem) {
alert('未检测到摄像头设备')
return;
}
mediaStreamTrack = typeof strem.stop === 'function' ? strem :
strem.getVideoTracks()[0];
mediaStreamTrack.applyConstraints(constraints)
payVideo.srcObject = strem;
payVideo.play();
payVideo.onerror = function () {
strem.stop();
};
strem.onended = (r) => {
console.log(r)
};
payVideo.onloadedmetadata = function () {
console.log('打开摄像头')
setTimeout(()=>{
beginImg()
},1000)
};
})
let i = 0;
let obj = {};
//渲染canvas
function beginImg() {
timer = setInterval(async () => {
let objP = await randerCanvas();
console.log(objP)
imgDbCy(objP)
}, 100)
}
//判断图片与静止时与初次进入的图片的差异
function imgDbCy(objP){
let res = objP.res,
callObj = objP.callObj;
if (res > 98.5) {
if(!window.dbData){
window.dbData = callObj['0'];
pStart(0)
}
//预存的底片与静止时图片做对比,如果相似度差异大则判断为物体没有出去,反之认定为出去了;
let simVal = searchImage(window.dbData,callObj['1']);
console.log(simVal)
if(qjState&&simVal>90){
console.log('移出视频区域了')
img1.src='';
img2.src='';
qjState=false;
window.dbData=''
}else{
if(!qjState&&simVal<88){
console.log('物体静止了,可以取景')
qjState=true
pStart(1)
}
}
}
}
//拍照
function pStart(s){
payVideo = document.getElementById('payVideo');
payVideo && ctx.drawImage(payVideo, 0, 0, w, h);
let img64 = canvas.toDataURL("image/jpeg");
if(s){
img1.src = img64; //取景
}else{
img2.src = img64; //底片
}
}
function randerCanvas () {
return new Promise((resolve,reject)=>{
payVideo = document.getElementById('payVideo');
payVideo && ctx.drawImage(payVideo, 0, 0, w, h,0,0,w_10,h_10);
let baseData = ctx.getImageData(0, 0, w_10, h_10)
obj[i + ''] = baseData;
i++;
if (i > 1) {
i = 0;
let simiVal = searchImage(obj['0'],obj['1']);
let objP={
res:simiVal,callObj:obj
}
resolve(objP)
};
})
}
//获取识别摄像头
function getMenuVideo(name, callback) {
navigator.mediaDevices.enumerateDevices().then((dev) => {
let at = false;
if (dev) {
dev.map((item, index) => {
if (item.kind === 'videoinput') {
if (!name || item.label.indexOf(name) > -1) {
window.navigator.getMedia({
audio: false, //不适用音频
video: {
optional: [{
sourceId: item.deviceId
}]
}
}, function (strem) {
callback(strem)
}, function (error) {
alert('获取摄像头失败')
console.log(error);
});
at = true
}
}
return null;
})
if (!at) {
callback()
}
}
}).then((stream2) => {
});
}
function searchImage(pixels, pixels2) {
pixels = toGrayBinary(pixels, true, null, true);
pixels2 = toGrayBinary(pixels2, true, null, true);
var similar = 0;
for (var i = 0, len = w_10 * h_10; i < len; i++) {
if (pixels[i] == pixels2[i]) similar++;
}
similar = (similar / (w_10 * h_10)) * 100;
return similar;
}
// 像素数据,是否二值化(bool),二值化闵值(0-255),是否返回二值化后序列(bool)
function toGrayBinary(pixels, binary, value, sn) {
var r, g, b, g, avg = 0, len = pixels.data.length, s = '';
for (var i = 0; i < len; i += 4) {
avg += (.299 * pixels.data[i] + .587 * pixels.data[i + 1] + .114 * pixels.data[i + 2]);
}
avg /= (len / 4);
for (var i = 0; i < len; i += 4) {
r = .299 * pixels.data[i],
g = .587 * pixels.data[i + 1],
b = .114 * pixels.data[i + 2];
if (binary) {
if ((r + g + b) >= (value || avg)) {
g = 255;
if (sn) s += '1';
} else {
g = 0;
if (sn) s += '0';
}
g = (r + g + b) > (value || avg) ? 255 : 0;
} else {
g = r + g + b;
}
pixels.data[i] = g,
pixels.data[i + 1] = g,
pixels.data[i + 2] = g;
}
if (sn) return s;
else return pixels;
}