def main(): parser = argparse.ArgumentParser( description='Convert bounding box file(s) from one format to the other', usage='%(prog)s inputformat inputpath outputformat outputpath [optional arguments]', epilog=f'Posible formats are: {list(bbb.formats.keys())}', ) parser.add_argument('inputformat', metavar='inputformat', choices=bbb.formats.keys(), help='Input format') parser.add_argument('inputpath', help='Bounding box file, folder or file sequence') parser.add_argument('outputformat', metavar='outputformat', choices=bbb.formats.keys(), help='Ouput format') parser.add_argument('outputpath', help='Output file or folder') parser.add_argument('--stride', '-s', metavar='N', type=int, default=1, help='If a sequence expression is given as input, this stride is used') parser.add_argument('--offset', '-o', metavar='N', type=int, default=0, help='If a sequence expression is given as input, this offset is used') parser.add_argument('--kwargs', '-k', metavar='KW=V', help='Keyword arguments for the parser', nargs='*', action=StoreKwargs, default={}) args = parser.parse_args() # Parse arguments indir = os.path.split(args.inputpath)[0] if not os.path.exists(indir): sys.exit(f'Input directory {indir} does not exist') if os.path.splitext(args.outputpath)[1] != '': outdir = os.path.split(args.outputpath)[0] else: outdir = args.outputpath if not os.path.exists(outdir): os.makedirs(outdir) # Convert bbox = bbb.parse(args.inputformat, args.inputpath, stride=args.stride, offset=args.offset, **args.kwargs) bbb.generate(args.outputformat, bbox, args.outputpath, **args.kwargs) print(f'Converted {len(bbox)} files')
def test(weight, device, save_det): log.debug('Creating network') net = ln.models.TinyYolo(len(CLASS_LABELS), weight, CONF_THRESH, NMS_THRESH) net.postprocess.append(ln.data.transform.TensorToBrambox(NETWORK_SIZE, CLASS_LABELS)) net = net.to(device) net.eval() log.debug('Creating dataset') loader = torch.utils.data.DataLoader( ln.models.DarknetDataset(TESTFILE, augment=False, input_dimension=NETWORK_SIZE, class_label_map=CLASS_LABELS), batch_size = MINI_BATCH, shuffle = False, drop_last = False, num_workers = WORKERS, pin_memory = PIN_MEM, collate_fn = ln.data.list_collate, ) log.debug('Running network') tot_loss = [] coord_loss = [] conf_loss = [] cls_loss = [] anno, det = {}, {} num_det = 0 with torch.no_grad(): for idx, (data, box) in enumerate(tqdm(loader, total=len(loader))): data = data.to(device) output, loss = net(data, box) tot_loss.append(net.loss.loss_tot.item()*len(box)) coord_loss.append(net.loss.loss_coord.item()*len(box)) conf_loss.append(net.loss.loss_conf.item()*len(box)) if net.loss.loss_cls is not None: cls_loss.append(net.loss.loss_cls.item()*len(box)) key_val = len(anno) anno.update({loader.dataset.keys[key_val+k]: v for k,v in enumerate(box)}) det.update({loader.dataset.keys[key_val+k]: v for k,v in enumerate(output)}) log.debug('Computing statistics') pr = bbb.pr(det, anno) m_ap = bbb.ap(*pr)*100 tot = sum(tot_loss)/len(anno) coord = sum(coord_loss)/len(anno) conf = sum(conf_loss)/len(anno) if len(cls_loss) > 0: cls = sum(cls_loss)/len(anno) log.test(f'{net.seen//BATCH} mAP:{m_ap:.2f}% Loss:{tot:.5f} (Coord:{coord:.2f} Conf:{conf:.2f} Cls:{cls:.2f})') else: log.test(f'{net.seen//BATCH} mAP:{m_ap:.2f}% Loss:{tot:.5f} (Coord:{coord:.2f} Conf:{conf:.2f})') if save_det is not None: # Note: These detection boxes are the coordinates for the letterboxed images, # you need ln.data.transform.ReverseLetterbox to have the right ones. # Alternatively, you can save the letterboxed annotations, and use those for statistics later on! bbb.generate('det_pickle', det, Path(arguments.save_det).with_suffix('.pkl'))
def process(name, verbose=True): config_dict = { 'train': ('training', TRAINSET), 'valid': ('validation', VALIDSET), 'test': ('testing', TESTSET), } name = name.lower() assert name in config_dict description, DATASET = config_dict[name] if len(DATASET) == 0: return print('Getting {description} annotation filenames'.format(description=description)) dataset = [] for (year, img_set) in DATASET: filename = '{ROOT}/VOCdevkit/VOC{year}/ImageSets/Main/{img_set}.txt'.format(ROOT=ROOT, year=year, img_set=img_set) with open(filename, 'r') as f: ids = f.read().strip().split() dataset += [ '{ROOT}/VOCdevkit/VOC{year}/Annotations/{xml_id}.xml'.format(ROOT=ROOT, year=year, xml_id=xml_id) for xml_id in ids ] if verbose: print('\t{len} xml files'.format( len=len(dataset), )) print('Parsing {description} annotation files'.format(description=description)) dataset_annos = bbb.parse('anno_pascalvoc', dataset, identify) print('Generating {description} annotation file'.format(description=description)) bbb.generate('anno_pickle', dataset_annos, '{ROOT}/{name}.pkl'.format(ROOT=ROOT, name=name)) print()
f'{ROOT}/VOC{year}/Annotations/{xml_id}.xml' for xml_id in ids ] if DEBUG: print(f'\t{len(train)} xml files') print('Parsing training annotation files') train_annos = bbb.parse('anno_pascalvoc', train, identify) # Remove difficult for training for k, annos in train_annos.items(): for i in range(len(annos) - 1, -1, -1): if annos[i].difficult: del annos[i] print('Generating training annotation file') bbb.generate('anno_pickle', train_annos, f'{ROOT}/onedet_cache/train.pkl') print() print('Getting testing annotation filenames') test = [] for (year, img_set) in TESTSET: with open(f'{ROOT}/VOC{year}/ImageSets/Main/{img_set}.txt', 'r') as f: ids = f.read().strip().split() test += [ f'{ROOT}/VOC{year}/Annotations/{xml_id}.xml' for xml_id in ids ] if DEBUG: print(f'\t{len(test)} xml files')
ids = f.read().strip().split() train += [f'{ROOT}/VOC{year}/Annotations/{xml_id}.xml' for xml_id in ids] if DEBUG: print(f'\t{len(train)} xml files') print('Parsing training annotation files') train_annos = bbb.parse('anno_pascalvoc', train, identify) # Remove difficult for training for k,annos in train_annos.items(): for i in range(len(annos)-1, -1, -1): if annos[i].difficult: del annos[i] print('Generating training annotation file') bbb.generate('anno_pickle', train_annos, f'{ROOT}/onedet_cache/train.pkl') print() print('Getting testing annotation filenames') test = [] for (year, img_set) in TESTSET: with open(f'{ROOT}/VOC{year}/ImageSets/Main/{img_set}.txt', 'r') as f: ids = f.read().strip().split() test += [f'{ROOT}/VOC{year}/Annotations/{xml_id}.xml' for xml_id in ids] if DEBUG: print(f'\t{len(test)} xml files') print('Parsing testing annotation files') test_annos = bbb.parse('anno_pascalvoc', test, identify)
ROOT=ROOT, year=year, xml_id=xml_id) for xml_id in ids ] if DEBUG: print('\t{length} xml files'.format(length=len(train))) print('Parsing training annotation files') train_annos = bbb.parse('anno_pascalvoc', train, identify) # Remove difficult for training for k, annos in train_annos.items(): for i in range(len(annos) - 1, -1, -1): if annos[i].difficult: del annos[i] print('Generating training annotation file') bbb.generate('anno_pickle', train_annos, '{ROOT}/train.pkl'.format(ROOT=ROOT)) print() print('Getting testing annotation filenames') test = [] for (year, img_set) in TESTSET: with open( '{ROOT}/VOCdevkit/VOC{year}/ImageSets/Main/{img_set}.txt'. format(ROOT=ROOT, year=year, img_set=img_set), 'r') as f: ids = f.read().strip().split() test += [ '{ROOT}/VOCdevkit/VOC{year}/Annotations/{xml_id}.xml'.format( ROOT=ROOT, year=year, xml_id=xml_id) for xml_id in ids ]
def test(arguments): log.debug('Creating network') net = ln.models.Yolo(CLASSES, arguments.weight, CONF_THRESH, NMS_THRESH) net.postprocess.append( ln.data.transform.TensorToBrambox(NETWORK_SIZE, LABELS)) net.eval() if arguments.cuda: net.cuda(non_blocking=PIN_MEM) log.debug('Creating dataset') loader = torch.utils.data.DataLoader( CustomDataset(TESTFILE, net), batch_size=MINI_BATCH, shuffle=False, drop_last=False, num_workers=WORKERS if arguments.cuda else 0, pin_memory=PIN_MEM if arguments.cuda else False, collate_fn=ln.data.list_collate, ) if arguments.visdom: log.debug('Creating visdom visualisation wrappers') vis = visdom.Visdom(port=VISDOM_PORT) plot_pr = ln.engine.VisdomLinePlotter(vis, 'pr', opts=dict( xlabel='Recall', ylabel='Precision', title='Precision Recall', xtickmin=0, xtickmax=1, ytickmin=0, ytickmax=1, showlegend=True)) if arguments.hyperdash: log.debug('Creating hyperdash visualisation wrappers') hd = hyperdash.Experiment('YOLOv2 Test') hyperdash_plot_pr = ln.engine.HyperdashLinePlotter(hd) log.debug('Running network') tot_loss = [] coord_loss = [] conf_loss = [] cls_loss = [] anno, det = {}, {} for idx, (data, box) in enumerate(tqdm(loader, total=len(loader))): if arguments.cuda: data = data.cuda(non_blocking=PIN_MEM) data = torch.autograd.Variable(data).no_grad() output, loss = net(data, box) if torch.__version__.startswith('0.3'): data = torch.autograd.Variable(data).no_grad() output, loss = net(data, box) else: with torch.no_grad(): output, loss = net(data, box) if torch.__version__.startswith('0.3'): tot_loss.append(net.loss.loss_tot.data[0] * len(box)) coord_loss.append(net.loss.loss_coord.data[0] * len(box)) conf_loss.append(net.loss.loss_conf.data[0] * len(box)) if net.loss.loss_cls is not None: cls_loss.append(net.loss.loss_cls.data[0] * len(box)) else: tot_loss.append(net.loss.loss_tot.item() * len(box)) coord_loss.append(net.loss.loss_coord.item() * len(box)) conf_loss.append(net.loss.loss_conf.item() * len(box)) if net.loss.loss_cls is not None: cls_loss.append(net.loss.loss_cls.item() * len(box)) key_val = len(anno) anno.update( {loader.dataset.keys[key_val + k]: v for k, v in enumerate(box)}) det.update({ loader.dataset.keys[key_val + k]: v for k, v in enumerate(output) }) pr_dict, ap_dict, m_ap, all_key = bbb.pr_ap_dicts(det, anno, LABELS, IGNORE) pr = pr_dict[all_key] log.info('Computed statistics') for label in sorted(ap_dict.keys()): log.info('\tLabel %r: m_ap = %0.04f' % ( label, ap_dict[label], )) tot = round(sum(tot_loss) / len(anno), 5) coord = round(sum(coord_loss) / len(anno), 2) conf = round(sum(conf_loss) / len(anno), 2) if len(cls_loss) > 0: cls = round(sum(cls_loss) / len(anno), 2) log.test( '\n{seen} mAP:{m_ap}% Loss:{tot} (Coord:{coord} Conf:{conf} Cls:{cls})' .format(seen=net.seen // BATCH, m_ap=m_ap, tot=tot, coord=coord, conf=conf, cls=cls)) else: log.test('\n{seen} mAP:{m_ap}% Loss:{tot} (Coord:{coord} Conf:{conf})'. format(seen=net.seen // BATCH, m_ap=m_ap, tot=tot, coord=coord, conf=conf)) name = 'mAP: {m_ap}%'.format(m_ap=m_ap) if arguments.visdom: plot_pr(np.array(pr[0]), np.array(pr[1]), name=name) if arguments.hyperdash: now = time.time() re_seen = None for index, (re_, pr_) in enumerate(sorted(zip(pr[1], pr[0]))): re_ = round(re_, 2) if re_ != re_seen: re_seen = re_ re_ = int(re_ * 100.0) hyperdash_plot_pr(name, pr_, now + re_, log=False) if arguments.save_det is not None: # Note: These detection boxes are the coordinates for the letterboxed images, # you need ln.data.ReverseLetterbox to have the right ones. # Alternatively, you can save the letterboxed annotations, and use those for statistics later on! bbb.generate('det_pickle', det, Path(arguments.save_det).with_suffix('.pkl')) #bbb.generate('anno_pickle', det, Path('anno-letterboxed_'+arguments.save_det).with_suffix('.pkl')) if arguments.hyperdash: hyperdash_plot_pr.close()
def get_label_for_single_file(year, dataset): data = json.load(open(f"{ROOT}/annotations/instances_{dataset}{year}.json")) cate = {x['id']: x['name'] for x in data['categories']} # parse one json file once, may need to conbine them later? # hold all images images = {} for image in data["images"]: images[image["id"]] = { # add more attributes if needed "file_name" : image["file_name"], "image_size" : { "height": image["height"], "width": image["width"], }, "img_id" : image["id"], "obj" : [] } for anno in data["annotations"]: # attach annotations to corresponding images images[anno["image_id"]]["obj"].append({ "class_label": cate[anno["category_id"]], "bbox": anno["bbox"] }) # delete images with no annotations del_keys = [] for image in images: if images[image]["obj"] == []: del_keys.append(image) for key in del_keys: del images[key] val_annos = {} for image in images: val_annos[f'{ROOT}/{dataset}{year}/{images[image]["file_name"]}'] = [] for obj in images[image]["obj"]: tmp_obj = bbb.annotations.PascalVocAnnotation() tmp_obj.class_label = obj["class_label"] tmp_obj.x_top_left = int(max(obj["bbox"][0], 0)) tmp_obj.y_top_left = int(max(obj["bbox"][1], 0)) # maybe out of boundry! need to check? tmp_obj.width = int(obj["bbox"][2]) tmp_obj.height = int(obj["bbox"][3]) val_annos[f'{ROOT}/{dataset}{year}/{images[image]["file_name"]}'].append(tmp_obj) # this one contains categories not in VOC bbb.generate('anno_pickle', val_annos, f'{DST}/onedet_cache/MSCOCO{dataset}{year}.pkl') val_annos_fix_label = {} for image in val_annos: val_annos_fix_label[image] = [] for anno in val_annos[image]: # map some coco label to voc labels if anno.class_label in change_list.keys(): anno.class_label = change_list[anno.class_label] if anno.class_label in labels: val_annos_fix_label[image].append(anno) del_keys = [] for image in val_annos_fix_label: if val_annos_fix_label[image] == []: del_keys.append(image) for key in del_keys: del val_annos_fix_label[key] print(len(val_annos_fix_label)) # this one can run like pkl generated from VOC #val_annos_fix_label = dict(itertools.islice(val_annos_fix_label.items(), 512)) bbb.generate('anno_pickle', val_annos_fix_label, f'{DST}/onedet_cache/MSCOCO{dataset}{year}_fix_label.pkl') # generate test file for each label if testing: main = {} for label in labels: main[label] = [] for img in val_annos_fix_label: has_obj = {} #print(img) for obj in val_annos_fix_label[img]: #print(obj) has_obj[obj.class_label] = 1 #print(has_obj) for label in labels: if label in has_obj: main[label].append([img.split('/')[-1].split('.')[0], 1]) else: main[label].append([img.split('/')[-1].split('.')[0], -1]) for label in labels: with open(f'{ROOT}/VOCtmp/ImageSets/Main/{label}_test.txt', 'w') as f: for case in main[label]: f.write(case[0] + ' ' + str(case[1]) + '\n')
def main(): parser = argparse.ArgumentParser( description='Convert bounding box file(s) from one format to the other', usage= '%(prog)s inputformat inputpath outputformat outputpath [optional arguments]', epilog=f'Posible formats are: {list(bbb.formats.keys())}', ) parser.add_argument( 'inputformat', metavar='inputformat', choices=bbb.formats.keys(), help='Input format', ) parser.add_argument('inputpath', help='Bounding box file, folder or file sequence') parser.add_argument( 'outputformat', metavar='outputformat', choices=bbb.formats.keys(), help='Ouput format', ) parser.add_argument('outputpath', help='Output file or folder') parser.add_argument( '--stride', '-s', metavar='N', type=int, default=1, help='If a sequence expression is given as input, this stride is used', ) parser.add_argument( '--offset', '-o', metavar='N', type=int, default=0, help='If a sequence expression is given as input, this offset is used', ) parser.add_argument( '--kwargs', '-k', metavar='KW=V', help='Keyword arguments for the parser', nargs='*', action=StoreKwargs, default={}, ) args = parser.parse_args() # Parse arguments if bbb.formats[args.outputformat].parser_type == bbb.ParserType.MULTI_FILE: out = Path(args.outputpath) if not out.is_dir() and len(out.suffixes) > 0: log.error( f'Output format [{args.outputformat}] requires a path to a directory' ) sys.exit(1) if not out.exists(): log.info( f'[{args.outputformat}] folder does not exist, creating...') os.makedirs(out) # Convert bbox = bbb.parse( args.inputformat, args.inputpath, stride=args.stride, offset=args.offset, **args.kwargs, ) bbb.generate(args.outputformat, bbox, args.outputpath, **args.kwargs) print(f'Converted {len(bbox)} files')