|
24 | 24 |
|
25 | 25 | def load(file_object, annotations):
|
26 | 26 | from pyunpack import Archive
|
27 |
| - import os |
| 27 | + import os.path as osp |
28 | 28 | from tempfile import TemporaryDirectory
|
29 | 29 | from glob import glob
|
30 |
| - |
31 |
| - def convert_from_yolo(img_size, box): |
32 |
| - # convertation formulas are based on https://github.com/pjreddie/darknet/blob/master/scripts/voc_label.py |
33 |
| - # <x> <y> <width> <height> - float values relative to width and height of image |
34 |
| - # <x> <y> - are center of rectangle |
35 |
| - def clamp(value, _min, _max): |
36 |
| - return max(min(_max, value), _min) |
37 |
| - xtl = clamp(img_size[0] * (box[0] - box[2] / 2), 0, img_size[0]) |
38 |
| - ytl = clamp(img_size[1] * (box[1] - box[3] / 2), 0, img_size[1]) |
39 |
| - xbr = clamp(img_size[0] * (box[0] + box[2] / 2), 0, img_size[0]) |
40 |
| - ybr = clamp(img_size[1] * (box[1] + box[3] / 2), 0, img_size[1]) |
41 |
| - |
42 |
| - return [xtl, ytl, xbr, ybr] |
43 |
| - |
44 |
| - def parse_yolo_obj(img_size, obj): |
45 |
| - label_id, x, y, w, h = obj.split(" ") |
46 |
| - return int(label_id), convert_from_yolo(img_size, (float(x), float(y), float(w), float(h))) |
47 |
| - |
48 |
| - def parse_yolo_file(annotation_file, labels_mapping): |
49 |
| - frame_number = annotations.match_frame(annotation_file) |
50 |
| - with open(annotation_file, "r") as fp: |
51 |
| - line = fp.readline() |
52 |
| - while line: |
53 |
| - frame_info = annotations.frame_info[frame_number] |
54 |
| - label_id, points = parse_yolo_obj((frame_info["width"], frame_info["height"]), line) |
55 |
| - annotations.add_shape(annotations.LabeledShape( |
56 |
| - type="rectangle", |
57 |
| - frame=frame_number, |
58 |
| - label=labels_mapping[label_id], |
59 |
| - points=points, |
60 |
| - occluded=False, |
61 |
| - attributes=[], |
62 |
| - )) |
63 |
| - line = fp.readline() |
64 |
| - |
65 |
| - def load_labels(labels_file): |
66 |
| - with open(labels_file, "r") as f: |
67 |
| - return {idx: label.strip() for idx, label in enumerate(f.readlines()) if label.strip()} |
| 30 | + from datumaro.plugins.yolo_format.importer import YoloImporter |
| 31 | + from cvat.apps.dataset_manager.bindings import import_dm_annotations |
68 | 32 |
|
69 | 33 | archive_file = file_object if isinstance(file_object, str) else getattr(file_object, "name")
|
70 | 34 | with TemporaryDirectory() as tmp_dir:
|
71 | 35 | Archive(archive_file).extractall(tmp_dir)
|
72 | 36 |
|
73 |
| - labels_file = glob(os.path.join(tmp_dir, "*.names")) |
74 |
| - if not labels_file: |
75 |
| - raise Exception("Could not find '*.names' file with labels in uploaded archive") |
76 |
| - elif len(labels_file) == 1: |
77 |
| - labels_mapping = load_labels(labels_file[0]) |
78 |
| - else: |
79 |
| - raise Exception("Too many '*.names' files in uploaded archive: {}".format(labels_file)) |
80 |
| - |
81 |
| - for dirpath, _, filenames in os.walk(tmp_dir): |
82 |
| - for file in filenames: |
83 |
| - if ".txt" == os.path.splitext(file)[1]: |
84 |
| - parse_yolo_file(os.path.join(dirpath, file), labels_mapping) |
| 37 | + image_info = {} |
| 38 | + anno_files = glob(osp.join(tmp_dir, '**', '*.txt'), recursive=True) |
| 39 | + for filename in anno_files: |
| 40 | + filename = osp.basename(filename) |
| 41 | + frame_info = None |
| 42 | + try: |
| 43 | + frame_info = annotations.frame_info[ |
| 44 | + int(osp.splitext(filename)[0])] |
| 45 | + except Exception: |
| 46 | + pass |
| 47 | + try: |
| 48 | + frame_info = annotations.match_frame(filename) |
| 49 | + frame_info = annotations.frame_info[frame_info] |
| 50 | + except Exception: |
| 51 | + pass |
| 52 | + if frame_info is not None: |
| 53 | + image_info[osp.splitext(filename)[0]] = \ |
| 54 | + (frame_info['height'], frame_info['width']) |
| 55 | + |
| 56 | + dm_project = YoloImporter()(tmp_dir, image_info=image_info) |
| 57 | + dm_dataset = dm_project.make_dataset() |
| 58 | + import_dm_annotations(dm_dataset, annotations) |
85 | 59 |
|
86 | 60 | def dump(file_object, annotations):
|
87 |
| - from zipfile import ZipFile |
88 |
| - import os |
89 |
| - |
90 |
| - # convertation formulas are based on https://github.com/pjreddie/darknet/blob/master/scripts/voc_label.py |
91 |
| - # <x> <y> <width> <height> - float values relative to width and height of image |
92 |
| - # <x> <y> - are center of rectangle |
93 |
| - def convert_to_yolo(img_size, box): |
94 |
| - x = (box[0] + box[2]) / 2 / img_size[0] |
95 |
| - y = (box[1] + box[3]) / 2 / img_size[1] |
96 |
| - w = (box[2] - box[0]) / img_size[0] |
97 |
| - h = (box[3] - box[1]) / img_size[1] |
98 |
| - |
99 |
| - return x, y, w, h |
100 |
| - |
101 |
| - labels_ids = {label[1]["name"]: idx for idx, label in enumerate(annotations.meta["task"]["labels"])} |
102 |
| - |
103 |
| - with ZipFile(file_object, "w") as output_zip: |
104 |
| - for frame_annotation in annotations.group_by_frame(): |
105 |
| - image_name = frame_annotation.name |
106 |
| - annotation_name = "{}.txt".format(os.path.splitext(os.path.basename(image_name))[0]) |
107 |
| - width = frame_annotation.width |
108 |
| - height = frame_annotation.height |
109 |
| - |
110 |
| - yolo_annotation = "" |
111 |
| - for shape in frame_annotation.labeled_shapes: |
112 |
| - if shape.type != "rectangle": |
113 |
| - continue |
114 |
| - |
115 |
| - label = shape.label |
116 |
| - yolo_bb = convert_to_yolo((width, height), shape.points) |
117 |
| - yolo_bb = " ".join("{:.6f}".format(p) for p in yolo_bb) |
118 |
| - yolo_annotation += "{} {}\n".format(labels_ids[label], yolo_bb) |
119 |
| - |
120 |
| - output_zip.writestr(annotation_name, yolo_annotation) |
121 |
| - output_zip.writestr("obj.names", "\n".join(l[0] for l in sorted(labels_ids.items(), key=lambda x:x[1]))) |
| 61 | + from cvat.apps.dataset_manager.bindings import CvatAnnotationsExtractor |
| 62 | + from cvat.apps.dataset_manager.util import make_zip_archive |
| 63 | + from datumaro.components.project import Environment |
| 64 | + from tempfile import TemporaryDirectory |
| 65 | + extractor = CvatAnnotationsExtractor('', annotations) |
| 66 | + converter = Environment().make_converter('yolo') |
| 67 | + with TemporaryDirectory() as temp_dir: |
| 68 | + converter(extractor, save_dir=temp_dir) |
| 69 | + make_zip_archive(temp_dir, file_object) |
0 commit comments