def verify_annotation(img_path, ann_path, labels): img = cv2.imread(img_path) boxes = [] # xywh with open(ann_path, 'r') as f: for line in f: line = line[:-1].split() line[0] = int(line[0]) line[1:] = [float(i) for i in line[1:]] boxes.append(line) boxes = np.asarray(boxes) boxes[:, 1:] = xywh2xyxy(boxes[:, 1:]) # xyxy if boxes[0, 1] <= 1: boxes[:, 1::2] *= img.shape[1] boxes[:, 2::2] *= img.shape[0] colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(labels))] for box in boxes: label = '%s' % (labels[int(box[0])]) plot_one_box(box[1:], img, label=label, color=colors[int(box[0])]) return img
def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, cache_labels=False, cache_images=False, single_cls=False): path = str(Path(path)) # os-agnostic assert os.path.isfile(path), 'File not found %s. See %s' % (path, help_url) with open(path, 'r') as f: self.img_files = [x.replace('/', os.sep) for x in f.read().splitlines() # os-agnostic if os.path.splitext(x)[-1].lower() in img_formats] n = len(self.img_files) assert n > 0, 'No images found in %s. See %s' % (path, help_url) bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index nb = bi[-1] + 1 # number of batches self.n = n self.batch = bi # batch index of image self.img_size = img_size self.augment = augment self.hyp = hyp self.image_weights = image_weights self.rect = False if image_weights else rect # Define labels self.label_files = [x.replace('images', 'labels').replace(os.path.splitext(x)[-1], '.txt') for x in self.img_files] # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 if self.rect: # Read image shapes (wh) sp = path.replace('.txt', '.shapes') # shapefile path try: with open(sp, 'r') as f: # read existing shapefile s = [x.split() for x in f.read().splitlines()] assert len(s) == n, 'Shapefile out of sync' except: s = [exif_size(Image.open(f)) for f in tqdm(self.img_files, desc='Reading image shapes')] np.savetxt(sp, s, fmt='%g') # overwrites existing (if any) # Sort by aspect ratio s = np.array(s, dtype=np.float64) ar = s[:, 1] / s[:, 0] # aspect ratio i = ar.argsort() self.img_files = [self.img_files[i] for i in i] self.label_files = [self.label_files[i] for i in i] self.shapes = s[i] # wh ar = ar[i] # 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) * img_size / 32.).astype(np.int) * 32 # Preload labels (required for weighted CE training) self.imgs = [None] * n self.labels = [None] * n if cache_labels or image_weights: # cache labels for faster training self.labels = [np.zeros((0, 5))] * n extract_bounding_boxes = False create_datasubset = False pbar = tqdm(self.label_files, desc='Caching labels') nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate for i, file in enumerate(pbar): try: with open(file, 'r') as f: l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) except: nm += 1 # print('missing labels for image %s' % self.img_files[i]) # file missing continue if l.shape[0]: assert l.shape[1] == 5, '> 5 label columns: %s' % file assert (l >= 0).all(), 'negative labels: %s' % file assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows if single_cls: l[:, 0] = 0 # force dataset into single-class mode self.labels[i] = l nf += 1 # file found # Create subdataset (a smaller dataset) if create_datasubset and ns < 1E4: if ns == 0: create_folder(path='./datasubset') os.makedirs('./datasubset/images') exclude_classes = 43 if exclude_classes not in l[:, 0]: ns += 1 # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image with open('./datasubset/images.txt', 'a') as f: f.write(self.img_files[i] + '\n') # Extract object detection boxes for a second stage classifier if extract_bounding_boxes: p = Path(self.img_files[i]) img = cv2.imread(str(p)) h, w = img.shape[:2] for j, x in enumerate(l): f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) if not os.path.exists(Path(f).parent): os.makedirs(Path(f).parent) # make new output folder b = x[1:] * [w, h, w, h] # box b[2:] = b[2:].max() # rectangle to square b[2:] = b[2:] * 1.3 + 30 # pad b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image b[[1, 3]] = np.clip(b[[1, 3]], 0, h) assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' else: ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove pbar.desc = 'Caching labels (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( nf, nm, ne, nd, n) assert nf > 0, 'No labels found. See %s' % help_url # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) if cache_images: # if training gb = 0 # Gigabytes of cached images pbar = tqdm(range(len(self.img_files)), desc='Caching images') self.img_hw0, self.img_hw = [None] * n, [None] * n for i in pbar: # max 10k images self.imgs[i], self.img_hw0[i], self.img_hw[i] = load_image(self, i) # img, hw_original, hw_resized gb += self.imgs[i].nbytes pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) # Detect corrupted images https://medium.com/joelthchao/programmatically-detect-corrupted-image-8c1b2006c3d3 detect_corrupted_images = False if detect_corrupted_images: from skimage import io # conda install -c conda-forge scikit-image for file in tqdm(self.img_files, desc='Detecting corrupted images'): try: _ = io.imread(file) except: print('Corrupted image detected: %s' % file)
img_paths = img_paths[restart_index:] ann_paths = ann_paths[restart_index:] # Labels with open(os.path.join(DS_PATH, 'diff.names'), 'w') as f: for n in NEW_CLS: f.write('%s\n' % n) for ip, ap in zip(img_paths, ann_paths): # Read original annotation img = cv2.imread(ip) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) boxes = get_ann_boxes(ap) np_boxes = np.asarray(boxes) np_boxes[:, 1:] = xywh2xyxy(np_boxes[:, 1:]) np_boxes[:, 1:] = np.clip(np_boxes[:, 1:], 0, 1) # IMPORTANT np_boxes[:, 1:] = scale_xyxy(np_boxes[:, 1:], img.shape[:2]) irt_np_boxes = np.insert(np_boxes, 1, 1, axis=1) # Info output print(('%20s: %s' * 2) % ('Image', os.path.basename(ap)[:-4] + '.jpg', 'Hands', np_boxes.shape[0])) # Differentiation lr_boxes = diff_hands(img, irt_np_boxes, extend_scale=0, color_thres=10, bin_thres=5, max_region=False,
def __init__(self, path, img_size=416, batch_size=16, augment=False, rect=True, image_weights=False): with open(path, 'r') as f: img_files = f.read().splitlines() self.img_files = list(filter(lambda x: len(x) > 0, img_files)) n = len(self.img_files) bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index nb = bi[-1] + 1 # number of batches assert n > 0, 'No images found in %s' % path self.n = n self.batch = bi # batch index of image self.img_size = img_size self.augment = augment self.image_weights = image_weights self.rect = False if image_weights else rect # Define labels self.label_files = [x.replace('images', 'labels') for x in self.img_files] for f in img_formats: self.label_files = [x.replace(f, '.txt') for x in self.label_files] # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 if self.rect: from PIL import Image # Read image shapes sp = 'data' + os.sep + path.replace('.txt', '.shapes').split(os.sep)[-1] # shapefile path if os.path.exists(sp): # read existing shapefile with open(sp, 'r') as f: s = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) assert len(s) == n, 'Shapefile out of sync, please delete %s and rerun' % sp else: # no shapefile, so read shape using PIL and write shapefile for next time (faster) s = np.array([Image.open(f).size for f in tqdm(self.img_files, desc='Reading image shapes')]) np.savetxt(sp, s, fmt='%g') # Sort by aspect ratio ar = s[:, 1] / s[:, 0] # aspect ratio i = ar.argsort() self.img_files = [self.img_files[i] for i in i] self.label_files = [self.label_files[i] for i in i] ar = ar[i] # 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) * img_size / 32.).astype(np.int) * 32 # Preload labels (required for weighted CE training) self.imgs = [None] * n self.labels = [None] * n preload_labels = False if preload_labels: self.labels = [np.zeros((0, 5))] * n iter = tqdm(self.label_files, desc='Reading labels') if n > 10 else self.label_files extract_bounding_boxes = False for i, file in enumerate(iter): try: with open(file, 'r') as f: l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) if l.shape[0]: assert l.shape[1] == 5, '> 5 label columns: %s' % file assert (l >= 0).all(), 'negative labels: %s' % file assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file self.labels[i] = l # Extract object detection boxes for a second stage classifier if extract_bounding_boxes: p = Path(self.img_files[i]) img = cv2.imread(str(p)) h, w, _ = img.shape for j, x in enumerate(l): f = '%s%sclassification%s%g_%g_%s' % ( p.parent.parent, os.sep, os.sep, x[0], j, p.name) if not os.path.exists(Path(f).parent): os.makedirs(Path(f).parent) # make new output folder box = xywh2xyxy(x[1:].reshape(-1, 4)).ravel() box = np.clip(box, 0, 1) # clip boxes outside of image result = cv2.imwrite(f, img[int(box[1] * h):int(box[3] * h), int(box[0] * w):int(box[2] * w)]) if not result: print('stop') except: pass # print('Warning: missing labels for %s' % self.img_files[i]) # missing label file assert len(np.concatenate(self.labels, 0)) > 0, 'No labels found. Incorrect label paths provided.'
def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=True, image_weights=False, cache_images=False): path = str(Path(path)) # os-agnostic with open(path, 'r') as f: self.img_files = [x.replace('/', os.sep) for x in f.read().splitlines() # os-agnostic if os.path.splitext(x)[-1].lower() in img_formats] n = len(self.img_files) bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index nb = bi[-1] + 1 # number of batches assert n > 0, 'No images found in %s' % path self.n = n self.batch = bi # batch index of image self.img_size = img_size self.augment = augment self.hyp = hyp self.image_weights = image_weights self.rect = False if image_weights else rect # Define labels class_ids = ['n02691156', 'n02419796', 'n02131653', 'n02834778', 'n01503061', 'n02924116', 'n02958343', 'n02402425', 'n02084071', 'n02121808', 'n02503517', 'n02118333', 'n02510455', 'n02342885', 'n02374451', 'n02129165', 'n01674464', 'n02484322', 'n03790512', 'n02324045', 'n02509815', 'n02411705', 'n01726692', 'n02355227', 'n02129604', 'n04468005', 'n01662784', 'n04530566', 'n02062744', 'n02391049'] self.id2idx = {id: idx for idx, id in enumerate(class_ids)} self.label_files = [x.replace('Data', 'Annotations').replace(os.path.splitext(x)[-1], '.xml') for x in self.img_files] # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 if self.rect: # Read image shapes sp = 'data' + os.sep + path.replace('.txt', '.shapes').split(os.sep)[-1] # shapefile path try: with open(sp, 'r') as f: # read existing shapefile s = [x.split() for x in f.read().splitlines()] assert len(s) == n, 'Shapefile out of sync' except: s = [exif_size(Image.open(f)) for f in tqdm(self.img_files, desc='Reading image shapes')] np.savetxt(sp, s, fmt='%g') # overwrites existing (if any) # Sort by aspect ratio s = np.array(s, dtype=np.float64) ar = s[:, 1] / s[:, 0] # aspect ratio i = ar.argsort() self.img_files = [self.img_files[i] for i in i] self.label_files = [self.label_files[i] for i in i] self.shapes = s[i] ar = ar[i] # 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) * img_size / 32.).astype(np.int) * 32 # Preload labels (required for weighted CE training) self.imgs = [None] * n self.labels = [None] * n if augment or image_weights: # cache labels for faster training self.labels = [np.zeros((0, 5))] * n extract_bounding_boxes = False pbar = tqdm(self.label_files, desc='Reading labels') nm, nf, ne = 0, 0, 0 # number missing, number found, number empty for i, file in enumerate(pbar): try: boxes = [] root = ET.parse(file).getroot() im_w = int(root.find('size/width').text) im_h = int(root.find('size/height').text) for obj in root.findall('object'): c = obj.find('name').text if c not in self.id2idx: continue cls = self.id2idx[c] x1 = int(obj.find('bndbox/xmin').text) y1 = int(obj.find('bndbox/ymin').text) x2 = int(obj.find('bndbox/xmax').text) y2 = int(obj.find('bndbox/ymax').text) x = 0.5 * (x1 + x2) / im_w y = 0.5 * (y1 + y2) / im_h ww = (x2 - x1) / im_w hh = (y2 - y1) / im_h boxes.append([cls, x, y, ww, hh]) l = np.array(boxes, dtype=np.float32) except: nm += 1 # print('missing labels for image %s' % self.img_files[i]) # file missing continue if l.shape[0]: assert l.shape[1] == 5, '> 5 label columns: %s' % file assert (l >= 0).all(), 'negative labels: %s' % file assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file self.labels[i] = l nf += 1 # file found # Extract object detection boxes for a second stage classifier if extract_bounding_boxes: p = Path(self.img_files[i]) img = cv2.imread(str(p)) h, w, _ = img.shape for j, x in enumerate(l): f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) if not os.path.exists(Path(f).parent): os.makedirs(Path(f).parent) # make new output folder box = xywh2xyxy(x[1:].reshape(-1, 4)).ravel() b = np.clip(box, 0, 1) # clip boxes outside of image ret_val = cv2.imwrite(f, img[int(b[1] * h):int(b[3] * h), int(b[0] * w):int(b[2] * w)]) assert ret_val, 'Failure extracting classifier boxes' else: ne += 1 # file empty pbar.desc = 'Reading labels (%g found, %g missing, %g empty for %g images)' % (nf, nm, ne, n) assert nf > 0, 'No labels found. Recommend correcting image and label paths.' # Cache images into memory for faster training (~5GB) if cache_images and augment: # if training for i in tqdm(range(min(len(self.img_files), 10000)), desc='Reading images'): # max 10k images img_path = self.img_files[i] img = cv2.imread(img_path) # BGR assert img is not None, 'Image Not Found ' + img_path r = self.img_size / max(img.shape) # size ratio if self.augment and r < 1: # if training (NOT testing), downsize to inference shape h, w, _ = img.shape img = cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_LINEAR) # or INTER_AREA self.imgs[i] = img # Detect corrupted images https://medium.com/joelthchao/programmatically-detect-corrupted-image-8c1b2006c3d3 detect_corrupted_images = False if detect_corrupted_images: from skimage import io # conda install -c conda-forge scikit-image for file in tqdm(self.img_files, desc='Detecting corrupted images'): try: _ = io.imread(file) except: print('Corrupted image detected: %s' % file)