glenn-jocher
commited on
Commit
•
b57abb1
1
Parent(s):
dc7e093
Move trainloader functions to class methods (#6559)
Browse files* Move trainloader functions to class methods
* results = ThreadPool(NUM_THREADS).imap(self.load_image, range(n))
* Cleanup
- utils/datasets.py +157 -159
utils/datasets.py
CHANGED
@@ -484,7 +484,7 @@ class LoadImagesAndLabels(Dataset):
|
|
484 |
|
485 |
self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride
|
486 |
|
487 |
-
# Cache images into
|
488 |
self.imgs, self.img_npy = [None] * n, [None] * n
|
489 |
if cache_images:
|
490 |
if cache_images == 'disk':
|
@@ -493,14 +493,14 @@ class LoadImagesAndLabels(Dataset):
|
|
493 |
self.im_cache_dir.mkdir(parents=True, exist_ok=True)
|
494 |
gb = 0 # Gigabytes of cached images
|
495 |
self.img_hw0, self.img_hw = [None] * n, [None] * n
|
496 |
-
results = ThreadPool(NUM_THREADS).imap(
|
497 |
pbar = tqdm(enumerate(results), total=n)
|
498 |
for i, x in pbar:
|
499 |
if cache_images == 'disk':
|
500 |
if not self.img_npy[i].exists():
|
501 |
np.save(self.img_npy[i].as_posix(), x[0])
|
502 |
gb += self.img_npy[i].stat().st_size
|
503 |
-
else:
|
504 |
self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i)
|
505 |
gb += self.imgs[i].nbytes
|
506 |
pbar.desc = f'{prefix}Caching images ({gb / 1E9:.1f}GB {cache_images})'
|
@@ -558,16 +558,16 @@ class LoadImagesAndLabels(Dataset):
|
|
558 |
mosaic = self.mosaic and random.random() < hyp['mosaic']
|
559 |
if mosaic:
|
560 |
# Load mosaic
|
561 |
-
img, labels = load_mosaic(
|
562 |
shapes = None
|
563 |
|
564 |
# MixUp augmentation
|
565 |
if random.random() < hyp['mixup']:
|
566 |
-
img, labels = mixup(img, labels, *load_mosaic(
|
567 |
|
568 |
else:
|
569 |
# Load image
|
570 |
-
img, (h0, w0), (h, w) = load_image(
|
571 |
|
572 |
# Letterbox
|
573 |
shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape
|
@@ -624,6 +624,157 @@ class LoadImagesAndLabels(Dataset):
|
|
624 |
|
625 |
return torch.from_numpy(img), labels_out, self.img_files[index], shapes
|
626 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
627 |
@staticmethod
|
628 |
def collate_fn(batch):
|
629 |
img, label, path, shapes = zip(*batch) # transposed
|
@@ -659,159 +810,6 @@ class LoadImagesAndLabels(Dataset):
|
|
659 |
|
660 |
|
661 |
# Ancillary functions --------------------------------------------------------------------------------------------------
|
662 |
-
def load_image(self, i):
|
663 |
-
# loads 1 image from dataset index 'i', returns im, original hw, resized hw
|
664 |
-
im = self.imgs[i]
|
665 |
-
if im is None: # not cached in ram
|
666 |
-
npy = self.img_npy[i]
|
667 |
-
if npy and npy.exists(): # load npy
|
668 |
-
im = np.load(npy)
|
669 |
-
else: # read image
|
670 |
-
path = self.img_files[i]
|
671 |
-
im = cv2.imread(path) # BGR
|
672 |
-
assert im is not None, f'Image Not Found {path}'
|
673 |
-
h0, w0 = im.shape[:2] # orig hw
|
674 |
-
r = self.img_size / max(h0, w0) # ratio
|
675 |
-
if r != 1: # if sizes are not equal
|
676 |
-
im = cv2.resize(im, (int(w0 * r), int(h0 * r)),
|
677 |
-
interpolation=cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR)
|
678 |
-
return im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized
|
679 |
-
else:
|
680 |
-
return self.imgs[i], self.img_hw0[i], self.img_hw[i] # im, hw_original, hw_resized
|
681 |
-
|
682 |
-
|
683 |
-
def load_mosaic(self, index):
|
684 |
-
# YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic
|
685 |
-
labels4, segments4 = [], []
|
686 |
-
s = self.img_size
|
687 |
-
yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y
|
688 |
-
indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices
|
689 |
-
random.shuffle(indices)
|
690 |
-
for i, index in enumerate(indices):
|
691 |
-
# Load image
|
692 |
-
img, _, (h, w) = load_image(self, index)
|
693 |
-
|
694 |
-
# place img in img4
|
695 |
-
if i == 0: # top left
|
696 |
-
img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles
|
697 |
-
x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image)
|
698 |
-
x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image)
|
699 |
-
elif i == 1: # top right
|
700 |
-
x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc
|
701 |
-
x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h
|
702 |
-
elif i == 2: # bottom left
|
703 |
-
x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)
|
704 |
-
x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h)
|
705 |
-
elif i == 3: # bottom right
|
706 |
-
x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h)
|
707 |
-
x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h)
|
708 |
-
|
709 |
-
img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax]
|
710 |
-
padw = x1a - x1b
|
711 |
-
padh = y1a - y1b
|
712 |
-
|
713 |
-
# Labels
|
714 |
-
labels, segments = self.labels[index].copy(), self.segments[index].copy()
|
715 |
-
if labels.size:
|
716 |
-
labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format
|
717 |
-
segments = [xyn2xy(x, w, h, padw, padh) for x in segments]
|
718 |
-
labels4.append(labels)
|
719 |
-
segments4.extend(segments)
|
720 |
-
|
721 |
-
# Concat/clip labels
|
722 |
-
labels4 = np.concatenate(labels4, 0)
|
723 |
-
for x in (labels4[:, 1:], *segments4):
|
724 |
-
np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective()
|
725 |
-
# img4, labels4 = replicate(img4, labels4) # replicate
|
726 |
-
|
727 |
-
# Augment
|
728 |
-
img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste'])
|
729 |
-
img4, labels4 = random_perspective(img4, labels4, segments4,
|
730 |
-
degrees=self.hyp['degrees'],
|
731 |
-
translate=self.hyp['translate'],
|
732 |
-
scale=self.hyp['scale'],
|
733 |
-
shear=self.hyp['shear'],
|
734 |
-
perspective=self.hyp['perspective'],
|
735 |
-
border=self.mosaic_border) # border to remove
|
736 |
-
|
737 |
-
return img4, labels4
|
738 |
-
|
739 |
-
|
740 |
-
def load_mosaic9(self, index):
|
741 |
-
# YOLOv5 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic
|
742 |
-
labels9, segments9 = [], []
|
743 |
-
s = self.img_size
|
744 |
-
indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices
|
745 |
-
random.shuffle(indices)
|
746 |
-
hp, wp = -1, -1 # height, width previous
|
747 |
-
for i, index in enumerate(indices):
|
748 |
-
# Load image
|
749 |
-
img, _, (h, w) = load_image(self, index)
|
750 |
-
|
751 |
-
# place img in img9
|
752 |
-
if i == 0: # center
|
753 |
-
img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles
|
754 |
-
h0, w0 = h, w
|
755 |
-
c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates
|
756 |
-
elif i == 1: # top
|
757 |
-
c = s, s - h, s + w, s
|
758 |
-
elif i == 2: # top right
|
759 |
-
c = s + wp, s - h, s + wp + w, s
|
760 |
-
elif i == 3: # right
|
761 |
-
c = s + w0, s, s + w0 + w, s + h
|
762 |
-
elif i == 4: # bottom right
|
763 |
-
c = s + w0, s + hp, s + w0 + w, s + hp + h
|
764 |
-
elif i == 5: # bottom
|
765 |
-
c = s + w0 - w, s + h0, s + w0, s + h0 + h
|
766 |
-
elif i == 6: # bottom left
|
767 |
-
c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h
|
768 |
-
elif i == 7: # left
|
769 |
-
c = s - w, s + h0 - h, s, s + h0
|
770 |
-
elif i == 8: # top left
|
771 |
-
c = s - w, s + h0 - hp - h, s, s + h0 - hp
|
772 |
-
|
773 |
-
padx, pady = c[:2]
|
774 |
-
x1, y1, x2, y2 = (max(x, 0) for x in c) # allocate coords
|
775 |
-
|
776 |
-
# Labels
|
777 |
-
labels, segments = self.labels[index].copy(), self.segments[index].copy()
|
778 |
-
if labels.size:
|
779 |
-
labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady) # normalized xywh to pixel xyxy format
|
780 |
-
segments = [xyn2xy(x, w, h, padx, pady) for x in segments]
|
781 |
-
labels9.append(labels)
|
782 |
-
segments9.extend(segments)
|
783 |
-
|
784 |
-
# Image
|
785 |
-
img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax]
|
786 |
-
hp, wp = h, w # height, width previous
|
787 |
-
|
788 |
-
# Offset
|
789 |
-
yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y
|
790 |
-
img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s]
|
791 |
-
|
792 |
-
# Concat/clip labels
|
793 |
-
labels9 = np.concatenate(labels9, 0)
|
794 |
-
labels9[:, [1, 3]] -= xc
|
795 |
-
labels9[:, [2, 4]] -= yc
|
796 |
-
c = np.array([xc, yc]) # centers
|
797 |
-
segments9 = [x - c for x in segments9]
|
798 |
-
|
799 |
-
for x in (labels9[:, 1:], *segments9):
|
800 |
-
np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective()
|
801 |
-
# img9, labels9 = replicate(img9, labels9) # replicate
|
802 |
-
|
803 |
-
# Augment
|
804 |
-
img9, labels9 = random_perspective(img9, labels9, segments9,
|
805 |
-
degrees=self.hyp['degrees'],
|
806 |
-
translate=self.hyp['translate'],
|
807 |
-
scale=self.hyp['scale'],
|
808 |
-
shear=self.hyp['shear'],
|
809 |
-
perspective=self.hyp['perspective'],
|
810 |
-
border=self.mosaic_border) # border to remove
|
811 |
-
|
812 |
-
return img9, labels9
|
813 |
-
|
814 |
-
|
815 |
def create_folder(path='./new'):
|
816 |
# Create folder
|
817 |
if os.path.exists(path):
|
|
|
484 |
|
485 |
self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride
|
486 |
|
487 |
+
# Cache images into RAM/disk for faster training (WARNING: large datasets may exceed system resources)
|
488 |
self.imgs, self.img_npy = [None] * n, [None] * n
|
489 |
if cache_images:
|
490 |
if cache_images == 'disk':
|
|
|
493 |
self.im_cache_dir.mkdir(parents=True, exist_ok=True)
|
494 |
gb = 0 # Gigabytes of cached images
|
495 |
self.img_hw0, self.img_hw = [None] * n, [None] * n
|
496 |
+
results = ThreadPool(NUM_THREADS).imap(self.load_image, range(n))
|
497 |
pbar = tqdm(enumerate(results), total=n)
|
498 |
for i, x in pbar:
|
499 |
if cache_images == 'disk':
|
500 |
if not self.img_npy[i].exists():
|
501 |
np.save(self.img_npy[i].as_posix(), x[0])
|
502 |
gb += self.img_npy[i].stat().st_size
|
503 |
+
else: # 'ram'
|
504 |
self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i)
|
505 |
gb += self.imgs[i].nbytes
|
506 |
pbar.desc = f'{prefix}Caching images ({gb / 1E9:.1f}GB {cache_images})'
|
|
|
558 |
mosaic = self.mosaic and random.random() < hyp['mosaic']
|
559 |
if mosaic:
|
560 |
# Load mosaic
|
561 |
+
img, labels = self.load_mosaic(index)
|
562 |
shapes = None
|
563 |
|
564 |
# MixUp augmentation
|
565 |
if random.random() < hyp['mixup']:
|
566 |
+
img, labels = mixup(img, labels, *self.load_mosaic(random.randint(0, self.n - 1)))
|
567 |
|
568 |
else:
|
569 |
# Load image
|
570 |
+
img, (h0, w0), (h, w) = self.load_image(index)
|
571 |
|
572 |
# Letterbox
|
573 |
shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape
|
|
|
624 |
|
625 |
return torch.from_numpy(img), labels_out, self.img_files[index], shapes
|
626 |
|
627 |
+
def load_image(self, i):
|
628 |
+
# loads 1 image from dataset index 'i', returns (im, original hw, resized hw)
|
629 |
+
im = self.imgs[i]
|
630 |
+
if im is None: # not cached in RAM
|
631 |
+
npy = self.img_npy[i]
|
632 |
+
if npy and npy.exists(): # load npy
|
633 |
+
im = np.load(npy)
|
634 |
+
else: # read image
|
635 |
+
f = self.img_files[i]
|
636 |
+
im = cv2.imread(f) # BGR
|
637 |
+
assert im is not None, f'Image Not Found {f}'
|
638 |
+
h0, w0 = im.shape[:2] # orig hw
|
639 |
+
r = self.img_size / max(h0, w0) # ratio
|
640 |
+
if r != 1: # if sizes are not equal
|
641 |
+
im = cv2.resize(im,
|
642 |
+
(int(w0 * r), int(h0 * r)),
|
643 |
+
interpolation=cv2.INTER_LINEAR if (self.augment or r > 1) else cv2.INTER_AREA)
|
644 |
+
return im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized
|
645 |
+
else:
|
646 |
+
return self.imgs[i], self.img_hw0[i], self.img_hw[i] # im, hw_original, hw_resized
|
647 |
+
|
648 |
+
def load_mosaic(self, index):
|
649 |
+
# YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic
|
650 |
+
labels4, segments4 = [], []
|
651 |
+
s = self.img_size
|
652 |
+
yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y
|
653 |
+
indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices
|
654 |
+
random.shuffle(indices)
|
655 |
+
for i, index in enumerate(indices):
|
656 |
+
# Load image
|
657 |
+
img, _, (h, w) = self.load_image(index)
|
658 |
+
|
659 |
+
# place img in img4
|
660 |
+
if i == 0: # top left
|
661 |
+
img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles
|
662 |
+
x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image)
|
663 |
+
x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image)
|
664 |
+
elif i == 1: # top right
|
665 |
+
x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc
|
666 |
+
x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h
|
667 |
+
elif i == 2: # bottom left
|
668 |
+
x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)
|
669 |
+
x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h)
|
670 |
+
elif i == 3: # bottom right
|
671 |
+
x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h)
|
672 |
+
x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h)
|
673 |
+
|
674 |
+
img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax]
|
675 |
+
padw = x1a - x1b
|
676 |
+
padh = y1a - y1b
|
677 |
+
|
678 |
+
# Labels
|
679 |
+
labels, segments = self.labels[index].copy(), self.segments[index].copy()
|
680 |
+
if labels.size:
|
681 |
+
labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format
|
682 |
+
segments = [xyn2xy(x, w, h, padw, padh) for x in segments]
|
683 |
+
labels4.append(labels)
|
684 |
+
segments4.extend(segments)
|
685 |
+
|
686 |
+
# Concat/clip labels
|
687 |
+
labels4 = np.concatenate(labels4, 0)
|
688 |
+
for x in (labels4[:, 1:], *segments4):
|
689 |
+
np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective()
|
690 |
+
# img4, labels4 = replicate(img4, labels4) # replicate
|
691 |
+
|
692 |
+
# Augment
|
693 |
+
img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste'])
|
694 |
+
img4, labels4 = random_perspective(img4, labels4, segments4,
|
695 |
+
degrees=self.hyp['degrees'],
|
696 |
+
translate=self.hyp['translate'],
|
697 |
+
scale=self.hyp['scale'],
|
698 |
+
shear=self.hyp['shear'],
|
699 |
+
perspective=self.hyp['perspective'],
|
700 |
+
border=self.mosaic_border) # border to remove
|
701 |
+
|
702 |
+
return img4, labels4
|
703 |
+
|
704 |
+
def load_mosaic9(self, index):
|
705 |
+
# YOLOv5 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic
|
706 |
+
labels9, segments9 = [], []
|
707 |
+
s = self.img_size
|
708 |
+
indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices
|
709 |
+
random.shuffle(indices)
|
710 |
+
hp, wp = -1, -1 # height, width previous
|
711 |
+
for i, index in enumerate(indices):
|
712 |
+
# Load image
|
713 |
+
img, _, (h, w) = self.load_image(index)
|
714 |
+
|
715 |
+
# place img in img9
|
716 |
+
if i == 0: # center
|
717 |
+
img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles
|
718 |
+
h0, w0 = h, w
|
719 |
+
c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates
|
720 |
+
elif i == 1: # top
|
721 |
+
c = s, s - h, s + w, s
|
722 |
+
elif i == 2: # top right
|
723 |
+
c = s + wp, s - h, s + wp + w, s
|
724 |
+
elif i == 3: # right
|
725 |
+
c = s + w0, s, s + w0 + w, s + h
|
726 |
+
elif i == 4: # bottom right
|
727 |
+
c = s + w0, s + hp, s + w0 + w, s + hp + h
|
728 |
+
elif i == 5: # bottom
|
729 |
+
c = s + w0 - w, s + h0, s + w0, s + h0 + h
|
730 |
+
elif i == 6: # bottom left
|
731 |
+
c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h
|
732 |
+
elif i == 7: # left
|
733 |
+
c = s - w, s + h0 - h, s, s + h0
|
734 |
+
elif i == 8: # top left
|
735 |
+
c = s - w, s + h0 - hp - h, s, s + h0 - hp
|
736 |
+
|
737 |
+
padx, pady = c[:2]
|
738 |
+
x1, y1, x2, y2 = (max(x, 0) for x in c) # allocate coords
|
739 |
+
|
740 |
+
# Labels
|
741 |
+
labels, segments = self.labels[index].copy(), self.segments[index].copy()
|
742 |
+
if labels.size:
|
743 |
+
labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady) # normalized xywh to pixel xyxy format
|
744 |
+
segments = [xyn2xy(x, w, h, padx, pady) for x in segments]
|
745 |
+
labels9.append(labels)
|
746 |
+
segments9.extend(segments)
|
747 |
+
|
748 |
+
# Image
|
749 |
+
img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax]
|
750 |
+
hp, wp = h, w # height, width previous
|
751 |
+
|
752 |
+
# Offset
|
753 |
+
yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y
|
754 |
+
img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s]
|
755 |
+
|
756 |
+
# Concat/clip labels
|
757 |
+
labels9 = np.concatenate(labels9, 0)
|
758 |
+
labels9[:, [1, 3]] -= xc
|
759 |
+
labels9[:, [2, 4]] -= yc
|
760 |
+
c = np.array([xc, yc]) # centers
|
761 |
+
segments9 = [x - c for x in segments9]
|
762 |
+
|
763 |
+
for x in (labels9[:, 1:], *segments9):
|
764 |
+
np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective()
|
765 |
+
# img9, labels9 = replicate(img9, labels9) # replicate
|
766 |
+
|
767 |
+
# Augment
|
768 |
+
img9, labels9 = random_perspective(img9, labels9, segments9,
|
769 |
+
degrees=self.hyp['degrees'],
|
770 |
+
translate=self.hyp['translate'],
|
771 |
+
scale=self.hyp['scale'],
|
772 |
+
shear=self.hyp['shear'],
|
773 |
+
perspective=self.hyp['perspective'],
|
774 |
+
border=self.mosaic_border) # border to remove
|
775 |
+
|
776 |
+
return img9, labels9
|
777 |
+
|
778 |
@staticmethod
|
779 |
def collate_fn(batch):
|
780 |
img, label, path, shapes = zip(*batch) # transposed
|
|
|
810 |
|
811 |
|
812 |
# Ancillary functions --------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
813 |
def create_folder(path='./new'):
|
814 |
# Create folder
|
815 |
if os.path.exists(path):
|