| import glob |
| import os |
| import random |
| import shutil |
| import time |
| from pathlib import Path |
| from threading import Thread |
|
|
| import cv2 |
| import math |
| import numpy as np |
| import torch |
| from PIL import Image, ExifTags |
| from torch.utils.data import Dataset |
| from tqdm import tqdm |
|
|
| from ..utils import letterbox_for_img, clean_str |
|
|
| img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.dng'] |
| vid_formats = ['.mov', '.avi', '.mp4', '.mpg', '.mpeg', '.m4v', '.wmv', '.mkv'] |
|
|
| class LoadImages: |
| def __init__(self, path, img_size=640): |
| p = str(Path(path)) |
| p = os.path.abspath(p) |
| if '*' in p: |
| files = sorted(glob.glob(p, recursive=True)) |
| elif os.path.isdir(p): |
| files = sorted(glob.glob(os.path.join(p, '*.*'))) |
| elif os.path.isfile(p): |
| files = [p] |
| else: |
| raise Exception('ERROR: %s does not exist' % p) |
|
|
| images = [x for x in files if os.path.splitext(x)[-1].lower() in img_formats] |
| videos = [x for x in files if os.path.splitext(x)[-1].lower() in vid_formats] |
| ni, nv = len(images), len(videos) |
|
|
| self.img_size = img_size |
| self.files = images + videos |
| self.nf = ni + nv |
| self.video_flag = [False] * ni + [True] * nv |
| self.mode = 'images' |
| if any(videos): |
| self.new_video(videos[0]) |
| else: |
| self.cap = None |
| assert self.nf > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \ |
| (p, img_formats, vid_formats) |
|
|
| def __iter__(self): |
| self.count = 0 |
| return self |
|
|
| def __next__(self): |
| if self.count == self.nf: |
| raise StopIteration |
| path = self.files[self.count] |
|
|
| if self.video_flag[self.count]: |
| |
| self.mode = 'video' |
| ret_val, img0 = self.cap.read() |
| if not ret_val: |
| self.count += 1 |
| self.cap.release() |
| if self.count == self.nf: |
| raise StopIteration |
| else: |
| path = self.files[self.count] |
| self.new_video(path) |
| ret_val, img0 = self.cap.read() |
| h0, w0 = img0.shape[:2] |
|
|
| self.frame += 1 |
| print('\n video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nf, self.frame, self.nframes, path), end='') |
|
|
| else: |
| |
| self.count += 1 |
| img0 = cv2.imread(path, cv2.IMREAD_COLOR | cv2.IMREAD_IGNORE_ORIENTATION) |
| |
| assert img0 is not None, 'Image Not Found ' + path |
| print('image %g/%g %s: \n' % (self.count, self.nf, path), end='') |
| h0, w0 = img0.shape[:2] |
|
|
| |
| img, ratio, pad = letterbox_for_img(img0, new_shape=self.img_size, auto=True) |
| h, w = img.shape[:2] |
| shapes = (h0, w0), ((h / h0, w / w0), pad) |
|
|
| |
| |
| img = np.ascontiguousarray(img) |
|
|
|
|
| |
| return path, img, img0, self.cap, shapes |
|
|
| def new_video(self, path): |
| self.frame = 0 |
| self.cap = cv2.VideoCapture(path) |
| self.nframes = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) |
|
|
| def __len__(self): |
| return self.nf |
|
|
|
|
|
|
| class LoadStreams: |
| def __init__(self, sources='streams.txt', img_size=640, auto=True): |
| self.mode = 'stream' |
| self.img_size = img_size |
|
|
| if os.path.isfile(sources): |
| with open(sources, 'r') as f: |
| sources = [x.strip() for x in f.read().strip().splitlines() if len(x.strip())] |
| else: |
| sources = [sources] |
|
|
| n = len(sources) |
| self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n |
| self.sources = [clean_str(x) for x in sources] |
| self.auto = auto |
| for i, s in enumerate(sources): |
| |
| print(f'{i + 1}/{n}: {s}... ', end='') |
| s = eval(s) if s.isnumeric() else s |
| cap = cv2.VideoCapture(s) |
| assert cap.isOpened(), f'Failed to open {s}' |
| w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) |
| h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
| self.fps[i] = max(cap.get(cv2.CAP_PROP_FPS) % 100, 0) or 30.0 |
| self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') |
|
|
| _, self.imgs[i] = cap.read() |
| self.threads[i] = Thread(target=self.update, args=([i, cap]), daemon=True) |
| print(f" success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") |
| self.threads[i].start() |
| print('') |
|
|
| |
|
|
| s = np.stack([letterbox_for_img(x, self.img_size, auto=self.auto)[0].shape for x in self.imgs], 0) |
| self.rect = np.unique(s, axis=0).shape[0] == 1 |
| if not self.rect: |
| print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.') |
|
|
| def update(self, i, cap): |
| |
| n, f, read = 0, self.frames[i], 1 |
| while cap.isOpened() and n < f: |
| n += 1 |
| |
| cap.grab() |
| if n % read == 0: |
| success, im = cap.retrieve() |
| self.imgs[i] = im if success else self.imgs[i] * 0 |
| time.sleep(1 / self.fps[i]) |
|
|
| def __iter__(self): |
| self.count = -1 |
| return self |
|
|
| def __next__(self): |
| self.count += 1 |
| if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): |
| cv2.destroyAllWindows() |
| raise StopIteration |
|
|
| |
| img0 = self.imgs.copy() |
|
|
| h0, w0 = img0[0].shape[:2] |
| img, _, pad = letterbox_for_img(img0[0], self.img_size, auto=self.rect and self.auto) |
|
|
| |
| h, w = img.shape[:2] |
| shapes = (h0, w0), ((h / h0, w / w0), pad) |
|
|
| |
| |
| img = np.ascontiguousarray(img) |
|
|
| return self.sources, img, img0[0], None, shapes |
|
|
| def __len__(self): |
| return len(self.sources) |