Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

renaming yolov8 to yolo ultralytics #68

Merged
merged 1 commit into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading