• 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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200

    请求之后的响应参数都在文档里面有,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)
          },()=>{})
        }
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    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; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
  • 相关阅读:
    1.1.4:DHTMLX Rich Text|JavaScript/HTML Rich Text Editor
    Golang手写RPC框架(day1)
    自动化测试基础——Pytest框架之YAML详解以及Parametrize数据驱动
    Ubuntu乌班图安装VIM文本编辑器工具
    Android项目集成flutter模块
    kubernetes(6)Service
    初识ES6
    C# wpf 实现任意控件(包括窗口)更多拖动功能
    C++圆的面积与周长 自定义函数
    Vulnhub_driftingblues1靶机渗透测试
  • 原文地址:https://blog.csdn.net/weixin_45389051/article/details/136719549