admin 管理员组文章数量: 1086019
人脸/物体识别,用 canvas 给图片画框(vue实现)
图片识别少不了画框,前端画框就用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"><divv-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"><divv-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存放imgDatavar 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存放imgDatavar 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());}// 清空新创建的canvasthis.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);}
};
};
参考案例
本文标签: 人脸物体识别,用 canvas 给图片画框(vue实现)
版权声明:本文标题:人脸物体识别,用 canvas 给图片画框(vue实现) 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1693583835a230643.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论