参考代码1
导入两js文件
前端人脸识别框架:https://trackingjs.com
下载zip包获取里面的 face.min.js 及 tracking-min.js
解压后仔细找找
<script src="./js/tracking-min.js"></script>
<script src="./js/face-min.js"></script>
下面代码中有注释可以看看。
代码1:是人脸的H5页面,需要引入上门提到的两个js文件。
代码2:切换摄像头的的一个实例,表达的意思就是先获取所有摄像的设备id,再通过设备id打开对应的摄像头。
<style>
#video_bind,
#canvas_bind {
width: 375rem;
height: 486rem;
object-fit: cover;
}
#canvas_bind {
position: absolute;
top: 0;
z-index: 2;
/* z-index: -1; */
}
.tip-box {
margin-top: 32rem;
font-size: 24rem;
}
</style>
<div>
<video width="375" height="486" id="video_bind" autoplay playsinline webkit-playsinline="true">
</video>
<div class="tip-box text-center"></div>
<canvas id="canvas_bind"></canvas>
</div>
<script src="./js/tracking-min.js"></script>
<script src="./js/face-min.js"></script>
<script type="text/javascript">
var tipFlag = false // 是否检测
var faceflag = false // 是否进行拍照
var informationTitle = document.querySelector(".tip-box") //人脸提示
// 获取video、canvas实例
var facevideo = document.getElementById('video_bind');
var facecanvas = document.getElementById('canvas_bind');
facecanvas.width = facecanvas.clientWidth;
facecanvas.height = facecanvas.clientHeight;
var videoWidth = videoHeight = 0
facevideo.addEventListener('canplay', function() {
videoWidth = this.videoWidth;
videoHeight = this.videoHeight;
});
var facecontext = facecanvas.getContext('2d');
var tracker = new tracking.ObjectTracker('face');
// 每次打开弹框先清除canvas没拍的照片
facecontext.clearRect(0, 0, facecanvas.width, facecanvas.height);
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {}
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function(constraints) {
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!getUserMedia) {
return Promise.reject(new Error("getUserMedia is not implemented in this browser"));
}
return new Promise(function(resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
})
}
}
navigator.mediaDevices.getUserMedia({
audio: false,
//打开摄像头方法1:
video: {
facingMode: "environment"
}
//打开摄像头方法2:
// video: {
// deviceId: "77604ab12bb8b7cf337c4069da4e701d3786adb8a4115436d0aef1792175c289"}
}).then(function(stream) {
// 使用监听人脸的包
tracker.setInitialScale(4);
tracker.setStepSize(2);
tracker.setEdgesDensity(0.1);
//打开摄像头方法1(这里有个问题,非手机端他只会打开默认的摄像头)
var tra = tracking.track('#video_bind', tracker, {
camera: true
});
//打开摄像头方法2:(上面的video要改,参数哪里来,看代码参考2)
// facevideo.srcObject = stream;
// facevideo.play();
// var tra = tracking.track('#video_bind', tracker);
var timer = null;
// 创建监听 每帧都会触发
tracker.on('track', function(event) {
if (!tipFlag) {
facecontext.clearRect(0, 0, facecanvas.width, facecanvas.height);
if (event.data.length === 0) {
//未检测到人脸
if (!faceflag && !timer) {
timer = setTimeout(() => {
informationTitle.innerHTML = '未检测到人脸'
}, 500)
}
} else if (event.data.length === 1) { // 长度为多少代表检测到几张人脸
window.clearTimeout(timer);
timer = null;
informationTitle.innerHTML = '请将脸部置于屏幕中央';
//检测到一张人脸
if (!tipFlag) {
// 给检测到的人脸绘制矩形
event.data.forEach(function(rect) {
facecontext.strokeStyle = '#a64ceb';
facecontext.strokeRect(rect.x, rect.y, rect.width, rect.height);
});
let rect = event.data[0];
//判断脸部是否在屏幕中间
if (!faceflag && rect.x > facevideo.clientWidth * 0.3 && rect.x < facevideo
.clientWidth * 0.7) { // 检测到人脸进行拍照,延迟0.5秒
informationTitle.innerHTML = '识别中,请勿乱动~';
faceflag = true;
tipFlag = true;
setTimeout(() => {
tackPhoto() // 拍照
}, 500);
}
}
} else {
//检测到多张人脸
if (!faceflag) {
informationTitle.innerHTML = '只可一人进行人脸识别!'
}
}
}
});
function tackPhoto() {
// 为什么调用getObjectFitSize,因为摄像头获取的图片和绘制的图片大小和区域可能不一致
// 所以需要把人脸置于屏幕中间,绘制中间部分图片,如果不需要直接调用第二种方式
const {
sx,
sy,
swidth,
sheight,
x,
y,
width,
height
} = getObjectFitSize('cover', facevideo.clientWidth, facevideo.clientHeight, videoWidth, videoHeight)
facecontext.drawImage(facevideo, sx, sy, swidth, sheight, x, y, width, height);
// 第二种方式
// facecontext.drawImage(facevideo, 0, 0, facevideo.clientWidth, facevideo.clientHeight);
var snapData = facecanvas.toDataURL('image/png');
var imgSrc = "data:image/png;" + snapData;
// document.querySelector("img").src = imgSrc;
sessionStorage.setItem("faceImage", imgSrc);
// history.go(-1);
history.back()
facevideo.srcObject.getTracks().forEach(track => track.stop());
// 取消监听
tra.stop();
}
}).catch(function(err) {
informationTitle.innerHTML = '打开摄像头失败'
})
/**
* 计算图片裁剪或者摆放位置
* @param {*} type contain, cover 暂时只兼容这两个模式
* @param {*} containerWidth 容器宽度
* @param {*} containerHeight 容器高度
* @param {*} imgWidth 图片宽度
* @param {*} imgHeight 图片高度
* @return {*} canvas drawImage的所有入参
*/
function getObjectFitSize(
type = "cover",
containerWidth,
containerHeight,
imgWidth,
imgHeight
) {
let radio = 1, // 容器与图片的比例
sx = 0, // 开始剪切的 x 坐标位置。
sy = 0, // 开始剪切的 y 坐标位置。
swidth = imgWidth, // 被剪切图像的宽度。
sheight = imgHeight, // 被剪切图像的高度。
x = 0, // 在画布上放置图像的 x 坐标位置。
y = 0, // 在画布上放置图像的 y 坐标位置。
width = containerWidth, // 要使用的图像的宽度(伸展或缩小图像)。
height = containerHeight; // 要使用的图像的高度(伸展或缩小图像)。
let cWHRatio = containerWidth / containerHeight;
let iWHRatio = imgWidth / imgHeight;
if (type === "cover") {
// cover模式,需要裁剪
if (iWHRatio >= cWHRatio) {
// 横图,高先匹配,裁剪宽度
radio = containerHeight / imgHeight;
sx = (imgWidth - containerWidth / radio) / 2;
swidth = containerWidth / radio;
sheight = imgHeight;
} else {
// 竖图,宽先匹配,裁剪高度
radio = containerWidth / imgWidth;
sy = (imgHeight - containerHeight / radio) / 2;
swidth = imgWidth;
sheight = containerHeight / radio;
}
} else if (type === "contain") {
if (iWHRatio >= cWHRatio) {
// 横图,宽先匹配,高度自适应
radio = containerWidth / imgWidth;
y = (containerHeight - imgHeight * radio) / 2;
height = imgHeight * radio;
} else {
// 竖图,高先匹配,宽度自适应
radio = containerHeight / imgHeight;
x = (containerWidth - imgWidth * radio) / 2;
width = imgWidth * radio;
}
}
return {
sx,
sy,
swidth,
sheight,
x,
y,
width,
height,
};
}
</script>
参考代码2:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>web获取设置和切换摄像头</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div id="container-video">
<video id="video" width="500" height="300" autoplay></video>
<br>
<select id="video-all"></select>
<br>
<button id="snap">摄像头照相功能</button>
<br>
<canvas id="canvas" width="500" height="300"></canvas>
</div>
<script type="text/javascript">
window.onload = () => {
cameraSwitchApply();
}
/**
* 【摄像头默认使用】或【摄像头切换使用】
*/
function cameraSwitchApply(){
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var Mvideo = document.getElementById("video");
var videoAll = document.getElementById("video-all");
//获取摄像头的名称和设备id
//select中设置摄像头选项
let VideoAllInfo=[];
navigator.mediaDevices.enumerateDevices().then((devices) => {
if(devices){
console.info(devices);
devices.forEach((value,index)=>{
/**
//kind: "videoinput";指的是摄像头输入设备。
//kind: "audiooutput"麦克风或笔记本自身的麦克风输入设备。
//kind: "audioinput" 麦克风或笔记本自身的麦克风输入设备。
* {
"deviceId":"d31e8fcdf03bd590df66d4cdef290e71431e3c8acc5e617948be13b6de35844a",
"kind":"videoinput",
"label":"Logitech HD Webcam C270 (046d:0825)",
"groupId":"7fb1407dbd9602f5e481567380a9fa9c360898f2de42be1abb0d201c75dea18f"
},
*/
if(value.kind=="videoinput"){
VideoAllInfo.push(value);
}
});
if(VideoAllInfo.length>0){
let videoAllItem="";
VideoAllInfo.forEach((value,index)=>{
let ItemDom=`<option value="${value.deviceId}">${value.label}</option>`
videoAllItem += ItemDom;
});
videoAll.innerHTML = videoAllItem;
}
}
});
//监听select的改变:切换摄像头
document.getElementById("video-all").onchange = () => {
if (document.getElementById("video-all").children.length > 0) {
let selIndex = document.getElementById("video-all").selectedIndex; // //获取当前选择的选项的index值
let selectedValue = document.getElementById("video-all").options[selIndex].value; //获取选中的value值
let selectedText = document.getElementById("video-all").options[selIndex].innerText; //获取选中的内容
console.log(selectedValue,selectedText);
//切换摄像头
setCatchVideo(Mvideo,selectedValue);
};
}
//设置默认摄像头
setCatchVideo(Mvideo,"");
//摄像头照相功能
document.getElementById("snap").onclick = () => {
context.drawImage(Mvideo, 0, 0, 500, 300);
}
}
/**
* 设置摄像头和切换摄像头
* @param {Object} videoDom 摄像头对象
* @param {Object} videoID 摄像头deviceId
*/
function setCatchVideo(videoDom,videoID){
let videoObj;
if(videoID==""){
//设置默认获取的摄像头
videoObj = {
"video": true
}
}else{
//切换摄像头
videoObj = {
"video": { deviceId: videoID},
};
}
let errBack = function(error) {
console.log("视频捕获错误: ", error.code,error);
};
if (navigator.getUserMedia) { //正常的情况下
navigator.getUserMedia(videoObj, (stream)=> {
videoDom.srcObject = stream;
videoDom.play();
}, errBack);
} else if (navigator.webkitGetUserMedia) { // WebKit
navigator.webkitGetUserMedia(videoObj, (stream)=> {
videoDom.src = window.webkitURL.createObjectURL(stream);
videoDom.play();
}, errBack);
} else if (navigator.mozGetUserMedia) { // Firefox
navigator.mozGetUserMedia(videoObj, (stream)=> {
videoDom.src = window.URL.createObjectURL(stream);
videoDom.play();
}, errBack);
};
}
</script>
</body>
</html>