169 lines
4.4 KiB
Vue
169 lines
4.4 KiB
Vue
|
|
<template>
|
||
|
|
<div>
|
||
|
|
<div ref="labelStudio" id="label-studio-container"></div>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import LabelStudio from 'label-studio';
|
||
|
|
import 'label-studio/build/static/css/main.css';
|
||
|
|
|
||
|
|
export default {
|
||
|
|
name: 'CustomLabelStudio',
|
||
|
|
props: {
|
||
|
|
task: {
|
||
|
|
type: String,
|
||
|
|
required: true
|
||
|
|
}
|
||
|
|
},
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
labelStudio: null,
|
||
|
|
customButtons: [
|
||
|
|
{
|
||
|
|
id: "custom-button",
|
||
|
|
name: "自定义按钮",
|
||
|
|
icon: "🔍",
|
||
|
|
action: () => {
|
||
|
|
console.log("自定义按钮被点击了!");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
],
|
||
|
|
chineseLocalization: {
|
||
|
|
"DONE": "完成",
|
||
|
|
"SKIP": "跳过",
|
||
|
|
"SUBMIT": "提交",
|
||
|
|
"ANNOTATION": "标注",
|
||
|
|
"ANNOTATIONS": "标注",
|
||
|
|
"LABEL": "标签",
|
||
|
|
"LABELS": "标签",
|
||
|
|
"RELATIONS": "关系",
|
||
|
|
"REGIONS": "区域",
|
||
|
|
"RESULTS": "结果",
|
||
|
|
},
|
||
|
|
labelConfig: `
|
||
|
|
<View>
|
||
|
|
<Image name="image" value="$image"/>
|
||
|
|
<RectangleLabels name="label" toName="image">
|
||
|
|
<Label value="人" background="#ff0000"/>
|
||
|
|
<Label value="车" background="#00ff00"/>
|
||
|
|
</RectangleLabels>
|
||
|
|
</View>
|
||
|
|
`,
|
||
|
|
previousAnnotations: [] // 用于保存上次的标注框数据
|
||
|
|
};
|
||
|
|
},
|
||
|
|
mounted() {
|
||
|
|
this.initLabelStudio();
|
||
|
|
},
|
||
|
|
beforeDestroy() {
|
||
|
|
if (this.labelStudio) {
|
||
|
|
this.labelStudio.destroy();
|
||
|
|
}
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
initLabelStudio() {
|
||
|
|
this.labelStudio = new LabelStudio('label-studio-container', {
|
||
|
|
config: this.labelConfig,
|
||
|
|
interfaces: [
|
||
|
|
"panel",
|
||
|
|
"update",
|
||
|
|
"controls",
|
||
|
|
],
|
||
|
|
user: {
|
||
|
|
pk: 1,
|
||
|
|
firstName: "James",
|
||
|
|
lastName: "Dean"
|
||
|
|
},
|
||
|
|
task: JSON.parse(this.task),
|
||
|
|
locale: 'zh_CN',
|
||
|
|
messages: this.chineseLocalization,
|
||
|
|
onLabelStudioLoad: (LS) => {
|
||
|
|
console.log("Label Studio 已加载", LS);
|
||
|
|
var c = LS.annotationStore.addAnnotation({
|
||
|
|
userGenerate: true
|
||
|
|
});
|
||
|
|
LS.annotationStore.selectAnnotation(c.id);
|
||
|
|
// 注册事件监听
|
||
|
|
LS.annotationStore.events.on('addAnnotation', this.handleAddAnnotation);
|
||
|
|
LS.annotationStore.events.on('updateAnnotation', this.handleUpdateAnnotation);
|
||
|
|
|
||
|
|
// 启动定期检查标注框数据
|
||
|
|
this.startAnnotationCheck(LS);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
// 处理新增标注框
|
||
|
|
handleAddAnnotation(annotation) {
|
||
|
|
console.log("新增标注框:", annotation);
|
||
|
|
},
|
||
|
|
|
||
|
|
// 处理更新标注框
|
||
|
|
handleUpdateAnnotation(annotation) {
|
||
|
|
console.log("更新标注框:", annotation);
|
||
|
|
},
|
||
|
|
|
||
|
|
// 启动定期检查标注框数据
|
||
|
|
startAnnotationCheck(LS) {
|
||
|
|
this.checkAnnotationsInterval = setInterval(() => {
|
||
|
|
this.checkAnnotations(LS);
|
||
|
|
}, 1000); // 每秒检查一次
|
||
|
|
},
|
||
|
|
|
||
|
|
// 停止定期检查
|
||
|
|
stopAnnotationCheck() {
|
||
|
|
if (this.checkAnnotationsInterval) {
|
||
|
|
clearInterval(this.checkAnnotationsInterval);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
// 检查标注框数据
|
||
|
|
checkAnnotations(LS) {
|
||
|
|
const currentAnnotations = LS.annotationStore.data; // 获取当前的标注数据
|
||
|
|
|
||
|
|
// 如果标注数据发生了变化
|
||
|
|
if (this.hasAnnotationsChanged(currentAnnotations)) {
|
||
|
|
console.log('标注数据发生变化:', currentAnnotations);
|
||
|
|
this.previousAnnotations = currentAnnotations; // 更新保存的标注数据
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
// 比较标注数据是否发生变化
|
||
|
|
hasAnnotationsChanged(currentAnnotations) {
|
||
|
|
// 直接比较标注数量变化
|
||
|
|
if (currentAnnotations.length !== this.previousAnnotations.length) {
|
||
|
|
return true; // 数量不一样说明发生了变化
|
||
|
|
}
|
||
|
|
|
||
|
|
// 比较每个标注框的 ID 和几何信息(减少深度比较)
|
||
|
|
for (let i = 0; i < currentAnnotations.length; i++) {
|
||
|
|
const current = currentAnnotations[i];
|
||
|
|
const previous = this.previousAnnotations[i];
|
||
|
|
|
||
|
|
if (current.id !== previous.id) {
|
||
|
|
return true; // 标注 ID 不同说明发生了变化
|
||
|
|
}
|
||
|
|
|
||
|
|
// 如果标注框的几何信息有变化,返回 true
|
||
|
|
if (JSON.stringify(current.geometry) !== JSON.stringify(previous.geometry)) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.label-studio-container {
|
||
|
|
height: 600px;
|
||
|
|
width: 100%;
|
||
|
|
border: 1px solid #e0e0e0;
|
||
|
|
border-radius: 8px;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
</style>
|