uniapp H5 Vue2 人脸识别功能
·
原理
通过调用系统的相机,进行拍照,将图片传递给后端比对
注意点
媒体权限属于隐私权限,网址协议必须是https,否则无法拉起相机进行拍照
代码
<template>
<view class="takePhotoView">
<video
ref="video"
style="object-fit: fill"
:show-center-play-btn="false"
muted
preload
:width="videoWidth"
:height="videoHeight"
></video>
<div
:device-position="device"
flash="off"
@error="error"
style="width: 100%; height: 100vh; position: fixed; top: 0; left: 0"
>
<cover-view
style="
position: relative;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
"
>
<cover-view
style="
position: absolute;
width: 100%;
height: 100%;
z-index: -9;
top:0;
left:0;
"
>
<cover-image
class="coverImage"
style="width: 100vw; height: 100vh"
src="https://www.douhuikao.cn/img/mall/face_bg2.png"
>
</cover-image>
</cover-view>
<!-- <cover-view
style="flex: 1;width: 100vw;display: flex;align-items: center;center;background:rgba(0,0,0,1);"
>
<cover-image
class="coverImage"
@click="close"
style="
z-index: 1001;
width: 60rpx;
height: 60rpx;
margin-left: 50rpx;
"
src="https://www.douhuikao.cn/img/mall/close.png"
></cover-image>
</cover-view> -->
<!-- <cover-view
:style="'width: 100vw; height:' + scale * 100 + 'vw;'"
></cover-view> -->
<!-- <cover-view
style="flex: 1;width: 100vw;height:100rpx; ; position: fixed;bottom:20rpx;display: flex;justify-content: space-around;align-items: center;center;background:rgba(0,0,0,1);"
>
<cover-image
class="coverImage"
@click="deviceQH"
:style="
'width: 60rpx;height: 60rpx;z-index: 1001;' +
(hasSwitch ? '' : 'opacity: 0;')
"
src="https://www.douhuikao.cn/img/mall/ph.png"
></cover-image>
<cover-image
class="coverImage"
@click="photoShoot"
style="width: 100rpx; height: 100rpx; z-index: 1001"
src="https://www.douhuikao.cn/img/mall/pz.png"
></cover-image>
<cover-image
class="coverImage"
@click="chooseImage"
:style="
'width: 60rpx;height: 60rpx;z-index: 1001;' +
(hasAlbum ? '' : 'opacity: 0;')
"
src="https://www.douhuikao.cn/img/mall/tk.png"
></cover-image>
</cover-view> -->
<!-- <cover-view
style="
position: absolute;
z-index: 1001;
width: 100%;
bottom: 250rpx;
font-size: 66upx;
text-align: center;
color: #000000;
font-weight: bold;
"
>
避免头发口罩遮挡
</cover-view> -->
</cover-view>
</div>
</view>
</template>
<script>
import axios from "axios";
import {
requestGet,
requestPost,
requestGetUrl,
requestPostUrl,
} from "@/service/request.js";
import { getLoginToken, setFaceFlag } from "@/service/localStorage";
import { faceCompare } from "@/service/api/login.js";
import { uploadImage } from "@/service/api/mall/user.js";
// import config from '@/config'
const baseUrl = "https://www.douhuikao.cn/api";
const constraints = {
audio: false,
video: {
width: 600,
height: 400,
facingMode: "user",
},
};
export default {
data() {
return {
hasSwitch: true,
hasAlbum: true,
initScale: 1.277,
original: true,
canvasW: 0,
canvasH: 0,
device: "front",
videoShow: false,
pictureShow: false,
// 图片地址
picture: "",
// 用于视频识别的节点
canvas: null,
video: null,
image: null,
timeout: 0,
// 模型识别的条件
options: "",
// 提示控制
noOne: "",
moreThanOne: "",
// 不是通过Https访问提示
httpsAlert: "",
videoWidth: 600,
videoHeight: 400,
useFrontCamera: true,
};
},
mounted() {
this.video = this.$refs.video;
uni.getSystemInfo({
success: function (res) {
this.videoWidth = Math.max(res.windowWidth, res.windowHeight) - 120;
constraints.video.width = this.videoWidth;
this.videoHeight = Math.min(res.windowWidth, res.windowHeight);
constraints.video.height = this.videoHeight;
},
});
// this.chooseImage()
this.useCamera();
this.deviceQH();
},
computed: {
scale: function () {
if (this.initScale > 1.77) return 1.77;
if (this.initScale < 1.27) return 1.27;
return this.initScale;
},
},
methods: {
/**
* 使用摄像头
*/
useCamera() {
let that = this;
if (window.stream) {
window.stream.getTracks().forEach((track) => {
track.stop();
});
}
// 如果不是通过loacalhost或者通过https访问会将报错捕获并提示
try {
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
navigator.oGetUserMedia;
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);
});
};
}
console.log(navigator, getUserMedia, "99");
let promise = navigator.mediaDevices.getUserMedia(constraints);
promise
.then((stream) => {
window.stream = stream;
// 返回参数
const video = document.querySelector("video");
if ("srcObject" in video) {
video.srcObject = stream;
} else {
// 防止在新的浏览器里使用它,应为它已经不再支持了
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = function (e) {
video.play();
};
})
.catch((error) => {
console.log(error);
});
} catch (err) {
this.httpsAlert = `您现在在使用非Https访问,
请先在chrome://flags/#unsafely-treat-insecure-origin-as-secure中修改配置,
添将当前链接${window.location.href}添加到列表,
并且将Insecure origins treated as secure修改为enabled,
修改完成后请重启浏览器后再次访问!`;
}
},
// 关闭摄像头
closeCamera() {
if (!this.$refs["video"].srcObject) return;
let stream = this.$refs["video"].srcObject;
let tracks = stream.getTracks();
tracks.forEach((track) => {
track.stop();
});
this.$refs["video"].srcObject = null;
},
base64ToFile(base64, fileName) {
// 提取 MIME 类型
const parts = base64.split(";base64,");
const mimeType = parts[0].split(":")[1];
// 解码 Base64 字符串
const byteCharacters = atob(parts[1]);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
// 创建 Blob 对象
const blob = new Blob([byteArray], { type: mimeType });
// 创建 File 对象
return new File([blob], fileName, { type: mimeType });
},
/**
* 拍照上传
*/
async photoShoot() {
// 拿到图片的base64
this.canvas = document.createElement("canvas");
let context = this.canvas.getContext("2d");
const video = document.querySelector("video");
this.canvas.width = Math.min(video.videoWidth, video.videoHeight);
this.canvas.height = Math.max(video.videoWidth, video.videoHeight);
context.drawImage(video, 0, 0, this.canvas.width, this.canvas.height);
let canvas = this.canvas.toDataURL("image/png");
// let canvas = "data:image/png;base64,ivosawfawdqwqfqwfasfqwqwfqw";
// alert(canvas);
// 拍照以后将video隐藏
// 停止摄像头成像
// video.srcObject.getTracks()[0].stop();
uni.showLoading({
title: "正在校验中...",
mask: true, // 显示透明蒙层,防止触摸穿透
});
video.pause();
if (canvas) {
// 拍照将base64转为file流文件
let blob = this.dataURLtoBlob(canvas);
let file = this.blobToFile(blob, "imgName.png");
console.log(file, "22");
// setTimeout(async () => {
const formData = new FormData();
formData.append("file", file);
axios
.post("https://www.douhuikao.cn/api/upload/image", formData, {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${getLoginToken()}`,
},
})
.then(async (response) => {
console.log(response.data.data.url, "22");
const resul = await requestPost(faceCompare, {
data: {
photo: response.data.data.url,
},
});
if (resul.status == 200) {
uni.hideLoading();
setFaceFlag("true");
uni.showToast({
title: "人脸识别成功",
icon: "success",
mask: true,
duration: 2000,
});
setTimeout(() => {
const entryUrl = uni.getStorageSync("entryUrl");
if (entryUrl.includes("mall")) {
uni.reLaunch({
url: "/pages/mall/index/index",
});
} else {
uni.reLaunch({
url: "/pages/index/index",
});
}
}, 2000);
} else {
// uni.showToast({
// title: resul.msg,
// icon: "none",
// mask: true,
// duration: 2000,
// });
setTimeout(() => {
uni.navigateBack();
}, 2000);
}
console.log("文件上传成功", response);
})
.catch((error) => {
console.error("文件上传失败", error);
});
// let image = window.URL.createObjectURL(file);
// console.log(image, "222");
// this.uploadFilePromise(image);
} else {
console.log("canvas生成失败");
}
},
/**
* 将图片转为blob格式
* dataurl 拿到的base64的数据
*/
dataURLtoBlob(dataurl) {
const arr = dataurl.split(",");
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
/**
* 生成文件信息
* theBlob 文件
* fileName 文件名字
*/
blobToFile(theBlob, fileName) {
return new File([theBlob], fileName, { type: theBlob.type });
},
deviceQH() {
this.useFrontCamera = !this.useFrontCamera;
if (window.stream) {
window.stream.getTracks().forEach((track) => {
track.stop();
});
}
constraints.video.facingMode = "user";
let promise = navigator.mediaDevices.getUserMedia(constraints); // 调用将询问用户是否允许访问摄像机。如果用户拒绝,它将引发异常并且不返回流。因此,必须在 try/catch 块内处理这种情况,它返回一个Promise,必须使用 async/await 或 then 块
promise
.then(async (stream) => {
window.stream = stream;
// 返回参数
const video = document.querySelector("video");
if ("srcObject" in video) {
video.srcObject = stream;
} else {
// 防止在新的浏览器里使用它,应为它已经不再支持了
video.src = window.URL.createObjectURL(stream);
}
if (this.useFrontCamera) {
video.onloadedmetadata = () => {
// 播放视频
video.play();
};
// 调用拍照方法
this.photoShoot();
} else {
setTimeout(() => {
this.deviceQH();
}, 100);
setTimeout(() => {
this.photoShoot();
}, 2000);
}
})
.catch((error) => {
this.deviceQH();
console.log(error);
});
},
close() {
this.$emit("close");
},
chooseImage() {
let _this = this;
if (!this.hasAlbum) {
return;
}
if (window.stream) {
window.stream.getTracks().forEach((track) => {
track.stop();
});
}
uni.chooseImage({
count: 1, //默认9
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["camera"], //从相册选择
success: (res) => {
console.log(res.tempFilePaths[0], "img");
_this.uploadFilePromise(res.tempFilePaths[0]);
},
});
},
error(e) {
console.log(e);
},
async uploadFilePromise(url) {
alert(url);
//弹出照片核验的效果
let _self = this;
// return new Promise((resolve, reject) => {
const uploadRes = await uni.uploadFile({
// url: baseUrl +'/file/uploadMinio',
url: baseUrl + "/upload/image",
filePath: url,
name: "file",
header: {
Authorization: `Bearer ${getLoginToken()}`,
},
// return
// success: async (res) => {
// alert(4);
// console.log(res, JSON.parse(res.data).data.url, "图片");
// const resul = await requestPost(faceCompare, {
// data: {
// photo: JSON.parse(res.data).data.url,
// },
// });
// //
// if (resul.status == 200) {
// alert(5);
// uni.showToast({
// title: "人脸识别成功",
// icon: "success",
// mask: true,
// duration: 2000,
// });
// setTimeout(() => {
// uni.navigateTo({
// url: `/pages/mall/index/index`,
// });
// }, 2000);
// } else {
// alert(6);
// uni.showToast({
// title: resul.msg,
// icon: "success",
// mask: true,
// duration: 2000,
// });
// }
// return;
// //弹出验证情况
// _self.$modal.loading("验证中,请耐心等待...");
// let result = JSON.parse(res.data);
// console.log(result);
// if (result.code == "" || result.code == null) {
// _self.$emit("takePhoto", null);
// return;
// }
// if (result.code != 200) {
// this.$tab.reLaunch(
// "/pages/face/faceValidate?code=" +
// result.code +
// "&msg=" +
// result.msg
// );
// return;
// }
// setTimeout(() => {
// let param = {};
// param.url = result.data.url;
// param.feature = result.data.feature;
// _self.$emit("takePhotoTwo", param);
// }, 500);
// },
});
// alert(JSON.parse(uploadRes.data).data.url)
const face_url = JSON.parse(uploadRes.data).data.url;
if (uploadRes.statusCode == 200) {
const resul = await requestPost(faceCompare, {
data: {
photo: face_url,
},
});
if (resul.status == 200) {
uni.showToast({
title: "人脸识别成功",
icon: "success",
mask: true,
duration: 2000,
});
// setTimeout(() => {
// uni.navigateTo({
// url: `/pages/mall/index/index`,
// });
// }, 2000);
} else {
uni.showToast({
title: resul.msg,
icon: "success",
mask: true,
duration: 2000,
});
}
} else {
}
},
},
};
</script>
<style scoped lang="scss">
::v-deep {
.uni-video-bar {
display: none;
}
}
.takePhotoView {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 9999;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.canvas {
opacity: 0;
position: fixed;
top: 100vh;
z-index: -999;
}
.coverImage {
z-index: 999;
}
uni-video {
width: 100%;
height: 100%;
}
</style>
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)