// pages/faceRecognition/index.ts import { base } from "../../config/index"; let ctx: WechatMiniprogram.CameraContext | undefined = undefined; let listener: WechatMiniprogram.CameraFrameListener | undefined; let createVKSession: WechatMiniprogram.VKSession | undefined = undefined; let innerAudioContext: WechatMiniprogram.InnerAudioContext; const app = getApp(); const topTips = { ready: '请正对手机,保持光线充足', front: '请正对屏幕', left: '请向左转头', right: '请向右转头', } const bottomTips = { recording: '脸部信息录入中...', complete: '脸部信息录入成功', error: '脸部信息录入失败' } let T: number = 0; let notify = "" const daoJiShi: number = 15; Page({ /** * 页面的初始数据 */ data: { isStartVideo: false, // 是否点击开始按钮 isEmpower: false, // 是否授权 isUpLoad: false, // 是否上传中 initFace: false, // 是否初始化人脸识别 isTranscribe: false, // 是否录制中 seconds: 0, // 倒计 topTips: topTips.ready, // 提示语句 bottomTips: "", // 底部提示语句 buttomText: "录制" }, // 开始初始化录制 async initCamera() { if (this.data.isStartVideo) return; wx.showLoading({ title: "" }) this.setData({ isStartVideo: true }) wx.nextTick(() => { this.getMssage().then(async (r: any) => { console.log('是否授权发送消息:', r); notify = r; if (!ctx) ctx = wx.createCameraContext(); this.createVK(); ctx.startRecord({ timeout: daoJiShi, // 录制时长 selfieMirror: false, timeoutCallback: (res) => { // 超出录制时长 关闭录屏 this.setData({ isStartVideo: false, bottomTips: "", topTips: topTips.ready, // 提示语句 }) createVKSession?.stop(); listener?.stop(); this.getUrl(res); }, success: () => { // 调用成功,开始录制 wx.hideLoading(); this.setData({ seconds: daoJiShi, bottomTips: bottomTips.recording, topTips: topTips.front }); innerAudioContext.src = "assets/voice/front.mp3"; innerAudioContext.play(); }, fail: () => { // 调用失败 wx.hideLoading(); wx.showToast({ icon: "none", title: "相机调用失败", duration: 2000 }) }, complete: () => { } }) }); }) }, // 添加监听 addListen() { createVKSession?.start(() => { }); T = Date.now(); !listener && (listener = ctx?.onCameraFrame((frame: any) => { const Time = daoJiShi * 1000 - (Date.now() - T); if (Time % 1000 >= 50) return const s = Math.floor(Time / 1000); if (s == 10) { innerAudioContext.src = "assets/voice/left.mp3"; this.setData({ topTips: topTips.left }) } if (s == 5) { innerAudioContext.src = "assets/voice/right.mp3"; this.setData({ topTips: topTips.right }) } if (s % 5 === 0 && s !== 0) innerAudioContext.play(); this.setData({ seconds: s }) // 识别人脸是否在画面种 createVKSession?.detectFace({ frameBuffer: frame.data, // 图片 ArrayBuffer 数据。人脸图像像素点数据,每四项表示一个像素点的 RGBA width: frame.width, // 图像宽度 height: frame.height, // 图像高度 scoreThreshold: 0.5, // 评分阈值 sourceType: 1 }) })); listener?.start(); }, // 创建人脸追踪 createVK() { // 初始化人脸识别 if (this.data.initFace) return this.addListen(); if (!createVKSession) createVKSession = wx.createVKSession({ version: "v1", track: { plane: { mode: 1 }, face: { mode: 2 } // mode: 1 - 使用摄像头;2 - 手动传入图像 }, }) // 静态图片检测模式下,每调一次 detectFace 接口就会触发一次 updateAnchors 事件 createVKSession?.on('updateAnchors', (anchors)=> { for (let I = 0; I < anchors.length; I++) { const anchor = anchors[I]; const W = anchor.size.width * 100; let titlet = ""; if(W < 20 || W > 80 ) titlet = "请远离屏幕" if(W < 20) titlet = "请靠近屏幕" titlet && wx.showToast({ icon: "none", title: titlet }) } }) createVKSession?.on('removeAnchors', () => { wx.showToast({ title: "未检测到人脸, 请重新采集", icon: "error" }); this.overVideo(); }) this.addListen(); }, // 结束录像 overVideo() { if (!ctx || !this.data.isStartVideo) return; ctx.stopRecord({ compressed: true, complete: () => { createVKSession?.stop(); innerAudioContext?.pause(); listener?.stop(); this.setData({ isStartVideo: false, bottomTips: "", topTips: topTips.ready, seconds: 0 }) } }) }, // 获取本地临时地址 getUrl(res: WechatMiniprogram.StartRecordTimeoutCallbackResult) { this.setData({ isUpLoad: true }) wx.showLoading({ title: '上传进度:0%', mask: true //是否显示透明蒙层,防止触摸穿透 }) const uploadTask = wx.uploadFile({ url: base.url + '/v3/upload', filePath: res.tempVideoPath, name: 'file', //服务器定义的Key值 formData: { notify }, header: { Authorization: wx.getStorageSync("token") }, success: () => { wx.hideLoading(); wx.showToast({ title: "上传成功", duration: 2000, icon: "none" }); this.setData({ topTips: topTips.ready, // 提示语句 bottomTips: bottomTips.complete }) let time = setTimeout(() => { clearTimeout(time); wx.reLaunch({ url: "/pages/downloadPage/index" }) }, 2000) }, fail: () => { wx.hideLoading(); wx.showToast({ title: "上传失败", icon: "none", duration: 2000 }) this.setData({ topTips: topTips.ready, // 提示语句 bottomTips: bottomTips.error }) }, complete: () => { this.setData({ isUpLoad: false }) } }) //监听上传进度变化事件 uploadTask.onProgressUpdate((res) => { wx.showLoading({ title: '上传进度:' + res.progress + '%', mask: true //是否显示透明蒙层,防止触摸穿透 }) }) }, // 非正常中止 improperStop() { wx.navigateBack(); }, // 未授权 unauthorized() { wx.showToast({ title: "拒绝授权将无法录制视频信息" }); wx.navigateBack(); }, // 初始化完成 initialization() { }, // 获取消息授权 getMssage() { return new Promise((resolve) => { if (!app.globalData.configPage?.messageID || !wx.canIUse("requestSubscribeMessage")) { resolve("reject"); return } wx.requestSubscribeMessage({ tmplIds: app.globalData.configPage?.messageID || [], success: (res: WechatMiniprogram.RequestSubscribeMessageSuccessCallbackResult) => { resolve(res.p1mpCydIQ6OtxCSa62NaSFiEkQiTsb8KPFaAs1SuKMw || 'reject'); }, fail: () => { resolve("reject"); } }) }) }, /** * 生命周期函数--监听页面加载 */ onLoad() { innerAudioContext = wx.createInnerAudioContext(); innerAudioContext.loop = false; }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady() { }, /** * 生命周期函数--监听页面显示 */ onShow() { }, /** * 生命周期函数--监听页面隐藏 */ onHide() { // 在录制中退出后台页面隐藏,返回上一页,确保重新进入当前页 this.overVideo(); }, /** * 生命周期函数--监听页面卸载 */ onUnload() { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh() { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom() { }, /** * 用户点击右上角分享 */ // onShareAppMessage() { // }, }) export { }