Fuyuu
1 year ago
14 changed files with 320 additions and 31 deletions
@ -0,0 +1,283 @@ |
|||
<!-- |
|||
测试页面 |
|||
|
|||
目录位置:无 |
|||
功能概述:用于测试2d数据标注插件canvas-select的相关功能,包括基础图形绘制.编辑,数据保存.回显 |
|||
同时结合rtsp视频播放功能,完成基于视频资源的图形标注 |
|||
--> |
|||
<template> |
|||
<div class="box"> |
|||
<div class="left"> |
|||
<div> |
|||
<canvas ref="canvas" class="container" @mouseup="handleMouseUp" @mousedown="handleMouseDown" @mousemove="handleMouseMove"></canvas> |
|||
<!-- <video width="500" height="280" autoplay muted loop> |
|||
<source src="./assets/big_buck_bunny.mp4" type="video/mp4" /> |
|||
</video> --> |
|||
<div class="mpegPlayer" ref="mpegPlayer"></div> |
|||
</div> |
|||
<div> |
|||
<div class="flexBox"> |
|||
<label>rtsp流地址:</label> |
|||
<a-input type="text" v-model:value="rtspUrl"></a-input> |
|||
<a-button @click="open">打开rtsp</a-button> |
|||
<a-button @click="close">关闭rtsp</a-button> |
|||
</div> |
|||
<div v-if="msg">消息:rtsp流{{ msg }}</div> |
|||
<a-button type="primary" @click="change(0)"><ApiOutlined />关闭创建</a-button> |
|||
<a-button type="primary" @click="change(1)">创建矩形</a-button> |
|||
<a-button type="primary" @click="change(2)">创建多边形</a-button> |
|||
<a-button type="primary" @click="change(3)">创建标记点</a-button> |
|||
<a-button type="primary" @click="change(4)">创建线</a-button> |
|||
<a-button type="primary" @click="change(5)">创建圆</a-button> |
|||
<!-- <a-button type="primary" @click="toggleLineType()">切换线型-测试</a-button> --> |
|||
<br /> |
|||
<br /> |
|||
<a-button type="primary" @click="zoom(true)"><PlusOutlined />放大</a-button> |
|||
<a-button type="primary" @click="zoom(false)"><MinusOutlined />缩小</a-button> |
|||
<!-- <a-button type="primary" @click="fitting()">最佳适配比</a-button> --> |
|||
<a-button type="primary" @click="onFocus()"><AimOutlined />专注模式</a-button> |
|||
<br /> |
|||
<br /> |
|||
<a-button type="primary" danger @click="clear()"><FormatPainterOutlined />清除绘制</a-button> |
|||
<a-button type="primary" danger @click="lock()"><LinkOutlined />锁定/解锁</a-button> |
|||
<br /> |
|||
<br /> |
|||
<a-button type="primary" @click="save()"><FileDoneOutlined />保存</a-button> |
|||
</div> |
|||
</div> |
|||
<div class="right"> |
|||
<pre> |
|||
1.设置 instance.createType 指定需要创建形状类型。 |
|||
|
|||
2.创建矩形时,按住鼠标左键拖动完成创建。 |
|||
|
|||
3.创建多边形时,鼠标左键单击添加点,双击闭合完成创建,Backspace退出创建,Escape退一步删除选择点。 |
|||
|
|||
4.创建折线时,鼠标左键单击添加点,双击完成创建,Backspace退出创建,Escape退一步删除选择点。 |
|||
|
|||
5.按住鼠标右键拖动画布。 |
|||
|
|||
6.鼠标滚轮缩放画布。 |
|||
|
|||
7.选中形状,Backspace删除。 |
|||
</pre |
|||
> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { onMounted, ref } from 'vue'; |
|||
import { |
|||
FileDoneOutlined, |
|||
FormatPainterOutlined, |
|||
LinkOutlined, |
|||
PlusOutlined, |
|||
MinusOutlined, |
|||
ApiOutlined, |
|||
AimOutlined, |
|||
} from '@ant-design/icons-vue'; |
|||
// 标注相关 |
|||
import CanvasSelect from 'canvas-select'; |
|||
// rtsp视频播放相关 |
|||
import MpegPlayer from 'jsmpeg-player'; |
|||
const { ipcRenderer } = require('electron'); |
|||
// rtsp流地址 |
|||
const rtspUrl = ref('rtsp://admin:hk123456@192.168.1.71:554/'); |
|||
const mpegPlayer = ref(); |
|||
// 消息 |
|||
const msg = ref(''); |
|||
// 播放容器 |
|||
let player: any = null; |
|||
//当前canvas实例 |
|||
const canvas = ref(null); |
|||
// 鼠标位置 |
|||
const mouseX = ref(0); |
|||
const mouseY = ref(0); |
|||
const isRightMouseDown = ref(false); |
|||
// |
|||
// 开启rtsp播放 |
|||
const open = () => { |
|||
const res = ipcRenderer.sendSync('openRtsp', rtspUrl.value); |
|||
if (res.code === 200) { |
|||
player = new MpegPlayer.VideoElement(mpegPlayer.value, res.ws); |
|||
} |
|||
msg.value = res.msg; |
|||
}; |
|||
// 关闭rtsp播放 |
|||
const close = () => { |
|||
const res = ipcRenderer.sendSync('closeRtsp', rtspUrl.value); |
|||
msg.value = res.msg; |
|||
}; |
|||
|
|||
// 导入静态图片 |
|||
const hideUrl = new URL('./assets/hide.png', import.meta.url).href; |
|||
//标注实例 |
|||
let instance: any = ref(null); |
|||
//图形标注列表 |
|||
const option: any = ref([]); |
|||
onMounted(() => { |
|||
// 载入绘图数据 |
|||
option.value = JSON.parse(localStorage.getItem('canvasData')!); |
|||
// 创建实例 |
|||
instance = new CanvasSelect('.container', hideUrl); |
|||
// 标签最大长度 |
|||
instance.labelMaxLen = 10; |
|||
// 禁用滚动缩放 |
|||
instance.scrollZoom = false; |
|||
// 图形数据赋值到实例 |
|||
instance.setData(option.value); |
|||
// 形状边线宽度 |
|||
instance.lineWidth = 2; |
|||
// 标签字体 |
|||
instance.labelFont = '12px Arial'; |
|||
// 标签填充颜色 |
|||
instance.labelFillStyle = '#fa4545'; |
|||
// 标签文字颜色 |
|||
instance.textFillStyle = '#fff'; |
|||
// 控制点半径 |
|||
instance.ctrlRadius = 4; |
|||
// 图片加载完成 |
|||
instance.on('load', (src: any) => { |
|||
console.log('image load', src); |
|||
}); |
|||
|
|||
// 添加 |
|||
instance.on('add', (info: any) => { |
|||
// 添加默认标签 |
|||
switch (instance.createType) { |
|||
case 1: |
|||
info.label = '矩形防区'; |
|||
break; |
|||
case 2: |
|||
info.label = '多边形防区'; |
|||
break; |
|||
case 3: |
|||
info.label = '标记点位'; |
|||
break; |
|||
case 4: |
|||
info.label = '报警界线'; |
|||
break; |
|||
case 5: |
|||
info.label = '圆形防区'; |
|||
break; |
|||
default: |
|||
info.label = '未定义'; |
|||
} |
|||
// 更新画布 |
|||
instance.update(); |
|||
}); |
|||
// 删除 |
|||
instance.on('delete', (info: any) => { |
|||
console.log('delete', info); |
|||
}); |
|||
// 选中 |
|||
instance.on('select', (shape: any) => { |
|||
console.log('select', shape); |
|||
}); |
|||
// 更新 |
|||
instance.on('updated', (result: any) => { |
|||
// console.log('标注结果', result); |
|||
}); |
|||
}); |
|||
|
|||
// 获取当前鼠标在画布上的位置 |
|||
function handleMouseMove(e) { |
|||
const rect = canvas.value.getBoundingClientRect(); |
|||
mouseX.value = e.clientX - rect.left; |
|||
mouseY.value = e.clientY - rect.top; |
|||
if (isRightMouseDown.value) { |
|||
// 在这里处理鼠标右键按住移动的逻辑 |
|||
// console.log('鼠标右键按住移动'); |
|||
// 可以根据需要执行其他操作 |
|||
console.log(instance); |
|||
} |
|||
} |
|||
// 鼠标抬起 |
|||
function handleMouseUp(e) { |
|||
if (e.button === 2) { |
|||
isRightMouseDown.value = false; |
|||
} |
|||
} |
|||
// 鼠标按下 |
|||
function handleMouseDown(e) { |
|||
if (e.button === 2) { |
|||
isRightMouseDown.value = true; |
|||
} |
|||
} |
|||
|
|||
// 选择绘制工具 |
|||
function change(num: any) { |
|||
instance.createType = num; |
|||
} |
|||
// 放大缩小画布 |
|||
function zoom(type: any) { |
|||
instance.setScale(type); |
|||
} |
|||
// 适配 |
|||
// function fitting() { |
|||
// instance.fitZoom(); |
|||
// } |
|||
// 专注模式 |
|||
function onFocus() { |
|||
instance.setFocusMode(!instance.focusMode); |
|||
} |
|||
//清除标注数据 |
|||
function clear() { |
|||
instance.setData([]); |
|||
} |
|||
// 锁定/解锁画布 |
|||
function lock() { |
|||
instance.lock = !instance.lock; |
|||
} |
|||
// 保存数据 |
|||
function save() { |
|||
// 保存绘制数据,用于回显 |
|||
// 清除所有激活状态 |
|||
instance.dataset.forEach((item) => { |
|||
item.active = false; |
|||
}); |
|||
console.log(JSON.stringify(instance.dataset)); |
|||
// 暂存数据到本地 |
|||
localStorage.setItem('canvasData', JSON.stringify(instance.dataset)); |
|||
} |
|||
</script> |
|||
<style scoped> |
|||
.box { |
|||
display: flex; |
|||
margin: 10px; |
|||
position: relative; |
|||
} |
|||
.container { |
|||
width: 800px; |
|||
height: 480px; |
|||
position: absolute; |
|||
z-index: 999; |
|||
left: 0; |
|||
top: 0; |
|||
} |
|||
button { |
|||
margin-right: 3px; |
|||
} |
|||
|
|||
.flexBox { |
|||
display: flex; |
|||
height: 50px; |
|||
margin-top: 20px; |
|||
} |
|||
.flexBox input { |
|||
height: 30px; |
|||
width: 400px; |
|||
box-sizing: border-box; |
|||
padding-left: 8px; |
|||
} |
|||
.flexBox button { |
|||
height: 30px; |
|||
padding: 0 12px; |
|||
} |
|||
.mpegPlayer { |
|||
width: 800px; |
|||
height: 480px; |
|||
background: #000; |
|||
} |
|||
</style> |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Loading…
Reference in new issue