uniapp---app端人脸识别组件(宽屏版1280*800组件,需手动截屏拍人脸识别,踩坑,成长)

一、首先记录下踩到的坑

我这边做的是一个挂在门口的门牌机,可以用于扫脸签到,扫码签到,扫脸实现用的是live-pusher组件(代码很长,放在最下面,不能直接用,需要根据实际情况修改)去做的人脸识别,在测试安卓机上一切正常,在安卓宽屏设备(akuvox牌子的门禁机)上出现各种问题,最主要是不能用usb调试!!!只能打包调试太折磨了

坑1:官方live-pusher组件的snapshot方法没有触发回调,原因是该设备不会主动询问是否开启存储权限,需要手动设置如果遇到点击快门没反应,请检查是否主动开启了设备的存储权限,没有的话点击这里,按照这个地址(Dcloud社区)方法去操作

 给懒得跳链接的朋友放个传送门,主要就是下面附带的代码,用于申请设备权限

 图片中的代码:

    "permissionExternalStorage": {  
        "request": "always",  
        "prompt": "应用保存运行状态等信息,需要获取读写手机存储(系统提示为访问设备上的照片、媒体内容和文件)权限,请允许。"  
     }

坑2:获取设备的mac地址 这个真的是几经波折,最后在插件市场找到了救命稻草,mt-device-info - DCloud 插件市场

云插件官方使用指南:uni-app官网


除了踩坑,也有获取到在uniapp在特殊(宽屏)设备上开发app的经验


1、首先设备尺寸是1280*800,我们打算用rpx来画页面,这边还有个需要注意的地方就是,uniapp官方秉承最大程度上保持界面不失真的策略,“限定了可适配的最大屏幕宽度为960px,在这个范围内,rpx可以根据屏幕宽度缩放。一旦超过960,rpx再根据屏幕宽度缩放就变的没有意义了”(也就是设计稿上的图像会失真)

当然也可以自己去手动设置来调整这个“可适配的最大屏幕宽度”,在page.json文件中加入以下属性,这边以我用到的这个设备为例

page.json文件:

2、 HBuilder开发的话 可以去设置px转rpx提示,这个也很方便,具体设置步骤如下

 

这边根据设计稿去配比就好了,最后设置成功效果如下:

 

最后附上代码,截屏页组件代码如下:

<template>
	<view class="live-camera" :style="{ width: windowWidth, height: windowHeight }">
		<view class="preview" :style="{ width: windowWidth, height: windowHeight - 10 }">
			<live-pusher id="livePusher" ref="livePusher" class="livePusher" mode="FHD" beauty="1" whiteness="0"
				:aspect="aspect" min-bitrate="1000" audio-quality="16KHz" device-position="back" :auto-focus="true"
				:muted="true" :enable-camera="true" :enable-mic="false" :zoom="false" @statechange="statechange"
				:style="{ width: cameraWidth, height: cameraHeight }"></live-pusher>
			<live-pusher />

			< <!--提示语-->
				<cover-view class="remind">
					<text class="remind-text" style="">{{ message }}</text>
				</cover-view>

				<!--辅助线-->
				<!-- <cover-view class="outline-box" :style="{ width: windowWidth, height: windowHeight - 80 }">
					<cover-image class="outline-img" src="/static/live-camera/outline/idphoto.png" style="">
					</cover-image>
				</cover-view> -->
		</view>

		<view class="menu">
			<!--底部菜单区域背景-->
			<cover-image class="menu-mask" src="/static/live-camera/bar.png"></cover-image>

			<!--返回键-->
			<cover-image class="menu-back" @tap="back" src="/static/live-camera/back.png"></cover-image>

			<!--快门键-->
			<cover-image class="menu-snapshot" @tap="snapshot" src="/static/live-camera/shutter.png"></cover-image>

			<!--反转键-->
			<!-- <cover-image class="menu-flip" @tap="flip" src="/static/live-camera/flip.png"></cover-image> -->
		</view>
	</view>
</template>

