Skip to content

공통 어노테이터 스키마

본 문서는 Datamaker의 모든 어노테이터(이미지, 비디오, 텍스트, 프롬프트, PCD 등)가 공통적으로 따라야 하는 데이터 모델을 정의합니다.

각 어노테이터별 스펙은 이 스키마를 상속하고, 도구별(툴별) 고유 필드를 추가로 확장합니다.

  • classification 구조는 tool(도구)와 무관하며, 관리자(운영자) 페이지에서 직접 정의한 class, attributes, options로 구성됩니다.

  • attributes, options 등 모든 하위 구조 역시 사용자가 직접 정의합니다.

  • 실제 어노테이션 데이터의 classification 필드는 트리 구조를 flatten(평탄화)한 key-value 쌍으로 저장됩니다.

  • 특정 class가 선택된 경우, 필수 하위 속성(종속성)은 프로젝트별 dm-schema 확장 JSON Schema로 관리됩니다.

flowchart TD
    Schema["관리자 정의 분류 스키마 (트리)"]
    Data["실제 어노테이션 데이터 (Flatten)"]
    Schema -->|Flatten 규칙| Data
    Schema -->|종속성 규칙| JSONSchema["dm-schema 확장 JSON Schema"]
    Data -->|유효성 검증| JSONSchema
┌─────────────────────────────────────────────────────────────┐
│ annotatorData (최상위) │
├─────────────────────────────────────────────────────────────┤
│ extra → 에셋별 추가 메타데이터 │
│ annotations → 어노테이션 메타 정보 (id, tool, 분류 등) │
│ annotationsData → 어노테이션 실제 좌표/데이터 │
│ relations → 어노테이션 간 관계 │
│ annotationGroups → 어노테이션 그룹 정보 │
│ assignmentId → 작업 식별자 │
└─────────────────────────────────────────────────────────────┘

모든 어노테이션 작업은 하나의 JSON 객체로 저장되며, 최상위 키는 어노테이터 종류와 관계없이 동일합니다.

타입설명
extraRecord<string, unknown>에셋별 메타데이터
relationsRecord<string, RelationItem[]>어노테이션 간 관계
annotationsRecord<string, AnnotationBase[]>에셋 단위의 어노테이션 목록
annotationsDataRecord<string, AnnotationDataItem[]>어노테이션 실제 좌표/데이터
annotationGroupsRecord<string, AnnotationGroupItem[]>어노테이션 그룹화
assignmentIdstring작업 식별자
type AnnotatorData = {
extra: Record<AssetId, unknown>
annotations: Record<AssetId, AnnotationBase[]>
annotationsData: Record<AssetId, AnnotationDataItem[]>
relations: Record<AssetId, RelationItem[]>
annotationGroups: Record<AssetId, AnnotationGroupItem[]>
assignmentId: number | string
}
// AssetId 예시: "image_1", "video_1", "text_1", "pcd"

소스코드 src/app/core/lib/data.js에서 확인된 구조:

type AnnotationBase = {
id: string // 10자 랜덤 문자열 (예: "Cd1qfFQFI4")
tool: string // 사용된 도구 코드
isLocked: boolean // 편집 잠금 여부 (기본값: false)
isVisible: boolean // 화면 표시 여부 (기본값: true)
isValid?: boolean // 유효성 여부 (기본값: false)
isDrawCompleted?: boolean // 그리기 완료 여부
classification: ClassificationObject | null
label?: string[] // 분류 기반 생성된 라벨 배열
// Sequential Data 전용
sequenceIndex?: number // 시퀀스 인덱스
instanceId?: string // 인스턴스 ID (자동 생성)
}
type RelationItem = {
id: string // 소스ID + 타겟ID 조합 (예: "Cd1qfFQFI4AUjPgaMzQa")
tool: 'relation' // 항상 "relation" 고정
isLocked: boolean
isVisible: boolean
isValid?: boolean
annotationId: string // 출발(소스) 어노테이션 ID
targetAnnotationId: string // 도착(타겟) 어노테이션 ID
classification: ClassificationObject | null
label?: string[]
}
type AnnotationGroupItem = {
id: string
tool: 'annotationGroup' // 항상 "annotationGroup" 고정
isLocked: boolean
isValid?: boolean
annotationList: GroupMemberItem[]
classification: ClassificationObject | null
}
type GroupMemberItem = {
annotationId: string
children: GroupMemberItem[] // 계층 구조 지원
}

2.5 AnnotationDataBase (공통 데이터 필드)

Section titled “2.5 AnnotationDataBase (공통 데이터 필드)”

annotationsData 배열 내 각 항목이 가질 수 있는 공통 필드입니다:

type AnnotationDataBase = {
id: string // AnnotationBase.id와 1:1 매칭
// 데이터 압축 (전역 공통 필드)
isCompressed?: boolean // 압축 여부
compressionFormat?: CompressionFormat // 압축 포맷
}
type CompressionFormat =
| 'rle' // Run-Length Encoding (현재 지원)

⚠️ 적용 범위: 현재 Image Annotator의 segmentation 도구에서 사용 중이며, 향후 모든 어노테이터에서 공통적으로 적용될 예정입니다.

필드타입필수설명
isCompressedboolean조건부데이터 압축 여부. true일 경우 compressionFormat 필수
compressionFormatstring조건부압축 알고리즘 식별자. isCompressed: true일 때 필수
포맷상태설명적용 대상
rle✅ 사용 중Run-Length Encoding연속된 인덱스/픽셀 데이터
┌────────────────┐ ┌─────────────┐ ┌─────────────┐
│ 원본 데이터 │ ──▶ │ 인코딩 │ ──▶ │ 저장/전송 │
│ (pixel_indices)│ │ (RLE 등) │ │ (압축 상태) │
└────────────────┘ └─────────────┘ └─────────────┘
┌───────────────┐ ┌─────────────┐ │
│ 사용 가능 │ ◀── │ 디코딩 │ ◀─────────┘
│ (복원된 배열) │ │ (압축 해제) │
└───────────────┘ └─────────────┘

압축 전 (Raw):

{
"id": "seg_001",
"pixel_indices": [100, 101, 102, 103, 104, 200, 201, 202]
}

압축 후 (RLE):

{
"id": "seg_001",
"pixel_indices": [100, 5, 200, 3],
"isCompressed": true,
"compressionFormat": "rle"
}

RLE 형식: [시작인덱스, 연속개수, 시작인덱스, 연속개수, ...]

관리자가 정의한 트리 구조의 분류 스키마는 1-depth key-value 쌍으로 평탄화됩니다:

{
"class": "boundingbox",
"text": "설명 텍스트",
"multiple": ["option1", "option2"],
"single_radio": "selected_option",
"single_dropdown": "dropdown_value"
}

classification 기반으로 label 배열이 자동 생성됩니다:

if (annotation.classification) {
annotation.label = getLabel(variables, annotation.id, annotation.tool, annotation.classification)
}

모든 어노테이터는 definedHooks.beforeAction을 통해 저장 전 데이터 정리를 수행합니다:

definedHooks: {
beforeAction: (annotatorData, variables) => {
return dataGrooming(annotatorData, variables)
}
}
어노테이터전처리 내용
ImagedataGrooming 실행
VideobakeInterpolatedFrames (bounding_box 키프레임 보간) + dataGrooming
TextdataGrooming 실행
PCDpoints 배열 가진 3d_segmentation 삭제 + dataGrooming
PromptdataGrooming 실행
AudiodataGrooming 실행