uniapp实现人脸识别功能的具体实现代码
作者:边中之城 发布时间:2024-04-17 09:57:36
前言
对于前端来说,需要后端提供一个人脸识别接口,前端传入图片,接口识别并返回结果,如此看来,其实前端只需实现图片传入即可,但是其实不然,在传入图片时,需要进行以下几点操作:
判断图片格式,市场上比较常见的是
.jpg
、.jpeg
、.png
计算文件大小,一般要求不超过5MB
对图片进行base64加密
其实前2点具体要看接口要求,但是第3点,是实现人脸识别必备步骤,下文重点讲述一下移动端实现人脸识别的base64加密方法
问题
项目主要使用的技术栈是uniapp,uniapp的优点是上手快,基于vue开发,但缺点也很明显,多环境兼容导致兼容性较差,真机调试和运行较慢。比如h5端可以轻松实现base64加密,但是安卓环境完全不行,因为本地上传图片时,会返回一个blob流,但是uniapp的blob流是以<http://localhost>…
(安卓环境无法识别localhost
)开始,导致无法进行base64加密
解决办法
经过多方实现后,借用html5+ api的多个结合方法(plus.zip.compressImage
、plus.io.resolveLocalFileSystemURL
、plus.io.FileReader
)实现加密,主要代码如下:
//app压缩图片 用for循环 来处理图片压缩 的问题,原因是 plus.zip.compressImage 方法 是异步执行的,for循环很快, 同时手机可执行的压缩方法有限制:应该是3个吧。超出直接就不执行了。所以 原理就是 在图片压缩成功后 继续 回调 压缩函数。 以到达循环压缩图片的功能。
app_img(num, rem) {
let that = this;
let index = rem.tempFiles[num].path.lastIndexOf('.'); //获取图片地址最后一个点的位置
let img_type = rem.tempFiles[num].path.substring(index + 1, rem.tempFiles[num].path.length); //截取图片类型如png jpg
let img_yuanshi = rem.tempFiles[num].path.substring(0, index); //截取图片原始路径
let d2 = new Date().getTime(); //时间戳
//压缩图片
plus.zip.compressImage(
{
src: rem.tempFiles[num].path, //你要压缩的图片地址
dst: img_yuanshi + d2 + '.' + img_type, //压缩之后的图片地址(注意压缩之后的路径最好和原生路径的位置一样,不然真机上报code-5)
quality: 70 //[10-100]
},
function (e) {
//压缩之后路径转base64位的
//通过URL参数获取目录对象或文件对象
plus.io.resolveLocalFileSystemURL(e.target, function (entry) {
// 可通过entry对象操作test.html文件
entry.file(function (file) {
//获取文件数据对象
var fileReader = new plus.io.FileReader(); // 文件系统中的读取文件对象,用于获取文件的内容
//alert("getFile:" + JSON.stringify(file));
fileReader.readAsDataURL(file); //以URL编码格式读取文件数据内容
fileReader.onloadend = function (evt) {
//读取文件成功完成的回调函数
that.base64Img = evt.target.result.split(',')[1]; //拿到‘data:image/jpeg;base64,‘后面的
console.log('that.base64Img', that.base64Img);
// rem.tempFiles[num].Base64_Path = evt.target.result.split(',')[1];
};
});
});
// that.base64Img = that.base64Img.concat(rem.tempFiles[num]);
// 【注意】在此人脸认证中,只会传一张图片,故不考虑多张图片情况
//利用递归循环来实现多张图片压缩
// if (num == rem.tempFiles.length - 1) {
// return;
// } else {
// that.app_img(num + 1, rem);
// }
},
function (error) {
console.log('Compress error!');
console.log(JSON.stringify(error));
uni.showToast({
title: '编码失败' + error
});
}
);
},
详细实现思路
其实对于uniapp实现人脸识别功能来讲,大概要经过这么几个步骤
onImage()
:打开手机相册上传图片,获取blob流(本地临时地址)#ifdef APP-PLUS
/#ifndef APP-PLUS
:判断系统环境,是h5还是安卓环境,然后在进行图片压缩和加密,具体实现代码如下:
//#ifdef APP-PLUS
//图片压缩
that.app_img(0, res);
//#endif
// #ifndef APP-PLUS
that.blobTobase64(res.tempFilePaths[0]);
// #endif
app_img()
/blobTobase64()
:对要识别的图片进行base64加密onSave()
—>upImage()
:附件上传,并处理识别信息
具体代码
<!-- 人脸认证 -->
<template>
<view>
<view class="u-margin-30 text-center"><u-avatar size="600" :src="imageSrc"></u-avatar></view>
<view class="u-margin-60">
<u-button type="primary" class="u-margin-top-60" @click="onImage">{{ !imageSrc ? '拍照' : '重拍' }}</u-button>
<!-- <u-button type="primary" class="u-margin-top-30">重拍</u-button> -->
<u-button type="primary" class="u-margin-top-50" @click="onSave">保存</u-button>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import { registerOrUpdateFaceInfo, UpdateLaborPersonnel } from '@/api/mww/labor.js';
import { UploadByProject } from '@/api/sys/upload.js';
import { sysConfig } from '@/config/config.js';
import storage from 'store';
import { ACCESS_TOKEN } from '@/store/mutation-types';
export default {
name: 'face-authentication',
data() {
return {
imageSrc: '',
lastData: {},
base64Img: '',
base64: ''
};
},
onLoad(option) {
this.lastData = JSON.parse(decodeURIComponent(option.lastData));
console.log('前一个页面数据', this.lastData);
uni.setNavigationBarTitle({
title: this.lastData.CnName + '-人脸认证 '
});
},
methods: {
onSave() {
if (!this.imageSrc) {
this.$refs.uToast.show({
title: '请先拍照',
type: 'error'
});
}
// 人脸上传,附件上传,劳务人员信息修改
this.upImage();
},
// h5压缩图片的方式,url为图片流
blobTobase64(url) {
console.log('进来了2', url);
let imgFile = url;
let _this = this;
uni.request({
url: url,
method: 'GET',
responseType: 'arraybuffer',
success: res => {
let base64 = uni.arrayBufferToBase64(res.data); //把arraybuffer转成base64
_this.base64Img = 'data:image/jpeg;base64,' + base64; //不加上这串字符,在页面无法显示
}
});
},
//app压缩图片 用for循环 来处理图片压缩 的问题,原因是 plus.zip.compressImage 方法 是异步执行的,for循环很快, 同时手机可执行的压缩方法有限制:应该是3个吧。超出直接就不执行了。所以 原理就是 在图片压缩成功后 继续 回调 压缩函数。 以到达循环压缩图片的功能。
app_img(num, rem) {
let that = this;
let index = rem.tempFiles[num].path.lastIndexOf('.'); //获取图片地址最后一个点的位置
let img_type = rem.tempFiles[num].path.substring(index + 1, rem.tempFiles[num].path.length); //截取图片类型如png jpg
let img_yuanshi = rem.tempFiles[num].path.substring(0, index); //截取图片原始路径
let d2 = new Date().getTime(); //时间戳
//压缩图片
plus.zip.compressImage(
{
src: rem.tempFiles[num].path, //你要压缩的图片地址
dst: img_yuanshi + d2 + '.' + img_type, //压缩之后的图片地址(注意压缩之后的路径最好和原生路径的位置一样,不然真机上报code-5)
quality: 70 //[10-100]
},
function(e) {
//压缩之后路径转base64位的
//通过URL参数获取目录对象或文件对象
plus.io.resolveLocalFileSystemURL(e.target, function(entry) {
// 可通过entry对象操作test.html文件
entry.file(function(file) {
//获取文件数据对象
var fileReader = new plus.io.FileReader(); // 文件系统中的读取文件对象,用于获取文件的内容
//alert("getFile:" + JSON.stringify(file));
fileReader.readAsDataURL(file); //以URL编码格式读取文件数据内容
fileReader.onloadend = function(evt) {
//读取文件成功完成的回调函数
that.base64Img = evt.target.result.split(',')[1]; //拿到‘data:image/jpeg;base64,‘后面的
console.log('that.base64Img', that.base64Img);
// rem.tempFiles[num].Base64_Path = evt.target.result.split(',')[1];
};
});
});
// that.base64Img = that.base64Img.concat(rem.tempFiles[num]);
// 【注意】在此人脸认证中,只会传一张图片,故不考虑多张图片情况
//利用递归循环来实现多张图片压缩
// if (num == rem.tempFiles.length - 1) {
// return;
// } else {
// that.app_img(num + 1, rem);
// }
},
function(error) {
console.log('Compress error!');
console.log(JSON.stringify(error));
uni.showToast({
title: '编码失败' + error
});
}
);
},
// 打开手机相机相册功能
onImage() {
const that = this;
// 安卓系统无法默认打开前置摄像头,具体请看下面app-plus原因,
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['camera'], // 打开摄像头-'camera',从相册选择-'album'
success: function(res) {
console.log('文件结果', res);
if (res.tempFilePaths.length > 0) {
// Blob流地址
that.imageSrc = res.tempFilePaths[0];
//#ifdef APP-PLUS
//图片压缩
that.app_img(0, res);
//#endif
// #ifndef APP-PLUS
that.blobTobase64(res.tempFilePaths[0]);
// #endif
} else {
that.$refs.uToast.show({
title: '无文件信息',
type: 'error'
});
}
},
fail: function(res) {
console.log('失败了', res.errMsg);
that.$refs.uToast.show({
title: res.errMsg,
type: 'error'
});
}
});
// #ifdef APP-PLUS
// console.log('app环境了');
// 指定要获取摄像头的索引值,1表示主摄像头,2表示辅摄像头。如果没有设置则使用系统默认主摄像头。
// 平台支持【注意注意注意】
// Android - 2.2+ (不支持) :
// 暂不支持设置默认使用的摄像头,忽略此属性值。打开拍摄界面后可操作切换。
// iOS - 4.3+ (支持)
// var cmr = plus.camera.getCamera(1);
// var res = cmr.supportedImageResolutions[0];
// var fmt = cmr.supportedImageFormats[0];
// console.log('Resolution: ' + res + ', Format: ' + fmt);
// cmr.captureImage(
// function(path) {
// alert('Capture image success: ' + path);
// },
// function(error) {
// alert('Capture image failed: ' + error.message);
// },
// { resolution: res, format: fmt }
// );
// #endif
},
// 上传附件至[人脸认证]服务器
upImage() {
if (!this.base64Img) {
this.$refs.uToast.show({
title: '无图片信息',
type: 'error'
});
return;
}
const params = {
identityId: this.lastData.IdCard, //身份证号码
imgInfo: this.base64Img, //头像采用base64编码
userId: this.lastData.Id, //劳务人员Id
userName: this.lastData.CnName //劳务姓名
};
uni.showLoading();
registerOrUpdateFaceInfo(params)
.then(res => {
if (res.success) {
this.$refs.uToast.show({
title: '认证成功',
type: 'success'
});
// 上传至附件服务器+修改劳务人员信息
this.uploadFile();
} else {
this.$refs.uToast.show({
title: '认证失败,' + res.message,
type: 'error'
});
uni.hideLoading();
}
})
.catch(err => {
uni.hideLoading();
uni.showModal({
title: '提示',
content: err
});
});
},
// 上传附件至附件服务器
uploadFile() {
const obj = {
project: this.lastData.OrgCode || this.$store.getters.projectCode.value,
module: 'mww.personnelCertification',
segment: this.lastData.OrgCode,
businessID: this.lastData.Id,
storageType: 1
};
let str = `project=${obj.project}&module=${obj.module}&segment=${obj.segment}&businessID=${obj.businessID}&storageType=${obj.storageType}`;
console.log('str', str);
// const url = '';
// console.log('url', url);
// const formData = new FormData();
// formData.append('file', this.imageSrc, '.png');
// UploadByProject(str, formData).then(res => {
// if (res.success) {
// this.$refs.uToast.show({
// title: '上传成功',
// type: 'success'
// });
// } else {
// this.$refs.uToast.show({
// title: res.message,
// type: 'error'
// });
// }
// });
const token = uni.getStorageSync(ACCESS_TOKEN);
const that = this;
// 需要使用uniapp提供的api,因为that.imageSrc的blob流为地址头为localhost(本地临时文件)
uni.uploadFile({
url: `${sysConfig().fileServer}/UploadFile/UploadByProject?${str}`,
filePath: that.imageSrc,
formData: {
...obj
},
header: {
// 必须传token,不然会报[系统标识不能为空]
authorization: `Bearer ${token}`
},
name: 'file',
success: res => {
that.$refs.uToast.show({
title: '上传成功',
type: 'success'
});
that.lastData.CertificationUrl = res.data[0].virtualPath;
that.lastData.Certification = 1;
that.updateLaborPersonnel();
},
fail: err => {
console.log('上传失败了', err);
that.$refs.uToast.show({
title: '上传失败,' + err,
type: 'error'
});
uni.hideLoading();
}
});
},
// 修改劳务人员信息
updateLaborPersonnel() {
UpdateLaborPersonnel(this.lastData)
.then(res => {
if (res.success) {
this.$refs.uToast.show({
title: '修改成功',
type: 'success'
});
// uni.showToast({
// title: '成功了'
// });
setTimeout(() => {
uni.navigateBack({
delta: 1
});
}, 800);
} else {
this.$refs.uToast.show({
title: '修改失败,' + res.message,
type: 'error'
});
}
})
.finally(() => {
uni.hideLoading();
});
}
}
};
</script>
<style scoped lang="less"></style>
来源:https://juejin.cn/post/7172555993304268808
猜你喜欢
- 一同事反馈有一MySQL实例因为断电之后,启动不了。用了innodb_force_recovery=6也无效,于是前往查看。排查过程:最早的
- 特征选择时困难耗时的,也需要对需求的理解和专业知识的掌握。在机器学习的应用开发中,最基础的是特征工程。——吴恩达1.数据预处理数据预处理需要
- 本文实现12306抢火车票/京东抢手机示例,具体如下:#12306秒抢Python代码from splinter.browser impor
- 数据结构:通俗点说,就是储存大量数据的容器。这里主要介绍Python的4种基本数据结构:列表、字典、元组、集合。格式如下:列表:list =
- 1.安装相应的库文件sudo apt-get install python-mysqldb2.数据库操作import MySQLdb db
- Mysql查看是否使用到索引mysql数据库创建索引优化之后,在查询时想看下是否使用到索引,使用执行计划查看:mysql> expla
- 图片轮播滤镜转换效果,只支持ie浏览器<img width="156" height="60"
- 本文实例讲述了Go语言结构体定义和使用方法。分享给大家供大家参考。具体分析如下:一个结构体(struct)就是一个字段的集合。(而 type
- SQL Server数据库日志清除的两个方法:方法一一般情况下,SQL数据库的收缩并不能很大程度上减小数据库大小,其主要作用是收缩日志大小,
- 也许自己真的就是有手残的毛病,你说好端端的环境配置好了,自己还在那里瞎鼓捣,我最不想看到的就是在安装一个别的模块的时候,自动卸载了本地的其他
- 数据库,顾名思义,就是一个存储数据的大仓库,涵盖了多个方面的知识和应用。其优点和特性颇多,为多种编程语言的高效运行都提供了可靠又准确的信息来
- 如果我需要在运行有SQL Server的机器上运行病毒扫描软件,怎样做才不会影响性能? 这取决于您希望运行的病毒扫描软件的类型。目前有三种类
- 在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往
- 本文实例为大家分享了小程序实现tab更换页面效果的具体代码,供大家参考,具体内容如下.wxml<scroll-view scroll-
- 这样做的好处是:利用表格来装载数据,不言而喻是最好的,你可以很灵活的为每个单元格定义样式。下面是具体的做法首先在photoshop设计一个效
- 本篇阅读的代码实现了将输入的数字转化成一个列表,输入数字中的每一位按照从左到右的顺序成为列表中的一项。本篇阅读的代码片段来自于30-seco
- 项目场景pytorch训练时我们一般把数据集放到数据加载器里,然后分批拿出来训练。训练前我们一般还要看一下训练数据长啥样,也就是训练数据集可
- 刚开始学习tensorflow,还不太会用,开个博记录,今天遇到一个问题是用tf.layers.dense创建的全连接层,如何查看权重?知道
- 前言每一个孩子都像星空中的一颗星星,散发着自己所特有的光芒照亮着整个夜空。今天就带大家用27行Python代码绘制一幅满天星吧。全局设置在绘
- python数据拟合主要可采用numpy库,库的安装可直接用pip install numpy等。1. 原始数据:假如要拟合的数据yyy来自