需求分析
1、电子围栏技术是采用基于深度神经网络的人工智能目标检测技术,通过在打包机四周监控范围,形成一个立体的电子围栏区域,根据视频场景中的信息准确识别目标区域内是否出现人员及其位置。
2、电子围栏系统通过AI 识别、人物自动检测等功能将区域形成电子围栏,在电子围栏区域检测到有人员活动时及时发出报警信号,并将打包机自动切换成无法强制工作的停止状态,提高打包机运行时的安全性,消除加护垫、整包、调试、检修作业安全隐患。
功能预览
<template>
<div class="mains">
<canvas
class="mycanvas"
ref="mycanvas"
:width="canvasWidth"
:height="canvasHeight"
@mousedown="canvasDown($event)"
@mousemove="canvasMove($event)"
@mouseup="canvasUp($event)"
>浏览器不持之canvas</canvas
>
</div>
</template>
<script>
import { message } from 'ant-design-vue';
export default {
data() {
return {
isdraw: false, //是否在画图形
ctx: null, //canvas对象
coordinates: [], //一个多边形的坐标信息
cor_index: 0, //当前多边形的索引
endtip: false, //是否结束一个多边形的绘制
all_coordinates: [], //所有多边形的信息
isdrag: false,
drag_index: [-1, -1],
img: '',
val: { cor_x: '', cor_y: '' }, //鼠标按下
upVal: { cor_x: '', cor_y: '' }, //鼠标抬起
isShowBox: false,
};
},
props: {
coordinatesData: {
type: Array, //需要展示的坐标
},
showBox: {
type: Boolean, //是否显示圆圈
},
canvasWidth: {
type: Number, //画布宽度
},
canvasHeight: {
type: Number, //画布高度
},
},
watch: {
showBox: {
// 监听是否编辑
handler(a) {
this.isShowBox = a;
this.initDraw();
},
},
},
methods: {
//清空
test() {
this.all_coordinates = [];
this.coordinates = [];
this.isdraw = false;
this.endtip = false;
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
},
//填充
fillarea() {
this.ctx.fillStyle = 'rgba(255, 77, 79,0.1)';
for (var i = 0; i < this.all_coordinates.length; i++) {
var cors = this.all_coordinates[i];
var x0 = cors[0].cor_x;
var y0 = cors[0].cor_y;
this.ctx.beginPath();
this.ctx.moveTo(x0, y0);
for (var j = 1; j < cors.length; j++) {
var x = cors[j].cor_x;
var y = cors[j].cor_y;
this.ctx.lineTo(x, y);
}
this.ctx.fill();
this.ctx.closePath();
}
},
//判断是否交叉
move(val) {
let flag1 = false;
let flag2 = false;
if (this.all_coordinates[0]) {
// console.log(69, this.all_coordinates[0], this.val);
let ind = this.isdragpoint(val.cor_x, val.cor_y);
let arr = [...this.all_coordinates[0]];
arr.push(arr[0]);
console.log(79, arr);
if (ind != -1) {
arr[ind] = val;
arr.some((item, index) => {
if (index < arr.length - 1) {
arr.some((v, i) => {
if (i < arr.length - 1) {
if (
this.isIntersect(
{
x1: item.cor_x,
y1: item.cor_y,
x2: arr[index + 1].cor_x,
y2: arr[index + 1].cor_y,
},
{
x1: v.cor_x,
y1: v.cor_y,
x2: arr[i + 1].cor_x,
y2: arr[i + 1].cor_y,
},
)
) {
flag2 = true;
}
}
});
}
});
}
} else {
flag1 = this.coordinates.some((v, i) => {
if (i < this.coordinates.length - 2) {
return this.isIntersect(
{ x1: v.cor_x, y1: v.cor_y, x2: this.coordinates[i + 1].cor_x, y2: this.coordinates[i + 1].cor_y },
{
x1: this.coordinates[this.coordinates.length - 1].cor_x,
y1: this.coordinates[this.coordinates.length - 1].cor_y,
x2: val.cor_x,
y2: val.cor_y,
},
);
}
});
}
console.log(flag1, flag2);
if (flag1 == false && flag2 == false) {
return false;
} else {
message.warning('线段不能交叉');
return true;
}
},
initDraw() {
//初始化画布对象
const canvas = document.querySelector('.mycanvas');
this.ctx = canvas.getContext('2d');
this.ctx.strokeStyle = 'rgb(235, 57, 65)';
console.log(147, this.coordinatesData);
if (this.coordinatesData.length > 0) {
this.all_coordinates = [];
this.coordinates = [];
//把传过来的百分比坐标转换为px
this.coordinatesData.forEach(e => {
this.coordinates.push({
cor_x: Math.round((this.canvasWidth * e[0]) / 100),
cor_y: Math.round((this.canvasHeight * e[1]) / 100),
});
});
console.log(189, this.coordinates);
this.drawClosePath();
}
},
//判断的是否是同一个点
isdragpoint(x, y) {
if (this.all_coordinates.length == 0) {
return false;
}
for (var i = 0; i < this.all_coordinates.length; i++) {
for (var j = 0; j < this.all_coordinates[i].length; j++) {
var px = this.all_coordinates[i][j].cor_x;
var py = this.all_coordinates[i][j].cor_y;
// console.log(j + ':', x, y, px, py);
if (Math.abs(x - px) <= 8 && Math.abs(y - py) <= 8) {
this.drag_index[0] = i;
this.drag_index[1] = j;
// this.val.cor_x = px;
// this.val.cor_y = py;
// console.log(px, py);
return j;
}
}
}
return false;
},
//手动闭合路径
handleClosePath(x, y) {
let arr = [this.coordinates];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
var px = arr[i][j].cor_x;
var py = arr[i][j].cor_y;
if (Math.abs(x - px) <= 8 && Math.abs(y - py) <= 8) {
console.log(this.isdraw, j === 0);
if (this.isdraw && j === 0 && !this.move(this.upVal)) {
this.drawClosePath();
return true;
}
}
}
}
return false;
},
//鼠标按下
canvasDown(e) {
if (!this.isShowBox) return;
var x = e.offsetX;
var y = e.offsetY;
this.val.cor_x = x;
this.val.cor_y = y;
if (this.handleClosePath(x, y)) return;
console.log(267, this.val);
this.isdragpoint(x, y);
if (this.move(this.val)) return;
if (this.isdragpoint(x, y) === 0 || this.isdragpoint(x, y)) {
this.isdrag = true;
return 0;
}
//画布中鼠标按下
if (this.endtip) {
//已经结束了上个多边形的绘制,把上个多边形的坐标放入数组,同时清空单个多边形数组信息
this.endtip = false;
}
//获取鼠标按下的坐标,放入数组中
if (this.all_coordinates.length == 1) {
return;
}
this.coordinates.push({ cor_x: x, cor_y: y });
this.isdraw = true; //正在画多边形
},
drawlines() {
//把所有多边形画出来
for (var i = 0; i < this.all_coordinates.length; i++) {
var cors = this.all_coordinates[i];
//前后坐标连线
for (var j = 0; j < cors.length - 1; j++) {
this.ctx.beginPath();
var x0 = cors[j].cor_x;
var y0 = cors[j].cor_y;
var x1 = cors[j + 1].cor_x;
var y1 = cors[j + 1].cor_y;
this.ctx.moveTo(x0, y0);
this.ctx.lineTo(x1, y1);
this.ctx.stroke();
this.ctx.closePath();
}
//最后一个与第一个连线
var begin_x = cors[0].cor_x;
var begin_y = cors[0].cor_y;
var end_x = cors[cors.length - 1].cor_x;
var end_y = cors[cors.length - 1].cor_y;
this.ctx.beginPath();
this.ctx.moveTo(begin_x, begin_y);
this.ctx.lineTo(end_x, end_y);
this.ctx.stroke();
this.ctx.closePath();
}
},
//绘制当前多边形线段
drawline() {
//把当前绘制的多边形之前的坐标线段绘制出来
for (var i = 0; i < this.coordinates.length - 1; i++) {
this.ctx.beginPath();
var x0 = this.coordinates[i].cor_x;
var y0 = this.coordinates[i].cor_y;
var x1 = this.coordinates[i + 1].cor_x;
var y1 = this.coordinates[i + 1].cor_y;
this.ctx.moveTo(x0, y0);
this.ctx.lineTo(x1, y1);
this.ctx.stroke();
this.ctx.closePath();
}
},
//为当前的多边形端点画圆
drawcircle() {
this.ctx.strokeStyle = 'rgb(235, 57, 65)';
this.ctx.fillStyle = '#fff';
for (var i = 0; i < this.coordinates.length; i++) {
var x = this.coordinates[i].cor_x;
var y = this.coordinates[i].cor_y;
this.ctx.beginPath();
this.ctx.moveTo(x, y);
this.ctx.arc(x, y, 8, 0, Math.PI * 2);
this.ctx.stroke();
this.ctx.fill();
this.ctx.closePath();
}
},
//为所有的多边形端点画圆
drawcircles() {
this.ctx.strokeStyle = 'rgb(235, 57, 65)';
this.ctx.fillStyle = '#fff';
for (var i = 0; i < this.all_coordinates.length; i++) {
var cors = this.all_coordinates[i];
for (var j = 0; j < cors.length; j++) {
var x = cors[j].cor_x;
var y = cors[j].cor_y;
this.ctx.beginPath();
this.ctx.moveTo(x, y);
this.ctx.arc(x, y, 8, 0, Math.PI * 2);
this.ctx.stroke();
this.ctx.fill();
this.ctx.closePath();
}
}
},
//鼠标抬起
canvasUp(e) {
if (!this.isShowBox) return;
this.drag_index = [-1, -1];
if (this.isdrag) {
if (this.all_coordinates.length) {
this.upVal.cor_x = e.offsetX;
this.upVal.cor_y = e.offsetY;
if (this.move(this.upVal)) {
console.log(273);
this.canvasMove({ offsetX: this.val.cor_x, offsetY: this.val.cor_y });
this.isdrag = false;
return;
}
}
this.isdrag = false;
}
// console.log(188, this.upVal, this.coordinates, this.all_coordinates);
},
// 辅助函数 检查两个线是否交叉
isIntersect(line1, line2) {
console.log(305, line1, line2);
// 转换成一般式: Ax+By = C
// console.log(305, line1, line2);
var a1 = line1.y2 - line1.y1;
var b1 = line1.x1 - line1.x2;
var c1 = a1 * line1.x1 + b1 * line1.y1;
//转换成一般式: Ax+By = C
var a2 = line2.y2 - line2.y1;
var b2 = line2.x1 - line2.x2;
var c2 = a2 * line2.x1 + b2 * line2.y1;
// 计算交点
var d = a1 * b2 - a2 * b1;
// 当d==0时,两线平行
if (d == 0) {
return false;
} else {
var x = (b2 * c1 - b1 * c2) / d;
var y = (a1 * c2 - a2 * c1) / d;
// 检测交点是否在两条线段上
if (
(this.isInBetween(line1.x1, x, line1.x2) || this.isInBetween(line1.y1, y, line1.y2)) &&
(this.isInBetween(line2.x1, x, line2.x2) || this.isInBetween(line2.y1, y, line2.y2))
) {
console.log(331);
return true;
}
}
console.log(335);
return false;
},
isInBetween(a, b, c) {
// 如果b几乎等于a或c,返回false.为了避免浮点运行时两值几乎相等,但存在相差0.00000...0001的这种情况出现使用下面方式进行避免
if (Math.abs(a - b) < 0.000001 || Math.abs(b - c) < 0.000001) {
return false;
}
return (a < b && b < c) || (c < b && b < a);
},
canvasMove(e) {
//画布中鼠标移动
//没开始画或者结束画之后不进行操作
var x = e.offsetX;
var y = e.offsetY;
if (this.isdrag) {
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.all_coordinates[this.drag_index[0]][this.drag_index[1]].cor_x = x;
this.all_coordinates[this.drag_index[0]][this.drag_index[1]].cor_y = y;
this.drawlines();
this.drawcircles();
this.fillarea();
}
// console.log(338, this.coordinates.length == 0, !this.isdraw, this.endtip);
if (this.coordinates.length == 0 || !this.isdraw || this.endtip) {
return 0;
}
//获取上一个点
var last_x = this.coordinates[this.coordinates.length - 1].cor_x;
var last_y = this.coordinates[this.coordinates.length - 1].cor_y;
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); //清空画布
this.drawline(); //把之前的点连线
this.drawcircle();
if (this.all_coordinates.length != 0) {
//不止一个多边形,把多边形们画出来
this.drawlines();
this.drawcircles();
this.fillarea();
}
//获取鼠标移动时的点,画线,实现线段跟踪效果。
this.ctx.beginPath();
this.ctx.moveTo(last_x, last_y);
this.ctx.lineTo(x, y);
this.ctx.stroke();
this.ctx.closePath();
},
//绘制闭合路径
drawClosePath() {
this.isdraw = false;
this.endtip = true;
this.all_coordinates.push(this.coordinates);
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.ctx.fillStyle = 'rgba(255, 77, 79,0.1)';
var bx = this.coordinates[0].cor_x;
var by = this.coordinates[0].cor_y;
this.ctx.beginPath();
this.ctx.moveTo(bx, by);
for (var k = 1; k < this.coordinates.length; k++) {
var x = this.coordinates[k].cor_x;
var y = this.coordinates[k].cor_y;
this.ctx.lineTo(x, y);
}
this.ctx.lineTo(bx, by);
this.ctx.stroke();
this.ctx.fill();
if (this.isShowBox) {
this.drawcircles();
}
this.ctx.closePath();
this.coordinates = [];
},
},
mounted() {
this.initDraw();
},
};
</script>
<style scoped>
.mains {
width: 100%;
height: 100%;
color: black;
/* background: white; */
}
.mycanvas {
border: 1px solid red;
margin: auto;
display: block;
box-sizing: border-box;
}
</style>