You've already forked DataMate
feat(annotation): 添加分段标注功能支持
- 定义分段标注相关常量(segmented、segments、result等键名) - 实现分段标注提取方法_extract_segment_annotations处理字典和列表格式 - 添加分段标注判断方法_is_segmented_annotation检测标注状态 - 修改_has_annotation_result方法使用新的分段标注处理逻辑 - 在任务创建过程中集成分段标注数据处理 - 更新导出服务中的分段标注结果扁平化处理 - 实现标注归一化方法支持分段标注格式转换 - 调整JSON和CSV导出格式适配分段标注结构
This commit is contained in:
@@ -63,6 +63,12 @@ from ..schema.export import (
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
SEGMENTED_KEY = "segmented"
|
||||
SEGMENTS_KEY = "segments"
|
||||
SEGMENT_RESULT_KEY = "result"
|
||||
SEGMENT_INDEX_KEY = "segmentIndex"
|
||||
SEGMENT_INDEX_FALLBACK_KEY = "segment_index"
|
||||
|
||||
|
||||
class AnnotationExportService:
|
||||
"""标注数据导出服务"""
|
||||
@@ -239,6 +245,61 @@ class AnnotationExportService:
|
||||
|
||||
return items
|
||||
|
||||
@staticmethod
|
||||
def _flatten_annotation_results(annotation: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
if not annotation or not isinstance(annotation, dict):
|
||||
return []
|
||||
segments = annotation.get(SEGMENTS_KEY)
|
||||
if annotation.get(SEGMENTED_KEY) or isinstance(segments, (dict, list)):
|
||||
results: List[Dict[str, Any]] = []
|
||||
if isinstance(segments, dict):
|
||||
for key, segment in segments.items():
|
||||
if not isinstance(segment, dict):
|
||||
continue
|
||||
segment_results = segment.get(SEGMENT_RESULT_KEY)
|
||||
if not isinstance(segment_results, list):
|
||||
continue
|
||||
for item in segment_results:
|
||||
if isinstance(item, dict):
|
||||
normalized = dict(item)
|
||||
if SEGMENT_INDEX_KEY not in normalized and SEGMENT_INDEX_FALLBACK_KEY not in normalized:
|
||||
normalized[SEGMENT_INDEX_KEY] = int(key) if str(key).isdigit() else key
|
||||
results.append(normalized)
|
||||
else:
|
||||
results.append({"value": item, SEGMENT_INDEX_KEY: key})
|
||||
elif isinstance(segments, list):
|
||||
for idx, segment in enumerate(segments):
|
||||
if not isinstance(segment, dict):
|
||||
continue
|
||||
segment_results = segment.get(SEGMENT_RESULT_KEY)
|
||||
if not isinstance(segment_results, list):
|
||||
continue
|
||||
segment_index = segment.get(SEGMENT_INDEX_KEY, segment.get(SEGMENT_INDEX_FALLBACK_KEY, idx))
|
||||
for item in segment_results:
|
||||
if isinstance(item, dict):
|
||||
normalized = dict(item)
|
||||
if SEGMENT_INDEX_KEY not in normalized and SEGMENT_INDEX_FALLBACK_KEY not in normalized:
|
||||
normalized[SEGMENT_INDEX_KEY] = segment_index
|
||||
results.append(normalized)
|
||||
else:
|
||||
results.append({"value": item, SEGMENT_INDEX_KEY: segment_index})
|
||||
return results
|
||||
result = annotation.get(SEGMENT_RESULT_KEY)
|
||||
return result if isinstance(result, list) else []
|
||||
|
||||
@classmethod
|
||||
def _normalize_annotation_for_export(cls, annotation: Dict[str, Any]) -> Dict[str, Any]:
|
||||
if not annotation or not isinstance(annotation, dict):
|
||||
return {}
|
||||
segments = annotation.get(SEGMENTS_KEY)
|
||||
if annotation.get(SEGMENTED_KEY) or isinstance(segments, (dict, list)):
|
||||
normalized = dict(annotation)
|
||||
normalized_result = cls._flatten_annotation_results(annotation)
|
||||
if SEGMENT_RESULT_KEY not in normalized or not isinstance(normalized.get(SEGMENT_RESULT_KEY), list):
|
||||
normalized[SEGMENT_RESULT_KEY] = normalized_result
|
||||
return normalized
|
||||
return annotation
|
||||
|
||||
def _export_json(
|
||||
self, items: List[AnnotationExportItem], project_name: str
|
||||
) -> Tuple[bytes, str, str]:
|
||||
@@ -252,7 +313,7 @@ class AnnotationExportService:
|
||||
"file_id": item.file_id,
|
||||
"file_name": item.file_name,
|
||||
"data": item.data,
|
||||
"annotations": item.annotations,
|
||||
"annotations": [self._normalize_annotation_for_export(ann) for ann in item.annotations],
|
||||
"created_at": item.created_at.isoformat() if item.created_at else None,
|
||||
"updated_at": item.updated_at.isoformat() if item.updated_at else None,
|
||||
}
|
||||
@@ -274,7 +335,7 @@ class AnnotationExportService:
|
||||
"file_id": item.file_id,
|
||||
"file_name": item.file_name,
|
||||
"data": item.data,
|
||||
"annotations": item.annotations,
|
||||
"annotations": [self._normalize_annotation_for_export(ann) for ann in item.annotations],
|
||||
"created_at": item.created_at.isoformat() if item.created_at else None,
|
||||
"updated_at": item.updated_at.isoformat() if item.updated_at else None,
|
||||
}
|
||||
@@ -307,7 +368,7 @@ class AnnotationExportService:
|
||||
# 提取标签信息(支持多种标注类型)
|
||||
labels = []
|
||||
for ann in item.annotations:
|
||||
results = ann.get("result", [])
|
||||
results = self._flatten_annotation_results(ann)
|
||||
for r in results:
|
||||
value = r.get("value", {})
|
||||
label_type = r.get("type", "")
|
||||
@@ -382,7 +443,7 @@ class AnnotationExportService:
|
||||
|
||||
# 处理标注
|
||||
for ann in item.annotations:
|
||||
results = ann.get("result", [])
|
||||
results = self._flatten_annotation_results(ann)
|
||||
for r in results:
|
||||
# 处理矩形框标注 (rectanglelabels)
|
||||
if r.get("type") == "rectanglelabels":
|
||||
@@ -434,7 +495,7 @@ class AnnotationExportService:
|
||||
lines = []
|
||||
|
||||
for ann in item.annotations:
|
||||
results = ann.get("result", [])
|
||||
results = self._flatten_annotation_results(ann)
|
||||
for r in results:
|
||||
# 处理矩形框标注
|
||||
if r.get("type") == "rectanglelabels":
|
||||
|
||||
Reference in New Issue
Block a user