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

效果如上,我用的是阿里云的人脸识别。首先,我们先封装一个阿里云的请求js文件

faceRecognition.js

typescript 复制代码
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

然后开始使用

typescript 复制代码
<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

typescript 复制代码
: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; 
}
相关推荐
Yaml47 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
尚梦7 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
清灵xmf10 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
paopaokaka_luck11 小时前
基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)
java·spring boot·小程序·毕业设计·mybatis·1024程序员节
尚学教辅学习资料14 小时前
基于SSM+uniapp的营养食谱系统+LW参考示例
java·uni-app·ssm·菜谱
Bessie23414 小时前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
蜕变菜鸟14 小时前
小程序跳转另一个小程序
小程序
17 小时前
躺平成长-代码开发,利用kimi开发小程序(09)
小程序
20 小时前
微信小程序运营日记(第四天)
微信小程序·小程序
guanpinkeji20 小时前
旧衣回收小程序:提高回收效率,扩大服务范围
大数据·小程序·团队开发·软件开发·小程序开发·旧衣回收·旧衣回收小程序