ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ содСрТимому

Бсылка для ultralytics/data/split_dota.py

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅

Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» доступСн ΠΏΠΎ адрСсу https://github.com/ultralytics/ ultralytics/blob/main/ ultralytics/data/split_dota .py. Если Ρ‚Ρ‹ Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ» ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ, поТалуйста, ΠΏΠΎΠΌΠΎΠ³ΠΈ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Π΅Π΅, ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ² Pull Request πŸ› οΈ. Бпасибо πŸ™!



ultralytics.data.split_dota.bbox_iof(polygon1, bbox2, eps=1e-06)

Вычисли ΠΈΠΎΡ„ ΠΌΠ΅ΠΆΠ΄Ρƒ bbox1 ΠΈ bbox2.

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹:

Имя Π’ΠΈΠΏ ОписаниС По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
polygon1 ndarray

ΠšΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ ΠΏΠΎΠ»ΠΈΠ³ΠΎΠ½Π°, (n, 8).

трСбуСтся
bbox2 ndarray

Π“Ρ€Π°Π½ΠΈΡ‡Π½Ρ‹Π΅ ΠΊΠΎΡ€ΠΎΠ±ΠΊΠΈ, (n ,4).

трСбуСтся
Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def bbox_iof(polygon1, bbox2, eps=1e-6):
    """
    Calculate iofs between bbox1 and bbox2.

    Args:
        polygon1 (np.ndarray): Polygon coordinates, (n, 8).
        bbox2 (np.ndarray): Bounding boxes, (n ,4).
    """
    polygon1 = polygon1.reshape(-1, 4, 2)
    lt_point = np.min(polygon1, axis=-2)
    rb_point = np.max(polygon1, axis=-2)
    bbox1 = np.concatenate([lt_point, rb_point], axis=-1)

    lt = np.maximum(bbox1[:, None, :2], bbox2[..., :2])
    rb = np.minimum(bbox1[:, None, 2:], bbox2[..., 2:])
    wh = np.clip(rb - lt, 0, np.inf)
    h_overlaps = wh[..., 0] * wh[..., 1]

    l, t, r, b = (bbox2[..., i] for i in range(4))
    polygon2 = np.stack([l, t, r, t, r, b, l, b], axis=-1).reshape(-1, 4, 2)

    sg_polys1 = [Polygon(p) for p in polygon1]
    sg_polys2 = [Polygon(p) for p in polygon2]
    overlaps = np.zeros(h_overlaps.shape)
    for p in zip(*np.nonzero(h_overlaps)):
        overlaps[p] = sg_polys1[p[0]].intersection(sg_polys2[p[-1]]).area
    unions = np.array([p.area for p in sg_polys1], dtype=np.float32)
    unions = unions[..., None]

    unions = np.clip(unions, eps, np.inf)
    outputs = overlaps / unions
    if outputs.ndim == 1:
        outputs = outputs[..., None]
    return outputs



ultralytics.data.split_dota.load_yolo_dota(data_root, split='train')

Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚Π΅ Π½Π°Π±ΠΎΡ€ Π΄Π°Π½Π½Ρ‹Ρ… DOTA.

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹:

Имя Π’ΠΈΠΏ ОписаниС По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
data_root str

ΠšΠΎΡ€Π΅Π½ΡŒ Π΄Π°Π½Π½Ρ‹Ρ….

трСбуСтся
split str

Π Π°Π·Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ Π΄Π°Π½Π½Ρ‹Ρ… ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ train ΠΈΠ»ΠΈ val.

'train'
ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΎΠ², принятая для Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ… DOTA: - data_root - изобраТСния - Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²ΠΊΠ° - val - ΠΌΠ΅Ρ‚ΠΊΠΈ - трСнируйся - val

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def load_yolo_dota(data_root, split="train"):
    """
    Load DOTA dataset.

    Args:
        data_root (str): Data root.
        split (str): The split data set, could be train or val.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
    """
    assert split in {"train", "val"}, f"Split must be 'train' or 'val', not {split}."
    im_dir = Path(data_root) / "images" / split
    assert im_dir.exists(), f"Can't find {im_dir}, please check your data root."
    im_files = glob(str(Path(data_root) / "images" / split / "*"))
    lb_files = img2label_paths(im_files)
    annos = []
    for im_file, lb_file in zip(im_files, lb_files):
        w, h = exif_size(Image.open(im_file))
        with open(lb_file) as f:
            lb = [x.split() for x in f.read().strip().splitlines() if len(x)]
            lb = np.array(lb, dtype=np.float32)
        annos.append(dict(ori_size=(h, w), label=lb, filepath=im_file))
    return annos



