uniapp中人脸识别图片并圈起人脸

在这里插入图片描述
效果如上,我用的是阿里云的人脸识别。首先,我们先封装一个阿里云的请求js文件

faceRecognition.js

import CryptoJS from 'crypto-js'

//SignatureNonce随机数字
function signNRandom() {
  const Rand = Math.random()
  const mineId = Math.round(Rand * 100000000000000)
  return mineId;
};
//Timestamp
function getTimestamp() {
  let date = new Date();
  let YYYY = pad2(date.getUTCFullYear());
  let MM = pad2(date.getUTCMonth() + 1);
  let DD = pad2(date.getUTCDate());
  let HH = pad2(date.getUTCHours());
  let mm = pad2(date.getUTCMinutes());
  let ss = pad2(date.getUTCSeconds());
  return `${YYYY}-${MM}-${DD}T${HH}:${mm}:${ss}Z`;
}
//补位占位
function pad2(num) {
  if (num < 10) {
    return '0' + num;
  }
  return '' + num;
};
// 排序
function ksort(params) {
  let keys = Object.keys(params).sort();
  let newParams = {};
  keys.forEach((key) => {
    newParams[key] = params[key];
  });
  return newParams;
};
// HmacSHA1加密+base64
function createHmac(stringToSign, key) {
  const CrypStringToSign = CryptoJS.HmacSHA1(stringToSign, key);
  const base64 = CryptoJS.enc.Base64.stringify(CrypStringToSign);
  return base64;
};
//编码
function encode(str) {
  var result = encodeURIComponent(str);
  return result.replace(/!/g, '%21')
    .replace(/'/g, '%27')
    .replace(/\(/g, '%28')
    .replace(/\)/g, '%29')
    .replace(/\*/g, '%2A');
};
function sha1(stringToSign, key) {
  return createHmac(stringToSign, key);
};
function getSignature(signedParams, method, secret) {
  var stringToSign = `${method}&${encode('/')}&${encode(signedParams)}`;
  const key = secret + "&";
  return sha1(stringToSign, key);
};
//参数拼接 &
function objToParam(param) {
  if (Object.prototype.toString.call(param) !== '[object Object]') {
    return '';
  }
  let queryParam = '';
  for (let key in param) {
    if (param.hasOwnProperty(key)) {
      let value = param[key];
      queryParam += toQueryPair(key, value);
    }
  }
  return queryParam;
};
function toQueryPair(key, value) {
  if (typeof value == 'undefined') {
    return `&${key}=`;
  }
  return `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
};
function generateUrl(request, httpMethod, endpoint, accessKeySecret) {
  //参数中key排序
  const sortParams = ksort(request);
  //拼成参数
  const sortQueryStringTmp = objToParam(sortParams);
  const sortedQueryString = sortQueryStringTmp.substring(1);// 去除第一个多余的&符号
  //构造待签名的字符串
  const Signature = getSignature(sortedQueryString, httpMethod, accessKeySecret)
  //签名最后也要做特殊URL编码
  request["Signature"] = encodeURIComponent(Signature);

  //最终生成出合法请求的URL
  const finalUrl = "https://" + endpoint + "/?Signature=" + encodeURIComponent(Signature) + sortQueryStringTmp;
  return finalUrl;
}

const callRecognizeBankCard  =    function (ImageURL,callback) {
  const accessKeyId = '';
  const accessKeySecret = '';
  const endpoint = "facebody.cn-shanghai.aliyuncs.com";
  const Action = "DetectFace";
	
  // API_HTTP_METHOD推荐使用POST
  const API_HTTP_METHOD = "POST";
  const API_VERSION = "2019-12-30";
	

  const request_ = {};
  //系统参数
  request_["SignatureMethod"] = "HMAC-SHA1";
  request_["SignatureNonce"] = signNRandom();
  request_["AccessKeyId"] = accessKeyId;
  request_["SignatureVersion"] = "1.0";
  request_["Timestamp"] = getTimestamp();
  request_["Format"] = "JSON";
  request_["RegionId"] = "cn-shanghai";
  request_["Version"] = API_VERSION;
	
	
  request_["Action"] = Action; 
  request_["ImageURL"] =  ImageURL
  callApiRequest(request_, API_HTTP_METHOD, endpoint, accessKeySecret, callback);
}

var http = {};
http.request = function (option, callback) {
  var url = option.url;
  var method = option.method;
  var data = option.data;
  var timeout = option.timeout || 0;
  //创建XMLhttpRequest对象
  var xhr = new XMLHttpRequest();
  // var xhr = new plus.net.XMLHttpRequest()
	
	// return
  (timeout > 0) && (xhr.timeout = timeout);
  //使用open方法设置和服务器的交互信息
  xhr.open(method, url, true);
  if (typeof data === 'object') {
    try {
      data = JSON.stringify(data);
    } catch (e) { }
  }
  //发送请求
  xhr.send(data);
  //如果请求完成,并响应完成,获取到响应数据
  xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
      var result = xhr.responseText;
      try { result = JSON.parse(xhr.responseText); } catch (e) { }
      callback && callback(null, result);
    }
  }.bind(this);
  //延时处理
  xhr.ontimeout = function () {
    callback && callback('timeout');
    console.log('error', '连接超时');
  };
};
// post请求
http.post = function (option, callback) {
  option.method = 'post';
  option.contentType = 'application/json;charset=UTF-8'
  this.request(option, callback);
};


// 封装请求方法
function httpRequest(url, data, method, callback) {
    uni.request({
        url: url,
        method: method,
        data: data,
        header: {
            'content-type': 'application/json'
        },
        success: function (res) {
            callback(null, res.data);
        },
        fail: function (err) {
            callback(err, null);
        }
    });
}


//请求数据
const callApiRequest = (request_, API_HTTP_METHOD, endpoint, accessKeySecret, callback) => {
  const url = generateUrl(request_, API_HTTP_METHOD, endpoint, accessKeySecret);
	
	 httpRequest(url, null, 'POST', function (err, result) {
	        if (err) {
	            console.error('Error:', err);
	            callback(null);
	        } else {
	            console.log('Result:', result);
	            callback(result);
	        }
	    });
}

export default callRecognizeBankCard;

请求之后的响应参数都在文档里面有,https://help.aliyun.com/zh/viapi/developer-reference/api-i5236v?spm=a2c4g.11186623.0.i2

然后开始使用

<view class="re-upload" @click="uploadImage">上传图片</view>

  	<u-modal :show="identifyShow" title="" :showConfirmButton="false">
  		<view class="slot-content" style="width: 100%;position: relative;display: flex;justify-content: center;background-color: #00112b;">
			<image class="ai-bg-top" src="" mode=""></image>
			<view class="ai-image" style="width: 330px !important;height: 350px;margin-top: 200rpx;position: relative;">
			<view class="animation" v-show="scanShow">
			<view class="animation-list"></view></view>
			  <image :src="aiAvatar" mode="" style="width: 100% !important;height: 100%;"></image>
			  <view class="faceRectangles" 
			  v-for="(item, index) in avatarPostionList"
			  :key="index"
			  :style="handlefaceRectanglesStyle(item, index)"
			  >
			  </view>
			</view>
			<image class="ai-bg-bottom" src="" mode=""></image>
  		</view>
  	</u-modal>

import faceRecognition from '@/utils/faceRecognition.js'

const identifyShow = ref(false)
const aiAvatar = ref('')
const scanShow = ref(false)
const studentForm = ref({ avatar: '' })
const avatarPostionList = ref([])

const handlefaceRectanglesStyle = (item, index) => {
	return {
		'position': 'absolute',
		'left': `${item[0]}px`,
		'top': `${item[1]}px`,
		'width': `${item[2]}px`,
		'height': `${item[3]}px`
	}
}

const chunkArray = (array, chunkSize) =>  {
  const groupedArray = [];
  for (let i = 0; i < array.length; i += chunkSize) {
    groupedArray.push(array.slice(i, i + chunkSize));
  }
  return groupedArray;
}

const handleClear = (boolean) => {
	avatarPostionList.value = []
	scanShow.value = boolean
	identifyShow.value = boolean
}

const handleFaceRecognition = (path) => {
	faceRecognition(path, avatar => {
		if(avatar.Code) {
			uni.showToast({
				title: avatar.Message,
				icon: 'none',
				duration: 5000
			})
			identifyShow.value = false
			return;
		}
		if(avatar.Data.FaceCount !== 1) {
			const avatarList = chunkArray(avatar.Data.FaceRectangles, 4)
			avatarPostionList.value = avatarList
			scanShow.value  = false
			setTimeout(() => {
				uni.showModal({
					title: '提示',
					content: '当前照片可能存在多张人脸,是否继续上传?',
					success: res => {
						if(res.confirm) {
							studentForm.value.avatar = path
						}else {
							uni.showToast({
								title: '已取消上传',
								icon: 'none'
							})
						}
						identifyShow.value = false
					}
				})
			}, 1000)
		}else {
			avatarPostionList.value = [avatar.Data.FaceRectangles]
			setTimeout(() => {
				handleClear(false)
				studentForm.value.avatar = path
			}, 1000)
		}
	})
}

const uploadImage = () => {
  uni.chooseImage({
    count: 1,
    success: (res) => {
      //uploadFile,封装的上传方法
      uploadFile(res.tempFilePaths[0], 'avatar', (path:string) => {
      // path为图片线上地址
	  const newPath = `${path}?x-oss-process=image/resize,limit_0,m_fill,w_330,h_350/quality,q_100`
	  // newPath 加宽高之后的图片
		aiAvatar.value = newPath
		handleClear(true)
		setTimeout(() => {
			handleFaceRecognition(newPath)
		}, 5000)
      },()=>{})
    }
  });
}

css

:deep(.u-popup__content){
	width: 350px !important;
	// border-radius: 0 !important;
}
:deep(.u-modal) {
	width: 100% !important;
}
.ai-bg-top {
	position: absolute;
	width: 100%;
	height: 200rpx;
	top: 0;
	left: 0;
}
.ai-bg-bottom {
	position: absolute;
	width: 100%;
	height: 200rpx;
	bottom: 0;
	left: 0;
}
.animation{
	  position: absolute;
	  top: 350rpx;
	  left: 0;
	  right: 0;
	  height: 700rpx;
	
	}
	.animation-list{
	  width: 100%;
	  height: 450rpx;
	  background: linear-gradient(to bottom,rgba(216,179,255,0),rgba(216,179,255,1));
	  position: relative;
	  top: 0;
	  animation: myfist 2s linear 1s infinite alternate;
	}
	
	/* 开始执行动画 */
	@keyframes myfist{
	  0%{
	    background: linear-gradient(to bottom,rgba(216,179,255,0),rgba(216,179,255,1));
	    left: 0;
	    top: -400rpx;
	  }
	  25%{
	    left: 0;
	    top: 100rpx;
	  }
	  50%{
	    left: 0;
	    top: 100rpx;
	  }
	  75%{
	    left: 0;
	    top: 100rpx;
	  }
	  100%{
	    left: 0;
	    top: -400rpx;
	  }
	}

.faceRectangles {
	border: 4rpx solid red;
}

:deep(.u-modal__content){
	padding: 0 !important;
	height: 1100rpx;
	width: 100%;
}
:deep(.u-line){
	display: none !important; 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/457557.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

visual studio 中添加qt类报错问题

添加ImportSetting类&#xff0c;在构造函数声名处已经写Q_OBJECT宏&#xff0c;但仍然报错。 无法解析的外部符号"public::virtual struct QMetaObject const*_cdecl ImportSettingFromFile::metaObject(void)const "(?metaObjectImportSettingFromFileUEBAPEBUQM…

Spring boot创建第一个项目

作者简介&#xff1a; zoro-1&#xff0c;目前大二&#xff0c;正在学习Java&#xff0c;数据结构&#xff0c;spring等 作者主页&#xff1a; zoro-1的主页 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; Spring boot创建第一个项目 sp…

Python 基于 OpenCV 视觉图像处理实战 之 图像相关的基本概念,以及图像的基础操作 二

Python 基于 OpenCV 视觉图像处理实战 之 图像相关的基本概念&#xff0c;以及图像的基础操作 二 目录 Python 基于 OpenCV 视觉图像处理实战 之 图像相关的基本概念&#xff0c;以及图像的基础操作 二 一、简单介绍 二、图像的几何变换 三、插值算法 1、最近邻插值算法 …

Spring中的BeanFactory

BeanFactory&#xff0c;以Factory结尾&#xff0c;表示是一种工厂。 作用&#xff1a; 是一个接口&#xff0c;定义了生产Bean对象的工厂应有的方法&#xff0c;如下图,定义了一个Bean工厂&#xff0c;最基本的方法。 职责&#xff1a; 它是负责生产和管理bean的一个工厂&…

AJAX 05 axios拦截器、数据管理平台

AJAX 学习 AJAX 05 黑马头条-数据管理平台项目准备业务1&#xff1a;验证码登录bootstrap提示框实际业务中的验证码登录token 【注】HTML遗落的知识【注】JS遗漏的知识业务2&#xff1a;个人信息设置 & axios拦截器axios请求拦截器axios响应拦截器 业务3&#xff1a;发布文…

LabVIEW电磁阀特性测控系统

LabVIEW电磁阀特性测控系统 电磁阀作为自动化工程中的重要组成部分&#xff0c;其性能直接影响系统的稳定性和可靠性。设计一种基于LabVIEW的电磁阀特性测控系统&#xff0c;通过高精度数据采集和智能化控制技术&#xff0c;实现电磁阀流阻、响应时间及脉冲特性的准确测量和分…

ts文件怎么无损转换mp4?这样设置转换模式~

TS格式&#xff08;Transport Stream&#xff09;的起源可追溯到数字电视广播领域。设计初衷是解决视频、音频等多媒体数据在传输和存储中的问题。采用一系列标准技术&#xff0c;TS格式让视频信号能够以流的形式传输&#xff0c;因此在数字电视、广播等领域得到广泛应用。 MP4…

ASP.NET Core Web API 流式返回,逐字显示

Websocket、SSE&#xff08;Server-Sent Events&#xff09;和长轮询&#xff08;Long Polling&#xff09;都是用于网页和服务端通信的技术。 Websocket是一种全双工通信协议&#xff0c;能够实现客户端和服务端之间的实时通信。它基于TCP协议&#xff0c;并且允许服务器主动向…

消除PyCharm的黄色波浪线和右侧黄色短线

旧版pycharm看这个链接&#xff1a;https://blog.csdn.net/weixin_39450145/article/details/113574921 新版pycharm往下看 消除代码中的黄色波浪线&#xff1a;在设置&#xff0c;编辑器&#xff0c;配色方案&#xff0c;常规里面。然后选择错误和警告。 消除右侧黄色短线&am…

【Flink SQL】Flink SQL 基础概念:SQL 的时间属性

Flink SQL 基础概念&#xff1a;SQL 的时间属性 1.Flink 三种时间属性简介2.Flink 三种时间属性的应用场景2.1 事件时间案例2.2 处理时间案例2.3 摄入时间案例 3.SQL 指定时间属性的两种方式4.SQL 事件时间案例5.SQL 处理时间案例 与离线处理中常见的时间分区字段一样&#xff…

重新认识BIO、NIO、IO多路复用、Select、Poll、Epollo它们之间的关系

目录 一、背景 二、名词理解 &#xff08;1&#xff09;BIO &#xff08;2&#xff09;NIO &#xff08;3&#xff09;IO多路复用 &#xff08;4&#xff09;Select、Poll、Epollo 三、他们之间的关系总结 一、背景 最近又在学习网络IO相关知识&#xff0c;对我们常说的…

【软件测试基础篇】第一节.软件测试基础1

文章目录 前言⼀、了解软件测试行业二、主流测试技能三、测试常用分类四、模型 4.1 质量模型 4.2 w模型五、测试流程六、测试用例总结 前言 一、了解软件测试行业 1.概念&#xff1a; 使用技术手段验证软件功能是否符合需求 2.特点&#xff1a; 岗位缺口&#xff1a…

【OceanBase诊断调优 】 —— 合并问题如何排查?

最近总结一些诊断OCeanBase的一些经验&#xff0c;出一个【OceanBase诊断调优】专题&#xff0c;也欢迎大家贡献自己的诊断OceanBase的方法。 1. 前言 OceanBase 数据库的存储引擎基于 LSM-Tree 架构&#xff0c;将数据分为静态基线数据&#xff08;放在 SSTable 中&#xff…

如何利用POI导出报表

一、报表格式 二、依赖坐标 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.16</version> </dependency> <dependency><groupId>org.apache.poi</groupId><art…

Spring, SpringBoot, SpringCloud,微服务

1,SSM (Spring+SpringMVC+MyBatis) SSM框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容),常作为数据源较简单的web项目的框架。 Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet,Controlle…

浅谈路由器基本结构与工作原理

目录 一、结构 1.1 输入端口 1.2 交换结构 1.3 输出端口 1.4 路由选择处理器 二、输入端口处理和基于目的地转发 三、交换 四、输出端口处理 五、何时出现排队 5.1 输入排队 5.2 输出排队 一、结构 下图是一个通用路由器体系结构的总体试图视图&#xff0c;其主要由…

亚信安慧AntDB在数据可靠性和系统安全中的实践

亚信安慧AntDB以持续创新和技术进步为理念&#xff0c;不断优化性能和功能&#xff0c;至今已经保持了15年的平稳运行。这一漫长的历程并非偶然&#xff0c;而是源于AntDB团队对技术的不懈探索和追求。他们始终秉承着“永不停歇&#xff0c;永不满足”的信念&#xff0c;将技术…

openwrt中时间同步ntp使用

前言 openwrt开发中&#xff0c;我们可能遇到这样需求&#xff0c;使用路由器支持局域网内设备ntp授时功能。 作者&#xff1a;羽林君 转载授权以及围观&#xff1a;欢迎关注微信公众号&#xff1a;羽林君 或者添加作者个人微信&#xff1a;become_me ntp是什么 NTP&#…

STM32-V5开发板和树莓派的区别介绍

STM32-V5开发板和树莓派是两种不同类型的嵌入式开发平台&#xff0c;它们在设计理念、性能、用途和编程方式上都有所区别。 STM32-V5开发板 STM32-V5开发板是基于STM32微控制器的开发平台&#xff0c;通常用于嵌入式系统开发、教学和实验。 区别&#xff1a; - **核心*…

冒泡排序,详详解解

目录 基本概念&#xff1a; 上图&#xff1a; 核心思路&#xff1a; 基本步骤&#xff1a; 关键&#xff1a; 代码核心&#xff1a; 补充&#xff1a; 代码&#xff08;规范&#xff09; &#xff1a; 代码&#xff08;优化&#xff09;&#xff1a; 今天我们不刷力扣了&…