1660033284021056

1. 微信小程序人脸识别

方案已废弃: 用到的第三方框架: upng.js及pako.js(速度太慢,容易卡顿)
推荐使用:微信小程序人脸识别改进版

1. 初始化人脸识别

	wx.initFaceDetect()

2. 创建 camera 上下文 CameraContext 对象

	this.cameraEngine = wx.createCameraContext();

3.获取 Camera 实时帧数据

	const listener = this.cameraEngine.onCameraFrame()

4.人脸识别,使用前需要通过 wx.initFaceDetect 进行一次初始化,推荐使用相机接口返回的帧数据

	wx.faceDetect()

5.完整代码

<template>
	<view>
		<view class="d-flex justify-content-between align-items-center update-box mt-40 mr-32">
			<!-- 可用iconfont -->
			<image @click="devicePosition=!devicePosition" class="camera-change-image" mode="widthFix"
				src="@/static/images/camera_change.png"></image>
		</view>
		<view class="head-image-box w-100 text-center position-relative">
			<!-- resolution:获取人脸图片后的清晰度 low:低 -->
			<camera v-if='isAuthCamera' :device-position="devicePosition ?'back': 'front'" class="camera" flash="off"
				resolution='low' />

			<view class="title mt-40" v-show="!tempImg && tipsText">{{ tipsText }}</view>
			<cover-view class="cover-box" v-show="isShow">
				<cover-image class="image-box" src="@/static/images/camera_verify.png"></cover-image>

				<!-- cover-view 不支持动画所以只能变通的形式实现 -->
				<cover-image :style="'transform: translateY('+translateY+'rpx);'" class="line"
					src="@/static/images/bg_line.png"></cover-image>
				<!-- <cover-view class="line"></cover-view> -->
			</cover-view>
		</view>
	</view>
</template>

<script>
	import upng from "@/common/js/upng.js"

	export default {
		name: 'index',
		data() {
			return {
				isShow: false,
				tipsText: '', // 错误文案提示
				tempImg: '', // 本地图片路径
				cameraEngine: null, // 相机引擎
				devicePosition: true, // 摄像头朝向
				isAuthCamera: true, // 是否拥有相机权限
				isVerify: false,
				translateY: -24,
				timer: null,
				isFlag: true,
				origin: null
			}
		},
		onShow: function() {
			this.isVerify = false;
			this.tipsText = "";
			this.isFlag = true;
		},
		onLoad(options) {
			this.origin = options.origin;

			this.initData();
			this.lineAnimation()
		},
		onUnload: function() {
			clearInterval(this.timer);
			this.timer = null;
			this.isFlag = false;
		},
		methods: {
			// 初始化相机引擎
			initData() {
				// #ifdef MP-WEIXIN
				// 1、初始化人脸识别
				wx.initFaceDetect()
				// 2、创建 camera 上下文 CameraContext 对象
				this.cameraEngine = wx.createCameraContext();
				this.isShow = true;
				// 3、获取 Camera 实时帧数据
				const listener = this.cameraEngine.onCameraFrame((frame) => {
					if (this.tempImg) {
						return;
					}
					// 4、人脸识别,使用前需要通过 wx.initFaceDetect 进行一次初始化,推荐使用相机接口返回的帧数据
					wx.faceDetect({
						frameBuffer: frame.data,
						width: frame.width,
						height: frame.height,
						enablePoint: true,
						enableConf: true,
						enableAngle: true,
						enableMultiFace: true,
						success: (faceData) => {

							if (this.isVerify) return
							let face = faceData.faceInfo[0]
							if (face.x == -1 || face.y == -1) {
								this.tipsText = '检测不到人'
							}
							if (faceData.faceInfo.length > 1) {
								this.tipsText = '请保证只有一个人'
							} else {
								const {
									pitch,
									roll,
									yaw
								} = face.angleArray;
								const standard = 0.5
								if (Math.abs(pitch) >= standard || Math.abs(roll) >= standard ||
									Math.abs(yaw) >= standard) {
									this.tipsText = '请平视摄像头'
								} else if (face.confArray.global <= 0.8 || face.confArray.leftEye <=
									0.8 || face.confArray.mouth <= 0.8 || face.confArray.nose <= 0.8 ||
									face.confArray.rightEye <= 0.8) {
									this.tipsText = '请勿遮挡五官'
								} else {
									this.tipsText = '校验中...'
									this.isVerify = true;
									
									// 太快获取的人脸可能比较抽象,给用户一个准备时间
									setTimeout(() => {
										//借助upng把流转为二进制数据
										let pngData = upng.encode([frame.data], frame.width,
												frame.height),
											base64 = arrayBufferToBase64(pngData);
											
										// 获取到base64后可以已上传,展示,或保存到本地
										
										var imageType = getImageType();

										function getImageType() {
											let type = "center"
											if (face.y / frame.height < 0.3333) {
												type = "top"
											} else if (face.y / frame.height > 0.6666) {
												type = "bottom"
											}
											return type;
										}

										//二进制转base64
										function arrayBufferToBase64(buffer) {
											var binary = '';
											var bytes = new Uint8Array(buffer);
											var len = bytes.byteLength;
											for (var i = 0; i < len; i++) {
												// unicode编码还原
												binary += String.fromCharCode(bytes[i]);
											}
											return "data:image/png;base64," + btoa(binary);
										}

										// 小程序没有window对象,需手动实现btoa()方法
										// 作用: 字符转base64
										function btoa(string) {
											const b64 =
												"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
											string = String(string);
											var bitmap, a, b, c,
												result = "",
												i = 0,
												rest = string.length %
												3; // To determine the final padding

											for (; i < string.length;) {
												if ((a = string.charCodeAt(i++)) > 255 ||
													(b = string.charCodeAt(i++)) > 255 ||
													(c = string.charCodeAt(i++)) > 255)
													throw new TypeError(
														"Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range."
													);

												bitmap = (a << 16) | (b << 8) | c;
												result += b64.charAt(bitmap >> 18 & 63) + b64
													.charAt(bitmap >> 12 & 63) +
													b64.charAt(bitmap >> 6 & 63) + b64.charAt(
														bitmap & 63);
											}

											return rest ? result.slice(0, rest - 3) + "==="
												.substring(rest) : result;
										};

										this.tipsText = '校验成功'
										setTimeout(() => {
											this.clickPushDetail(imageType);
										}, 50)
									}, 300)
								}
							}
						},
						fail: (err) => {
							if (this.isVerify) return
							if (err.x == -1 || err.y == -1) {
								this.tipsText = '检测不到人'
							} else {
								this.tipsText = err.errMsg || '网络错误,请退出页面重试'
							}
						},
					})
				})
				// 5、开始监听帧数据
				listener.start()
				// #endif
			},

			clickPushDetail(imageType) {
				if (!this.isFlag) return
				// 可以跳转到详情页面
			},
			lineAnimation() {
				if (this.timer) return
				this.timer = setInterval(() => {
					this.translateY += 3;
					if (this.translateY >= 460) {
						this.translateY = 10;
					}
				}, 12)
			},
		}
	}
