2024-11-28 12:27:07 +08:00
|
|
|
|
<template>
|
2024-12-01 15:08:48 +08:00
|
|
|
|
<div class="label-studio-annotator">
|
|
|
|
|
|
<div id="label-studio" class="annotation-container"></div>
|
2024-11-28 12:27:07 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2024-12-01 15:08:48 +08:00
|
|
|
|
import LabelStudio from 'label-studio';
|
|
|
|
|
|
import 'label-studio/build/static/css/main.css';
|
|
|
|
|
|
import { manualAnnotate } from '../../../../api/dataCenter/annotationTask';
|
2024-11-28 12:27:07 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
2024-12-01 15:08:48 +08:00
|
|
|
|
name: 'LabelStudioAnnotator',
|
2024-11-28 12:27:07 +08:00
|
|
|
|
props: {
|
2024-12-01 15:08:48 +08:00
|
|
|
|
fileUrl: { type: String, required: true },
|
|
|
|
|
|
taskId: { type: Number, required: true },
|
|
|
|
|
|
config: { type: String, required: true },
|
|
|
|
|
|
id: { type: Number, required: true },
|
|
|
|
|
|
itemIndex: { type: Number, required: true },
|
|
|
|
|
|
annotations: {
|
|
|
|
|
|
type: Array,
|
|
|
|
|
|
default: () => [] // 默认值为空数组
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
index: {
|
|
|
|
|
|
get() {
|
|
|
|
|
|
return this.itemIndex;
|
|
|
|
|
|
},
|
|
|
|
|
|
set(value) {
|
|
|
|
|
|
this.$parent.updateItemIndex(value); // 更新父组件的索引
|
|
|
|
|
|
}
|
2024-11-28 12:27:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
labelStudio: null,
|
2024-12-01 15:08:48 +08:00
|
|
|
|
annotationsList: [] // 用于存储当前标注的结果
|
|
|
|
|
|
};
|
2024-11-28 12:27:07 +08:00
|
|
|
|
},
|
2024-12-01 15:08:48 +08:00
|
|
|
|
watch: {
|
|
|
|
|
|
fileUrl: 'resetLabelStudio' // 当文件地址变化时,重置LabelStudio
|
2024-12-01 09:48:41 +08:00
|
|
|
|
},
|
2024-11-28 12:27:07 +08:00
|
|
|
|
mounted() {
|
2024-12-01 15:08:48 +08:00
|
|
|
|
this.initLabelStudio(); // 组件挂载完成后初始化LabelStudio
|
2024-11-28 12:27:07 +08:00
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2024-12-01 15:08:48 +08:00
|
|
|
|
// 处理返回的标注数据
|
|
|
|
|
|
getAnnotations() {
|
|
|
|
|
|
return [{
|
|
|
|
|
|
result: this.annotations.map(annotation => ({
|
|
|
|
|
|
type: "rectanglelabels",
|
|
|
|
|
|
from_name: "label",
|
|
|
|
|
|
to_name: "image",
|
|
|
|
|
|
value: {
|
|
|
|
|
|
rectanglelabels: [annotation.label],
|
|
|
|
|
|
x: annotation.x,
|
|
|
|
|
|
y: annotation.y,
|
|
|
|
|
|
width: annotation.width,
|
|
|
|
|
|
height: annotation.height
|
|
|
|
|
|
}
|
|
|
|
|
|
}))
|
|
|
|
|
|
}];
|
|
|
|
|
|
},
|
|
|
|
|
|
// 初始化 LabelStudio
|
2024-11-28 12:27:07 +08:00
|
|
|
|
initLabelStudio() {
|
2024-12-01 15:08:48 +08:00
|
|
|
|
console.log(this.annotations);
|
|
|
|
|
|
this.cleanupLabelStudio(); // 清理之前的实例
|
|
|
|
|
|
|
|
|
|
|
|
const task = {
|
|
|
|
|
|
id: this.id,
|
|
|
|
|
|
data: { image: this.fileUrl },
|
|
|
|
|
|
};
|
2024-11-28 17:30:25 +08:00
|
|
|
|
|
2024-12-01 15:08:48 +08:00
|
|
|
|
if (this.annotations.length) {
|
|
|
|
|
|
task.annotations = this.getAnnotations();
|
|
|
|
|
|
}
|
2024-11-28 17:30:25 +08:00
|
|
|
|
|
2024-12-01 15:08:48 +08:00
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
const labelStudioElement = document.getElementById('label-studio');
|
|
|
|
|
|
if (!labelStudioElement) {
|
|
|
|
|
|
console.error('Label Studio element not found');
|
|
|
|
|
|
return;
|
2024-11-28 12:27:07 +08:00
|
|
|
|
}
|
2024-12-01 15:08:48 +08:00
|
|
|
|
|
|
|
|
|
|
this.labelStudio = new LabelStudio('label-studio', {
|
|
|
|
|
|
config: this.config,
|
|
|
|
|
|
interfaces: ["update", "submit", "controls"],
|
|
|
|
|
|
user: { pk: 1, firstName: '标注者', lastName: '用户' },
|
|
|
|
|
|
task,
|
|
|
|
|
|
onLabelStudioLoad: (LS) => {
|
|
|
|
|
|
if (!LS.annotationStore.selectedAnnotation) {
|
|
|
|
|
|
const annotation = LS.annotationStore.addAnnotation({ userGenerate: true });
|
|
|
|
|
|
LS.annotationStore.selectAnnotation(annotation.id);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
onSubmitAnnotation: (LS, annotation) => this.handleAnnotationSubmit(LS, annotation, task),
|
|
|
|
|
|
onUpdateAnnotation:(LS, annotation) => this.handleAnnotationSubmit(LS, annotation, task),
|
|
|
|
|
|
});
|
2024-11-28 12:27:07 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
2024-12-01 15:08:48 +08:00
|
|
|
|
// 提交标注结果
|
|
|
|
|
|
async handleAnnotationSubmit(LS, annotation, task) {
|
|
|
|
|
|
const results = annotation.serializeAnnotation();
|
|
|
|
|
|
if (!results) return;
|
|
|
|
|
|
|
|
|
|
|
|
const formattedAnnotations = results.map(result => {
|
|
|
|
|
|
if (result.type === 'rectanglelabels') {
|
|
|
|
|
|
return {
|
|
|
|
|
|
label: result.value.rectanglelabels[0],
|
|
|
|
|
|
x: result.value.x,
|
|
|
|
|
|
y: result.value.y,
|
|
|
|
|
|
width: result.value.width,
|
|
|
|
|
|
height: result.value.height
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
});
|
2024-11-28 12:27:07 +08:00
|
|
|
|
|
2024-12-01 15:08:48 +08:00
|
|
|
|
const data = {
|
|
|
|
|
|
annotationResult: JSON.stringify(formattedAnnotations),
|
|
|
|
|
|
taskId: this.taskId,
|
|
|
|
|
|
fileId: this.id
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
await manualAnnotate(data);
|
|
|
|
|
|
this.annotationsList.push({
|
|
|
|
|
|
taskId: task.id,
|
|
|
|
|
|
annotation: JSON.stringify(formattedAnnotations),
|
|
|
|
|
|
url: this.fileUrl
|
|
|
|
|
|
});
|
|
|
|
|
|
this.index++; // 更新索引
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Failed to submit annotation:', error);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
this.cleanupLabelStudio(); // 清理 LabelStudio 实例
|
2024-11-28 12:27:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2024-12-01 15:08:48 +08:00
|
|
|
|
// 重置 LabelStudio
|
|
|
|
|
|
resetLabelStudio() {
|
|
|
|
|
|
this.cleanupLabelStudio();
|
|
|
|
|
|
this.initLabelStudio(); // 重新初始化
|
|
|
|
|
|
},
|
|
|
|
|
|
// 清理 LabelStudio 实例
|
|
|
|
|
|
cleanupLabelStudio() {
|
|
|
|
|
|
if (this.labelStudio && this.labelStudio.destroy) {
|
|
|
|
|
|
this.labelStudio.destroy();
|
2024-11-28 12:27:07 +08:00
|
|
|
|
}
|
2024-12-01 15:08:48 +08:00
|
|
|
|
const labelStudioElement = document.getElementById('label-studio');
|
|
|
|
|
|
if (labelStudioElement) {
|
|
|
|
|
|
labelStudioElement.innerHTML = ''; // 清空容器
|
2024-11-28 12:27:07 +08:00
|
|
|
|
}
|
2024-12-01 15:08:48 +08:00
|
|
|
|
this.labelStudio = null; // 置空实例
|
2024-11-28 12:27:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-12-01 15:08:48 +08:00
|
|
|
|
};
|
2024-11-28 12:27:07 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2024-12-01 15:08:48 +08:00
|
|
|
|
.label-studio-annotator {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.annotation-container {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2024-11-28 12:27:07 +08:00
|
|
|
|
width: 100%;
|
2024-12-01 15:08:48 +08:00
|
|
|
|
height: 100%;
|
|
|
|
|
|
min-height: 500px; /* 设置最小高度 */
|
2024-11-28 12:27:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|