c5_labsci/fapp/ciyon_ap/components/ciy-aicameraocr/ciy-aicameraocr.vue

272 lines
9.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="_vocr">
<view>
<view v-if="workstep == 1" class="rel">
<cover-image v-if="maskpng" :src="file_stor(maskpng)" class="abs t0 l0" :style="{opacity:0.8,width: '100%', height: height + 'vw'}"></cover-image>
<camera device-position="back" flash="off" :style="{width: '100%', height: height + 'vw'}"></camera>
</view>
<view v-if="workstep == 2" class="rel">
<image :src="src" :style="{width: '100%', height: height + 'vw',display:'block'}"></image>
<view v-for="txtpo in txtpos" class='abs' @tap="boxclick(txtpo)" :style="{top:txtpo.top,left:txtpo.left,width:txtpo.width,height:txtpo.height,minWidth:'0.7em',minHeight:'0.7em',border:'1px solid ' + bordercolor,borderRadius:'3px'}"></view>
<view v-if="txtpos.length == 0" class='abs b0 r0 _noocr'>无文字</view>
</view>
<view class="flex px2" style="justify-content: space-between;height:3em;">
<view>
<ciy-svgimg v-if="workstep==0" @tap="workstep=1" :src="svg.opencamera" ciystyle="width:2em;height:2em;"></ciy-svgimg>
<ciy-svgimg v-else @tap="workstep=0" :src="svg.closecamera" ciystyle="width:2em;height:2em;"></ciy-svgimg>
</view>
<view>
<button v-if="workstep==1" class="btn lg cc" @tap="ocrnow">拍摄识别</button>
</view>
<view>
<ciy-svgimg v-if="workstep == 2" @tap="workstep=1" :src="svg.recamera" ciystyle="width:2em;height:2em;"></ciy-svgimg>
<view v-else style="width:2em;height:2em;"></view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
emits: ['change', 'textclick'],
props: {
maskpng: {
type: String,
default: ''
},
height: {
type: String,
default: '66'
},
bordercolor: {
type: String,
default: '#00e112'
},
mode: {
type: String,
default: 'text' //idcard身份证自动校正none 无文字不ocrtext ocr有文字(无文字5秒超时)
},
checkidcard: {
type: String,
default: '' //front人像back国徽
},
},
data() {
return {
txtpos: [],
src: '',
svg:{
opencamera:'<svg viewBox="0 0 1024 1024" version="1" xmlns="http://www.w3.org/2000/svg"><path d="M868 288a64 64 0 0 1 101 52l3 303a64 64 0 0 1-103 51l-207-158a64 64 0 0 1 2-103l204-145z" fill="#1296db"></path><path d="M144 192h456a96 96 0 0 1 96 96v417a96 96 0 0 1-96 96H144a96 96 0 0 1-96-96V288a96 96 0 0 1 96-96z" fill="#1296db"></path></svg>',
closecamera:'<svg viewBox="0 0 1024 1024" version="1" xmlns="http://www.w3.org/2000/svg"><path d="M107 152A32 32 0 1 1 149 104l768 672a32 32 0 0 1-42 48l-768-672z" fill="#1296db"></path><path d="M733 462l-37-52 172-122a64 64 0 0 1 101 52l3 303a64 64 0 0 1-20 47l-44-47-3-303-172 122z m-35-54l36 53c-11 7-24 12-37 12a64 64 0 0 1-64-64V288a32 32 0 0 0-32-32h-206V192h206a96 96 0 0 1 96 96v121c0-0 1-1 2-1zM632 608h64v97a96 96 0 0 1-96 96H144a96 96 0 0 1-96-96V288a96 96 0 0 1 96-96h96v64h-96a32 32 0 0 0-32 32v417a32 32 0 0 0 32 32h456a32 32 0 0 0 32-32V608z" fill="#1296db"></path></svg>',
recamera:'<svg viewBox="0 0 1024 1024" version="1" xmlns="http://www.w3.org/2000/svg"><path d="M533 175v-62l-228 143 228 143v-107c114 26 200 128 200 249 0 141-116 257-257 257s-257-116-257-257c0-32-26-57-57-57-32 0-57 26-57 57 0 204 167 371 371 371s371-167 371-371c0-185-137-339-314-366z" fill="#1296db"></path></svg>'
},
workstep: 0,
};
},
watch: {},
computed: {},
mounted() {
var vkopn = {};
vkopn.version = 'v1';
vkopn.track = {};
vkopn.track.IDCard = {};
vkopn.track.IDCard.mode = 2;
vkopn.track.OCR = {};
vkopn.track.OCR.mode = 2;
vkopn.gl = this.gl;
this.session = wx.createVKSession(vkopn);
this.session.start(err => {
this.session.on('updateAnchors', this.onanchor);
});
},
unmounted() {
this.session.off('updateAnchors', this.onanchor);
this.session.stop();
this.session.destroy();
},
methods: {
boxclick(po) {
this.$emit('textclick', po);
},
onanchor(anchors) {
if (typeof(this.auchorcb) == 'function')
this.auchorcb(anchors);
},
Step(step) {
this.workstep = step;
},
//摄像头开关在下,且用图标占位。
//重新拍摄在下右。方便点击。
//拍摄识别在中。
//按拍摄后,自动识别
//无文字,在图片旁边标注即可。
//拍照完成,上面有文字。
//用户点门头,上传门头。
//用户点企业,再点文字,文字进企业框。
//用户点展位号,
//
//拍照,拍照+识别
//在摄像头正常的时候,点一下门头,拍照,上传。
//在摄像头正常的时候,点一下企业,拍照识别,点框
//在摄像头正常的时候,点一下企业,拍照识别,点框
async runvk(mode, file) {
return new Promise(async (resolve, reject) => {
var _time = setTimeout(() => {
reject('timeout');
}, 5000);
this.auchorcb = anchors => {
clearTimeout(_time);
resolve(anchors);
};
if (mode == 'idcard') {
this.session.detectIDCard({
frameBuffer: file.buffer,
width: file.width,
height: file.height,
getAffineImg: true,
});
} else {
this.session.runOCR({
frameBuffer: file.buffer,
width: file.width,
height: file.height,
});
}
}).catch(e => {
console.error('vk error', e);
return e;
});
},
ocrnow() {
const ctx = wx.createCameraContext();
ctx.takePhoto({
quality: 'high',
success: async (res) => {
this.workstep = 2;
this.txtpos = [];
this.src = res.tempImagePath;
res.buffer = await this.getimgbuffer(res);
var ret = {};
ret.tempimg = res.tempImagePath;
ret.width = res.width;
ret.height = res.height;
if (this.mode == 'idcard') {
var anchors = await this.runvk('idcard', res);
var anchor = anchors[0];
if (anchor.isComplete != 1)
return this.alert('身份证拍摄不完整');
if (this.checkidcard == 'front') {
if (anchor.label != 0)
return this.alert('请拍摄身份证人像面');
if (anchor.orientation != 0)
return this.alert('请朝上放正拍摄身份证');
}
if (this.checkidcard == 'back') {
if (anchor.label != 1)
return this.alert('请拍摄身份证国徽面');
if (anchor.orientation != 0)
return this.alert('请朝上放正拍摄身份证');
}
ret.idcardface = anchor.label; //0 照片面 / 1 国徽面
ret.orientation = anchor.orientation; // 身份证朝向 0 朝上 1 朝下 2 朝下 3 朝左)
const canvas = wx.createOffscreenCanvas({
type: '2d',
width: anchor.affineImgWidth,
height: anchor.affineImgHeight,
});
const context = canvas.getContext('2d');
context.clearRect(0, 0, anchor.affineImgWidth, anchor.affineImgHeight);
context.setTransform(
Number(anchor.affineMat[0]), Number(anchor.affineMat[3]), Number(anchor.affineMat[1]),
Number(anchor.affineMat[4]), Number(anchor.affineMat[2]), Number(anchor.affineMat[5])
);
context.drawImage(this._img, 0, 0, res.width, res.height);
const imageData = context.getImageData(0, 0, anchor.affineImgWidth, anchor.affineImgHeight);
res.buffer = imageData.data.buffer;
res.width = anchor.affineImgWidth;
res.height = anchor.affineImgHeight;
this.src = canvas.toDataURL();
}
ret.txts = [];
ret.txtall = '';
if (this.mode != 'none') { //无文字时会有直接卡死bug
try {
var anchors = await this.runvk('ocr', res);
ret.anchors = anchors;
for (var i in anchors) {
if (anchors[i].text)
ret.txtall = anchors[i].text;
if (!anchors[i].subtext)
continue;
ret.txts.push(anchors[i].subtext);
var pos = anchors[i].box;
this.txtpos.push({
text: anchors[i].subtext,
alltext: anchors[i].text,
pos: pos,
top: (pos[0].y * 100) + '%',
left: (pos[0].x * 100) + '%',
width: ((pos[1].x - pos[0].x) * 100) + '%',
height: ((pos[2].y - pos[0].y) * 100) + '%',
});
}
} catch (e) {
console.log(e);
//this.toast('无文字,请重新拍摄');
//this.workstep = 1;
//return;
}
}
this.$emit('change', ret);
}
});
},
async getimgbuffer(file) {
const canvas = wx.createOffscreenCanvas({
type: '2d',
width: file.width,
height: file.height,
});
const context = canvas.getContext('2d');
this._img = canvas.createImage();
this._img.src = file.tempImagePath;
var err = await this.goe(this.go_load(this._img));
if (err)
return reject('Image Load Error');
context.clearRect(0, 0, file.width, file.height);
context.drawImage(this._img, 0, 0, file.width, file.height);
var imgData = context.getImageData(0, 0, file.width, file.height);
return imgData.data.buffer;
}
}
}
</script>
<style scoped>
._vocr {
margin: 0;
padding: 0;
position: relative;
}
._noocr {
background: #00000044;
color: #000000;
text-shadow: 1px 1px 0 #ffffff88;
padding: 0.3em 0.8em;
border-radius: 0.5em 0 0 0;
}
</style>