돌아가기 비디오 어노테이터 스키마
## 비디오 어노테이터 전용 스키마

### 지원 도구(Tools)

| Tool Code      | 설명                 | 특이사항                                          |
| -------------- | -------------------- | ------------------------------------------------- |
| `segmentation` | 비디오 구간 분리     | -                                                 |
| `bounding_box` | 프레임별 바운딩 박스 | 키프레임 보간 지원, `bakeInterpolatedFrames` 처리 |
> 

### 비디오 전용 extra (메타데이터)

| 키 | 타입 | 설명 |
| --- | --- | --- |
| frameCount | number | 전체 프레임 수 |
| frameRate | number | FPS(프레임/초) |
| durationSeconds | number | 영상 길이(초) |
| width / height | number | 원본 해상도(px) |

> 필요 시 카메라 정보, 코덱 등 프로젝트별 속성을 자유롭게 추가합니다.
> 

#### annotationsData 구조

**Segmentation (구간):**

```json
{
  "id": "L3xevRklfm",
  "section": {
    "startFrame": 17,
    "endFrame": 29
  }
}
```

**Bounding Box (프레임별 좌표 + 구간):**

```json
{
  "id": "bbox_001",
  "section": {
    "startFrame": 10,
    "endFrame": 50
  },
  "frames": {
    "10": { "bbox": { "x": 100, "y": 100, "width": 50, "height": 50 } },
    "30": { "bbox": { "x": 150, "y": 120, "width": 55, "height": 52 } },
    "50": { "bbox": { "x": 200, "y": 140, "width": 60, "height": 55 } }
  },
  "segments": [{ "start": 10, "end": 50 }]
}
```

### beforeAction Hook

```javascript
// 키프레임 보간 데이터를 실제 프레임 데이터로 변환
beforeAction: (annotatorData, variables) => {
  for (const annotation of annotationData) {
    if (annotationData.tool === 'bounding_box') {
      bakeInterpolatedFrames(annotation)
    }
  }
  return dataGrooming(annotatorData, variables)
}
```

### 샘플

프레임 구간 기반의 세그멘테이션과 바운딩박스(키프레임 보간 포함) 예제:

```json
{
  "extra": {
    "video_1": {
      "totalFrames": 300,
      "fps": 30,
      "currentFrame": 50
    }
  },
  "relations": {
    "video_1": []
  },
  "annotations": {
    "video_1": [
      {
        "id": "L3xevRklfm",
        "tool": "segmentation",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "장면_전환",
          "scene_type": "outdoor"
        },
        "label": ["장면_전환"]
      },
      {
        "id": "Yf3yNlPxfj",
        "tool": "segmentation",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "액션",
          "action_type": "walking"
        },
        "label": ["액션"]
      },
      {
        "id": "bbox_video_001",
        "tool": "bounding_box",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "사람",
          "person_id": "person_1"
        },
        "label": ["사람"]
      },
      {
        "id": "bbox_video_002",
        "tool": "bounding_box",
        "isLocked": false,
        "isVisible": true,
        "isValid": true,
        "classification": {
          "class": "자동차",
          "vehicle_type": "sedan"
        },
        "label": ["자동차"]
      }
    ]
  },
  "annotationsData": {
    "video_1": [
      {
        "id": "L3xevRklfm",
        "section": {
          "startFrame": 17,
          "endFrame": 89
        }
      },
      {
        "id": "Yf3yNlPxfj",
        "section": {
          "startFrame": 90,
          "endFrame": 150
        }
      },
      {
        "id": "bbox_video_001",
        "section": {
          "startFrame": 10,
          "endFrame": 100
        },
        "frames": {
          "10": {
            "bbox": { "x": 100, "y": 150, "width": 50, "height": 120 },
            "isKeyframe": true
          },
          "30": {
            "bbox": { "x": 150, "y": 145, "width": 52, "height": 122 },
            "isKeyframe": true
          },
          "60": {
            "bbox": { "x": 220, "y": 140, "width": 55, "height": 125 },
            "isKeyframe": true
          },
          "100": {
            "bbox": { "x": 350, "y": 130, "width": 58, "height": 128 },
            "isKeyframe": true
          }
        },
        "segments": [{ "start": 10, "end": 100 }]
      },
      {
        "id": "bbox_video_002",
        "section": {
          "startFrame": 50,
          "endFrame": 200
        },
        "frames": {
          "50": {
            "bbox": { "x": 400, "y": 200, "width": 80, "height": 60 },
            "isKeyframe": true
          },
          "100": {
            "bbox": { "x": 300, "y": 195, "width": 85, "height": 62 },
            "isKeyframe": true
          },
          "150": {
            "bbox": { "x": 180, "y": 190, "width": 90, "height": 65 },
            "isKeyframe": true
          },
          "200": {
            "bbox": { "x": 50, "y": 185, "width": 95, "height": 68 },
            "isKeyframe": true
          }
        },
        "segments": [{ "start": 50, "end": 200 }]
      }
    ]
  },
  "annotationGroups": {
    "video_1": [
      {
        "id": "RDdQzKr5B3",
        "tool": "annotationGroup",
        "isLocked": false,
        "isValid": true,
        "annotationList": [
          { "annotationId": "L3xevRklfm", "children": [] },
          { "annotationId": "Yf3yNlPxfj", "children": [] }
        ],
        "classification": {
          "class": "장면_그룹"
        }
      },
      {
        "id": "q5VHfub1YF",
        "tool": "annotationGroup",
        "isLocked": false,
        "isValid": true,
        "annotationList": [
          { "annotationId": "bbox_video_001", "children": [] },
          { "annotationId": "bbox_video_002", "children": [] }
        ],
        "classification": {
          "class": "객체_그룹",
          "interaction": "approaching"
        }
      }
    ]
  },
  "assignmentId": 3087
}
```