掘金链接
华为云自定义模板识别是服务于AI领域的流程控制系统,我们一起了解下其中一个模块的界面化操作实例。如下图,针对图片的高精度识别,我们需要处理图片的样式以便获得更好的模型训练数据和高精度识别结果。我们针对三个场景来实现图片处理需求:
在初始化模板的时候,可视化区域内加载图片并呈现出来:
1. 图片的拖拽移动
/**
* 拖拽图片:
* @param e
* @returns
*/
public dragImage(e) {
e.stopPropagation(); // 阻止事件冒泡
this.editImgWrapper = this.el.nativeElement.querySelector('#editImgWrapper');// 取图片信息
let isDraging = false; // 拖动的标志
let nodePositon = { // 当前图片在可视区域内的坐标位置
left: parseFloat(this.editImgWrapper.style.left.replace('px', '')),
top: parseFloat(this.editImgWrapper.style.top.replace('px', '')),
};
this.deafultPosition = { // 滑动的时候鼠标在可视窗口的坐标(纯数字)
left: e.clientX,
top: e.clientY,
};
let movePosition = {
left: 0,
top: 0,
};
document.onmousedown = e => {
isDraging = true;
}
// move事件
document.onmousemove = e => {
if(!isDraging) return;
e.stopPropagation();
movePosition.left = e.clientX - this.deafultPosition.left;
movePosition.top = e.clientY - this.deafultPosition.top;
this.editImgWrapper.style.left = nodePositon.left + movePosition.left + 'px';
this.editImgWrapper.style.top = nodePositon.top + movePosition.top + 'px';
};
// 鼠标放开
document.onmouseup = function (event) {
// 释放事件
isDraging = false;
event.stopPropagation();
document.onmousemove = null;
document.onmouseup = null;
};
}
2. 图片某区域的框选
private toDrawImage = e => {
// 标注框相对图片的位置
let nodePositon = {
left: e.pageX - this.editImgWrapper.getBoundingClientRect().left,
top: e.pageY - this.editImgWrapper.getBoundingClientRect().top,
};
// 鼠标按下时的位置
let mousePosition = {
left: e.clientX,
top: e.clientY,
};
// 鼠标移动的距离
let movePosition = {
left: 0,
top: 0,
};
// 初始化tmp标注框的位置和宽高
let tmpDivStyles = {
top: '',
left: '',
width: '',
height: '',
};
// 最终生成的标注框宽和高的数值
let width;
let height;
// 文档流添加鼠标 move 事件:
document.onmousemove = e => {
e.stopPropagation();
movePosition.left = (e.clientX - mousePosition.left) / this.editImgWrapper.scaleRatio;
movePosition.top = (e.clientY - mousePosition.top) / this.editImgWrapper.scaleRatio;
width = Math.abs(movePosition.left);
height = Math.abs(movePosition.top);
if (e.clientY > mousePosition.top) {
tmpDivStyles.top = nodePositon.top / this.editImgWrapper.scaleRatio + 'px';
} else {
tmpDivStyles.top =
(e.clientY - this.editImgWrapper.getBoundingClientRect().top) / this.editImgWrapper.scaleRatio + 'px';
}
if (e.clientX < mousePosition.left) {
tmpDivStyles.left =
(e.clientX - this.editImgWrapper.getBoundingClientRect().left) / this.editImgWrapper.scaleRatio + 'px';
} else {
tmpDivStyles.left = nodePositon.left / this.editImgWrapper.scaleRatio + 'px';
}
tmpDivStyles.width = width + 'px';
tmpDivStyles.height = height + 'px';
this.tmpDivStyles = tmpDivStyles; // 记录框选的样式大小和位置区域
};
document.onmouseup = event => {
// 释放事件
event.stopPropagation();
document.onmousemove = null;
document.onmouseup = null;
this.addClip(); // 图片绘制
};
};
// 截取框选区域的图片,并调用高精度识别出图片内容,并回显框选区域
private addClip = () => {
let tmpStyles = this.tmpDivStyles;
let position = {
top: parseFloat(tmpStyles.top.replace('px', '')),
left: parseFloat(tmpStyles.left.replace('px', '')),
height: parseFloat(tmpStyles.height.replace('px', '')),
width: parseFloat(tmpStyles.width.replace('px', '')),
};
let list = [];
// 此处使用生成的64位图片对象
let image = this.generateImg(position, this.editImgObj, this.editImgCanvas);
let res: any = await this.service.generalOcr(image, true); // 调用高精度识别接口
// 进一步处理回显的框选区域:
......
}
};
// 根据坐标和宽高生成图片
private generateImg(position, imgobj, canvasObj) {
canvasObj.width = position.width;
canvasObj.height = position.height;
let ctx = canvasObj.getContext('2d');
ctx.drawImage(
imgobj,
position.left,
position.top,
position.width,
position.height,
0,
0,
position.width,
position.height
);
let base64Img = canvasObj.toDataURL('image/jpg').split('base64,')[1].toString();
return base64Img;
}
3. 移动框选识别区域,改变识别区域内的内容:
public moveBox(e, item, index) {
e.stopPropagation();
// 选取的当前要移动的框选区域:
let thisBox = this.el.nativeElement.querySelector('.anchor-box-' + index);
let nodePositon = {
left: parseFloat(thisBox.style.left.replace('px', '')),
top: parseFloat(thisBox.style.top.replace('px', '')),
clientWidth: thisBox.getBoundingClientRect().width,
clientHeight: thisBox.getBoundingClientRect().height,
};
let mousePosition = {
left: e.clientX,
top: e.clientY,
};
let movePosition = {
left: 0,
top: 0,
};
let maxPosition = {
left: this.editImgWrapper.clientWidth - thisBox.clientWidth,
top: this.editImgWrapper.clientHeight - thisBox.clientHeight
};
document.onmousemove = e => {
e.stopPropagation();
movePosition.left = (e.clientX - mousePosition.left) / this.editImgWrapper.scaleRatio;
movePosition.top = (e.clientY - mousePosition.top) / this.editImgWrapper.scaleRatio;
thisBox.style.left = Math.min(Math.max(0, nodePositon.left + movePosition.left), maxPosition.left) + 'px';
thisBox.style.top = Math.min(Math.max(0, nodePositon.top + movePosition.top), maxPosition.top) + 'px';
};
document.onmouseup = event => {
event.stopPropagation();
if (Math.abs(movePosition.left) > 1 || Math.abs(movePosition.top) > 1) {
this.setClip(item, thisBox); // 重新绘图并回显
}
document.onmousemove = null;
document.onmouseup = null;
};
}