<script>
	import config from "@/utils/config.js"
	let _this = null;
	export default {
		data() {
			return {
				// actions: config.VUE_APP_BASE_API + '/jeecg-boot/fjxhx/file/upload/file',
				actions: 'http://172.30.1.132:10038/arcface/user/face/get',
				dotype: 'idphoto', //操作类型
				message: '', //提示
				aspect: '2:3', //比例
				cameraWidth: '', //相机画面宽度
				cameraHeight: '', //相机画面宽度
				windowWidth: '', //屏幕可用宽度
				windowHeight: '', //屏幕可用高度
				camerastate: false, //相机准备好了
				livePusher: null, //流视频对象
				snapshotsrc: null, //快照
				isStopPreview: false // 关闭视频流,轮询不开启。
			};
		},
		onLoad(e) {
			_this = this;
			if (e.dotype != undefined) this.dotype = e.dotype;
			this.initCamera();
		},
		onReady() {
			this.livePusher = uni.createLivePusherContext('livePusher', this);
			// this.startPreview(); //开启预览并设置摄像头
			this.poenCarme();
		},
		methods: {
			//轮询打开
			poenCarme() {
				//#ifdef APP-PLUS
				if (plus.os.name == 'Android') {
					this.poenCarmeInterval = setInterval(function() {
						// console.log(_this.camerastate);
						if (!_this.camerastate) _this.startPreview();
					}, 2500);
				}
				//#endif
			},

			//初始化相机
			initCamera() {
				uni.getSystemInfo({
					success: function(res) {
						_this.windowWidth = res.windowWidth;
						_this.windowHeight = res.windowHeight;
						_this.cameraWidth = res.windowWidth;
						_this.cameraHeight = res.windowWidth / 1.5;
					}
				});
			},

			//开始预览
			startPreview() {
				if (_this.isStopPreview) {
					return
				}
				this.livePusher.startPreview({
					success: a => {
						console.log(a);
					}
				});
			},
			//停止预览
			stopPreview() {
				this.livePusher.stopPreview({
					success: a => {
						_this.camerastate = false; //标记相机未启动
					}
				});
			},

			//状态
			statechange(e) {
				//状态改变
				console.log(e);
				if (e.detail.code == 1007) {
					_this.camerastate = true;
				} else if (e.detail.code == -1301) {
					_this.camerastate = false;
				}
			},

			//返回
			back() {
				uni.navigateBack();
			},

			//抓拍
			snapshot() {

				this.livePusher.snapshot({
					success: e => {

						console.log('snapshot123', e)
						_this.isStopPreview = true
						uni.showLoading({
							title: '上传图片中',
							mask: true
						})
						_this.snapshotsrc = e.message.tempImagePath;
						_this.stopPreview();
						const fileInfo = {
							'fileName': 'wxImg.jpg',
							'fileHash': '1111'
						}
						const formData = {
							// 'file': e,
							'ct': JSON.stringify(fileInfo)
						}
						// this.uploadImg(formData)
						// return
						uni.compressImage({ // 压缩图片
							src: e.message.tempImagePath,
							quality: 20,
							success: res => {
								console.log('res.tempFilePath', res.tempFilePath)
								_this.snapshotsrc = res.tempFilePath;
								this.uploadImg(formData)
							},
							fail: res => {
								console.log(1112)
								_this.uploadFail()
							},
							computed: res => {
								console.log('res.tempFilePath', res.tempFilePath)
								// _this.snapshotsrc = res.tempFilePath;
								// this.uploadImg(formData)
							}
						})
					},
					error: e => {

					}
				});
			},
			// 上传图片
			uploadImg(formData) {
				console.log('_this.actions11133', _this.actions, _this.snapshotsrc)
				uni.uploadFile({
					// url: _this.actions, 
					url: _this.actions,
					// filePath: _this.snapshotsrc,
					files: [{
						uri: _this.snapshotsrc
					}],
					name: 'file',
					formData: formData,
					success: (uploadFileRes) => {
						console.log(uploadFileRes, typeof uploadFileRes.data);
						if (JSON.parse(uploadFileRes.data).code === 200) {
							let data = JSON.parse(uploadFileRes.data).result
							console.log('========uploadFileRes', JSON.parse(uploadFileRes.data).result, JSON
								.parse(uploadFileRes.data).code);
							_this.setImage(JSON.parse(uploadFileRes.data));
							_this.isStopPreview = false
							uni.hideLoading();
							// _this.$utils.nnToast('图片上传成功')
							uni.navigateBack();
						} else {
							_this.uploadFail(JSON.parse(uploadFileRes.data).message)
						}
					},
					fail: () => {
						console.log(1112)
						_this.uploadFail(JSON.parse(uploadFileRes.data).message)
					},
				})

			},
			uploadFail(msg) {
				uni.showLoading({
					title: msg,
					mask: true
				})
				// _this.$utils.nnToast('图片上传失败')
				setTimeout(function() {
					_this.isStopPreview = false
					uni.hideLoading();
					uni.navigateBack();
				}, 2000);
			},
			//反转
			flip() {
				this.livePusher.switchCamera();
			},

			//如果人脸识别成功 则带参数返回上一页进行签到
			setImage(data) {

				console.log('------------------setImage(data) ', data, );
				uni.$emit('setImage', {
					// path: _this.snapshotsrc,
					// dotype: this.dotype,
					userId: data.result.userId
				})
				//直接调用上一个页面的setImage()方法,把数据存到上一个页面中去
				// let pages = getCurrentPages();
				// let prevPage = pages[pages.length - 2]; //上一个页面
				// prevPage.setImage({
				// 	path: _this.snapshotsrc,
				// 	dotype: this.dotype,
				// 	imgId: imgId
				// });
			}
		}
	};
