Skip to content

Commit

Permalink
renaming yolov8 to yolo ultralytics (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eldies authored Dec 24, 2024
1 parent 40fe751 commit 232c175
Show file tree
Hide file tree
Showing 41 changed files with 209 additions and 193 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
(<https://github.com/cvat-ai/datumaro/pull/46>)
- Skeleton support in datumaro format
(<https://github.com/cvat-ai/datumaro/pull/47>)
- Support for YOLOv8 formats
- Support for Ultralytics YOLO formats
(<https://github.com/cvat-ai/datumaro/pull/50>)
- Support for YOLOv8 Classification format
- Support for Ultralytics YOLO Classification format
(<https://github.com/cvat-ai/datumaro/pull/59>)

### Changed
Expand Down
26 changes: 13 additions & 13 deletions datumaro/plugins/yolo_format/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from datumaro.util import dump_json_file, str_to_bool
from datumaro.util.os_util import split_path

from .format import YoloPath, YOLOv8ClassificationFormat, YOLOv8Path
from .format import YoloPath, YoloUltralyticsClassificationFormat, YoloUltralyticsPath


def _make_yolo_bbox(img_size, box):
Expand Down Expand Up @@ -278,8 +278,8 @@ def patch(cls, dataset: IExtractor, patch: DatasetPatch, save_dir: str, **kwargs
os.remove(ann_path)


class YOLOv8DetectionConverter(YoloConverter):
RESERVED_CONFIG_KEYS = YOLOv8Path.RESERVED_CONFIG_KEYS
class YoloUltralyticsDetectionConverter(YoloConverter):
RESERVED_CONFIG_KEYS = YoloUltralyticsPath.RESERVED_CONFIG_KEYS

def __init__(
self,
Expand All @@ -291,7 +291,7 @@ def __init__(
**kwargs,
) -> None:
super().__init__(extractor, save_dir, add_path_prefix=add_path_prefix, **kwargs)
self._config_filename = config_file or YOLOv8Path.DEFAULT_CONFIG_FILE
self._config_filename = config_file or YoloUltralyticsPath.DEFAULT_CONFIG_FILE

def _save_annotation_file(self, annotation_path, yolo_annotation):
if yolo_annotation:
Expand All @@ -302,7 +302,7 @@ def build_cmdline_parser(cls, **kwargs):
parser = super().build_cmdline_parser(**kwargs)
parser.add_argument(
"--config-file",
default=YOLOv8Path.DEFAULT_CONFIG_FILE,
default=YoloUltralyticsPath.DEFAULT_CONFIG_FILE,
type=str,
help="config file name (default: %(default)s)",
)
Expand All @@ -326,14 +326,14 @@ def _save_config_files(self, subset_lists: Dict[str, str], **extra_config_fields

@staticmethod
def _make_image_subset_folder(save_dir: str, subset: str) -> str:
return osp.join(save_dir, YOLOv8Path.IMAGES_FOLDER_NAME, subset)
return osp.join(save_dir, YoloUltralyticsPath.IMAGES_FOLDER_NAME, subset)

@staticmethod
def _make_annotation_subset_folder(save_dir: str, subset: str) -> str:
return osp.join(save_dir, YOLOv8Path.LABELS_FOLDER_NAME, subset)
return osp.join(save_dir, YoloUltralyticsPath.LABELS_FOLDER_NAME, subset)


class YOLOv8SegmentationConverter(YOLOv8DetectionConverter):
class YoloUltralyticsSegmentationConverter(YoloUltralyticsDetectionConverter):
def _make_annotation_line(self, width: int, height: int, anno: Annotation) -> Optional[str]:
if anno.label is None or not isinstance(anno, Polygon):
return
Expand All @@ -342,7 +342,7 @@ def _make_annotation_line(self, width: int, height: int, anno: Annotation) -> Op
return "%s %s\n" % (self._map_labels_for_save[anno.label], string_values)


class YOLOv8OrientedBoxesConverter(YOLOv8DetectionConverter):
class YoloUltralyticsOrientedBoxesConverter(YoloUltralyticsDetectionConverter):
def _make_annotation_line(self, width: int, height: int, anno: Annotation) -> Optional[str]:
if anno.label is None or not isinstance(anno, Bbox):
return
Expand All @@ -352,7 +352,7 @@ def _make_annotation_line(self, width: int, height: int, anno: Annotation) -> Op
return "%s %s\n" % (self._map_labels_for_save[anno.label], string_values)


class YOLOv8PoseConverter(YOLOv8DetectionConverter):
class YoloUltralyticsPoseConverter(YoloUltralyticsDetectionConverter):
@cached_property
def _labels_to_save(self) -> List[int]:
point_categories = self._extractor.categories().get(
Expand Down Expand Up @@ -403,7 +403,7 @@ def _make_annotation_line(self, width: int, height: int, skeleton: Annotation) -
return f"{self._map_labels_for_save[skeleton.label]} {bbox_string_values} {' '.join(points_values)}\n"


class YOLOv8ClassificationConverter(Converter):
class YoloUltralyticsClassificationConverter(Converter):
DEFAULT_IMAGE_EXT = ".jpg"

def apply(self):
Expand Down Expand Up @@ -438,7 +438,7 @@ def apply(self):
if anno.type == AnnotationType.label
]
for label_name in items_info[item.id]["labels"] or [
YOLOv8ClassificationFormat.IMAGE_DIR_NO_LABEL
YoloUltralyticsClassificationFormat.IMAGE_DIR_NO_LABEL
]:
items_info[item.id]["path"] = self._export_media_for_label(
item, subset_name, label_name
Expand All @@ -450,7 +450,7 @@ def apply(self):
labels_path = osp.join(
self._save_dir,
subset_name,
YOLOv8ClassificationFormat.LABELS_FILE,
YoloUltralyticsClassificationFormat.LABELS_FILE,
)
dump_json_file(labels_path, items_info)

Expand Down
50 changes: 29 additions & 21 deletions datumaro/plugins/yolo_format/extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@
from datumaro.util.meta_file_util import get_meta_file, has_meta_file, parse_meta_file
from datumaro.util.os_util import split_path

from .format import YoloPath, YOLOv8ClassificationFormat, YOLOv8Path, YOLOv8PoseFormat
from .format import (
YoloPath,
YoloUltralyticsClassificationFormat,
YoloUltralyticsPath,
YoloUltralyticsPoseFormat,
)

T = TypeVar("T")

Expand Down Expand Up @@ -345,8 +350,8 @@ def _load_categories(self) -> CategoriesInfo:
return {AnnotationType.label: label_categories}


class YOLOv8DetectionExtractor(YoloExtractor):
RESERVED_CONFIG_KEYS = YOLOv8Path.RESERVED_CONFIG_KEYS
class YoloUltralyticsDetectionExtractor(YoloExtractor):
RESERVED_CONFIG_KEYS = YoloUltralyticsPath.RESERVED_CONFIG_KEYS

def __init__(
self,
Expand Down Expand Up @@ -417,17 +422,20 @@ def _load_categories(self) -> CategoriesInfo:
def _get_labels_path_from_image_path(self, image_path: str) -> str:
rel_image_path = osp.relpath(image_path, self._path)
split_rel_path = rel_image_path.split(osp.sep, 2)
if len(split_rel_path) < 3 or YOLOv8Path.IMAGES_FOLDER_NAME not in split_rel_path[:2]:
if (
len(split_rel_path) < 3
or YoloUltralyticsPath.IMAGES_FOLDER_NAME not in split_rel_path[:2]
):
raise InvalidAnnotationError(f"Malformed folder structure for image {rel_image_path}")

split_rel_path[
next(
index
for index in range(len(split_rel_path) - 1, -1, -1)
if split_rel_path[index] == YOLOv8Path.IMAGES_FOLDER_NAME
if split_rel_path[index] == YoloUltralyticsPath.IMAGES_FOLDER_NAME
)
] = YOLOv8Path.LABELS_FOLDER_NAME
split_rel_path[2] = osp.splitext(split_rel_path[2])[0] + YOLOv8Path.LABELS_EXT
] = YoloUltralyticsPath.LABELS_FOLDER_NAME
split_rel_path[2] = osp.splitext(split_rel_path[2])[0] + YoloUltralyticsPath.LABELS_EXT

return osp.join(self._path, *split_rel_path)

Expand Down Expand Up @@ -465,7 +473,7 @@ def _get_subset_image_paths(self, subset_name: str):
yield from subset_images_source


class YOLOv8SegmentationExtractor(YOLOv8DetectionExtractor):
class YoloUltralyticsSegmentationExtractor(YoloUltralyticsDetectionExtractor):
def _load_segmentation_annotation(
self, parts: List[str], image_height: int, image_width: int
) -> Polygon:
Expand All @@ -492,7 +500,7 @@ def _load_one_annotation(
)


class YOLOv8OrientedBoxesExtractor(YOLOv8DetectionExtractor):
class YoloUltralyticsOrientedBoxesExtractor(YoloUltralyticsDetectionExtractor):
def _load_one_annotation(
self, parts: List[str], image_height: int, image_width: int
) -> Annotation:
Expand Down Expand Up @@ -525,7 +533,7 @@ def _load_one_annotation(
)


class YOLOv8PoseExtractor(YOLOv8DetectionExtractor):
class YoloUltralyticsPoseExtractor(YoloUltralyticsDetectionExtractor):
def __init__(
self,
*args,
Expand All @@ -537,24 +545,24 @@ def __init__(

@cached_property
def _kpt_shape(self) -> list[int]:
if YOLOv8PoseFormat.KPT_SHAPE_FIELD_NAME not in self._config:
if YoloUltralyticsPoseFormat.KPT_SHAPE_FIELD_NAME not in self._config:
raise InvalidAnnotationError(
f"Failed to parse {YOLOv8PoseFormat.KPT_SHAPE_FIELD_NAME} from config"
f"Failed to parse {YoloUltralyticsPoseFormat.KPT_SHAPE_FIELD_NAME} from config"
)
kpt_shape = self._config[YOLOv8PoseFormat.KPT_SHAPE_FIELD_NAME]
kpt_shape = self._config[YoloUltralyticsPoseFormat.KPT_SHAPE_FIELD_NAME]
if not isinstance(kpt_shape, list) or len(kpt_shape) != 2:
raise InvalidAnnotationError(
f"Failed to parse {YOLOv8PoseFormat.KPT_SHAPE_FIELD_NAME} from config"
f"Failed to parse {YoloUltralyticsPoseFormat.KPT_SHAPE_FIELD_NAME} from config"
)
if kpt_shape[1] not in [2, 3]:
raise InvalidAnnotationError(
f"Unexpected values per point {kpt_shape[1]} in field"
f"{YOLOv8PoseFormat.KPT_SHAPE_FIELD_NAME}. Expected 2 or 3."
f"{YoloUltralyticsPoseFormat.KPT_SHAPE_FIELD_NAME}. Expected 2 or 3."
)
if not isinstance(kpt_shape[0], int) or kpt_shape[0] < 0:
raise InvalidAnnotationError(
f"Unexpected number of points {kpt_shape[0]} in field "
f"{YOLOv8PoseFormat.KPT_SHAPE_FIELD_NAME}. Expected non-negative integer."
f"{YoloUltralyticsPoseFormat.KPT_SHAPE_FIELD_NAME}. Expected non-negative integer."
)

return kpt_shape
Expand Down Expand Up @@ -689,7 +697,7 @@ def _load_one_annotation(
return Skeleton(points, label=label_id)


class YOLOv8ClassificationExtractor(YoloBaseExtractor):
class YoloUltralyticsClassificationExtractor(YoloBaseExtractor):
def _get_subset_names(self):
return [
subset_name
Expand All @@ -699,7 +707,7 @@ def _get_subset_names(self):

def _get_image_paths_for_subset_and_label(self, subset_name: str, label_name: str) -> list[str]:
category_folder = osp.join(self._path, subset_name, label_name)
image_list_path = osp.join(category_folder, YOLOv8ClassificationFormat.LABELS_FILE)
image_list_path = osp.join(category_folder, YoloUltralyticsClassificationFormat.LABELS_FILE)
if osp.isfile(image_list_path):
with open(image_list_path, "r", encoding="utf-8") as f:
yield from (osp.join(subset_name, label_name, line.strip()) for line in f)
Expand All @@ -711,7 +719,7 @@ def _get_image_paths_for_subset_and_label(self, subset_name: str, label_name: st

def _get_item_info_from_labels_file(self, subset_name: str) -> Optional[Dict]:
subset_path = osp.join(self._path, subset_name)
labels_file_path = osp.join(subset_path, YOLOv8ClassificationFormat.LABELS_FILE)
labels_file_path = osp.join(subset_path, YoloUltralyticsClassificationFormat.LABELS_FILE)
if osp.isfile(labels_file_path):
return parse_json_file(labels_file_path)

Expand Down Expand Up @@ -740,7 +748,7 @@ def _parse_annotations(self, image: Image, *, item_id: Tuple[str, str]) -> List[
return [
Label(label=self._categories[AnnotationType.label].find(label)[0])
for label in label_names
if label != YOLOv8ClassificationFormat.IMAGE_DIR_NO_LABEL
if label != YoloUltralyticsClassificationFormat.IMAGE_DIR_NO_LABEL
]

def _load_categories(self) -> CategoriesInfo:
Expand All @@ -756,7 +764,7 @@ def _load_categories(self) -> CategoriesInfo:
for label_dir_name in os.listdir(subset_path):
if not osp.isdir(osp.join(subset_path, label_dir_name)):
continue
if label_dir_name == YOLOv8ClassificationFormat.IMAGE_DIR_NO_LABEL:
if label_dir_name == YoloUltralyticsClassificationFormat.IMAGE_DIR_NO_LABEL:
continue
categories.add(label_dir_name)
return {AnnotationType.label: LabelCategories.from_iterable(sorted(categories))}
Expand Down
6 changes: 3 additions & 3 deletions datumaro/plugins/yolo_format/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class YoloPath:
SUBSET_LIST_EXT = ".txt"


class YOLOv8Path(YoloPath):
class YoloUltralyticsPath(YoloPath):
CONFIG_FILE_EXT = ".yaml"
DEFAULT_CONFIG_FILE = "data.yaml"
RESERVED_CONFIG_KEYS = YoloPath.RESERVED_CONFIG_KEYS + [
Expand All @@ -24,10 +24,10 @@ class YOLOv8Path(YoloPath):
LABELS_FOLDER_NAME = "labels"


class YOLOv8PoseFormat:
class YoloUltralyticsPoseFormat:
KPT_SHAPE_FIELD_NAME = "kpt_shape"


class YOLOv8ClassificationFormat:
class YoloUltralyticsClassificationFormat:
IMAGE_DIR_NO_LABEL = "no_label"
LABELS_FILE = "labels.json"
Loading

0 comments on commit 232c175

Please sign in to comment.