|
@@ -0,0 +1,357 @@
|
|
|
+<template>
|
|
|
+ <view>
|
|
|
+ <nav-bar title="身份证"></nav-bar>
|
|
|
+ <div class="camera-wrap">
|
|
|
+ <camera ref="camera" resolution="high" class="camera" frame-size="small" device-position="back" flash="off" @error="error"></camera>
|
|
|
+ <image class="avatar" :src="face ? '../static/avatar.png' : '../static/back.png' "></image>
|
|
|
+ </div>
|
|
|
+ <canvas class="canvas" canvas-id="canvas1"></canvas>
|
|
|
+ <canvas class="canvas" canvas-id="canvas"></canvas>
|
|
|
+ <view>精度{{point}}</view>
|
|
|
+ <view>人脸面符合次数{{frontIsCard}}</view>
|
|
|
+ <view>国徽面合次数{{backIsCard}}</view>
|
|
|
+ <!-- <image class="img" :src="src" mode="widthFix"></image> -->
|
|
|
+ <button @click="takePhoto(true)">人脸面</button>
|
|
|
+ <button @click="takePhoto(false)">国徽面</button>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { mapGetters } from 'vuex';
|
|
|
+import { templateFront, templateBack } from '../../common/isCardTemplate.js'
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ face:true,
|
|
|
+ point:0,
|
|
|
+ context:null,
|
|
|
+ src:"",
|
|
|
+ isCompare:false,
|
|
|
+ frontIsCard:0,
|
|
|
+ backIsCard:0,
|
|
|
+ frontData:templateFront, //身份证人脸面模板特征值
|
|
|
+ backData:templateBack //身份证国徽面模板特征值
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: { ...mapGetters(['userInfo','goodsAuditionConfigIdList','playSectionId']) },
|
|
|
+ onLoad(option) {
|
|
|
+
|
|
|
+ },
|
|
|
+ onUnload(option) {
|
|
|
+
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+
|
|
|
+ this.context = uni.createCanvasContext('canvas')
|
|
|
+ const ctx = uni.createCameraContext();
|
|
|
+ const listener = ctx.onCameraFrame(frame => {
|
|
|
+ if(!this.isCompare) {
|
|
|
+ this.isCompare = true;
|
|
|
+
|
|
|
+ uni.getSystemInfo({
|
|
|
+ success: (res) => { // res - 各种参数
|
|
|
+
|
|
|
+ let info = uni.createSelectorQuery().select(".canvas");
|
|
|
+ info.boundingClientRect((data1) => { //data - 各种参数
|
|
|
+ var buffer = new Uint8ClampedArray(frame.data);
|
|
|
+ //获取是实时拍照原图
|
|
|
+ uni.canvasPutImageData({
|
|
|
+ canvasId: 'canvas',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: frame.width,
|
|
|
+ height: frame.height,
|
|
|
+ data: buffer,
|
|
|
+ success:(res) => {
|
|
|
+ //生成图片
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ quality:1,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: frame.width,
|
|
|
+ height: frame.height,
|
|
|
+ destWidth:data1.width,
|
|
|
+ destHeight:data1.height,
|
|
|
+ canvasId: 'canvas',
|
|
|
+ success: (res) => {
|
|
|
+ // 在H5平台下,tempFilePath 为 base64
|
|
|
+
|
|
|
+ //绘制原图到canvas上
|
|
|
+
|
|
|
+ this.context.drawImage(res.tempFilePath,0,0,data1.width,data1.height)
|
|
|
+ this.context.draw();
|
|
|
+
|
|
|
+ let avatarInfo = uni.createSelectorQuery().select(".avatar");
|
|
|
+
|
|
|
+ //获取原图扫描框大小
|
|
|
+ avatarInfo.boundingClientRect((data) => {
|
|
|
+ // //data - 各种参数
|
|
|
+ let left = data.left;
|
|
|
+ let top = data.top;
|
|
|
+ let width = data.width;
|
|
|
+ let height = data.height;
|
|
|
+
|
|
|
+ //获取原图扫描框内容
|
|
|
+ uni.canvasGetImageData({
|
|
|
+ canvasId: 'canvas',
|
|
|
+ x: left,
|
|
|
+ y: top,
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ success:(res) => {
|
|
|
+ // this.isCompare = false;
|
|
|
+
|
|
|
+
|
|
|
+ //绘制扫描图片
|
|
|
+ uni.canvasPutImageData({
|
|
|
+ canvasId: 'canvas',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ data: res.data,
|
|
|
+ success:(res) => {
|
|
|
+ //生成图片
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ quality:1,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ destWidth:width,
|
|
|
+ destHeight:height,
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ canvasId: 'canvas',
|
|
|
+ success:async (res1) => {
|
|
|
+ //绘制并压缩
|
|
|
+
|
|
|
+ this.context.drawImage(res1.tempFilePath,0,0,width,height,0,0,200,200)
|
|
|
+ this.context.draw();
|
|
|
+
|
|
|
+ let res = await this.canvasGetImageData('canvas');
|
|
|
+ let newData = Array(res.data.length)
|
|
|
+ newData.fill(0)
|
|
|
+ res.data.forEach((_data, index) => {
|
|
|
+ if ((index + 1) % 4 === 0) {
|
|
|
+ const R = res.data[index - 3]
|
|
|
+ const G = res.data[index - 2]
|
|
|
+ const B = res.data[index - 1]
|
|
|
+ const gray = ~~((R + G + B) / 3)
|
|
|
+
|
|
|
+ res.data[index - 3] = gray
|
|
|
+ res.data[index - 2] = gray
|
|
|
+ res.data[index - 1] = gray
|
|
|
+ res.data[index] = 255 // Alpha 值固定为255
|
|
|
+ }
|
|
|
+ })
|
|
|
+ uni.canvasPutImageData({
|
|
|
+ canvasId: 'canvas1',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: res.width,
|
|
|
+ height: res.height,
|
|
|
+ data: res.data,
|
|
|
+ success:(res) => {
|
|
|
+ // this.isCompare = false;
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ destWidth:res.width,
|
|
|
+ destHeight:res.height,
|
|
|
+ quality:1,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ canvasId: 'canvas1',
|
|
|
+ success: (res2) => {
|
|
|
+ this.src = res2.tempFilePath
|
|
|
+ },
|
|
|
+ })
|
|
|
+ },
|
|
|
+ fail:err => {
|
|
|
+ console.log(err,'err')
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // for (let i = 0; i < newData.length; i += 4) {
|
|
|
+ // let R = newData[i]
|
|
|
+ // let G = newData[i + 1]
|
|
|
+ // let B = newData[i + 2]
|
|
|
+ // let Alpha = newData[i + 3]
|
|
|
+ // }
|
|
|
+ let getData = this.getHashFingerprint(res)
|
|
|
+ let similarty = this.cosineSimilarity(this.face ? this.frontData : this.backData,getData)
|
|
|
+ // let distance = this.hammingDistance(this.frontData,result)
|
|
|
+ // let similarty = (this.frontData.length - distance) / this.frontData.length
|
|
|
+ if(similarty >= 0.8) {
|
|
|
+ this.src = res1.tempFilePath
|
|
|
+ if(this.face) {
|
|
|
+ this.frontIsCard++;
|
|
|
+ } else {
|
|
|
+ this.backIsCard++;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ this.point = similarty
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ this.isCompare = false;
|
|
|
+ },200)
|
|
|
+ console.log(similarty,'similarty')
|
|
|
+
|
|
|
+ },
|
|
|
+ })
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }).exec()
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+ },
|
|
|
+ fail(err) {
|
|
|
+ console.log(err)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }).exec()
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ listener.start()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ error(err) {
|
|
|
+ console.log(err)
|
|
|
+ },
|
|
|
+
|
|
|
+ canvasGetImageData(id) {
|
|
|
+ return new Promise(resolve => {
|
|
|
+ uni.canvasGetImageData({
|
|
|
+ canvasId: id,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ width: 200,
|
|
|
+ height: 200,
|
|
|
+ success:(res) => {
|
|
|
+ resolve(res)
|
|
|
+ },
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ hammingDistance (str1, str2) {
|
|
|
+ let distance = 0
|
|
|
+ const str1str1Arr = str1.split('')
|
|
|
+ const str2str2Arr = str2.split('')
|
|
|
+ str1str1Arr.forEach((letter, index) => {
|
|
|
+ if (letter !== str2str2Arr[index]) {
|
|
|
+ distance++
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return distance
|
|
|
+ } ,
|
|
|
+
|
|
|
+ cosineSimilarity (sampleFingerprint, targetFingerprint) {
|
|
|
+ // cosθ = ∑n, i=1(Ai × Bi) / (√∑n, i=1(Ai)^2) × (√∑n, i=1(Bi)^2) = A · B / |A| × |B|
|
|
|
+ const length = sampleFingerprint.length
|
|
|
+ let innerProduct = 0
|
|
|
+ for (let i = 0; i < length; i++) {
|
|
|
+ innerProduct += sampleFingerprint[i] * targetFingerprint[i]
|
|
|
+ }
|
|
|
+ let vecA = 0
|
|
|
+ let vecB = 0
|
|
|
+ for (let i = 0; i < length; i++) {
|
|
|
+ vecA += sampleFingerprint[i] ** 2
|
|
|
+ vecB += targetFingerprint[i] ** 2
|
|
|
+ }
|
|
|
+ const outerProduct = Math.sqrt(vecA) * Math.sqrt(vecB)
|
|
|
+ return innerProduct / outerProduct
|
|
|
+ } ,
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ getHashFingerprint (imgData) {
|
|
|
+ const grayList = imgData.data.reduce((pre, cur, index) => {
|
|
|
+ if ((index + 1) % 4 === 0) {
|
|
|
+ pre.push(imgData.data[index - 1])
|
|
|
+ }
|
|
|
+ return pre
|
|
|
+ }, [])
|
|
|
+ const length = grayList.length
|
|
|
+ const grayAverage = grayList.reduce((pre, next) => (pre + next), 0) / length
|
|
|
+ return grayList.map(gray => (gray >= grayAverage ? 1 : 0)).join('')
|
|
|
+ } ,
|
|
|
+
|
|
|
+
|
|
|
+ takePhoto(bo) {
|
|
|
+ this.face = bo
|
|
|
+ // const ctx = uni.createCameraContext();
|
|
|
+ // ctx.takePhoto({
|
|
|
+ // quality: 'high',
|
|
|
+ // success: res => {
|
|
|
+ // this.src = res.tempImagePath;
|
|
|
+ // },
|
|
|
+ // fail: err => {
|
|
|
+ // console.log(err);
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style >
|
|
|
+ page{
|
|
|
+ background-color: #EAEEF1;
|
|
|
+ }
|
|
|
+</style>
|
|
|
+<style scope lang="scss">
|
|
|
+ .camera-wrap {
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .camera {
|
|
|
+ width: 750rpx;
|
|
|
+ height: 916.67rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .avatar {
|
|
|
+ opacity: 0.3;
|
|
|
+ position:absolute;
|
|
|
+ left:50%;
|
|
|
+ top:40rpx;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ width:633rpx;
|
|
|
+ height:400rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .canvas {
|
|
|
+ position:fixed;
|
|
|
+ top:9999999%;
|
|
|
+ left:9999999%; //canvas藏起来
|
|
|
+ width: 750rpx;
|
|
|
+ height: 916.67rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .img {
|
|
|
+ display: block;
|
|
|
+ margin:0 auto;
|
|
|
+ width:633rpx;
|
|
|
+ height:400rpx;
|
|
|
+ }
|
|
|
+</style>
|