def test_converters_gts(): # Defining paths with images and annotations images_dir = 'data/database/images' gts_dir = 'data/database/gts' assert os.path.isdir(images_dir) assert os.path.isdir(gts_dir) # COCO coco_dir = os.path.join(gts_dir, 'coco_format_v1') coco_bbs_v1 = converter.coco2bb(coco_dir) coco_bbs_v1.sort(key=lambda x: str(x), reverse=True) # COCO coco_dir = os.path.join(gts_dir, 'coco_format_v2') coco_bbs_v2 = converter.coco2bb(coco_dir) coco_bbs_v2.sort(key=lambda x: str(x), reverse=True) # CVAT cvat_dir = os.path.join(gts_dir, 'cvat_format') cvat_bbs = converter.cvat2bb(cvat_dir) cvat_bbs.sort(key=lambda x: str(x), reverse=True) # IMAGENET imagenet_dir = os.path.join(gts_dir, 'imagenet_format/Annotations') imagenet_bbs = converter.imagenet2bb(imagenet_dir) imagenet_bbs.sort(key=lambda x: str(x), reverse=True) # LABEL ME labelme_dir = os.path.join(gts_dir, 'labelme_format') labelme_bbs = converter.labelme2bb(labelme_dir) labelme_bbs.sort(key=lambda x: str(x), reverse=True) # OPEN IMAGE openimage_dir = os.path.join(gts_dir, 'openimages_format') openimage_bbs = converter.openimage2bb(openimage_dir, images_dir) openimage_bbs.sort(key=lambda x: str(x), reverse=True) # VOC PASCAL vocpascal_dir = os.path.join(gts_dir, 'pascalvoc_format') vocpascal_bbs = converter.vocpascal2bb(vocpascal_dir) vocpascal_bbs.sort(key=lambda x: str(x), reverse=True) # YOLO yolo_annotations_dir = os.path.join(gts_dir, 'yolo_format/obj_train_data') yolo_names_file = os.path.join(gts_dir, 'yolo_format/obj.names') yolo_bbs = converter.yolo2bb(yolo_annotations_dir, images_dir, yolo_names_file, bb_type=BBType.GROUND_TRUTH) yolo_bbs.sort(key=lambda x: str(x), reverse=True) assert len(coco_bbs_v1) == len(coco_bbs_v2) == len(cvat_bbs) == len( imagenet_bbs) == len(labelme_bbs) == len(openimage_bbs) == len( vocpascal_bbs) == len(yolo_bbs) for coco_bb_v1, coco_bb_v2, cvat_bb, imagenet_bb, labelme_bb, openimage_bb, vocpascal_bb, yolo_bb in zip( coco_bbs_v1, coco_bbs_v2, cvat_bbs, imagenet_bbs, labelme_bbs, openimage_bbs, vocpascal_bbs, yolo_bbs): assert coco_bb_v1 == coco_bb_v2 == cvat_bb == imagenet_bb == labelme_bb == openimage_bb == vocpascal_bb == yolo_bb
def load_annotations_gt(self): ret = [] if self.rad_gt_format_coco_json.isChecked(): ret = converter.coco2bb(self.dir_annotations_gt) elif self.rad_gt_format_cvat_xml.isChecked(): ret = converter.cvat2bb(self.dir_annotations_gt) elif self.rad_gt_format_openimages_csv.isChecked(): ret = converter.openimage2bb(self.dir_annotations_gt, self.dir_images_gt, BBType.GROUND_TRUTH) elif self.rad_gt_format_labelme_xml.isChecked(): ret = converter.labelme2bb(self.dir_annotations_gt) elif self.rad_gt_format_pascalvoc_xml.isChecked(): ret = converter.vocpascal2bb(self.dir_annotations_gt) elif self.rad_gt_format_imagenet_xml.isChecked(): ret = converter.imagenet2bb(self.dir_annotations_gt) elif self.rad_gt_format_abs_values_text.isChecked(): ret = converter.text2bb(self.dir_annotations_gt, bb_type=BBType.GROUND_TRUTH) elif self.rad_gt_format_yolo_text.isChecked(): ret = converter.yolo2bb(self.dir_annotations_gt, self.dir_images_gt, self.filepath_classes_gt, bb_type=BBType.GROUND_TRUTH) # Make all types as GT [bb.set_bb_type(BBType.GROUND_TRUTH) for bb in ret] return ret
def test_toy_example_gts(): ############################################################################ # Verify if all files in the toy example follow their expected format ############################################################################ # PASCAL VOC dir_annots_gts_pascal = 'toyexample/gts_vocpascal_format' files = general_utils.get_files_recursively(dir_annots_gts_pascal) assert len(files) > 0 for f in files: assert validations.is_pascal_format( f), 'File {f} does not follow the expected format (PASCAL VOC)' # COCO dir_annots_gts_coco = 'toyexample/gts_coco_format' files = general_utils.get_files_recursively(dir_annots_gts_coco) assert len(files) > 0 for f in files: assert validations.is_coco_format(f), 'File {f} does not follow the expected format (COCO)' ############################################################################ # Compare if all bounding boxes are the same ############################################################################ pascal_bbs = converter.vocpascal2bb(dir_annots_gts_pascal) coco_bbs = converter.coco2bb(dir_annots_gts_coco) coco_bbs.sort(key=lambda x: str(x), reverse=True) pascal_bbs.sort(key=lambda x: str(x), reverse=True) assert len(coco_bbs) == len(pascal_bbs) for coco_bb, pascal_bb in zip(coco_bbs, pascal_bbs): assert coco_bb == pascal_bb
def load_annotations_det(self): ret = [] if not self.validate_det_choices(): return ret, False if self.rad_det_format_coco_json.isChecked(): ret = converter.coco2bb(self.dir_dets, bb_type=BBType.DETECTED) elif self.rad_det_ci_format_text_xywh_rel.isChecked( ) or self.rad_det_cn_format_text_xywh_rel.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYWH, type_coordinates=CoordinatesType.RELATIVE, img_dir=self.dir_images_gt) elif self.rad_det_ci_format_text_xyx2y2_abs.isChecked( ) or self.rad_det_cn_format_text_xyx2y2_abs.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYX2Y2, type_coordinates=CoordinatesType.ABSOLUTE, img_dir=self.dir_images_gt) elif self.rad_det_ci_format_text_xywh_abs.isChecked( ) or self.rad_det_cn_format_text_xywh_abs.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYWH, type_coordinates=CoordinatesType.ABSOLUTE, img_dir=self.dir_images_gt) # If detection requires class_id, replace the detection names (integers) by a class from the txt file if self.rad_det_ci_format_text_xywh_rel.isChecked( ) or self.rad_det_ci_format_text_xyx2y2_abs.isChecked( ) or self.rad_det_ci_format_text_xywh_abs.isChecked(): ret = self.replace_id_with_classes(ret, self.filepath_classes_det) return ret, True
def load_annotations_det(self): ret = [] if not self.validate_det_choices(): return ret, False if self.rad_det_format_coco_json.isChecked(): ret = converter.coco2bb(self.dir_dets, bb_type=BBType.DETECTED) elif self.rad_det_ci_format_text_yolo_rel.isChecked( ) or self.rad_det_cn_format_text_yolo_rel.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.YOLO, type_coordinates=CoordinatesType.RELATIVE, img_dir=self.dir_images_gt) elif self.rad_det_ci_format_text_xyx2y2_abs.isChecked( ) or self.rad_det_cn_format_text_xyx2y2_abs.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYX2Y2, type_coordinates=CoordinatesType.ABSOLUTE, img_dir=self.dir_images_gt) elif self.rad_det_ci_format_text_xywh_abs.isChecked( ) or self.rad_det_cn_format_text_xywh_abs.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYWH, type_coordinates=CoordinatesType.ABSOLUTE, img_dir=self.dir_images_gt) # Verify if for the selected format, detections were found if len(ret) == 0: self.show_popup( 'No file was found for the selected detection format in the annotations directory.', 'No file was found', buttons=QMessageBox.Ok, icon=QMessageBox.Information) return ret, False # If detection requires class_id, replace the detection names (integers) by a class from the txt file if self.rad_det_ci_format_text_yolo_rel.isChecked( ) or self.rad_det_ci_format_text_xyx2y2_abs.isChecked( ) or self.rad_det_ci_format_text_xywh_abs.isChecked(): ret = general_utils.replace_id_with_classes( ret, self.filepath_classes_det) return ret, True
def test_toy_example_dets_compatibility(): # Checks if all different formats in the toyexample represent the same coordinates dir_img_dir = 'toyexample/images' filepath_classes_det = 'toyexample/voc.names' dir_dets_classid_abs_xywh = 'toyexample/dets_classid_abs_xywh' dets_classid_abs_xywh = converter.text2bb(dir_dets_classid_abs_xywh, bb_type=BBType.DETECTED, bb_format=BBFormat.XYWH, type_coordinates=CoordinatesType.ABSOLUTE) dets_classid_abs_xywh = general_utils.replace_id_with_classes(dets_classid_abs_xywh, filepath_classes_det) dets_classid_abs_xywh.sort(key=lambda x: str(x), reverse=True) dir_dets_classid_abs_xyx2y2 = 'toyexample/dets_classid_abs_xyx2y2' dets_classid_abs_xyx2y2 = converter.text2bb(dir_dets_classid_abs_xyx2y2, bb_type=BBType.DETECTED, bb_format=BBFormat.XYX2Y2, type_coordinates=CoordinatesType.ABSOLUTE) dets_classid_abs_xyx2y2 = general_utils.replace_id_with_classes(dets_classid_abs_xyx2y2, filepath_classes_det) dets_classid_abs_xyx2y2.sort(key=lambda x: str(x), reverse=True) dir_dets_classid_rel_xcycwh = 'toyexample/dets_classid_rel_xcycwh' dets_classid_rel_xcycwh = converter.text2bb(dir_dets_classid_rel_xcycwh, bb_type=BBType.DETECTED, bb_format=BBFormat.YOLO, type_coordinates=CoordinatesType.RELATIVE, img_dir=dir_img_dir) dets_classid_rel_xcycwh = general_utils.replace_id_with_classes(dets_classid_rel_xcycwh, filepath_classes_det) dets_classid_rel_xcycwh.sort(key=lambda x: str(x), reverse=True) dir_dets_classname_abs_xywh = 'toyexample/dets_classname_abs_xywh' dets_classname_abs_xywh = converter.text2bb(dir_dets_classname_abs_xywh, bb_type=BBType.DETECTED, bb_format=BBFormat.XYWH, type_coordinates=CoordinatesType.ABSOLUTE) dets_classname_abs_xywh.sort(key=lambda x: str(x), reverse=True) dir_dets_classname_abs_xyx2y2 = 'toyexample/dets_classname_abs_xyx2y2' dets_classname_abs_xyx2y2 = converter.text2bb(dir_dets_classname_abs_xyx2y2, bb_type=BBType.DETECTED, bb_format=BBFormat.XYX2Y2, type_coordinates=CoordinatesType.ABSOLUTE) dets_classname_abs_xyx2y2.sort(key=lambda x: str(x), reverse=True) dir_dets_classname_rel_xcycwh = 'toyexample/dets_classname_rel_xcycwh' dets_classname_rel_xcycwh = converter.text2bb(dir_dets_classname_rel_xcycwh, bb_type=BBType.DETECTED, bb_format=BBFormat.YOLO, type_coordinates=CoordinatesType.RELATIVE, img_dir=dir_img_dir) dets_classname_rel_xcycwh.sort(key=lambda x: str(x), reverse=True) dir_dets_coco_format = 'toyexample/dets_coco_format' dets_coco_format = converter.coco2bb(dir_dets_coco_format, bb_type=BBType.DETECTED) dets_coco_format.sort(key=lambda x: str(x), reverse=True) for a, b, c, d, e, f, g in zip(dets_classid_abs_xywh, dets_classid_abs_xyx2y2, dets_classid_rel_xcycwh, dets_classname_abs_xywh, dets_classname_abs_xyx2y2, dets_classname_rel_xcycwh, dets_coco_format): assert a == b == c == d == e == f == g
def load_annotations_det(self): ret = [] # If relative format was required if self.rad_det_ci_format_text_xywh_rel.isChecked( ) or self.rad_det_cn_format_text_xywh_rel.isChecked(): # Verify if directory with images was provided if self.dir_images_gt is None or not os.path.isdir(self.dir_images_gt): self.show_popup( f'For the selected annotation type, it is necessary to inform a directory with the dataset images.\nDirectory is empty or does not have valid images.', 'Invalid image directory', buttons=QMessageBox.Ok, icon=QMessageBox.Information) return ret, False if self.rad_det_format_coco_json.isChecked(): ret = converter.coco2bb(self.dir_dets, bb_type=BBType.DETECTED) elif self.rad_det_ci_format_text_xywh_rel.isChecked( ) or self.rad_det_cn_format_text_xywh_rel.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYWH, type_coordinates=CoordinatesType.RELATIVE, img_dir=self.dir_images_gt) elif self.rad_det_ci_format_text_xyx2y2_abs.isChecked( ) or self.rad_det_cn_format_text_xyx2y2_abs.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYX2Y2, type_coordinates=CoordinatesType.ABSOLUTE, img_dir=self.dir_images_gt) elif self.rad_det_ci_format_text_xywh_abs.isChecked( ) or self.rad_det_cn_format_text_xywh_abs.isChecked(): ret = converter.text2bb(self.dir_dets, bb_type=BBType.DETECTED, bb_format=BBFormat.XYWH, type_coordinates=CoordinatesType.ABSOLUTE, img_dir=self.dir_images_gt) # if its format is in a format that requires class_id, replace the class_id by the class name if self.rad_det_ci_format_text_xywh_rel.isChecked( ) or self.rad_det_ci_format_text_xyx2y2_abs.isChecked( ) or self.rad_det_ci_format_text_xywh_abs.isChecked(): if self.filepath_classes_det is None or os.path.isfile( self.filepath_classes_det) is False or len( general_utils.get_files_dir( self.dir_images_gt, extensions=['jpg', 'jpge', 'png', 'bmp', 'tiff', 'tif'])) == 0: self.show_popup( f'For the selected annotation type, it is necessary to inform a directory with the dataset images.\nDirectory is empty or does not have valid images.', 'Invalid image directory', buttons=QMessageBox.Ok, icon=QMessageBox.Information) return ret, False ret = self.replace_id_with_classes(ret, self.filepath_classes_det) if len(ret) == 0: self.show_popup( f'No files was found in the selected directory for the selected annotation format.\nDirectory is empty or does not have valid annotation files.', 'Invalid directory', buttons=QMessageBox.Ok, icon=QMessageBox.Information) return ret, False return ret, True
import json from math import isclose from src.bounding_box import BBFormat, BBType, BoundingBox from src.evaluators.coco_evaluator import get_coco_summary from src.utils.converter import coco2bb # Load coco samples gts = coco2bb('tests/test_coco_eval/gts', BBType.GROUND_TRUTH) dts = coco2bb('tests/test_coco_eval/dets', BBType.DETECTED) res = get_coco_summary(gts, dts) # Compare results to those obtained with coco's official implementation tol = 1e-6 assert abs(res["AP"] - 0.503647) < tol assert abs(res["AP50"] - 0.696973) < tol assert abs(res["AP75"] - 0.571667) < tol assert abs(res["APsmall"] - 0.593252) < tol assert abs(res["APmedium"] - 0.557991) < tol assert abs(res["APlarge"] - 0.489363) < tol assert abs(res["AR1"] - 0.386813) < tol assert abs(res["AR10"] - 0.593680) < tol assert abs(res["AR100"] - 0.595353) < tol assert abs(res["ARsmall"] - 0.654764) < tol assert abs(res["ARmedium"] - 0.603130) < tol assert abs(res["ARlarge"] - 0.553744) < tol