产品展示网站模板,网站短片怎么做,seo变现培训,大连建设网水电官网查询需求#xff1a;
1、前端实现模拟用户人脸识别#xff0c;识别成功后抓取视频流或认证的一张静态图给服务端。
2、服务端调用第三方活体认证接口#xff0c;验证前端传递的人脸是否存在#xff0c;把认证结果反馈给前端。
3、前端根据服务端返回的状态#xff0c;显示在…需求
1、前端实现模拟用户人脸识别识别成功后抓取视频流或认证的一张静态图给服务端。
2、服务端调用第三方活体认证接口验证前端传递的人脸是否存在把认证结果反馈给前端。
3、前端根据服务端返回的状态显示在页面上用于提示用户。
难点
1、前端APP如果要实现人脸活体校验验证需要对接大厂的SDK实现。
2、一开始我采用用使用在App内嵌套H5来单独部署一套人脸验证把结果通过webview与APP进行数据交互但是H5试了使用好用高效的effet.js 库人脸识别 目前仅支持H5但是发现最后在手机上识别人像整个人被压缩似得而且是反向镜头跟作者已反馈等待作者持续更新。
3、抛弃了使用App嵌套H5方法因此最终选择了使用原生live-pusher直播流来模拟实现人脸识别效果。本打算给大家写成组件方便大家直接调用来着但是发现组件内获取实例仅支持在onReady页面生命周期使用。
实现思路
1、首先需要获取手机是否有录音以及相机权限没有的话引导用户前去设置页主动设置。
2、其次创建live-pusher实例根据业务需求实现自己的模拟人脸识别思路目前我们这是在用户手动点击5s后进行自动抓拍的。
3、前端拿到抓拍最后一帧图片调用接口给服务端传递服务端调用第三方进行人脸活体检测一般是需要付费的哈。
4、最后前端把服务端返回的识别状态展示在页面上方便后续用户操作。
代码步骤当前是vue3项目示例最低sdk 21版本并且勾选livepusher 1、获取当前手机是否允许开启相机和录音权限。建议直接使用官方大佬写的js sdkApp权限判断和提示 引入js sdk插件vue3版本需要转换为export functionvue2版本直接按照官方大佬的直接使用即可
import {requestAndroidPermission,gotoAppPermissionSetting} from /js_sdk/wa-permission/permission.js
2、创建live-pusher实例根据业务需求写业务逻辑注意一定要用nvue页面哈cover-image覆盖一个矢量图在直播流画面上。
ilve-pusher详细参数说明具体看live-pusher官方文档
templateview classcontainerlive-pusher idlivePusher reflivePusher classlivePusher url modeFHD :mutedtrue:enable-cameratrue :auto-focustrue :beauty2 whiteness2 aspect9:16 local-mirrordisablestatechangestatechange errorerror netstatusnetstatus :style[{width:400rpx,height: 400rpx,marginLeft: 175rpx,marginTop:20rpx,}]/live-pushercover-image stylewidth: 400rpx;height: 400rpx;transform: scale(1.01);position: absolute;left: 175rpx;top: 190.5rpx; src/static/circleBg.png //view
/template
script
export default{onReady() {//需要在onReady页面生命周期函数来写this.livePusher uni.createLivePusherContext(livePusher, this);},
}
/script
3、5s后抓拍最后一帧图片给服务端人脸识别成功即登录系统识别失败跳转认证失败页面这里跟服务端对接采用的formdata格式上传文件流你也可以采取转成base64
临时路径转base64 // 定时器 几秒后自动抓拍handleSetTime() {this.timeFlag setInterval(async () {if (this.timeOut 0) {this.timeOut--this.titleTips this.countDownTimerStartTipsthis.buttonTip ${this.countDownTimerStartBtnTips} ${this.timeOut}秒}if (this.timeOut 1) {this.livePusher.snapshot({success: (res) {this.snapshotInfo res.message}})}// 进行快照人脸认证if (this.timeOut 0) {clearInterval(this.timeFlag);this.titleTips this.countDownTimerZeroTipsthis.buttonTip this.countDownTimerZeroBtnTipsuni.showLoading({title: this.countDownTimerZeroBtnTips})uni.uploadFile({url: http://192.168.60.2:8080/bsCheckImage/checkImg,filePath: this.snapshotInfo.tempImagePath,name: file,success: (uploadFileRes) {const jxStrData JSON.parse(uploadFileRes.data)console.log(jxStrData)const resResultCode jxStrData.codeconst resResultData jxStrData.dataif (resResultCode ! 00000) {uni.navigateTo({url: /pages/liveb-result/liveb-result?failResultObj this.passData(jxStrData)})this.handleStop()return}if (resResultCode 00000 resResultData.score 0.8) {uni.showToast({title: this.faceSucessTips})this.buttonTip this.faceSucessTipsthis.handleStop()return}if (resResultCode 00000 resResultData.score 0.8) {const paramsData {success: false,code: A9901,message: 人脸校验失败请将人脸正对取景框内重新认证,failCode: A9901,faceScore: resResultData.score}uni.navigateTo({url: /pages/liveb-result/liveb-result?failResultObj this.passData(paramsData)})this.handleStop()return}},fail: (error) {uni.hideLoading()uni.navigateTo({url: /pages/liveb-result/liveb-result,animationType: zoom-out,animationDuration: 1000})this.handleStop()},complete: () {uni.hideLoading()clearInterval(this.timeFlag) // 清除定时器防止再次执行}});}}, 1000)},
4、人脸认证失败服务端返回状态前端跳转认证失败页面返回时给上个页面传递监听参数。liveb-result.vue页面
templateview classcontainerview classresult-areaview classresult-iconimage classresult-icon-pic src../../static/fece_result.png/image/viewview classresult-tips{{failInfos.message}}/viewview classresult-button clickhandleRetryFace重新认证/view/view/view
/templatescript setupimport {ref} from vueimport {onLoad,onBackPress} from dcloudio/uni-appconst faceStatus ref()const failInfos ref({})const failResultMsg (() {const data {code: 3698,msg: 人脸认证失败}uni.$emit(failResult, data);})onLoad((options) {if (options.failResultObj) {const resultObj JSON.parse(decodeURIComponent(options.failResultObj));failInfos.value resultObj}})const handleRetryFace (() {console.log(handleRetryFace)failResultMsg()uni.navigateBack()})onBackPress((e) {failResultMsg()})
/scriptstyle langscss scoped.container {width: 750rpx;.result-area {position: absolute;top: 44%;left: 50%;transform: translate(-50%, -50%);.result-icon {display: flex;align-items: center;justify-content: center;.result-icon-pic {width: 140rpx;height: 140rpx;}}.result-tips {font-weight: 600;text-align: center;font-size: 32rpx;color: #515151;margin-top: 20rpx;margin-bottom: 60rpx;}.result-button {padding: 20rpx 100rpx;background-color: rgba(12, 75, 158, 1);border-radius: 60rpx;color: #eeeeee;}}}
/style
人脸识别页面所有代码liveb.nvue
templateview classcontainerview classheaderview classheader-titletext classheader-title-tips{{titleTips}}/textview classheader-title-carmeraimage classheader-title-img src../../static/change_camera.png clickhandleChangeCrame/image/view/view/viewlive-pusher idlivePusher reflivePusher classlivePusher url modeFHD :mutedtrue:enable-cameratrue :auto-focustrue :beauty2 whiteness2 aspect9:16 local-mirrordisablestatechangestatechange errorerror netstatusnetstatus :style[{width:400rpx,height: 400rpx,marginLeft: 175rpx,marginTop:20rpx,}]/live-pushercover-image stylewidth: 400rpx;height: 400rpx;transform: scale(1.01);position: absolute;left: 175rpx;top: 190.5rpx; src/static/circleBg.png /view classfooterview classfooter-tipstext classfooter-tips-first{{footerTipsFirst}}/texttext classfooter-tips-second{{footerTipsSecond}}/text/viewview classfooter-requiredview classfooter-required-rowview classrow-area v-for(item,index) in tipList :keyindeximage classrow-area-img :srcitem.icon/imagetext classrow-area-tip{{item.name}}/text/view/view/view/view!-- 手动抓拍 --view classstart-button :style{marginTop:footerBtnStyle.marginTop}view classbutton-hover:style{width:footerBtnStyle.width,padding:footerBtnStyle.padding,borderRadius:footerBtnStyle.borderRadius,backgroundColor:footerBtnStyle.btnBackground}clickstartFacetext classbutton-tip :style{fontSize:footerBtnStyle.fontSize,color:footerBtnStyle.textColor}{{buttonTip}}/text/view/view/view
/templatescriptimport {requestAndroidPermission,gotoAppPermissionSetting} from /js_sdk/wa-permission/permission.jsexport default {name: sevenq-faceLiver,props: {//是否默认开启抓拍isDeaultStartLive: {type: Boolean,default: false},//默认开启的话需要设置延迟时间(毫秒级)defaultStartDelayTime: {type: Number,default: 600},//是否需要监听结果页传递的事件needListenResultPage: {type: Boolean,default: true},//是否开启可以翻转摄像头isCanChangeCarame: {type: Boolean,default: true},//抓拍倒计时 如果默认开启需要1)snapCountdownTimer: {type: Number,default: 6},//如果不允许翻转摄像头 提示词notAllowChangeCarameMsg: {type: String,default: 刷脸认证仅支持前置摄像头},//顶部提示词topTitleTips: {type: String,default: 请把人脸放在圆圈内拍摄脸部开始人脸识别},//提示词 1 footerTipsFirst: {type: String,default: 确认为您本人照片},//提示词 2footerTipsSecond: {type: String,default: 保持正脸在取景框中系统将在5s后自动抓拍},//提示展示列表tipList: {type: Object,default: [{icon: ../../static/img3.png,name: 正对手机},{icon: ../../static/img2.png,name: 光线充足},{icon: ../../static/img1.png,name: 脸无遮挡},]},//抓拍倒计时开始时提示词countDownTimerStartTips: {type: String,default: 请保存人脸在实景框中正在进行抓拍},//抓拍倒计时为0时提示词countDownTimerZeroTips: {type: String,default: 正在人脸认证中请稍等...},//按钮默认文本buttonTips: {type: String,default: 开始人脸识别},//抓拍倒计时开始时按钮显示提示词countDownTimerStartBtnTips: {type: String,default: 正在抓拍中},//抓拍倒计时为0时按钮提示词countDownTimerZeroBtnTips: {type: String,default: 人脸认证中....},//认证成功按钮提示词faceSucessTips: {type: String,default: 认证成功},//权限提示开启提示词premissonTips: {type: String,default: 当前应用需要使用相机权限进行拍照但相机权限暂未开启。是否前往应用设置打开相机权限},//底部按钮样式footerBtnStyle: {type: Object,default: {marginTop: 120rpx,width: 480rpx,padding: 24rpx,btnBackground: rgba(12, 75, 158, 1),borderRadius: 300rpx,textColor: #dfdfdf,fontSize: 32rpx}}},data() {return {titleTips: this.topTitleTips,buttonTip: this.buttonTips,livePusher: , // livePusher实例snapshotInfo: , // 快照信息showCountDown: false, // 拍摄倒计时timeOut: this.snapCountdownTimer, // 签到倒计时timeFlag: null, // 定时器isPass: null, // 是否通过人脸认证phoneSysInfos: {}, //当前手机系统信息}},onReady() {this.livePusher uni.createLivePusherContext(livePusher, this);},onShow() {//监听结果页面传递的失败事件if (this.needListenResultPage) {uni.$on(failResult, (resultData) {if (resultData.code 3698) {clearInterval(this.timeFlag)this.resertAll()this.livePusher.startPreview()}});}},async mounted() {const that_ thisif (!that_.showCountDown) {setTimeout(function() {that_.getCarmeraPremisson()}, this.defaultStartDelayTime)}that_.getPhoneSys()},onUnload() {if (this.needListenResultPage) {uni.$off(failResult);}clearInterval(this.timeFlag)uni.hideLoading();},onHide() {console.log(页面隐藏)},methods: {//校验是否获取相机权限async getCarmeraPremisson() {const currentSystem uni.getSystemInfoSync().platformif (currentSystem android) {const result await requestAndroidPermission(android.permission.CAMERA)if (result 1) {if (this.isDeaultStartLive) { //如果打开页面就进行抓拍this.showCountDown true}this.startPreview()} else {uni.showModal({title: 提示,content: this.premissonTips,confirmText: 去设置,cancelText: 取消,success: function(res) {if (res.confirm) {gotoAppPermissionSetting()} else if (res.cancel) {uni.showToast({icon: error,title: 暂无相机权限})}}});}}},//重置初始化值 需要在认证失败时候再次调用resertAll() {this.titleTips this.topTitleTipsthis.buttonTip this.buttonTipsthis.snapshotInfo // 快照信息this.showCountDown false // 拍摄倒计时this.timeOut this.snapCountdownTimer // 签到倒计时this.timeFlag null // 定时器this.isPass null // 是否通过人脸认证},//手动翻转摄像头handleChangeCrame() {if (!this.isCanChangeCarame) {uni.showToast({icon: none,title: this.notAllowChangeCarameMsg})return}this.livePusher.switchCamera({success: (a) {uni.showToast({icon: none,title: 摄像头翻转成功})}});},//手动开始人脸识别startFace() {const that_ thisif (!that_.showCountDown) {that_.showCountDown trueif (that_.showCountDown) {const {platform,osVersion} that_.phoneSysInfosif (platform android osVersion 10) { //判断兼容安卓10以下效果that_.startPreview()return}that_.handleSetTime()}}},// 开始预览直播流startPreview() {const _that thisthis.livePusher.startPreview({success: (res) {if (_that.showCountDown) {_that.handleSetTime()}}})},// 定时器 几秒后自动抓拍handleSetTime() {this.timeFlag setInterval(async () {if (this.timeOut 0) {this.timeOut--this.titleTips this.countDownTimerStartTipsthis.buttonTip ${this.countDownTimerStartBtnTips} ${this.timeOut}秒}if (this.timeOut 1) {this.livePusher.snapshot({success: (res) {this.snapshotInfo res.message}})}// 进行快照人脸认证if (this.timeOut 0) {clearInterval(this.timeFlag);this.titleTips this.countDownTimerZeroTipsthis.buttonTip this.countDownTimerZeroBtnTipsuni.showLoading({title: this.countDownTimerZeroBtnTips})// this.$emit(handleStartFaceApi, {// code: 4364,// msg: 开始人脸与服务端进行人脸,// currentTempImagePath: this.snapshotInfo.tempImagePath// })uni.uploadFile({url: http://192.168.60.2:8080/bsCheckImage/checkImg,filePath: this.snapshotInfo.tempImagePath,name: file,success: (uploadFileRes) {const jxStrData JSON.parse(uploadFileRes.data)console.log(jxStrData)const resResultCode jxStrData.codeconst resResultData jxStrData.dataif (resResultCode ! 00000) {uni.navigateTo({url: /pages/liveb-result/liveb-result?failResultObj this.passData(jxStrData)})this.handleStop()return}if (resResultCode 00000 resResultData.score 0.8) {uni.showToast({title: this.faceSucessTips})this.buttonTip this.faceSucessTipsthis.handleStop()return}if (resResultCode 00000 resResultData.score 0.8) {const paramsData {success: false,code: A9901,message: 人脸校验失败请将人脸正对取景框内重新认证,failCode: A9901,faceScore: resResultData.score}uni.navigateTo({url: /pages/liveb-result/liveb-result?failResultObj this.passData(paramsData)})this.handleStop()return}},fail: (error) {uni.hideLoading()uni.navigateTo({url: /pages/liveb-result/liveb-result,animationType: zoom-out,animationDuration: 1000})this.handleStop()},complete: () {uni.hideLoading()clearInterval(this.timeFlag) // 清除定时器防止再次执行}});}}, 1000)},//向下个页面传递参数passData(obj) {let passDataStr JSON.stringify(obj)let newPassDataStr passDataStr.replace(/%/g, %25);return encodeURIComponent(newPassDataStr);},//抛出停止推流 在调用成功与失败都得调用handleStop() {this.livePusher.stop()},//监听直播流状态变化statechange(val) {console.log(val, 监听直播流变化)},//监听直播流警告error(err) {console.log(err, 监听直播流警告)},//监听网络状态netstatus(status) {console.log(status, 监听直播流网络状态)},//获取手机型号getPhoneSys() {const system uni.getDeviceInfo()this.phoneSysInfos system}}}
/scriptstyle langscss scoped.container {width: 750rpx;}
/style
效果图如下所示 注意代码仅可自己使用不可进行二次转载哈有问题在请私信我哦