人脸/物体识别,用 canvas 给图片画框(vue实现)
图片识别少不了画框,前端画框就用canvas,后端返回画框数据点,图片可以是前端自己传的也可以是后端返回的。实现思路:1、算好比例尺2、确定上、左位置,确定宽高(后端如果给上下左右,前端自行计算宽高)3、图片预加载时画图4、注意 js 的乘除会有出入,所以要精确化处理效果图实现代码:<template><div class="carDetect"><div class
·
图片识别少不了画框,前端画框就用canvas,后端返回画框数据点,图片可以是前端自己传的也可以是后端返回的。
实现思路:
1、算好比例尺
2、确定上、左位置,确定宽高(后端如果给上下左右,前端自行计算宽高)
3、图片预加载时画图
4、注意 js 的乘除会有出入,所以要精确化处理
效果图
实现代码:
<template>
<div class="carDetect">
<div class="uploadImg">
<el-button type="primary">上传图片</el-button>
<input type="file" class="upload" @change="uploadImg($event)" />
</div>
<div class="faceCon">
<div class="canvasCon">
<canvas width="800" height="400" ref="canvas"></canvas>
</div>
<div class="faceInfo">
<div
v-for="(item, index) in imgCarArr"
:key="index"
:class="index == activeIndex ? 'active' : ''"
>
<img
:class="index == activeIndex ? 'active' : ''"
:src="item"
alt=""
@click="showCarInfo(index)"
/>
</div>
</div>
<veri-car :carData="carOneData" :visibleCar.sync="visibleCar"></veri-car>
<!-- <div class="faceInfo">
<div
v-for="(item, index) in imgArr"
:key="index"
:class="index == activeIndex ? 'active' : ''"
>
<img
:class="index == activeIndex ? 'active' : ''"
:src="item"
alt=""
@click="showFaceInfo(index)"
/>
</div>
</div>
<veri-car-face
:faceData="faceOneData"
:visible.sync="visible"
></veri-car-face> -->
</div>
<canvas v-for="i in canvasLength" :key="i" :id="'canvas' + i"></canvas>
</div>
</template>
<script>
var div = require("../../../utils/accDiv.js");
var mul = require("../../../utils/accMul.js");
//使用用户上传图片画图时需要做的处理
uploadImg(el) {
this.faceOneData = {};
this.carOneData = {};
if (!el.target.files[0].size) return; // 如果文件大小为0,则返回
if (
el.target.files[0].type.indexOf("image/png") === -1 &&
el.target.files[0].type.indexOf("image/jpeg") === -1 &&
el.target.files[0].type.indexOf("image/svg") === -1
) {
// 如果不是图片格式
this.$message.warning("请选择文件为png/jpg格式的图片");
} else {
const that = this;
const reader = new FileReader(); // 创建读取文件对象
reader.readAsDataURL(el.target.files[0]); // 发起异步请求,读取文件
reader.onload = function() {
that.value = this.result;
};
this.getFaceInfo(el.target.files[0]);
}
},
// 正式画图
drawFace(data) { //data就是后端返回的数据
this.imgCarArr = []; //存放框出来的每一个具体图片
this.canvasLength = data.length; //多个框时候用来遍历展示
var canvas = this.$refs.canvas; //获取元素实例
var context = canvas.getContext("2d"); //getContext() 方法返回一个用于在画布上绘图的环境。
var ratioX = ""; //X轴比例尺
var ratioY = ""; //Y轴比例尺
context.clearRect(0, 0, 800, 400); //画布大小和起止点
var newImg = new Image(); //创建一个Image对象
newImg.src = this.value; //返回的图片地址,或者自己上传的base64图片
newImg.onload = () => { //img.onload 实现图片预加载
ratioX = div.accDiv(canvas.width, newImg.width);
ratioY = div.accDiv(canvas.height, newImg.height);
context.drawImage(newImg, 0, 0, canvas.width, canvas.height); //drawImage() 方法在画布上绘制图像、画布或视频。
data.forEach((item, index) => { //如果返回数据只有一个框,可以不循环
context.beginPath();
if (item.faceInfoParam) {
let facePosition =
item.faceInfoParam.faceDetectInfoParam.face_position;
context.rect( //rect() 方法创建矩形
mul.accMul(ratioX, facePosition.left), //精确计算乘(比例尺*坐标点)
mul.accMul(ratioY, facePosition.top),
mul.accMul(ratioX, facePosition.width),
mul.accMul(ratioY, facePosition.height)
);
context.lineWidth = 1;
context.strokeStyle = "#0f0";
context.stroke();
context.closePath();
// 获取人脸部分
var imageData = context.getImageData(
mul.accMul(ratioX, facePosition.left),
mul.accMul(ratioY, facePosition.top),
mul.accMul(ratioX, facePosition.width),
mul.accMul(ratioY, facePosition.height)
);
// 人脸关键点
item.faceInfoParam.faceDetectInfoParam.syPointParams.forEach( //遍历返回值
(v, i) => {
context.beginPath();
context.arc( //arc() 方法创建弧/曲线(用于创建圆或部分圆),中心:arc(100,75,50,0*Math.PI,1.5*Math.PI)
mul.accMul(ratioX, v.x),
mul.accMul(ratioY, v.y),
1.5,
0,
Math.PI * 2
);
// context.strokeStyle = "#00f";
context.fillStyle = "#5AC5BD";
context.fill();
context.closePath();
}
);
// 创建新的canvas存放imgData
var newCanvas = document.getElementById("canvas" + (index + 1));
newCanvas.width = mul.accMul(ratioX, facePosition.width);
newCanvas.height = mul.accMul(ratioY, facePosition.height);
var newCxt = newCanvas.getContext("2d");
newCxt.putImageData(imageData, 0, 0); //通过 getImageData() 复制画布上指定矩形的像素数据
this.imgArr.push(newCanvas.toDataURL()); //得到以 base64 编码的 dataURL
}
if (item.vehicleInfoParam) {
let vechiPosition =
item.vehicleInfoParam.vehicle_detect_res.syRectParam;
context.rect(
mul.accMul(ratioX, vechiPosition.left),
mul.accMul(ratioY, vechiPosition.top),
mul.accMul(ratioX, vechiPosition.width),
mul.accMul(ratioY, vechiPosition.height)
);
context.lineWidth = 1;
context.strokeStyle = "#0f0";
context.stroke(); //使用 stroke() 方法在画布上绘制确切的路径。
context.closePath(); //closePath() 方法创建从当前点到开始点的路径。
// 获取车辆部分
var imageCarData = context.getImageData(
mul.accMul(ratioX, vechiPosition.left),
mul.accMul(ratioY, vechiPosition.top),
mul.accMul(ratioX, vechiPosition.width),
mul.accMul(ratioY, vechiPosition.height)
);
// 创建新的canvas存放imgData
var newCarCanvas = document.getElementById("canvas" + (index + 1));
newCarCanvas.width = mul.accMul(ratioX, vechiPosition.width);
newCarCanvas.height = mul.accMul(ratioY, vechiPosition.height);
var newCarCxt = newCarCanvas.getContext("2d");
newCarCxt.putImageData(imageCarData, 0, 0); //通过 getImageData() 复制画布上指定矩形的像素数据,然后通过 putImageData() 将图像数据放回画布
this.imgCarArr.push(newCarCanvas.toDataURL());
}
// 清空新创建的canvas
this.canvasLength = 0;
this.showFaceInfo(0);
this.showCarInfo(0);
});
};//img.onload 图片预加载完毕
},
</script>
//mul.js & div.js
// 浮点数精确计算乘
module.exports = {
accMul: function(num1, num2) {
var m = 0,
s1 = num1.toString(),
s2 = num2.toString();
try {
m += s1.split(".")[1].length;
} catch (e) {}
try {
m += s2.split(".")[1].length;
} catch (e) {}
return (
(Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
Math.pow(10, m)
);
}
// 浮点数精确计算除
module.exports = {
accDiv: function(num1, num2) {
var t1, t2, r1, r2;
try {
t1 = num1.toString().split(".")[1].length;
} catch (e) {
t1 = 0;
}
try {
t2 = num2.toString().split(".")[1].length;
} catch (e) {
t2 = 0;
}
r1 = Number(num1.toString().replace(".", ""));
r2 = Number(num2.toString().replace(".", ""));
return (r1 / r2) * Math.pow(10, t2 - t1);
}
};
};
更多推荐
已为社区贡献3条内容
所有评论(0)