</script>

<style>
	page {
		background-color: #000000;
	}
</style>
<style lang="scss" scoped>
	.d-flex {
	  display: flex;
	}
	
	.justify-content-center {
	  justify-content: center;
	}
	
	.align-items-center {
	  align-items: center;
	}
	
	
	.camera-change-image {
		width: 48rpx;
		margin-left: 40rpx;
	}
	
	.mr-32{
		margin-right: 32rpx;
	}
	
	.mt-40 {
	  margin-top: 40rpx;
	}
	
	.text-center {
	  text-align: center;
	}
	
	.position-relative{
		position: relative;
	}
	
	.w-100{
		width: 100%;
	}

	.update-box {
		color: #ffffff;
	}

	.head-image-box {
		position: absolute;
		top: 10vh;
		color: white;

		.camera {
			width: 100%;
			height: 872rpx;
		}

		.title {
			font-size: 48rpx;
			font-weight: bold;
		}

		.cover-box {
			position: absolute;
			top: 40%;
			left: 50%;
			transform: translate(-50%, -50%);
			width: 500rpx;
			height: 500rpx;
		}

		.image-box {
			width: 100%;
			height: 100%;
		}

		.line {
			position: absolute;
			top: 0rpx;
			left: 8rpx;
			right: 8rpx;
			width: auto;
			height: 30rpx;
			// transform: translateY(-24rpx);
			// animation: radar-beam 1.5s infinite;
			// background: linear-gradient(180deg, rgba(13, 110, 217, 0) 0%, rgba(13, 110, 217, 0.4000) 100%);
			z-index: 2;
		}

		// @keyframes radar-beam {
		// 	0% {
		// 		transform: translateY(24rpx);
		// 	}

		// 	100% {
		// 		transform: translateY(450rpx);
		// 	}
		// }

	}
</style>

附带绝对定位的圆角图片真机展示问题

父元素添加:-webkit-backface-visibility: hidden;
-webkit-transform: translate3d(0, 0, 0);

.image-box {
				overflow: hidden;
				border-radius: 50%;
				-webkit-backface-visibility: hidden;
				-webkit-transform: translate3d(0, 0, 0);
				z-index: 1;

				.face-image {
					width: 100%;
					height: 100%;
					position: absolute;
					left: 0;

					&.top {
						top: 0;
					}

					&.bottom {
						bottom: 0;
					}

					&.center {
						top: 50%;
						transform: translateY(-50%);
					}
				}
			}

借鉴于:ZegTsai

2. H5人脸识别

详见:h5人脸识别

Logo

鸿蒙生态一站式服务平台。

更多推荐