Reference for ultralytics/data/base.py#
This page is sourced from https://github.com/ultralytics/ultralytics/blob/main/ultralytics/data/base.py. Have an improvement or example to add? Open a Pull Request — thank you! 🙏
Class ultralytics.data.base.BaseDataset#
BaseDataset(
img_path: str | list[str],
imgsz: int = 640,
cache: bool | str | None = False,
augment: bool = True,
hyp: IterableSimpleNamespace = DEFAULT_CFG,
prefix: str = "",
rect: bool = False,
batch_size: int = 16,
stride: int = 32,
pad: float = 0.5,
single_cls: bool = False,
classes: list[int] | None = None,
fraction: float = 1.0,
channels: int = 3,
)Bases: Dataset
Base dataset class for loading and processing image data.
This class provides core functionality for loading images, caching, and preparing data for training and inference in object detection tasks.
Args
| Name | Type | Description | Default |
|---|---|---|---|
img_path | str | list[str] | Path to the folder containing images or list of image paths. | required |
imgsz | int | Image size for resizing. | 640 |
cache | bool | str | None | Cache images to RAM (True or 'ram') or disk ('disk'); False or None disables. | False |
augment | bool | If True, data augmentation is applied. | True |
hyp | IterableSimpleNamespace | Hyperparameters to apply data augmentation. | DEFAULT_CFG |
prefix | str | Prefix to print in log messages. | "" |
rect | bool | If True, rectangular training is used. | False |
batch_size | int | Size of batches. | 16 |
stride | int | Stride used in the model. | 32 |
pad | float | Padding value. | 0.5 |
single_cls | bool | If True, single class training is used. | False |
classes | list[int], optional | List of included classes. | None |
fraction | float | int | Dataset ratio or image count to use. | 1.0 |
channels | int | Number of channels in the images (1 for grayscale, 3 for color). Color images loaded with OpenCV are in BGR channel order. | 3 |
Attributes
| Name | Type | Description |
|---|---|---|
img_path | str | list[str] | Path to the folder containing images. |
imgsz | int | Target image size for resizing. |
augment | bool | Whether to apply data augmentation. |
single_cls | bool | Whether to treat all objects as a single class. |
prefix | str | Prefix to print in log messages. |
fraction | float | int | Dataset ratio or image count to use. |
channels | int | Number of channels in the images (1 for grayscale, 3 for color). Color images loaded with OpenCV are in BGR channel order. |
cv2_flag | int | OpenCV flag for reading images. |
im_files | list[str] | List of image file paths. |
labels | list[dict] | List of label data dictionaries. |
ni | int | Number of images in the dataset. |
rect | bool | Whether to use rectangular training. |
batch_size | int | Size of batches. |
stride | int | Stride used in the model. |
pad | float | Padding value. |
buffer | list | Buffer for mosaic images. |
max_buffer_length | int | Maximum buffer size. |
ims | list | List of loaded images. |
im_hw0 | list | List of original image dimensions (h, w). |
im_hw | list | List of resized image dimensions (h, w). |
npy_files | list[Path] | List of numpy file paths. |
cache | str | None | Cache setting ('ram', 'disk', or None for no caching). |
transforms | callable | Image transformation function. |
batch_shapes | np.ndarray | Batch shapes for rectangular training. |
batch | np.ndarray | Batch index of each image. |
Methods
| Name | Description |
|---|---|
__getitem__ | Return transformed label information for given index. |
__len__ | Return the length of the labels list for the dataset. |
build_transforms | Build the augmentation pipeline; subclasses must override this. |
cache_images | Cache images to memory or disk for faster training. |
cache_images_to_disk | Save an image as an *.npy file for faster loading. |
check_cache_disk | Check if there's enough disk space for caching images. |
check_cache_ram | Check if there's enough RAM for caching images. |
get_image_and_label | Get and return label information from the dataset. |
get_img_files | Read image files from the specified path. |
get_labels | Users can customize their own format here. |
load_image | Load an image from dataset index 'i'. |
set_rectangle | Sort images by aspect ratio and set batch shapes for rectangular training. |
update_labels | Update labels to include only specified classes, and set all classes to 0 if single_cls is True. |
update_labels_info | Customize your label format here. |
ultralytics/data/base.py
class BaseDataset(Dataset):
"""Base dataset class for loading and processing image data.
This class provides core functionality for loading images, caching, and preparing data for training and inference in
object detection tasks.
Attributes:
img_path (str | list[str]): Path to the folder containing images.
imgsz (int): Target image size for resizing.
augment (bool): Whether to apply data augmentation.
single_cls (bool): Whether to treat all objects as a single class.
prefix (str): Prefix to print in log messages.
fraction (float | int): Dataset ratio or image count to use.
channels (int): Number of channels in the images (1 for grayscale, 3 for color). Color images loaded with OpenCV
are in BGR channel order.
cv2_flag (int): OpenCV flag for reading images.
im_files (list[str]): List of image file paths.
labels (list[dict]): List of label data dictionaries.
ni (int): Number of images in the dataset.
rect (bool): Whether to use rectangular training.
batch_size (int): Size of batches.
stride (int): Stride used in the model.
pad (float): Padding value.
buffer (list): Buffer for mosaic images.
max_buffer_length (int): Maximum buffer size.
ims (list): List of loaded images.
im_hw0 (list): List of original image dimensions (h, w).
im_hw (list): List of resized image dimensions (h, w).
npy_files (list[Path]): List of numpy file paths.
cache (str | None): Cache setting ('ram', 'disk', or None for no caching).
transforms (callable): Image transformation function.
batch_shapes (np.ndarray): Batch shapes for rectangular training.
batch (np.ndarray): Batch index of each image.
Methods:
get_img_files: Read image files from the specified path.
update_labels: Update labels to include only specified classes.
load_image: Load an image from the dataset.
cache_images: Cache images to memory or disk.
cache_images_to_disk: Save an image as an *.npy file for faster loading.
check_cache_disk: Check image caching requirements vs available disk space.
check_cache_ram: Check image caching requirements vs available memory.
set_rectangle: Sort images by aspect ratio and set batch shapes for rectangular training.
get_image_and_label: Get and return label information from the dataset.
update_labels_info: Custom label format method to be implemented by subclasses.
build_transforms: Build transformation pipeline to be implemented by subclasses.
get_labels: Get labels method to be implemented by subclasses.
"""
class _ImageCache:
"""Store images in one tensor, shared copy-on-write by fork workers and as shared memory by pickled ones."""
def __init__(self, images: list[np.ndarray]):
"""Pack images into one contiguous uint8 tensor and their layouts into NumPy arrays."""
self.shapes = np.array([im.shape for im in images])
self.dtypes = np.array([im.dtype.str for im in images])
self.offsets = np.concatenate(([0], np.cumsum([im.nbytes for im in images])))
self.buffer = torch.empty(int(self.offsets[-1]), dtype=torch.uint8)
buffer = self.buffer.numpy()
for i, im in enumerate(images):
buffer[self.offsets[i] : self.offsets[i + 1]] = im.reshape(-1).view(np.uint8)
images[i] = None
def __getitem__(self, i: int) -> np.ndarray:
"""Return an image view by index."""
i = range(len(self.shapes))[i]
return (
self.buffer.numpy()[self.offsets[i] : self.offsets[i + 1]].view(self.dtypes[i]).reshape(self.shapes[i])
)
def __getstate__(self) -> dict[str, Any]:
"""Pickle the buffer by value, as each worker's own copy, when Linux shared memory is too small to share it."""
state = self.__dict__.copy()
shm = Path("/dev/shm") # also carries worker batches, so require the same 2x margin as check_cache_ram()
if not self.buffer.is_shared() and shm.is_dir() and shutil.disk_usage(shm).free < 2 * self.offsets[-1]:
LOGGER.warning(f"{shm} too small to share {self.offsets[-1] / (1 << 30):.1f}GB image cache, copying it")
state["buffer"] = self.buffer.numpy()
return state
def __setstate__(self, state: dict[str, Any]):
"""Restore the buffer as a tensor."""
state["buffer"] = torch.as_tensor(state["buffer"])
self.__dict__.update(state)
def __init__(
self,
img_path: str | list[str],
imgsz: int = 640,
cache: bool | str | None = False,
augment: bool = True,
hyp: IterableSimpleNamespace = DEFAULT_CFG,
prefix: str = "",
rect: bool = False,
batch_size: int = 16,
stride: int = 32,
pad: float = 0.5,
single_cls: bool = False,
classes: list[int] | None = None,
fraction: float = 1.0,
channels: int = 3,
):
"""Initialize BaseDataset with given configuration and options.
Args:
img_path (str | list[str]): Path to the folder containing images or list of image paths.
imgsz (int): Image size for resizing.
cache (bool | str | None): Cache images to RAM (True or 'ram') or disk ('disk'); False or None disables.
augment (bool): If True, data augmentation is applied.
hyp (IterableSimpleNamespace): Hyperparameters to apply data augmentation.
prefix (str): Prefix to print in log messages.
rect (bool): If True, rectangular training is used.
batch_size (int): Size of batches.
stride (int): Stride used in the model.
pad (float): Padding value.
single_cls (bool): If True, single class training is used.
classes (list[int], optional): List of included classes.
fraction (float | int): Dataset ratio or image count to use.
channels (int): Number of channels in the images (1 for grayscale, 3 for color). Color images loaded with
OpenCV are in BGR channel order.
"""
super().__init__()
self.img_path = img_path
self.imgsz = imgsz
self.augment = augment
self.single_cls = single_cls
self.prefix = prefix
self.fraction = get_split_fraction(fraction, "train")
self.channels = channels
self.cv2_flag = {1: cv2.IMREAD_GRAYSCALE, 3: cv2.IMREAD_COLOR}.get(channels, cv2.IMREAD_UNCHANGED)
self.im_files = self.get_img_files(self.img_path)
self.labels = self.get_labels()
self.update_labels(include_class=classes) # single_cls and include_class
self.ni = len(self.labels) # number of images
self.rect = rect
self.batch_size = batch_size
self.stride = stride
self.pad = pad
if self.rect:
assert self.batch_size is not None
self.set_rectangle()
# Buffer thread for mosaic images
self.buffer = [] # indices of recently loaded images kept in memory for mosaic
self.max_buffer_length = min((self.ni, self.batch_size * 8, 1000)) if self.augment else 0
# Cache images (options are cache = True, False, None, "ram", "disk")
self.ims, self.im_hw0, self.im_hw = [None] * self.ni, [None] * self.ni, [None] * self.ni
# image.npy caches persist across runs and versions: renaming, moving, or invalidating them orphans every
# existing user cache and forces a full recache, so keep this exact naming
self.npy_files = [Path(f).with_suffix(".npy") for f in self.im_files]
self.cache = cache.lower() if isinstance(cache, str) else "ram" if cache is True else None
if self.cache == "ram" and self.check_cache_ram():
if hyp.deterministic:
LOGGER.warning(
"cache='ram' may produce non-deterministic training results. "
"Consider cache='disk' as a deterministic alternative if your disk space allows."
)
self.cache_images()
elif self.cache == "disk" and self.check_cache_disk():
self.cache_images()
# Transforms
self.transforms = self.build_transforms(hyp=copy(hyp)) # subclasses zero unsupported keys, never the caller'sMethod ultralytics.data.base.BaseDataset.__getitem__#
def __getitem__(self, index: int) -> dict[str, Any]Return transformed label information for given index.
Args
| Name | Type | Description | Default |
|---|---|---|---|
index | int | required |
ultralytics/data/base.py
def __getitem__(self, index: int) -> dict[str, Any]:
"""Return transformed label information for given index."""
return self.transforms(self.get_image_and_label(index))Method ultralytics.data.base.BaseDataset.__len__#
def __len__(self) -> intReturn the length of the labels list for the dataset.
ultralytics/data/base.py
def __len__(self) -> int:
"""Return the length of the labels list for the dataset."""
return len(self.labels)Method ultralytics.data.base.BaseDataset.build_transforms#
def build_transforms(self, hyp: IterableSimpleNamespace)Build the augmentation pipeline; subclasses must override this.
Args
| Name | Type | Description | Default |
|---|---|---|---|
hyp | IterableSimpleNamespace | Hyperparameters for the transforms. | required |
Returns
| Type | Description |
|---|---|
Compose | Composed transforms applied to each sample. |
Examples
>>> from ultralytics.data.augment import Compose
>>> from ultralytics.data.base import BaseDataset
>>> class CustomDataset(BaseDataset):
... def build_transforms(self, hyp):
... return Compose([]) # add training or validation transforms hereRaises
| Type | Description |
|---|---|
NotImplementedError | If a subclass does not override this method. |
ultralytics/data/base.py
def build_transforms(self, hyp: IterableSimpleNamespace):
"""Build the augmentation pipeline; subclasses must override this.
Args:
hyp (IterableSimpleNamespace): Hyperparameters for the transforms.
Returns:
(Compose): Composed transforms applied to each sample.
Raises:
NotImplementedError: If a subclass does not override this method.
Examples:
>>> from ultralytics.data.augment import Compose
>>> from ultralytics.data.base import BaseDataset
>>> class CustomDataset(BaseDataset):
... def build_transforms(self, hyp):
... return Compose([]) # add training or validation transforms here
"""
raise NotImplementedErrorMethod ultralytics.data.base.BaseDataset.cache_images#
def cache_images(self) -> NoneCache images to memory or disk for faster training.
ultralytics/data/base.py
def cache_images(self) -> None:
"""Cache images to memory or disk for faster training."""
b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes
fcn, storage = (self.cache_images_to_disk, "Disk") if self.cache == "disk" else (self.load_image, "RAM")
with ThreadPool(NUM_THREADS) as pool:
results = pool.imap(fcn, range(self.ni))
pbar = TQDM(enumerate(results), total=self.ni, disable=LOCAL_RANK > 0)
for i, x in pbar:
if self.cache == "disk":
b += self.npy_files[i].stat().st_size if self.npy_files[i].exists() else 0 # failed writes unlink
else: # 'ram'
self.ims[i], self.im_hw0[i], self.im_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i)
b += self.ims[i].nbytes
pbar.desc = f"{self.prefix}Caching images ({b / gb:.1f}GB {storage})"
pbar.close()
if self.cache == "ram":
self.ims = self._ImageCache(self.ims)Method ultralytics.data.base.BaseDataset.cache_images_to_disk#
def cache_images_to_disk(self, i: int) -> NoneSave an image as an *.npy file for faster loading.
Args
| Name | Type | Description | Default |
|---|---|---|---|
i | int | required |
ultralytics/data/base.py
def cache_images_to_disk(self, i: int) -> None:
"""Save an image as an *.npy file for faster loading."""
f = self.npy_files[i]
if not f.exists() or f.stat().st_mtime < Path(self.im_files[i]).stat().st_mtime: # missing or stale
try:
np.save(f.as_posix(), imread(self.im_files[i], flags=self.cv2_flag), allow_pickle=False)
except Exception as e:
f.unlink(missing_ok=True)
LOGGER.warning(f"{self.prefix}Failed to cache image {f}: {e}")Method ultralytics.data.base.BaseDataset.check_cache_disk#
def check_cache_disk(self, safety_margin: float = 0.1) -> boolCheck if there's enough disk space for caching images.
Args
| Name | Type | Description | Default |
|---|---|---|---|
safety_margin | float | Safety margin factor for disk space calculation. | 0.1 |
Returns
| Type | Description |
|---|---|
bool | True if there's enough disk space, False otherwise. |
ultralytics/data/base.py
def check_cache_disk(self, safety_margin: float = 0.1) -> bool:
"""Check if there's enough disk space for caching images.
Args:
safety_margin (float): Safety margin factor for disk space calculation.
Returns:
(bool): True if there's enough disk space, False otherwise.
"""
b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes
n = min(self.ni, 30) # extrapolate from 30 random images
for _ in range(n):
im_file = random.choice(self.im_files)
im = imread(im_file, flags=self.cv2_flag)
if im is None:
continue
b += im.nbytes
if not os.access(Path(im_file).parent, os.W_OK):
self.cache = None
LOGGER.warning(f"{self.prefix}Skipping caching images to disk, directory not writable")
return False
disk_required = b * self.ni / n * (1 + safety_margin) # bytes required to cache dataset to disk
total, _used, free = shutil.disk_usage(Path(self.im_files[0]).parent)
if disk_required > free:
self.cache = None
LOGGER.warning(
f"{self.prefix}{disk_required / gb:.1f}GB disk space required, "
f"with {int(safety_margin * 100)}% safety margin but only "
f"{free / gb:.1f}/{total / gb:.1f}GB free, not caching images to disk"
)
return False
return TrueMethod ultralytics.data.base.BaseDataset.check_cache_ram#
def check_cache_ram(self, safety_margin: float = 1.0) -> boolCheck if there's enough RAM for caching images.
Args
| Name | Type | Description | Default |
|---|---|---|---|
safety_margin | float | Safety margin factor for RAM calculation. | 1.0 |
Returns
| Type | Description |
|---|---|
bool | True if there's enough RAM, False otherwise. |
ultralytics/data/base.py
def check_cache_ram(self, safety_margin: float = 1.0) -> bool:
"""Check if there's enough RAM for caching images.
Args:
safety_margin (float): Safety margin factor for RAM calculation.
Returns:
(bool): True if there's enough RAM, False otherwise.
"""
b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes
n = min(self.ni, 30) # extrapolate from 30 random images
for _ in range(n):
b += self.load_image(random.randrange(self.ni))[0].nbytes
mem_required = b * self.ni / n * (1 + safety_margin) # bytes required to cache dataset into RAM
mem = __import__("psutil").virtual_memory()
if mem_required > mem.available:
self.cache = None
LOGGER.warning(
f"{self.prefix}{mem_required / gb:.1f}GB RAM required to cache images "
f"with {int(safety_margin * 100)}% safety margin but only "
f"{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, not caching images"
)
return False
return TrueMethod ultralytics.data.base.BaseDataset.get_image_and_label#
def get_image_and_label(self, index: int) -> dict[str, Any]Get and return label information from the dataset.
Args
| Name | Type | Description | Default |
|---|---|---|---|
index | int | Index of the image to retrieve. | required |
Returns
| Type | Description |
|---|---|
dict[str, Any] | Label dictionary with image and metadata. |
ultralytics/data/base.py
def get_image_and_label(self, index: int) -> dict[str, Any]:
"""Get and return label information from the dataset.
Args:
index (int): Index of the image to retrieve.
Returns:
(dict[str, Any]): Label dictionary with image and metadata.
"""
label = deepcopy(self.labels[index]) # requires deepcopy() https://github.com/ultralytics/ultralytics/pull/1948
label.pop("shape", None) # shape is for rect, remove it
label["img"], label["ori_shape"], label["resized_shape"] = self.load_image(index)
label["ratio_pad"] = (
label["resized_shape"][0] / label["ori_shape"][0],
label["resized_shape"][1] / label["ori_shape"][1],
) # for evaluation
if self.rect:
label["rect_shape"] = self.batch_shapes[self.batch[index]]
return self.update_labels_info(label)Method ultralytics.data.base.BaseDataset.get_img_files#
def get_img_files(self, img_path: str | list[str]) -> list[str]Read image files from the specified path.
Args
| Name | Type | Description | Default |
|---|---|---|---|
img_path | str | list[str] | Path or list of paths to image directories or files. | required |
Returns
| Type | Description |
|---|---|
list[str] | List of image file paths. |
Raises
| Type | Description |
|---|---|
FileNotFoundError | If no images are found or the path doesn't exist. |
ultralytics/data/base.py
def get_img_files(self, img_path: str | list[str]) -> list[str]:
"""Read image files from the specified path.
Args:
img_path (str | list[str]): Path or list of paths to image directories or files.
Returns:
(list[str]): List of image file paths.
Raises:
FileNotFoundError: If no images are found or the path doesn't exist.
"""
try:
f = [] # image files
for p in img_path if isinstance(img_path, list) else [img_path]:
p = Path(p) # os-agnostic
if p.is_dir(): # dir
f += glob.glob(str(Path(glob.escape(p)) / "**" / "*.*"), recursive=True)
# F = list(p.rglob('*.*')) # pathlib
elif p.is_file(): # file
with open(p, encoding="utf-8") as t:
t = t.read().strip().splitlines()
parent = str(p.parent) + os.sep
f += [x.replace("./", parent, 1) if x.startswith("./") else x for x in t] # local to global
# F += [p.parent / x.lstrip(os.sep) for x in t] # local to global (pathlib)
else:
raise FileNotFoundError(f"{self.prefix}{p} does not exist")
im_files = sorted(x.replace("/", os.sep) for x in f if x.rpartition(".")[-1].lower() in IMG_FORMATS)
# self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS]) # pathlib
assert im_files, f"{self.prefix}No images found in {img_path}. {FORMATS_HELP_MSG}"
except Exception as e:
raise FileNotFoundError(f"{self.prefix}Error loading data from {img_path}\n{HELP_URL}") from e
count = self.fraction if isinstance(self.fraction, int) else max(1, round(len(im_files) * self.fraction))
im_files = im_files[:count] if count < len(im_files) else im_files
check_file_speeds(im_files, prefix=self.prefix) # check image read speeds
return im_filesMethod ultralytics.data.base.BaseDataset.get_labels#
def get_labels(self) -> list[dict[str, Any]]Users can customize their own format here.
Examples
Ensure output is a dictionary with the following keys:
>>> dict(
... im_file=im_file,
... shape=shape, # format: (height, width)
... cls=cls,
... bboxes=bboxes, # xywh
... segments=segments, # xy
... keypoints=keypoints, # xy
... normalized=True, # or False
... bbox_format="xywh", # or xyxy, ltwh
... )ultralytics/data/base.py
def get_labels(self) -> list[dict[str, Any]]:
"""Users can customize their own format here.
Examples:
Ensure output is a dictionary with the following keys:
>>> dict(
... im_file=im_file,
... shape=shape, # format: (height, width)
... cls=cls,
... bboxes=bboxes, # xywh
... segments=segments, # xy
... keypoints=keypoints, # xy
... normalized=True, # or False
... bbox_format="xywh", # or xyxy, ltwh
... )
"""
raise NotImplementedErrorMethod ultralytics.data.base.BaseDataset.load_image#
def load_image(
self, i: int, rect_mode: bool = True, resize_short: bool = False
) -> tuple[np.ndarray, tuple[int, int], tuple[int, int]]Load an image from dataset index 'i'.
An existing *.npy cache is the fastest image read, so it is loaded in any cache mode unless it is older than its image. With cache='disk', cache_images_to_disk has already refreshed stale files, so that check is skipped.
Args
| Name | Type | Description | Default |
|---|---|---|---|
i | int | Index of the image to load. | required |
rect_mode | bool | Whether to use rectangular resizing (long side to imgsz). | True |
resize_short | bool | Whether to resize the shorter side (instead of the longer side) to imgsz while maintaining aspect ratio. Only used when rect_mode is True. | False |
Returns
| Type | Description |
|---|---|
im (np.ndarray) | Loaded image as a NumPy array. |
hw_original (tuple[int, int]) | Original image dimensions in (height, width) format. |
hw_resized (tuple[int, int]) | Resized image dimensions in (height, width) format. |
Raises
| Type | Description |
|---|---|
FileNotFoundError | If the image file is not found. |
ultralytics/data/base.py
def load_image(
self, i: int, rect_mode: bool = True, resize_short: bool = False
) -> tuple[np.ndarray, tuple[int, int], tuple[int, int]]:
"""Load an image from dataset index 'i'.
An existing *.npy cache is the fastest image read, so it is loaded in any cache mode unless it is older than its
image. With cache='disk', `cache_images_to_disk` has already refreshed stale files, so that check is skipped.
Args:
i (int): Index of the image to load.
rect_mode (bool): Whether to use rectangular resizing (long side to imgsz).
resize_short (bool): Whether to resize the shorter side (instead of the longer side) to imgsz while
maintaining aspect ratio. Only used when rect_mode is True.
Returns:
im (np.ndarray): Loaded image as a NumPy array.
hw_original (tuple[int, int]): Original image dimensions in (height, width) format.
hw_resized (tuple[int, int]): Resized image dimensions in (height, width) format.
Raises:
FileNotFoundError: If the image file is not found.
"""
im, f, fn = self.ims[i], self.im_files[i], self.npy_files[i]
if im is None: # not cached in RAM
if fn.exists() and (self.cache == "disk" or fn.stat().st_mtime >= Path(f).stat().st_mtime):
try:
im = np.load(fn)
npy_channels = im.shape[-1] if im.ndim >= 3 else 1
if npy_channels != self.channels or im.dtype == np.uint16:
LOGGER.warning(
f"{self.prefix}Refreshing stale *.npy image file {fn} with {npy_channels} channels and "
f"{im.dtype} dtype"
)
im = imread(f, flags=self.cv2_flag)
np.save(fn.as_posix(), im, allow_pickle=False) # keep disk-cache benefits for this image
except Exception as e:
LOGGER.warning(f"{self.prefix}Removing corrupt *.npy image file {fn} due to: {e}")
Path(fn).unlink(missing_ok=True)
im = imread(f, flags=self.cv2_flag) # BGR
else: # read image
im = imread(f, flags=self.cv2_flag) # BGR
if im is None:
raise FileNotFoundError(f"Image Not Found {f}")
h0, w0 = im.shape[:2] # orig hw
if rect_mode: # resize long side to imgsz while maintaining aspect ratio
if resize_short: # resize short side to imgsz while maintaining aspect ratio
r = self.imgsz / min(h0, w0) # ratio
if r != 1: # if sizes are not equal
w, h = (math.ceil(w0 * r), self.imgsz) if h0 < w0 else (self.imgsz, math.ceil(h0 * r))
im = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR)
else:
r = self.imgsz / max(h0, w0) # ratio
if r != 1: # if sizes are not equal
w, h = (min(math.ceil(w0 * r), self.imgsz), min(math.ceil(h0 * r), self.imgsz))
im = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR)
elif not (h0 == w0 == self.imgsz): # resize by stretching image to square imgsz
im = cv2.resize(im, (self.imgsz, self.imgsz), interpolation=cv2.INTER_LINEAR)
if im.ndim == 2:
im = im[..., None]
# Add to buffer if training with augmentations
if self.augment and self.cache != "ram":
self.ims[i], self.im_hw0[i], self.im_hw[i] = im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized
self.buffer.append(i)
if 1 < len(self.buffer) >= self.max_buffer_length: # prevent empty buffer
j = self.buffer.pop(0)
if self.cache != "ram":
self.ims[j], self.im_hw0[j], self.im_hw[j] = None, None, None
return im, (h0, w0), im.shape[:2]
return self.ims[i], self.im_hw0[i], self.im_hw[i]Method ultralytics.data.base.BaseDataset.set_rectangle#
def set_rectangle(self) -> NoneSort images by aspect ratio and set batch shapes for rectangular training.
ultralytics/data/base.py
def set_rectangle(self) -> None:
"""Sort images by aspect ratio and set batch shapes for rectangular training."""
bi = np.floor(np.arange(self.ni) / self.batch_size).astype(int) # batch index
nb = bi[-1] + 1 # number of batches
s = np.array([x.pop("shape") for x in self.labels]) # hw
ar = s[:, 0] / s[:, 1] # aspect ratio
irect = ar.argsort()
self.im_files = [self.im_files[i] for i in irect]
self.labels = [self.labels[i] for i in irect]
ar = ar[irect]
# Set training image shapes
shapes = [[1, 1]] * nb
for i in range(nb):
ari = ar[bi == i]
mini, maxi = ari.min(), ari.max()
if maxi < 1:
shapes[i] = [maxi, 1]
elif mini > 1:
shapes[i] = [1, 1 / mini]
self.batch_shapes = np.ceil(np.array(shapes) * self.imgsz / self.stride + self.pad).astype(int) * self.stride
self.batch = bi # batch index of imageMethod ultralytics.data.base.BaseDataset.update_labels#
def update_labels(self, include_class: list[int] | None) -> NoneUpdate labels to include only specified classes, and set all classes to 0 if single_cls is True.
Args
| Name | Type | Description | Default |
|---|---|---|---|
include_class | list[int], optional | List of classes to include. If None, all classes are included. | required |
ultralytics/data/base.py
def update_labels(self, include_class: list[int] | None) -> None:
"""Update labels to include only specified classes, and set all classes to 0 if single_cls is True.
Args:
include_class (list[int], optional): List of classes to include. If None, all classes are included.
"""
include_class_array = np.array(include_class).reshape(1, -1)
for i in range(len(self.labels)):
if include_class is not None:
cls = self.labels[i]["cls"]
bboxes = self.labels[i]["bboxes"]
segments = self.labels[i]["segments"]
keypoints = self.labels[i].get("keypoints")
j = (cls == include_class_array).any(1)
self.labels[i]["cls"] = cls[j]
self.labels[i]["bboxes"] = bboxes[j]
if segments:
self.labels[i]["segments"] = [segments[si] for si, idx in enumerate(j) if idx]
if keypoints is not None:
self.labels[i]["keypoints"] = keypoints[j]
if self.single_cls:
self.labels[i]["cls"][:] = 0Method ultralytics.data.base.BaseDataset.update_labels_info#
def update_labels_info(self, label: dict[str, Any]) -> dict[str, Any]Customize your label format here.
Args
| Name | Type | Description | Default |
|---|---|---|---|
label | dict[str, Any] | required |
ultralytics/data/base.py
def update_labels_info(self, label: dict[str, Any]) -> dict[str, Any]:
"""Customize your label format here."""
return label