Add YOLO & COCO 어노테이션 유틸리티 스크립트
This commit is contained in:
499
README_YOLO.md
Normal file
499
README_YOLO.md
Normal file
@@ -0,0 +1,499 @@
|
||||
# YOLO Annotation Utility Tool
|
||||
|
||||
YOLO 형식의 어노테이션 파일을 자유롭게 조작할 수 있는 유틸리티 스크립트입니다.
|
||||
|
||||
## 주요 기능
|
||||
|
||||
- **대화형 모드** (interactive): 터미널에서 대화형으로 편집 (추천!)
|
||||
- **클래스 제거** (remove): 특정 클래스 삭제 (ID 또는 이름으로 지정 가능)
|
||||
- **클래스 통합** (merge): 여러 클래스를 하나로 병합 (ID 또는 이름으로 지정 가능)
|
||||
- **클래스 이름 변경** (rename): 클래스 이름 수정 (ID 또는 이름으로 지정 가능)
|
||||
- **클래스 ID 재할당** (reindex): ID를 순차적으로 재정렬
|
||||
- **정보 확인** (info): 어노테이션 파일 정보 출력 (클래스별 개수 및 합계 표시)
|
||||
|
||||
## 설치
|
||||
|
||||
PyYAML 라이브러리가 필요합니다:
|
||||
|
||||
```bash
|
||||
pip install pyyaml
|
||||
```
|
||||
|
||||
## YOLO 데이터셋 구조
|
||||
|
||||
이 도구는 다음과 같은 YOLO 데이터셋 구조를 기준으로 동작합니다:
|
||||
|
||||
```
|
||||
dataset/
|
||||
├── data.yaml # 클래스 정의 파일
|
||||
├── images/
|
||||
│ ├── train/
|
||||
│ │ ├── image1.jpg
|
||||
│ │ └── image2.jpg
|
||||
│ └── val/
|
||||
│ ├── image3.jpg
|
||||
│ └── image4.jpg
|
||||
└── labels/
|
||||
├── train/
|
||||
│ ├── image1.txt
|
||||
│ └── image2.txt
|
||||
└── val/
|
||||
├── image3.txt
|
||||
└── image4.txt
|
||||
```
|
||||
|
||||
**data.yaml 예시:**
|
||||
```yaml
|
||||
names:
|
||||
0: person
|
||||
1: car
|
||||
2: truck
|
||||
3: bus
|
||||
train: images/train
|
||||
val: images/val
|
||||
```
|
||||
|
||||
**label 파일(.txt) 예시:**
|
||||
```
|
||||
0 0.5 0.5 0.3 0.4
|
||||
1 0.7 0.3 0.2 0.3
|
||||
```
|
||||
형식: `class_id center_x center_y width height` (모든 좌표는 정규화된 값 0-1)
|
||||
|
||||
## 빠른 시작 - 대화형 모드 (권장)
|
||||
|
||||
인수 없이 실행하면 대화형 모드로 진입합니다:
|
||||
|
||||
```bash
|
||||
python yolo_annotation_modify.py
|
||||
```
|
||||
|
||||
대화형 모드에서는:
|
||||
1. **데이터셋 선택**: 자동으로 찾은 YOLO 데이터셋 목록에서 선택하거나 직접 경로 입력
|
||||
2. **작업 선택**: 메뉴에서 원하는 작업을 선택하고 여러 작업을 순차적으로 수행 가능
|
||||
3. **저장**: 모든 작업 완료 후 결과를 저장
|
||||
|
||||
### 대화형 모드 예시
|
||||
|
||||
```
|
||||
============================================================
|
||||
YOLO 어노테이션 편집기 - 대화형 모드
|
||||
============================================================
|
||||
|
||||
[1/3] 데이터셋 선택
|
||||
------------------------------------------------------------
|
||||
|
||||
발견된 YOLO 데이터셋:
|
||||
1. dataset/yolo
|
||||
2. data/custom_dataset
|
||||
0. 직접 경로 입력
|
||||
|
||||
데이터셋 번호 선택 (직접 입력은 0): 1
|
||||
|
||||
[+] 로딩 중: dataset/yolo
|
||||
[+] Found 150 label files
|
||||
|
||||
============================================================
|
||||
Dataset: dataset/yolo
|
||||
============================================================
|
||||
|
||||
전체 통계:
|
||||
- 라벨 파일 수: 150
|
||||
- 클래스 수: 3
|
||||
|
||||
클래스 상세:
|
||||
ID 클래스명 어노테이션 수
|
||||
------------------------------------------------------------
|
||||
0 person 450
|
||||
1 car 320
|
||||
2 truck 180
|
||||
------------------------------------------------------------
|
||||
합계 950
|
||||
============================================================
|
||||
|
||||
[2/3] 작업 선택
|
||||
------------------------------------------------------------
|
||||
|
||||
사용 가능한 작업:
|
||||
1. 클래스 제거
|
||||
2. 클래스 통합 (병합)
|
||||
3. 클래스 이름 변경
|
||||
4. 클래스 ID 재할당
|
||||
5. 현재 정보 표시
|
||||
0. 완료 (저장 단계로)
|
||||
|
||||
작업 선택 (0-5): 2
|
||||
|
||||
현재 클래스:
|
||||
0: person
|
||||
1: car
|
||||
2: truck
|
||||
|
||||
통합할 클래스 입력 (ID 또는 이름, 쉼표로 구분): 1,2
|
||||
|
||||
통합 후 클래스 이름 입력: vehicle
|
||||
|
||||
[*] 'vehicle'로 통합 중: ['1', '2']
|
||||
- 통합 대상: car (ID: 1)
|
||||
- 통합 대상: truck (ID: 2)
|
||||
[+] 'vehicle' (ID: 1)로 통합되었습니다
|
||||
[+] 500개의 어노테이션이 변경되었습니다
|
||||
|
||||
작업 선택 (0-5): 0
|
||||
|
||||
[3/3] 결과 저장
|
||||
------------------------------------------------------------
|
||||
|
||||
수행된 작업:
|
||||
1. 통합: 1, 2 → vehicle
|
||||
|
||||
[!] 주의: labels 폴더의 모든 .txt 파일이 수정됩니다.
|
||||
labels 폴더 백업 생성? (Y/n): Y
|
||||
|
||||
[*] labels 폴더 백업 중...
|
||||
[+] 백업 생성됨: dataset/yolo/labels_backup_20250117_143025
|
||||
|
||||
data.yaml 백업 생성? (Y/n): Y
|
||||
|
||||
[*] 저장 중...
|
||||
[+] data.yaml 백업 생성됨: dataset/yolo/data_backup_20250117_143026.yaml
|
||||
[+] data.yaml 저장 완료
|
||||
|
||||
============================================================
|
||||
작업이 성공적으로 완료되었습니다!
|
||||
============================================================
|
||||
|
||||
데이터셋: dataset/yolo
|
||||
설정 파일: dataset/yolo/data.yaml
|
||||
라벨 파일: 150개 업데이트됨
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLI 모드 사용법
|
||||
|
||||
명령행 인수를 사용하여 스크립트 방식으로도 실행할 수 있습니다.
|
||||
|
||||
### 1. 정보 확인 (info)
|
||||
|
||||
데이터셋의 전체 정보를 확인합니다.
|
||||
|
||||
```bash
|
||||
python yolo_annotation_modify.py info --dataset dataset/yolo
|
||||
```
|
||||
|
||||
출력 예시:
|
||||
```
|
||||
============================================================
|
||||
Dataset: dataset/yolo
|
||||
============================================================
|
||||
|
||||
전체 통계:
|
||||
- 라벨 파일 수: 150
|
||||
- 클래스 수: 3
|
||||
|
||||
클래스 상세:
|
||||
ID 클래스명 어노테이션 수
|
||||
------------------------------------------------------------
|
||||
0 person 450
|
||||
1 car 320
|
||||
2 truck 180
|
||||
------------------------------------------------------------
|
||||
합계 950
|
||||
============================================================
|
||||
```
|
||||
|
||||
### 2. 클래스 제거 (remove)
|
||||
|
||||
특정 클래스와 해당 어노테이션을 삭제합니다. **클래스 이름 또는 ID로 지정 가능**합니다.
|
||||
|
||||
```bash
|
||||
# 이름으로 클래스 제거
|
||||
python yolo_annotation_modify.py remove \
|
||||
--dataset dataset/yolo \
|
||||
--classes "person,bicycle"
|
||||
|
||||
# ID로 클래스 제거
|
||||
python yolo_annotation_modify.py remove \
|
||||
--dataset dataset/yolo \
|
||||
--classes "0,5"
|
||||
|
||||
# 이름과 ID 혼합 가능
|
||||
python yolo_annotation_modify.py remove \
|
||||
--dataset dataset/yolo \
|
||||
--classes "0,bicycle,5"
|
||||
|
||||
# 백업 생성 안 함
|
||||
python yolo_annotation_modify.py remove \
|
||||
--dataset dataset/yolo \
|
||||
--classes "0,1" \
|
||||
--no-backup
|
||||
```
|
||||
|
||||
### 3. 클래스 통합 (merge)
|
||||
|
||||
여러 클래스를 하나로 병합합니다. **클래스 이름 또는 ID로 지정 가능**합니다.
|
||||
|
||||
```bash
|
||||
# 이름으로 클래스 통합
|
||||
python yolo_annotation_modify.py merge \
|
||||
--dataset dataset/yolo \
|
||||
--source "car,truck,bus,motorcycle" \
|
||||
--target "vehicle"
|
||||
|
||||
# ID로 클래스 통합
|
||||
python yolo_annotation_modify.py merge \
|
||||
--dataset dataset/yolo \
|
||||
--source "1,2,3,4" \
|
||||
--target "vehicle"
|
||||
|
||||
# 이름과 ID 혼합 가능
|
||||
python yolo_annotation_modify.py merge \
|
||||
--dataset dataset/yolo \
|
||||
--source "1,truck,3" \
|
||||
--target "vehicle"
|
||||
|
||||
# 백업 생성 안 함
|
||||
python yolo_annotation_modify.py merge \
|
||||
--dataset dataset/yolo \
|
||||
--source "1,2,3" \
|
||||
--target "vehicle" \
|
||||
--no-backup
|
||||
```
|
||||
|
||||
### 4. 클래스 이름 변경 (rename)
|
||||
|
||||
클래스 이름을 변경합니다. **기존 클래스를 이름 또는 ID로 지정 가능**합니다.
|
||||
|
||||
```bash
|
||||
# 이름으로 클래스 이름 변경
|
||||
python yolo_annotation_modify.py rename \
|
||||
--dataset dataset/yolo \
|
||||
--mapping "person:human,car:automobile"
|
||||
|
||||
# ID로 클래스 이름 변경
|
||||
python yolo_annotation_modify.py rename \
|
||||
--dataset dataset/yolo \
|
||||
--mapping "0:human,1:automobile"
|
||||
|
||||
# 이름과 ID 혼합 가능
|
||||
python yolo_annotation_modify.py rename \
|
||||
--dataset dataset/yolo \
|
||||
--mapping "0:human,car:automobile"
|
||||
```
|
||||
|
||||
### 5. 클래스 ID 재할당 (reindex)
|
||||
|
||||
클래스 ID를 순차적으로 재할당합니다. 클래스를 삭제하거나 통합한 후 ID를 정리할 때 유용합니다.
|
||||
|
||||
```bash
|
||||
# ID를 0부터 재할당 (YOLO 기본값)
|
||||
python yolo_annotation_modify.py reindex \
|
||||
--dataset dataset/yolo
|
||||
|
||||
# ID를 1부터 재할당
|
||||
python yolo_annotation_modify.py reindex \
|
||||
--dataset dataset/yolo \
|
||||
--start 1
|
||||
|
||||
# 백업 생성 안 함
|
||||
python yolo_annotation_modify.py reindex \
|
||||
--dataset dataset/yolo \
|
||||
--no-backup
|
||||
```
|
||||
|
||||
## 고급 사용 예시
|
||||
|
||||
### 예시 1: 데이터셋 정리 워크플로우
|
||||
|
||||
```bash
|
||||
# 1. 현재 상태 확인
|
||||
python yolo_annotation_modify.py info --dataset dataset/yolo
|
||||
|
||||
# 2. ID로 불필요한 클래스 제거
|
||||
python yolo_annotation_modify.py remove \
|
||||
--dataset dataset/yolo \
|
||||
--classes "5,7,9"
|
||||
|
||||
# 3. 유사 클래스 통합
|
||||
python yolo_annotation_modify.py merge \
|
||||
--dataset dataset/yolo \
|
||||
--source "1,2,3" \
|
||||
--target "vehicle"
|
||||
|
||||
# 4. 클래스 이름 정리
|
||||
python yolo_annotation_modify.py rename \
|
||||
--dataset dataset/yolo \
|
||||
--mapping "0:person,vehicle:car"
|
||||
|
||||
# 5. ID 재할당
|
||||
python yolo_annotation_modify.py reindex \
|
||||
--dataset dataset/yolo \
|
||||
--start 0
|
||||
|
||||
# 6. 최종 결과 확인
|
||||
python yolo_annotation_modify.py info --dataset dataset/yolo
|
||||
```
|
||||
|
||||
### 예시 2: Train/Valid 데이터셋 동시 처리
|
||||
|
||||
YOLO 데이터셋의 경우 train과 val이 같은 data.yaml을 공유하므로, 한 번의 명령으로 모든 라벨 파일이 함께 업데이트됩니다:
|
||||
|
||||
```bash
|
||||
# 데이터셋 전체 클래스 이름 변경 (train/val 모두 자동 처리)
|
||||
python yolo_annotation_modify.py rename \
|
||||
--dataset dataset/yolo \
|
||||
--mapping "0:person,1:vehicle"
|
||||
```
|
||||
|
||||
### 예시 3: 대규모 클래스 통합
|
||||
|
||||
COCO 80개 클래스를 커스텀 클래스로 통합하는 예시:
|
||||
|
||||
```bash
|
||||
# 모든 vehicle 클래스를 하나로 통합
|
||||
python yolo_annotation_modify.py merge \
|
||||
--dataset dataset/yolo \
|
||||
--source "car,truck,bus,motorcycle,bicycle" \
|
||||
--target "vehicle"
|
||||
|
||||
# 모든 animal 클래스를 하나로 통합
|
||||
python yolo_annotation_modify.py merge \
|
||||
--dataset dataset/yolo \
|
||||
--source "cat,dog,bird,horse,cow" \
|
||||
--target "animal"
|
||||
|
||||
# ID 재정렬
|
||||
python yolo_annotation_modify.py reindex \
|
||||
--dataset dataset/yolo
|
||||
```
|
||||
|
||||
## Python 스크립트에서 사용
|
||||
|
||||
유틸리티를 Python 코드에서 직접 사용할 수도 있습니다.
|
||||
|
||||
```python
|
||||
from yolo_annotation_modify import YOLOAnnotationEditor
|
||||
|
||||
# 데이터셋 로드
|
||||
editor = YOLOAnnotationEditor('dataset/yolo')
|
||||
|
||||
# 정보 확인
|
||||
editor.print_info()
|
||||
|
||||
# 작업 수행 (이름 또는 ID로 지정 가능)
|
||||
editor.remove_classes(['0', '1']) # ID로 제거
|
||||
editor.remove_classes(['person', 'car']) # 이름으로 제거
|
||||
editor.rename_classes({'0': 'human', 'car': 'automobile'}) # ID와 이름 혼합 가능
|
||||
editor.reindex_classes(start_id=0)
|
||||
|
||||
# 저장 (data.yaml만 저장, label 파일은 이미 수정됨)
|
||||
editor.save_yaml(backup=True)
|
||||
|
||||
# 체이닝도 가능
|
||||
editor = YOLOAnnotationEditor('dataset/yolo')
|
||||
editor.remove_classes(['5', '7']) \
|
||||
.merge_classes(['1', '2'], 'vehicle') \
|
||||
.reindex_classes(start_id=0) \
|
||||
.save_yaml(backup=True)
|
||||
```
|
||||
|
||||
## 옵션
|
||||
|
||||
### 백업 관련
|
||||
|
||||
기본적으로 labels 폴더와 data.yaml 파일 모두 백업이 생성됩니다.
|
||||
|
||||
```bash
|
||||
# 백업 생성 (기본값)
|
||||
python yolo_annotation_modify.py rename --dataset dataset/yolo --mapping "0:human"
|
||||
|
||||
# 모든 백업 생성 안 함
|
||||
python yolo_annotation_modify.py rename --dataset dataset/yolo --mapping "0:human" --no-backup
|
||||
|
||||
# labels 폴더 백업만 생성 안 함 (data.yaml은 백업)
|
||||
python yolo_annotation_modify.py rename --dataset dataset/yolo --mapping "0:human" --no-labels-backup
|
||||
```
|
||||
|
||||
백업 파일명 형식:
|
||||
- Labels 폴더: `labels_backup_{YYYYMMDD_HHMMSS}/`
|
||||
- data.yaml: `data_backup_{YYYYMMDD_HHMMSS}.yaml`
|
||||
|
||||
## 주요 특징
|
||||
|
||||
### ID와 이름 모두 지원
|
||||
- 모든 작업(제거, 통합, 이름 변경)에서 클래스를 **ID 또는 이름**으로 지정 가능
|
||||
- 숫자로 입력하면 자동으로 ID로 인식, 문자로 입력하면 이름으로 인식
|
||||
- ID와 이름을 혼합하여 사용 가능
|
||||
|
||||
### 어노테이션 통계
|
||||
- 클래스별 어노테이션 개수 자동 계산
|
||||
- 전체 어노테이션 합계 표시
|
||||
- 실시간 정보 확인 가능
|
||||
|
||||
### 자동 백업
|
||||
- labels 폴더 전체 백업
|
||||
- data.yaml 파일 백업
|
||||
- 타임스탬프로 백업 파일 구분
|
||||
|
||||
### 입력 오류 처리
|
||||
- 잘못된 경로 입력 시 재입력 요청
|
||||
- 잘못된 선택 입력 시 재입력 요청
|
||||
- 존재하지 않는 클래스 ID/이름 입력 시 경고 표시
|
||||
|
||||
## YOLO vs COCO 차이점
|
||||
|
||||
| 항목 | YOLO | COCO (MMDetection) |
|
||||
|------|------|---------------------|
|
||||
| 설정 파일 | data.yaml | JSON |
|
||||
| 클래스 ID | 0부터 시작 | 1부터 시작 |
|
||||
| 어노테이션 파일 | 이미지별 .txt 파일 | 단일 JSON 파일 |
|
||||
| 좌표 형식 | 정규화된 중심점+크기 | 픽셀 좌표 (bbox/polygon) |
|
||||
| 백업 대상 | labels 폴더 전체 + data.yaml | JSON 파일 하나 |
|
||||
|
||||
## 주의사항
|
||||
|
||||
1. **데이터 백업**: 중요한 데이터는 항상 백업 후 작업하세요.
|
||||
2. **Train/Val 일치**: Train과 Val은 같은 data.yaml을 공유하므로 한 번의 작업으로 모두 수정됩니다.
|
||||
3. **ID 순서**: `reindex` 명령은 기존 ID 순서를 기준으로 재할당합니다.
|
||||
4. **병합 ID**: `merge` 명령은 가장 작은 ID를 새 카테고리 ID로 사용합니다.
|
||||
5. **좌표 유지**: 모든 작업은 bounding box 좌표를 그대로 유지하고 클래스 ID만 수정합니다.
|
||||
6. **파일 직접 수정**: label 파일(.txt)은 원본이 직접 수정되므로 반드시 백업을 생성하세요.
|
||||
|
||||
## 문제 해결
|
||||
|
||||
### data.yaml을 찾을 수 없음
|
||||
|
||||
```bash
|
||||
# 올바른 데이터셋 디렉토리 지정 (data.yaml이 있는 폴더)
|
||||
python yolo_annotation_modify.py info --dataset dataset/yolo
|
||||
|
||||
# 절대 경로 사용
|
||||
python yolo_annotation_modify.py info --dataset /full/path/to/dataset
|
||||
```
|
||||
|
||||
### label 파일 형식 오류
|
||||
|
||||
YOLO 형식 확인:
|
||||
```python
|
||||
# 올바른 형식: class_id center_x center_y width height
|
||||
0 0.5 0.5 0.3 0.4
|
||||
1 0.7 0.3 0.2 0.3
|
||||
```
|
||||
|
||||
모든 값은 0-1 사이의 정규화된 값이어야 합니다.
|
||||
|
||||
### data.yaml 형식 확인
|
||||
|
||||
```yaml
|
||||
names:
|
||||
0: class_name_1
|
||||
1: class_name_2
|
||||
2: class_name_3
|
||||
train: images/train
|
||||
val: images/val
|
||||
```
|
||||
|
||||
## 라이선스
|
||||
|
||||
이 도구는 YOLO 형식 어노테이션 작업을 위한 유틸리티입니다.
|
||||
Reference in New Issue
Block a user