ultralytics.data.split_dota.get_windows(im_size, crop_sizes=[1024], gaps=[200], im_rate_thr=0.6, eps=0.01)

ΠŸΠΎΠ»ΡƒΡ‡ΠΈ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ ΠΎΠΊΠΎΠ½.

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹:

Имя Π’ΠΈΠΏ ОписаниС По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
im_size tuple

Π Π°Π·ΠΌΠ΅Ρ€ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ изобраТСния, (h, w).

трСбуСтся
crop_sizes List(int

ΠžΠ±Ρ€Π΅ΠΆΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΎΠΊΠΎΠ½.

[1024]
gaps List(int

ΠŸΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΠΊ ΠΌΠ΅ΠΆΠ΄Ρƒ посСвами.

[200]
im_rate_thr float

ΠŸΠΎΡ€ΠΎΠ³ областСй ΠΎΠΊΠΎΠ½, Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Π½Ρ‹Ρ… Π½Π° ΠΏΠ»ΠΎΡ‰Π°Π΄ΠΈ изобраТСния.

0.6
Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def get_windows(im_size, crop_sizes=[1024], gaps=[200], im_rate_thr=0.6, eps=0.01):
    """
    Get the coordinates of windows.

    Args:
        im_size (tuple): Original image size, (h, w).
        crop_sizes (List(int)): Crop size of windows.
        gaps (List(int)): Gap between crops.
        im_rate_thr (float): Threshold of windows areas divided by image ares.
    """
    h, w = im_size
    windows = []
    for crop_size, gap in zip(crop_sizes, gaps):
        assert crop_size > gap, f"invalid crop_size gap pair [{crop_size} {gap}]"
        step = crop_size - gap

        xn = 1 if w <= crop_size else ceil((w - crop_size) / step + 1)
        xs = [step * i for i in range(xn)]
        if len(xs) > 1 and xs[-1] + crop_size > w:
            xs[-1] = w - crop_size

        yn = 1 if h <= crop_size else ceil((h - crop_size) / step + 1)
        ys = [step * i for i in range(yn)]
        if len(ys) > 1 and ys[-1] + crop_size > h:
            ys[-1] = h - crop_size

        start = np.array(list(itertools.product(xs, ys)), dtype=np.int64)
        stop = start + crop_size
        windows.append(np.concatenate([start, stop], axis=1))
    windows = np.concatenate(windows, axis=0)

    im_in_wins = windows.copy()
    im_in_wins[:, 0::2] = np.clip(im_in_wins[:, 0::2], 0, w)
    im_in_wins[:, 1::2] = np.clip(im_in_wins[:, 1::2], 0, h)
    im_areas = (im_in_wins[:, 2] - im_in_wins[:, 0]) * (im_in_wins[:, 3] - im_in_wins[:, 1])
    win_areas = (windows[:, 2] - windows[:, 0]) * (windows[:, 3] - windows[:, 1])
    im_rates = im_areas / win_areas
    if not (im_rates > im_rate_thr).any():
        max_rate = im_rates.max()
        im_rates[abs(im_rates - max_rate) < eps] = 1
    return windows[im_rates > im_rate_thr]



ultralytics.data.split_dota.get_window_obj(anno, windows, iof_thr=0.7)

ΠŸΠΎΠ»ΡƒΡ‡ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΎΠΊΠ½Π°.

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def get_window_obj(anno, windows, iof_thr=0.7):
    """Get objects for each window."""
    h, w = anno["ori_size"]
    label = anno["label"]
    if len(label):
        label[:, 1::2] *= w
        label[:, 2::2] *= h
        iofs = bbox_iof(label[:, 1:], windows)
        # Unnormalized and misaligned coordinates
        return [(label[iofs[:, i] >= iof_thr]) for i in range(len(windows))]  # window_anns
    else:
        return [np.zeros((0, 9), dtype=np.float32) for _ in range(len(windows))]  # window_anns



ultralytics.data.split_dota.crop_and_save(anno, windows, window_objs, im_dir, lb_dir)

ΠžΠ±Ρ€Π΅Π·Π°ΠΉ изобраТСния ΠΈ сохраняй Π½ΠΎΠ²Ρ‹Π΅ ярлыки.

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹:

Имя Π’ΠΈΠΏ ОписаниС По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
anno dict

Π”ΠΈΠΊΡ‚Π°Π½Ρ‚ с Π°Π½Π½ΠΎΡ‚Π°Ρ†ΠΈΠ΅ΠΉ, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ filepath, label, ori_size Π² качСствС ΠΊΠ»ΡŽΡ‡Π΅ΠΉ.

трСбуСтся
windows list

Бписок ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ ΠΎΠΊΠΎΠ½.

трСбуСтся
window_objs list

Бписок ярлыков Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΎΠΊΠ½Π°.

трСбуСтся
im_dir str

ΠŸΡƒΡ‚ΡŒ ΠΊ Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ с изобраТСниями.

трСбуСтся
lb_dir str

ΠŸΡƒΡ‚ΡŒ ΠΊ Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ ярлыков.

трСбуСтся
ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΎΠ², принятая для Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ… DOTA: - data_root - изобраТСния - Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²ΠΊΠ° - val - ΠΌΠ΅Ρ‚ΠΊΠΈ - трСнируйся - val

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def crop_and_save(anno, windows, window_objs, im_dir, lb_dir):
    """
    Crop images and save new labels.

    Args:
        anno (dict): Annotation dict, including `filepath`, `label`, `ori_size` as its keys.
        windows (list): A list of windows coordinates.
        window_objs (list): A list of labels inside each window.
        im_dir (str): The output directory path of images.
        lb_dir (str): The output directory path of labels.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
    """
    im = cv2.imread(anno["filepath"])
    name = Path(anno["filepath"]).stem
    for i, window in enumerate(windows):
        x_start, y_start, x_stop, y_stop = window.tolist()
        new_name = f"{name}__{x_stop - x_start}__{x_start}___{y_start}"
        patch_im = im[y_start:y_stop, x_start:x_stop]
        ph, pw = patch_im.shape[:2]

        cv2.imwrite(str(Path(im_dir) / f"{new_name}.jpg"), patch_im)
        label = window_objs[i]
        if len(label) == 0:
            continue
        label[:, 1::2] -= x_start
        label[:, 2::2] -= y_start
        label[:, 1::2] /= pw
        label[:, 2::2] /= ph

        with open(Path(lb_dir) / f"{new_name}.txt", "w") as f:
            for lb in label:
                formatted_coords = ["{:.6g}".format(coord) for coord in lb[1:]]
                f.write(f"{int(lb[0])} {' '.join(formatted_coords)}\n")



ultralytics.data.split_dota.split_images_and_labels(data_root, save_dir, split='train', crop_sizes=[1024], gaps=[200])

РаздСляй ΠΊΠ°ΠΊ изобраТСния, Ρ‚Π°ΠΊ ΠΈ ярлыки.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΎΠ², принятая для Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ… DOTA: - data_root - изобраТСния - сплит - ΠΌΠ΅Ρ‚ΠΊΠΈ - split А структура Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ Ρ‚Π°ΠΊΠΎΠ²Π°: - save_dir - изобраТСния - split - этикСтки - Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def split_images_and_labels(data_root, save_dir, split="train", crop_sizes=[1024], gaps=[200]):
    """
    Split both images and labels.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - split
                - labels
                    - split
        and the output directory structure is:
            - save_dir
                - images
                    - split
                - labels
                    - split
    """
    im_dir = Path(save_dir) / "images" / split
    im_dir.mkdir(parents=True, exist_ok=True)
    lb_dir = Path(save_dir) / "labels" / split
    lb_dir.mkdir(parents=True, exist_ok=True)

    annos = load_yolo_dota(data_root, split=split)
    for anno in tqdm(annos, total=len(annos), desc=split):
        windows = get_windows(anno["ori_size"], crop_sizes, gaps)
        window_objs = get_window_obj(anno, windows)
        crop_and_save(anno, windows, window_objs, str(im_dir), str(lb_dir))



ultralytics.data.split_dota.split_trainval(data_root, save_dir, crop_size=1024, gap=200, rates=[1.0])

Π‘ΠΏΠ»ΠΈΡ‚-ΠΏΠΎΠ΅Π·Π΄ ΠΈ Π²Π°Π»ΠΊΠΈΠΉ Π½Π°Π±ΠΎΡ€ DOTA.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΎΠ², принятая для Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ… DOTA: - data_root - изобраТСния - Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²ΠΊΠ° - val - ΠΌΠ΅Ρ‚ΠΊΠΈ - трСнируйся - val А структура Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ Ρ‚Π°ΠΊΠΎΠ²Π°: - save_dir - изобраТСния - train - val - ΠΌΠ΅Ρ‚ΠΊΠΈ - ΠΏΠΎΠ΅Π·Π΄ - val

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def split_trainval(data_root, save_dir, crop_size=1024, gap=200, rates=[1.0]):
    """
    Split train and val set of DOTA.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
        and the output directory structure is:
            - save_dir
                - images
                    - train
                    - val
                - labels
                    - train
                    - val
    """
    crop_sizes, gaps = [], []
    for r in rates:
        crop_sizes.append(int(crop_size / r))
        gaps.append(int(gap / r))
    for split in ["train", "val"]:
        split_images_and_labels(data_root, save_dir, split, crop_sizes, gaps)



ultralytics.data.split_dota.split_test(data_root, save_dir, crop_size=1024, gap=200, rates=[1.0])

Набор для сплит-тСстирования DOTA, Π½Π°ΠΊΠ»Π΅ΠΉΠΊΠΈ Π² этот Π½Π°Π±ΠΎΡ€ Π½Π΅ входят.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΎΠ², принятая для Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ… DOTA: - data_root - изобраТСния - test Π° структура Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ Ρ‚Π°ΠΊΠΎΠ²Π°: - save_dir - изобраТСния - тСст

Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² ultralytics/data/split_dota.py
def split_test(data_root, save_dir, crop_size=1024, gap=200, rates=[1.0]):
    """
    Split test set of DOTA, labels are not included within this set.

    Notes:
        The directory structure assumed for the DOTA dataset:
            - data_root
                - images
                    - test
        and the output directory structure is:
            - save_dir
                - images
                    - test
    """
    crop_sizes, gaps = [], []
    for r in rates:
        crop_sizes.append(int(crop_size / r))
        gaps.append(int(gap / r))
    save_dir = Path(save_dir) / "images" / "test"
    save_dir.mkdir(parents=True, exist_ok=True)

    im_dir = Path(data_root) / "images" / "test"
    assert im_dir.exists(), f"Can't find {im_dir}, please check your data root."
    im_files = glob(str(im_dir / "*"))
    for im_file in tqdm(im_files, total=len(im_files), desc="test"):
        w, h = exif_size(Image.open(im_file))
        windows = get_windows((h, w), crop_sizes=crop_sizes, gaps=gaps)
        im = cv2.imread(im_file)
        name = Path(im_file).stem
        for window in windows:
            x_start, y_start, x_stop, y_stop = window.tolist()
            new_name = f"{name}__{x_stop - x_start}__{x_start}___{y_start}"
            patch_im = im[y_start:y_stop, x_start:x_stop]
            cv2.imwrite(str(save_dir / f"{new_name}.jpg"), patch_im)





Боздано 2024-01-05, ОбновлСно 2024-05-08
Авторы: Burhan-Q (1), glenn-jocher (2)