dgenerate-ultralytics-headless 8.3.214__py3-none-any.whl → 8.4.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/METADATA +64 -74
- dgenerate_ultralytics_headless-8.4.7.dist-info/RECORD +311 -0
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/WHEEL +1 -1
- tests/__init__.py +7 -9
- tests/conftest.py +8 -15
- tests/test_cli.py +1 -1
- tests/test_cuda.py +13 -10
- tests/test_engine.py +9 -9
- tests/test_exports.py +65 -13
- tests/test_integrations.py +13 -13
- tests/test_python.py +125 -69
- tests/test_solutions.py +161 -152
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +86 -92
- ultralytics/cfg/datasets/Argoverse.yaml +7 -6
- ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
- ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
- ultralytics/cfg/datasets/ImageNet.yaml +1 -1
- ultralytics/cfg/datasets/TT100K.yaml +346 -0
- ultralytics/cfg/datasets/VOC.yaml +15 -16
- ultralytics/cfg/datasets/african-wildlife.yaml +1 -1
- ultralytics/cfg/datasets/coco-pose.yaml +21 -0
- ultralytics/cfg/datasets/coco12-formats.yaml +101 -0
- ultralytics/cfg/datasets/coco128-seg.yaml +1 -1
- ultralytics/cfg/datasets/coco8-pose.yaml +21 -0
- ultralytics/cfg/datasets/dog-pose.yaml +28 -0
- ultralytics/cfg/datasets/dota8-multispectral.yaml +1 -1
- ultralytics/cfg/datasets/dota8.yaml +2 -2
- ultralytics/cfg/datasets/hand-keypoints.yaml +26 -2
- ultralytics/cfg/datasets/kitti.yaml +27 -0
- ultralytics/cfg/datasets/lvis.yaml +5 -5
- ultralytics/cfg/datasets/open-images-v7.yaml +1 -1
- ultralytics/cfg/datasets/tiger-pose.yaml +16 -0
- ultralytics/cfg/datasets/xView.yaml +16 -16
- ultralytics/cfg/default.yaml +4 -2
- ultralytics/cfg/models/11/yolo11-pose.yaml +1 -1
- ultralytics/cfg/models/11/yoloe-11-seg.yaml +2 -2
- ultralytics/cfg/models/11/yoloe-11.yaml +2 -2
- ultralytics/cfg/models/26/yolo26-cls.yaml +33 -0
- ultralytics/cfg/models/26/yolo26-obb.yaml +52 -0
- ultralytics/cfg/models/26/yolo26-p2.yaml +60 -0
- ultralytics/cfg/models/26/yolo26-p6.yaml +62 -0
- ultralytics/cfg/models/26/yolo26-pose.yaml +53 -0
- ultralytics/cfg/models/26/yolo26-seg.yaml +52 -0
- ultralytics/cfg/models/26/yolo26.yaml +52 -0
- ultralytics/cfg/models/26/yoloe-26-seg.yaml +53 -0
- ultralytics/cfg/models/26/yoloe-26.yaml +53 -0
- ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +1 -1
- ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +1 -1
- ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +1 -1
- ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +1 -1
- ultralytics/cfg/models/v10/yolov10b.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10l.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10m.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10n.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10s.yaml +2 -2
- ultralytics/cfg/models/v10/yolov10x.yaml +2 -2
- ultralytics/cfg/models/v3/yolov3-tiny.yaml +1 -1
- ultralytics/cfg/models/v6/yolov6.yaml +1 -1
- ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +9 -6
- ultralytics/cfg/models/v8/yoloe-v8.yaml +9 -6
- ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +2 -2
- ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +2 -2
- ultralytics/cfg/models/v8/yolov8-ghost.yaml +2 -2
- ultralytics/cfg/models/v8/yolov8-obb.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-p2.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-world.yaml +1 -1
- ultralytics/cfg/models/v8/yolov8-worldv2.yaml +6 -6
- ultralytics/cfg/models/v9/yolov9s.yaml +1 -1
- ultralytics/data/__init__.py +4 -4
- ultralytics/data/annotator.py +5 -6
- ultralytics/data/augment.py +300 -475
- ultralytics/data/base.py +18 -26
- ultralytics/data/build.py +147 -25
- ultralytics/data/converter.py +108 -87
- ultralytics/data/dataset.py +47 -75
- ultralytics/data/loaders.py +42 -49
- ultralytics/data/split.py +5 -6
- ultralytics/data/split_dota.py +8 -15
- ultralytics/data/utils.py +36 -45
- ultralytics/engine/exporter.py +351 -263
- ultralytics/engine/model.py +186 -225
- ultralytics/engine/predictor.py +45 -54
- ultralytics/engine/results.py +198 -325
- ultralytics/engine/trainer.py +165 -106
- ultralytics/engine/tuner.py +41 -43
- ultralytics/engine/validator.py +55 -38
- ultralytics/hub/__init__.py +16 -19
- ultralytics/hub/auth.py +6 -12
- ultralytics/hub/google/__init__.py +7 -10
- ultralytics/hub/session.py +15 -25
- ultralytics/hub/utils.py +5 -8
- ultralytics/models/__init__.py +1 -1
- ultralytics/models/fastsam/__init__.py +1 -1
- ultralytics/models/fastsam/model.py +8 -10
- ultralytics/models/fastsam/predict.py +18 -30
- ultralytics/models/fastsam/utils.py +1 -2
- ultralytics/models/fastsam/val.py +5 -7
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +5 -8
- ultralytics/models/nas/predict.py +7 -9
- ultralytics/models/nas/val.py +1 -2
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +5 -8
- ultralytics/models/rtdetr/predict.py +15 -19
- ultralytics/models/rtdetr/train.py +10 -13
- ultralytics/models/rtdetr/val.py +21 -23
- ultralytics/models/sam/__init__.py +15 -2
- ultralytics/models/sam/amg.py +14 -20
- ultralytics/models/sam/build.py +26 -19
- ultralytics/models/sam/build_sam3.py +377 -0
- ultralytics/models/sam/model.py +29 -32
- ultralytics/models/sam/modules/blocks.py +83 -144
- ultralytics/models/sam/modules/decoders.py +19 -37
- ultralytics/models/sam/modules/encoders.py +44 -101
- ultralytics/models/sam/modules/memory_attention.py +16 -30
- ultralytics/models/sam/modules/sam.py +200 -73
- ultralytics/models/sam/modules/tiny_encoder.py +64 -83
- ultralytics/models/sam/modules/transformer.py +18 -28
- ultralytics/models/sam/modules/utils.py +174 -50
- ultralytics/models/sam/predict.py +2248 -350
- ultralytics/models/sam/sam3/__init__.py +3 -0
- ultralytics/models/sam/sam3/decoder.py +546 -0
- ultralytics/models/sam/sam3/encoder.py +529 -0
- ultralytics/models/sam/sam3/geometry_encoders.py +415 -0
- ultralytics/models/sam/sam3/maskformer_segmentation.py +286 -0
- ultralytics/models/sam/sam3/model_misc.py +199 -0
- ultralytics/models/sam/sam3/necks.py +129 -0
- ultralytics/models/sam/sam3/sam3_image.py +339 -0
- ultralytics/models/sam/sam3/text_encoder_ve.py +307 -0
- ultralytics/models/sam/sam3/vitdet.py +547 -0
- ultralytics/models/sam/sam3/vl_combiner.py +160 -0
- ultralytics/models/utils/loss.py +14 -26
- ultralytics/models/utils/ops.py +13 -17
- ultralytics/models/yolo/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +10 -13
- ultralytics/models/yolo/classify/train.py +12 -33
- ultralytics/models/yolo/classify/val.py +30 -29
- ultralytics/models/yolo/detect/predict.py +9 -12
- ultralytics/models/yolo/detect/train.py +17 -23
- ultralytics/models/yolo/detect/val.py +77 -59
- ultralytics/models/yolo/model.py +43 -60
- ultralytics/models/yolo/obb/predict.py +7 -16
- ultralytics/models/yolo/obb/train.py +14 -17
- ultralytics/models/yolo/obb/val.py +40 -37
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +7 -22
- ultralytics/models/yolo/pose/train.py +13 -16
- ultralytics/models/yolo/pose/val.py +39 -58
- ultralytics/models/yolo/segment/predict.py +17 -21
- ultralytics/models/yolo/segment/train.py +7 -10
- ultralytics/models/yolo/segment/val.py +95 -47
- ultralytics/models/yolo/world/train.py +8 -14
- ultralytics/models/yolo/world/train_world.py +11 -34
- ultralytics/models/yolo/yoloe/__init__.py +7 -7
- ultralytics/models/yolo/yoloe/predict.py +16 -23
- ultralytics/models/yolo/yoloe/train.py +36 -44
- ultralytics/models/yolo/yoloe/train_seg.py +11 -11
- ultralytics/models/yolo/yoloe/val.py +15 -20
- ultralytics/nn/__init__.py +7 -7
- ultralytics/nn/autobackend.py +159 -85
- ultralytics/nn/modules/__init__.py +68 -60
- ultralytics/nn/modules/activation.py +4 -6
- ultralytics/nn/modules/block.py +260 -224
- ultralytics/nn/modules/conv.py +52 -97
- ultralytics/nn/modules/head.py +831 -299
- ultralytics/nn/modules/transformer.py +76 -88
- ultralytics/nn/modules/utils.py +16 -21
- ultralytics/nn/tasks.py +180 -195
- ultralytics/nn/text_model.py +45 -69
- ultralytics/optim/__init__.py +5 -0
- ultralytics/optim/muon.py +338 -0
- ultralytics/solutions/__init__.py +12 -12
- ultralytics/solutions/ai_gym.py +13 -19
- ultralytics/solutions/analytics.py +15 -16
- ultralytics/solutions/config.py +6 -7
- ultralytics/solutions/distance_calculation.py +10 -13
- ultralytics/solutions/heatmap.py +8 -14
- ultralytics/solutions/instance_segmentation.py +6 -9
- ultralytics/solutions/object_blurrer.py +7 -10
- ultralytics/solutions/object_counter.py +12 -19
- ultralytics/solutions/object_cropper.py +8 -14
- ultralytics/solutions/parking_management.py +34 -32
- ultralytics/solutions/queue_management.py +10 -12
- ultralytics/solutions/region_counter.py +9 -12
- ultralytics/solutions/security_alarm.py +15 -20
- ultralytics/solutions/similarity_search.py +10 -15
- ultralytics/solutions/solutions.py +77 -76
- ultralytics/solutions/speed_estimation.py +7 -10
- ultralytics/solutions/streamlit_inference.py +2 -4
- ultralytics/solutions/templates/similarity-search.html +7 -18
- ultralytics/solutions/trackzone.py +7 -10
- ultralytics/solutions/vision_eye.py +5 -8
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +3 -5
- ultralytics/trackers/bot_sort.py +10 -27
- ultralytics/trackers/byte_tracker.py +21 -37
- ultralytics/trackers/track.py +4 -7
- ultralytics/trackers/utils/gmc.py +11 -22
- ultralytics/trackers/utils/kalman_filter.py +37 -48
- ultralytics/trackers/utils/matching.py +12 -15
- ultralytics/utils/__init__.py +124 -124
- ultralytics/utils/autobatch.py +2 -4
- ultralytics/utils/autodevice.py +17 -18
- ultralytics/utils/benchmarks.py +57 -71
- ultralytics/utils/callbacks/base.py +8 -10
- ultralytics/utils/callbacks/clearml.py +5 -13
- ultralytics/utils/callbacks/comet.py +32 -46
- ultralytics/utils/callbacks/dvc.py +13 -18
- ultralytics/utils/callbacks/mlflow.py +4 -5
- ultralytics/utils/callbacks/neptune.py +7 -15
- ultralytics/utils/callbacks/platform.py +423 -38
- ultralytics/utils/callbacks/raytune.py +3 -4
- ultralytics/utils/callbacks/tensorboard.py +25 -31
- ultralytics/utils/callbacks/wb.py +16 -14
- ultralytics/utils/checks.py +127 -85
- ultralytics/utils/cpu.py +3 -8
- ultralytics/utils/dist.py +9 -12
- ultralytics/utils/downloads.py +25 -33
- ultralytics/utils/errors.py +6 -14
- ultralytics/utils/events.py +2 -4
- ultralytics/utils/export/__init__.py +4 -236
- ultralytics/utils/export/engine.py +246 -0
- ultralytics/utils/export/imx.py +117 -63
- ultralytics/utils/export/tensorflow.py +231 -0
- ultralytics/utils/files.py +26 -30
- ultralytics/utils/git.py +9 -11
- ultralytics/utils/instance.py +30 -51
- ultralytics/utils/logger.py +212 -114
- ultralytics/utils/loss.py +601 -215
- ultralytics/utils/metrics.py +128 -156
- ultralytics/utils/nms.py +13 -16
- ultralytics/utils/ops.py +117 -166
- ultralytics/utils/patches.py +75 -21
- ultralytics/utils/plotting.py +75 -80
- ultralytics/utils/tal.py +125 -59
- ultralytics/utils/torch_utils.py +53 -79
- ultralytics/utils/tqdm.py +24 -21
- ultralytics/utils/triton.py +13 -19
- ultralytics/utils/tuner.py +19 -10
- dgenerate_ultralytics_headless-8.3.214.dist-info/RECORD +0 -283
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/entry_points.txt +0 -0
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/licenses/LICENSE +0 -0
- {dgenerate_ultralytics_headless-8.3.214.dist-info → dgenerate_ultralytics_headless-8.4.7.dist-info}/top_level.txt +0 -0
ultralytics/data/converter.py
CHANGED
|
@@ -15,18 +15,17 @@ import numpy as np
|
|
|
15
15
|
from PIL import Image
|
|
16
16
|
|
|
17
17
|
from ultralytics.utils import ASSETS_URL, DATASETS_DIR, LOGGER, NUM_THREADS, TQDM, YAML
|
|
18
|
-
from ultralytics.utils.checks import check_file
|
|
18
|
+
from ultralytics.utils.checks import check_file
|
|
19
19
|
from ultralytics.utils.downloads import download, zip_directory
|
|
20
20
|
from ultralytics.utils.files import increment_path
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def coco91_to_coco80_class() -> list[int]:
|
|
24
|
-
"""
|
|
25
|
-
Convert 91-index COCO class IDs to 80-index COCO class IDs.
|
|
24
|
+
"""Convert 91-index COCO class IDs to 80-index COCO class IDs.
|
|
26
25
|
|
|
27
26
|
Returns:
|
|
28
|
-
(list[int]): A list of 91 class IDs where the index represents the 80-index class ID and the value
|
|
29
|
-
|
|
27
|
+
(list[int]): A list of 91 class IDs where the index represents the 80-index class ID and the value is the
|
|
28
|
+
corresponding 91-index class ID.
|
|
30
29
|
"""
|
|
31
30
|
return [
|
|
32
31
|
0,
|
|
@@ -124,15 +123,11 @@ def coco91_to_coco80_class() -> list[int]:
|
|
|
124
123
|
|
|
125
124
|
|
|
126
125
|
def coco80_to_coco91_class() -> list[int]:
|
|
127
|
-
r"""
|
|
128
|
-
Convert 80-index (val2014) to 91-index (paper).
|
|
126
|
+
r"""Convert 80-index (val2014) to 91-index (paper).
|
|
129
127
|
|
|
130
128
|
Returns:
|
|
131
129
|
(list[int]): A list of 80 class IDs where each value is the corresponding 91-index class ID.
|
|
132
130
|
|
|
133
|
-
References:
|
|
134
|
-
https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/
|
|
135
|
-
|
|
136
131
|
Examples:
|
|
137
132
|
>>> import numpy as np
|
|
138
133
|
>>> a = np.loadtxt("data/coco.names", dtype="str", delimiter="\n")
|
|
@@ -143,6 +138,9 @@ def coco80_to_coco91_class() -> list[int]:
|
|
|
143
138
|
|
|
144
139
|
Convert the COCO to darknet format
|
|
145
140
|
>>> x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)]
|
|
141
|
+
|
|
142
|
+
References:
|
|
143
|
+
https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/
|
|
146
144
|
"""
|
|
147
145
|
return [
|
|
148
146
|
1,
|
|
@@ -236,8 +234,7 @@ def convert_coco(
|
|
|
236
234
|
cls91to80: bool = True,
|
|
237
235
|
lvis: bool = False,
|
|
238
236
|
):
|
|
239
|
-
"""
|
|
240
|
-
Convert COCO dataset annotations to a YOLO annotation format suitable for training YOLO models.
|
|
237
|
+
"""Convert COCO dataset annotations to a YOLO annotation format suitable for training YOLO models.
|
|
241
238
|
|
|
242
239
|
Args:
|
|
243
240
|
labels_dir (str, optional): Path to directory containing COCO dataset annotation files.
|
|
@@ -308,7 +305,7 @@ def convert_coco(
|
|
|
308
305
|
continue
|
|
309
306
|
|
|
310
307
|
cls = coco80[ann["category_id"] - 1] if cls91to80 else ann["category_id"] - 1 # class
|
|
311
|
-
box = [cls
|
|
308
|
+
box = [cls, *box.tolist()]
|
|
312
309
|
if box not in bboxes:
|
|
313
310
|
bboxes.append(box)
|
|
314
311
|
if use_segments and ann.get("segmentation") is not None:
|
|
@@ -321,7 +318,7 @@ def convert_coco(
|
|
|
321
318
|
else:
|
|
322
319
|
s = [j for i in ann["segmentation"] for j in i] # all segments concatenated
|
|
323
320
|
s = (np.array(s).reshape(-1, 2) / np.array([w, h])).reshape(-1).tolist()
|
|
324
|
-
s = [cls
|
|
321
|
+
s = [cls, *s]
|
|
325
322
|
segments.append(s)
|
|
326
323
|
if use_keypoints and ann.get("keypoints") is not None:
|
|
327
324
|
keypoints.append(
|
|
@@ -348,8 +345,7 @@ def convert_coco(
|
|
|
348
345
|
|
|
349
346
|
|
|
350
347
|
def convert_segment_masks_to_yolo_seg(masks_dir: str, output_dir: str, classes: int):
|
|
351
|
-
"""
|
|
352
|
-
Convert a dataset of segmentation mask images to the YOLO segmentation format.
|
|
348
|
+
"""Convert a dataset of segmentation mask images to the YOLO segmentation format.
|
|
353
349
|
|
|
354
350
|
This function takes the directory containing the binary format mask images and converts them into YOLO segmentation
|
|
355
351
|
format. The converted masks are saved in the specified output directory.
|
|
@@ -357,7 +353,7 @@ def convert_segment_masks_to_yolo_seg(masks_dir: str, output_dir: str, classes:
|
|
|
357
353
|
Args:
|
|
358
354
|
masks_dir (str): The path to the directory where all mask images (png, jpg) are stored.
|
|
359
355
|
output_dir (str): The path to the directory where the converted YOLO segmentation masks will be stored.
|
|
360
|
-
classes (int): Total classes in the dataset
|
|
356
|
+
classes (int): Total number of classes in the dataset, e.g., 80 for COCO.
|
|
361
357
|
|
|
362
358
|
Examples:
|
|
363
359
|
>>> from ultralytics.data.converter import convert_segment_masks_to_yolo_seg
|
|
@@ -424,8 +420,7 @@ def convert_segment_masks_to_yolo_seg(masks_dir: str, output_dir: str, classes:
|
|
|
424
420
|
|
|
425
421
|
|
|
426
422
|
def convert_dota_to_yolo_obb(dota_root_path: str):
|
|
427
|
-
"""
|
|
428
|
-
Convert DOTA dataset annotations to YOLO OBB (Oriented Bounding Box) format.
|
|
423
|
+
"""Convert DOTA dataset annotations to YOLO OBB (Oriented Bounding Box) format.
|
|
429
424
|
|
|
430
425
|
The function processes images in the 'train' and 'val' folders of the DOTA dataset. For each image, it reads the
|
|
431
426
|
associated label from the original labels directory and writes new labels in YOLO OBB format to a new directory.
|
|
@@ -517,8 +512,7 @@ def convert_dota_to_yolo_obb(dota_root_path: str):
|
|
|
517
512
|
|
|
518
513
|
|
|
519
514
|
def min_index(arr1: np.ndarray, arr2: np.ndarray):
|
|
520
|
-
"""
|
|
521
|
-
Find a pair of indexes with the shortest distance between two arrays of 2D points.
|
|
515
|
+
"""Find a pair of indexes with the shortest distance between two arrays of 2D points.
|
|
522
516
|
|
|
523
517
|
Args:
|
|
524
518
|
arr1 (np.ndarray): A NumPy array of shape (N, 2) representing N 2D points.
|
|
@@ -533,14 +527,14 @@ def min_index(arr1: np.ndarray, arr2: np.ndarray):
|
|
|
533
527
|
|
|
534
528
|
|
|
535
529
|
def merge_multi_segment(segments: list[list]):
|
|
536
|
-
"""
|
|
537
|
-
|
|
530
|
+
"""Merge multiple segments into one list by connecting the coordinates with the minimum distance between each
|
|
531
|
+
segment.
|
|
538
532
|
|
|
539
533
|
This function connects these coordinates with a thin line to merge all segments into one.
|
|
540
534
|
|
|
541
535
|
Args:
|
|
542
|
-
segments (list[list]): Original segmentations in COCO's JSON file.
|
|
543
|
-
|
|
536
|
+
segments (list[list]): Original segmentations in COCO's JSON file. Each element is a list of coordinates, like
|
|
537
|
+
[segmentation1, segmentation2,...].
|
|
544
538
|
|
|
545
539
|
Returns:
|
|
546
540
|
s (list[np.ndarray]): A list of connected segments represented as NumPy arrays.
|
|
@@ -584,14 +578,13 @@ def merge_multi_segment(segments: list[list]):
|
|
|
584
578
|
|
|
585
579
|
|
|
586
580
|
def yolo_bbox2segment(im_dir: str | Path, save_dir: str | Path | None = None, sam_model: str = "sam_b.pt", device=None):
|
|
587
|
-
"""
|
|
588
|
-
|
|
589
|
-
YOLO format. Generate segmentation data using SAM auto-annotator as needed.
|
|
581
|
+
"""Convert existing object detection dataset (bounding boxes) to segmentation dataset or oriented bounding box (OBB)
|
|
582
|
+
in YOLO format. Generate segmentation data using SAM auto-annotator as needed.
|
|
590
583
|
|
|
591
584
|
Args:
|
|
592
585
|
im_dir (str | Path): Path to image directory to convert.
|
|
593
|
-
save_dir (str | Path, optional): Path to save the generated labels, labels will be saved
|
|
594
|
-
|
|
586
|
+
save_dir (str | Path, optional): Path to save the generated labels, labels will be saved into `labels-segment`
|
|
587
|
+
in the same directory level of `im_dir` if save_dir is None.
|
|
595
588
|
sam_model (str): Segmentation model to use for intermediate segmentation data.
|
|
596
589
|
device (int | str, optional): The specific device to run SAM models.
|
|
597
590
|
|
|
@@ -648,12 +641,11 @@ def yolo_bbox2segment(im_dir: str | Path, save_dir: str | Path | None = None, sa
|
|
|
648
641
|
|
|
649
642
|
|
|
650
643
|
def create_synthetic_coco_dataset():
|
|
651
|
-
"""
|
|
652
|
-
Create a synthetic COCO dataset with random images based on filenames from label lists.
|
|
644
|
+
"""Create a synthetic COCO dataset with random images based on filenames from label lists.
|
|
653
645
|
|
|
654
|
-
This function downloads COCO labels, reads image filenames from label list files,
|
|
655
|
-
|
|
656
|
-
|
|
646
|
+
This function downloads COCO labels, reads image filenames from label list files, creates synthetic images for
|
|
647
|
+
train2017 and val2017 subsets, and organizes them in the COCO dataset structure. It uses multithreading to generate
|
|
648
|
+
images efficiently.
|
|
657
649
|
|
|
658
650
|
Examples:
|
|
659
651
|
>>> from ultralytics.data.converter import create_synthetic_coco_dataset
|
|
@@ -704,11 +696,10 @@ def create_synthetic_coco_dataset():
|
|
|
704
696
|
|
|
705
697
|
|
|
706
698
|
def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bool = False, zip: bool = False):
|
|
707
|
-
"""
|
|
708
|
-
Convert RGB images to multispectral images by interpolating across wavelength bands.
|
|
699
|
+
"""Convert RGB images to multispectral images by interpolating across wavelength bands.
|
|
709
700
|
|
|
710
|
-
This function takes RGB images and interpolates them to create multispectral images with a specified number
|
|
711
|
-
|
|
701
|
+
This function takes RGB images and interpolates them to create multispectral images with a specified number of
|
|
702
|
+
channels. It can process either a single image or a directory of images.
|
|
712
703
|
|
|
713
704
|
Args:
|
|
714
705
|
path (str | Path): Path to an image file or directory containing images to convert.
|
|
@@ -730,7 +721,7 @@ def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bo
|
|
|
730
721
|
path = Path(path)
|
|
731
722
|
if path.is_dir():
|
|
732
723
|
# Process directory
|
|
733
|
-
im_files =
|
|
724
|
+
im_files = [f for ext in (IMG_FORMATS - {"tif", "tiff"}) for f in path.rglob(f"*.{ext}")]
|
|
734
725
|
for im_path in im_files:
|
|
735
726
|
try:
|
|
736
727
|
convert_to_multispectral(im_path, n_channels)
|
|
@@ -756,24 +747,24 @@ def convert_to_multispectral(path: str | Path, n_channels: int = 10, replace: bo
|
|
|
756
747
|
|
|
757
748
|
|
|
758
749
|
async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Path | None = None) -> Path:
|
|
759
|
-
"""
|
|
760
|
-
Convert NDJSON dataset format to Ultralytics YOLO11 dataset structure.
|
|
750
|
+
"""Convert NDJSON dataset format to Ultralytics YOLO dataset structure.
|
|
761
751
|
|
|
762
|
-
This function converts datasets stored in NDJSON (Newline Delimited JSON) format to the standard YOLO
|
|
763
|
-
|
|
764
|
-
|
|
752
|
+
This function converts datasets stored in NDJSON (Newline Delimited JSON) format to the standard YOLO format. For
|
|
753
|
+
detection/segmentation/pose/obb tasks, it creates separate directories for images and labels. For classification
|
|
754
|
+
tasks, it creates the ImageNet-style {split}/{class_name}/ folder structure. It supports parallel processing for
|
|
755
|
+
efficient conversion of large datasets and can download images from URLs.
|
|
765
756
|
|
|
766
757
|
The NDJSON format consists of:
|
|
767
|
-
- First line: Dataset metadata with class names and configuration
|
|
758
|
+
- First line: Dataset metadata with class names, task type, and configuration
|
|
768
759
|
- Subsequent lines: Individual image records with annotations and optional URLs
|
|
769
760
|
|
|
770
761
|
Args:
|
|
771
762
|
ndjson_path (Union[str, Path]): Path to the input NDJSON file containing dataset information.
|
|
772
|
-
output_path (Optional[Union[str, Path]], optional): Directory where the converted YOLO dataset
|
|
773
|
-
|
|
763
|
+
output_path (Optional[Union[str, Path]], optional): Directory where the converted YOLO dataset will be saved. If
|
|
764
|
+
None, uses the parent directory of the NDJSON file. Defaults to None.
|
|
774
765
|
|
|
775
766
|
Returns:
|
|
776
|
-
(Path): Path to the generated data.yaml file
|
|
767
|
+
(Path): Path to the generated data.yaml file (detection) or dataset directory (classification).
|
|
777
768
|
|
|
778
769
|
Examples:
|
|
779
770
|
Convert a local NDJSON file:
|
|
@@ -785,9 +776,11 @@ async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Pat
|
|
|
785
776
|
|
|
786
777
|
Use with YOLO training
|
|
787
778
|
>>> from ultralytics import YOLO
|
|
788
|
-
>>> model = YOLO("
|
|
779
|
+
>>> model = YOLO("yolo26n.pt")
|
|
789
780
|
>>> model.train(data="https://github.com/ultralytics/assets/releases/download/v0.0.0/coco8-ndjson.ndjson")
|
|
790
781
|
"""
|
|
782
|
+
from ultralytics.utils.checks import check_requirements
|
|
783
|
+
|
|
791
784
|
check_requirements("aiohttp")
|
|
792
785
|
import aiohttp
|
|
793
786
|
|
|
@@ -800,50 +793,68 @@ async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Pat
|
|
|
800
793
|
dataset_dir = output_path / ndjson_path.stem
|
|
801
794
|
splits = {record["split"] for record in image_records}
|
|
802
795
|
|
|
803
|
-
#
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
data_yaml["names"] = {int(k): v for k, v in dataset_record.get("class_names", {}).items()}
|
|
807
|
-
data_yaml.pop("class_names")
|
|
796
|
+
# Check if this is a classification dataset
|
|
797
|
+
is_classification = dataset_record.get("task") == "classify"
|
|
798
|
+
class_names = {int(k): v for k, v in dataset_record.get("class_names", {}).items()}
|
|
808
799
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
800
|
+
# Create base directories
|
|
801
|
+
dataset_dir.mkdir(parents=True, exist_ok=True)
|
|
802
|
+
data_yaml = None
|
|
803
|
+
|
|
804
|
+
if not is_classification:
|
|
805
|
+
# Detection/segmentation/pose/obb: prepare YAML and create base structure
|
|
806
|
+
data_yaml = dict(dataset_record)
|
|
807
|
+
data_yaml["names"] = class_names
|
|
808
|
+
data_yaml.pop("class_names", None)
|
|
809
|
+
data_yaml.pop("type", None) # Remove NDJSON-specific fields
|
|
810
|
+
for split in sorted(splits):
|
|
811
|
+
(dataset_dir / "images" / split).mkdir(parents=True, exist_ok=True)
|
|
812
|
+
(dataset_dir / "labels" / split).mkdir(parents=True, exist_ok=True)
|
|
813
|
+
data_yaml[split] = f"images/{split}"
|
|
813
814
|
|
|
814
815
|
async def process_record(session, semaphore, record):
|
|
815
816
|
"""Process single image record with async session."""
|
|
816
817
|
async with semaphore:
|
|
817
818
|
split, original_name = record["split"], record["file"]
|
|
818
|
-
label_path = dataset_dir / "labels" / split / f"{Path(original_name).stem}.txt"
|
|
819
|
-
image_path = dataset_dir / "images" / split / original_name
|
|
820
|
-
|
|
821
819
|
annotations = record.get("annotations", {})
|
|
822
|
-
lines_to_write = []
|
|
823
|
-
for key in annotations.keys():
|
|
824
|
-
lines_to_write = [" ".join(map(str, item)) for item in annotations[key]]
|
|
825
|
-
break
|
|
826
|
-
if "classification" in annotations:
|
|
827
|
-
lines_to_write = [str(cls) for cls in annotations["classification"]]
|
|
828
|
-
|
|
829
|
-
label_path.write_text("\n".join(lines_to_write) + "\n" if lines_to_write else "")
|
|
830
820
|
|
|
821
|
+
if is_classification:
|
|
822
|
+
# Classification: place image in {split}/{class_name}/ folder
|
|
823
|
+
class_ids = annotations.get("classification", [])
|
|
824
|
+
class_id = class_ids[0] if class_ids else 0
|
|
825
|
+
class_name = class_names.get(class_id, str(class_id))
|
|
826
|
+
image_path = dataset_dir / split / class_name / original_name
|
|
827
|
+
else:
|
|
828
|
+
# Detection: write label file and place image in images/{split}/
|
|
829
|
+
image_path = dataset_dir / "images" / split / original_name
|
|
830
|
+
label_path = dataset_dir / "labels" / split / f"{Path(original_name).stem}.txt"
|
|
831
|
+
lines_to_write = []
|
|
832
|
+
for key in annotations.keys():
|
|
833
|
+
lines_to_write = [" ".join(map(str, item)) for item in annotations[key]]
|
|
834
|
+
break
|
|
835
|
+
label_path.write_text("\n".join(lines_to_write) + "\n" if lines_to_write else "")
|
|
836
|
+
|
|
837
|
+
# Download image if URL provided and file doesn't exist
|
|
831
838
|
if http_url := record.get("url"):
|
|
832
839
|
if not image_path.exists():
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
840
|
+
image_path.parent.mkdir(parents=True, exist_ok=True)
|
|
841
|
+
# Retry with exponential backoff (3 attempts: 0s, 2s, 4s delays)
|
|
842
|
+
for attempt in range(3):
|
|
843
|
+
try:
|
|
844
|
+
async with session.get(http_url, timeout=aiohttp.ClientTimeout(total=30)) as response:
|
|
845
|
+
response.raise_for_status()
|
|
846
|
+
image_path.write_bytes(await response.read())
|
|
847
|
+
return True
|
|
848
|
+
except Exception as e:
|
|
849
|
+
if attempt < 2: # Don't sleep after last attempt
|
|
850
|
+
await asyncio.sleep(2**attempt) # 1s, 2s backoff
|
|
851
|
+
else:
|
|
852
|
+
LOGGER.warning(f"Failed to download {http_url} after 3 attempts: {e}")
|
|
853
|
+
return False
|
|
843
854
|
return True
|
|
844
855
|
|
|
845
|
-
# Process all images with async downloads
|
|
846
|
-
semaphore = asyncio.Semaphore(
|
|
856
|
+
# Process all images with async downloads (limit connections for small datasets)
|
|
857
|
+
semaphore = asyncio.Semaphore(min(128, len(image_records)))
|
|
847
858
|
async with aiohttp.ClientSession() as session:
|
|
848
859
|
pbar = TQDM(
|
|
849
860
|
total=len(image_records),
|
|
@@ -855,11 +866,21 @@ async def convert_ndjson_to_yolo(ndjson_path: str | Path, output_path: str | Pat
|
|
|
855
866
|
pbar.update(1)
|
|
856
867
|
return result
|
|
857
868
|
|
|
858
|
-
await asyncio.gather(*[tracked_process(record) for record in image_records])
|
|
869
|
+
results = await asyncio.gather(*[tracked_process(record) for record in image_records])
|
|
859
870
|
pbar.close()
|
|
860
871
|
|
|
861
|
-
#
|
|
862
|
-
|
|
863
|
-
|
|
872
|
+
# Validate images were downloaded successfully
|
|
873
|
+
success_count = sum(1 for r in results if r)
|
|
874
|
+
if success_count == 0:
|
|
875
|
+
raise RuntimeError(f"Failed to download any images from {ndjson_path}. Check network connection and URLs.")
|
|
876
|
+
if success_count < len(image_records):
|
|
877
|
+
LOGGER.warning(f"Downloaded {success_count}/{len(image_records)} images from {ndjson_path}")
|
|
864
878
|
|
|
865
|
-
|
|
879
|
+
if is_classification:
|
|
880
|
+
# Classification: return dataset directory (check_cls_dataset expects a directory path)
|
|
881
|
+
return dataset_dir
|
|
882
|
+
else:
|
|
883
|
+
# Detection: write data.yaml and return its path
|
|
884
|
+
yaml_path = dataset_dir / "data.yaml"
|
|
885
|
+
YAML.save(yaml_path, data_yaml)
|
|
886
|
+
return yaml_path
|