</script>

<style scoped lang="scss">
	.live-camera {
		.preview {
			justify-content: center;
			align-items: center;

			.outline-box {
				position: absolute;
				top: 0;
				left: 0;
				bottom: 0;
				z-index: 99;
				align-items: center;
				justify-content: center;

				.outline-img {
					width: 750px;
					// height: 1125rpx;
				}
			}

			.remind {
				position: absolute;
				top: 880rpx;
				width: 750rpx;
				z-index: 100;
				align-items: center;
				justify-content: center;

				.remind-text {
					color: #dddddd;
					font-weight: bold;
				}
			}
		}

		.menu {
			position: absolute;
			left: 0;
			bottom: 0;
			width: 750rpx;
			height: 60rpx;
			z-index: 98;
			align-items: center;
			justify-content: center;

			.menu-mask {
				position: absolute;
				left: 0;
				bottom: 0;
				width: 750rpx;
				height: 80rpx;
				z-index: 98;
			}

			.menu-back {
				position: absolute;
				left: 30rpx;
				bottom: 0rpx;
				width: 60rpx;
				height: 60rpx;
				z-index: 99;
				align-items: center;
				justify-content: center;
			}

			.menu-snapshot {
				width: 60rpx;
				height: 60rpx;
				z-index: 999999;
				position: absolute;
				bottom: 0rpx;
			}

			.menu-flip {
				position: absolute;
				right: 30rpx;
				bottom: 0rpx;
				width: 80rpx;
				height: 80rpx;
				z-index: 99;
				align-items: center;
				justify-content: center;
			}
		}
	}
</style>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
模仿人脸表情的高逼真机器人概述: 和之前的迹APP一样,我给颜艺Boy也提供了Arduino的库函数支持,可以让Arduino通过蓝牙读取人脸的表情、姿态、位置信息,库的使用非常简单,看示例代码就知道了。支持通过蓝牙输出人脸数据,开发板通过蓝牙串口读取,可以结合Arduino实现一些有趣的作品。见“相关文件”下载。 制作的手机APP截图: 模仿人脸表情的高逼真机器人程序功能模块: OpenCV人脸识别 基于多级回归树的人脸关键点回归 基于SVM的人脸训练集表情分类识别 3D GUI显示 蓝牙通信用于连接硬件 模仿人脸表情的高逼真机器人视频演示: 模仿人脸表情的高逼真机器人总结: 其中关键点的检测效果还不错,而表情分类由于样本量的原因稍有些许不稳定(各种表情只用了25个训练样本) 由于训练样本运算量较大,所以先通过手机采集图像数据,然后加好标签在PC读取数据进行训练,APP中则直接加载训练好的XML文件。值得一提的是,在表情分类模块中,对人脸关键点数据的归一化操作十分重要,在网上看到一些案例是直接将点的像素坐标归一化,然而这样无法保证对所有头部姿态都进行正确分类。所以程序里我使用了一个坐标转换,将点的像素坐标转换为以人眉心为原点的坐标系,这样再归一化之后泛化效果就好了很多。 蓝牙模块连接,连接线如图: 注意的是只要接蓝牙的Tx,不要接Rx,这样是为了让Arduino的print函数依然可以往控制台打印数据,另外下载程序的时候不要连接蓝牙不然会数据冲突无法下载。还要注意初始化的波特率必须跟蓝牙模块移植。 其实用软串口的话就没有这些问题了,但是我好懒。。没时间完善库&#128549;,要是有同学加上了软串口功能可以找我把代码整合进去。 APP兼容性 由于市面上手机型号繁多,对于不同架构的CPU不一定全部都能支持,有安装问题的可以在下载页面留言反馈我有空的话会尽量适配的。安装好了之后如果打开应用卡住或者闪退可能是手机上的安全软件限制了APP的权限,这时候要去手机设置里开启APP使用摄像头和蓝牙的权限,以原生系统为例操作步骤如下:设置-应用-已安装-i颜艺Boy-权限管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值