def post(self, dataset_id): """ Updates dataset by ID """ dataset = current_user.find_exist_dataset_by_id(dataset_id) if dataset is None: return {"message": "Invalid dataset id"}, 400 args = Parser.update_dataset_parser().parse_args() categories = args.get('categories') default_annotation_metadata = args.get('default_annotation_metadata') set_default_annotation_metadata = args.get( 'set_default_annotation_metadata') if categories is not None: from usecase.changeDatasetCategoriesUseCase import ChangeDatasetCategoriesUseCase ChangeDatasetCategoriesUseCase().execute(dataset_id, categories) if default_annotation_metadata is not None: update = {} for key, value in default_annotation_metadata.items(): if key not in dataset.default_annotation_metadata: update[f'set__metadata__{key}'] = value dataset.default_annotation_metadata = default_annotation_metadata if len(update.keys()) > 0: AnnotationModel.objects(dataset_id=dataset.id, deleted=False)\ .update(**update) dataset.update( #categories=dataset.categories, default_annotation_metadata=dataset.default_annotation_metadata) return {"success": True}
def post(self, dataset_id): """ Updates dataset by ID """ dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() if dataset is None: return {"message": "Invalid dataset id"}, 400 args = update_dataset.parse_args() categories = args.get('categories') default_annotation_metadata = args.get('default_annotation_metadata') set_default_annotation_metadata = args.get( 'set_default_annotation_metadata') if categories is not None: dataset.categories = CategoryModel.bulk_create(categories) if default_annotation_metadata is not None: update = {} for key, value in default_annotation_metadata.items(): if key not in dataset.default_annotation_metadata: update[f'set__metadata__{key}'] = value dataset.default_annotation_metadata = default_annotation_metadata if len(update.keys()) > 0: AnnotationModel.objects(dataset_id=dataset.id, deleted=False)\ .update(**update) dataset.update( categories=dataset.categories, default_annotation_metadata=dataset.default_annotation_metadata) return {"success": True}
def post(self): """ Creates an annotation """ args = create_annotation.parse_args() image_id = args.get('image_id') category_id = args.get('category_id') isbbox = args.get('isbbox') metadata = args.get('metadata', {}) segmentation = args.get('segmentation', []) keypoints = args.get('keypoints', []) image = current_user.images.filter(id=image_id, deleted=False).first() if image is None: return {"message": "Invalid image id"}, 400 logger.info( f'{current_user.username} has created an annotation for image {image_id} with {isbbox}' ) logger.info( f'{current_user.username} has created an annotation for image {image_id}' ) try: annotation = AnnotationModel(image_id=image_id, category_id=category_id, metadata=metadata, segmentation=segmentation, keypoints=keypoints, isbbox=isbbox) annotation.save() except (ValueError, TypeError) as e: return {'message': str(e)}, 400 return query_util.fix_ids(annotation)
def get(self, dataset_id): """ All users in the dataset """ args = dataset_generate.parse_args() dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() if dataset is None: return {"message": "Invalid dataset id"}, 400 images = ImageModel.objects(dataset_id=dataset.id, deleted=False) annotated_images = images.filter(annotated=True) annotations = AnnotationModel.objects(dataset_id=dataset_id, deleted=False) # Calculate annotation counts by category in this dataset category_count = dict() image_category_count = dict() for category in dataset.categories: # Calculate the annotation count in the current category in this dataset cat_name = CategoryModel.objects(id=category).first()['name'] cat_count = AnnotationModel.objects(dataset_id=dataset_id, category_id=category, deleted=False).count() category_count.update({str(cat_name): cat_count}) # Calculate the annotated images count in the current category in this dataset image_count = len( AnnotationModel.objects(dataset_id=dataset_id, category_id=category, deleted=False).distinct('image_id')) image_category_count.update({str(cat_name): image_count}) stats = { 'total': { 'Users': dataset.get_users().count(), 'Images': images.count(), 'Annotated Images': annotated_images.count(), 'Annotations': annotations.count(), 'Categories': len(dataset.categories), 'Time Annotating (s)': (images.sum('milliseconds') or 0) / 1000 }, 'average': { 'Image Size (px)': images.average('width'), 'Image Height (px)': images.average('height'), 'Annotation Area (px)': annotations.average('area'), 'Time (ms) per Image': images.average('milliseconds') or 0, 'Time (ms) per Annotation': annotations.average('milliseconds') or 0 }, 'categories': category_count, 'images_per_category': image_category_count } return stats
def get(self, dataset_id): args = dataset_generate.parse_args() dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() if dataset is None: return {"message": "Invalid dataset id"}, 400 AnnotationModel.objects(dataset_id=dataset.id).delete() ImageModel.objects(dataset_id=dataset.id).update( set__annotated=False, set__num_annotations=0) return {'success': True}
def create_annotation(image_id): annotation = AnnotationModel( image_id=image_id, category_id=0, metadata={}, segmentation=[[1, 2, 3, 4]], keypoints=[1, 2, 3, 4], isbbox=False ) annotation.save() return annotation.id
def get(self, refset_id): """ All users in the refset """ args = refset_generate.parse_args() refset = current_user.refsets.filter(id=refset_id, deleted=False).first() if refset is None: return {"message": "Invalid refset id"}, 400 AnnotationModel.objects(refset_id=refset.id)\ .update(metadata=refset.default_annotation_metadata) PixelModel.objects(refset_id=refset.id)\ .update(metadata={}) return {'success': True}
def get(self, dataset_id): """ All users in the dataset """ args = dataset_generate.parse_args() dataset = current_user.find_exist_dataset_by_id(dataset_id) if dataset is None: return {"message": "Invalid dataset id"}, 400 AnnotationModel.objects(dataset_id=dataset.id)\ .update(metadata=dataset.default_annotation_metadata) ImageModel.objects(dataset_id=dataset.id)\ .update(metadata={}) return {'success': True}
def get(self, dataset_id): """ All users in the dataset """ args = dataset_generate.parse_args() dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() if dataset is None: return {"message": "Invalid dataset id"}, 400 AnnotationModel.objects(dataset_id=dataset.id).update( metadata=dataset.default_annotation_metadata) ImageModel.objects(dataset_id=dataset.id).update(metadata={}) return {'success': True}
def get(self, category_id): """"Endpoint called by category image list """ args = page_data.parse_args() limit = args['limit'] page = args['page'] category = current_user.categories.filter(id=category_id).first() # check if the id exits if category is None: return {"message": "Invalid category id"}, 400 image_ids = AnnotationModel.objects(category_id=category_id).distinct('image_id') image_ids.sort() pagination = Pagination(len(image_ids), limit, page) image_ids = image_ids[pagination.start:pagination.end] images = [] for image_id in image_ids: img = ImageModel.objects(id=image_id, annotated=True).first() if img: images.append(query_util.fix_ids(img)) return { "category": query_util.fix_ids(category), "pagination": pagination.export(), "page": page, "images": images, }
def post(self, from_id, to_id): args = copy_annotations.parse_args() category_ids = args.get('category_ids') image_from = current_user.images.filter(id=from_id).first() image_to = current_user.images.filter(id=to_id).first() if image_from is None or image_to is None: return {'success': False, 'message': 'Invalid image ids'}, 400 if image_from == image_to: return {'success': False, 'message': 'Cannot copy self'}, 400 if image_from.width != image_to.width or image_from.height != image_to.height: return { 'success': False, 'message': 'Image sizes do not match' }, 400 if category_ids is None: category_ids = DatasetModel.objects( id=image_from.dataset_id).first().categories query = AnnotationModel.objects(image_id=image_from.id, category_id__in=category_ids, deleted=False) return {'annotations_created': image_to.copy_annotations(query)}
def get(self, image_id): """ Called when loading from the annotator client """ image = ImageModel.objects(id=image_id)\ .exclude('events').first() if image is None: return {'success': False, 'message': 'Could not load image'}, 400 dataset = current_user.datasets.filter(id=image.dataset_id).first() if dataset is None: return { 'success': False, 'message': 'Could not find associated dataset' }, 400 categories = CategoryModel.objects(deleted=False)\ .in_bulk(dataset.categories).items() # Get next and previous image images = ImageModel.objects(dataset_id=dataset.id, deleted=False) pre = images.filter( file_name__lt=image.file_name).order_by('-file_name').first() nex = images.filter( file_name__gt=image.file_name).order_by('file_name').first() preferences = {} if not Config.LOGIN_DISABLED: preferences = current_user.preferences # Generate data about the image to return to client data = { 'image': query_util.fix_ids(image), 'categories': [], 'dataset': query_util.fix_ids(dataset), 'preferences': preferences, 'permissions': { 'dataset': dataset.permissions(current_user), 'image': image.permissions(current_user) } } data['image']['previous'] = pre.id if pre else None data['image']['next'] = nex.id if nex else None for category in categories: category = query_util.fix_ids(category[1]) category_id = category.get('id') annotations = AnnotationModel.objects(image_id=image_id, category_id=category_id, deleted=False)\ .exclude('events').all() category['show'] = True category['visualize'] = False category[ 'annotations'] = [] if annotations is None else query_util.fix_ids( annotations) data.get('categories').append(category) return data
def get(self, refset_id): """ All users in the refset """ args = refset_generate.parse_args() refset = current_user.refsets.filter(id=refset_id, deleted=False).first() if refset is None: return {"message": "Invalid refset id"}, 400 pixels = PixelModel.objects(refset_id=refset.id, deleted=False) annotated_pixels = pixels.filter(annotated=True) annotations = AnnotationModel.objects(refset_id=refset_id, deleted=False) # Calculate annotation counts by category in this refset category_count = dict() image_category_count = dict() for category in refset.categories: # Calculate the annotation count in the current category in this refset cat_name = CategoryModel.objects(id=category).first()['name'] cat_count = AnnotationModel.objects(refset_id=refset_id, category_id=category, deleted=False).count() category_count.update({str(cat_name): cat_count}) # Calculate the annotated pixels count in the current category in this refset image_count = len(AnnotationModel.objects(refset_id=refset_id, category_id=category, deleted=False).distinct('image_id')) image_category_count.update({str(cat_name): image_count}) stats = { 'total': { 'Users': refset.get_users().count(), 'Pixels': pixels.count(), 'Annotated Pixels': annotated_pixels.count(), 'Annotations': annotations.count(), 'Categories': len(refset.categories), 'Time Annotating (s)': (pixels.sum('milliseconds') or 0) / 1000 }, 'average': { 'Pixel Size (px)': pixels.average('width'), 'Pixel Height (px)': pixels.average('height'), 'Annotation Area (px)': annotations.average('area'), 'Time (ms) per Pixel': pixels.average('milliseconds') or 0, 'Time (ms) per Annotation': annotations.average('milliseconds') or 0 }, 'categories': category_count, 'pixels_per_category': image_category_count } return stats
def post(self, image_id): """ COCO data test """ print("Origin Model") image_model = ImageModel.objects(id=image_id).first() if not image_model: return {"message": "Invalid image ID"}, 400 #image = Image.open(image_model.path) annotations = AnnotationModel.objects(image_id=image_id) for annotation in annotations: for segmentation in annotation.segmentation: print(segmentation) origin(image_model.path, segmentation) AnnotationModel.objects(image_id=image_id).delete() return {"success": True}
def post(self): """ Creates an annotation """ args = create_annotation.parse_args() image_id = args.get('image_id') category_id = args.get('category_id') isbbox = args.get('isbbox') metadata = args.get('metadata', {}) segmentation = args.get('segmentation', []) bbox = args.get('bbox', []) keypoints = args.get('keypoints', []) # change appro after setting login_user # image = current_user.images.filter(id=image_id, deleted=False).first() # image = ImageModel.objects.get(id=image_id, deleted=False).first() image = ImageModel.objects(id=image_id).first() if image is None: return {"message": "Invalid image id"}, 400 logger.info( f'{current_user.username} has created an annotation for image {image_id} with {isbbox}' ) logger.info( f'{current_user.username} has created an annotation for image {image_id}' ) # add condition if user is not authenticed or dataset is public try: annotation = AnnotationModel(image_id=image_id, category_id=category_id, metadata=metadata, segmentation=segmentation, bbox=bbox, keypoints=keypoints, isbbox=isbbox) annotation.save() except (ValueError, TypeError) as e: return {'message': str(e)}, 400 return query_util.fix_ids(annotation)
def post(self, image_id): """ COCO data test """ print("Converter Model") image_model = ImageModel.objects(id=image_id).first() if not image_model: return {"message": "Invalid image ID"}, 400 #image = Image.open(image_model.path) annotations = AnnotationModel.objects(image_id=image_id) for annotation in annotations: category_id = annotation.category_id category = CategoryModel.objects(id=category_id).first() for segmentation in annotation.segmentation: print(segmentation) convert(image_model.path, segmentation, category.color) AnnotationModel.objects(image_id=image_id).delete() return {"success": True}
def post(self): """ Creates an annotation """ args = create_annotation.parse_args() image_id = args.get('image_id') category_id = args.get('category_id') metadata = args.get('metadata', {}) segmentation = args.get('segmentation', []) keypoints = args.get('keypoints', []) logger.info( f'{current_user.username} has created an annotation for image {image_id}' ) try: annotation = AnnotationModel(image_id=image_id, category_id=category_id, metadata=metadata, segmentation=segmentation, keypoints=keypoints) annotation.save() except (ValueError, TypeError) as e: return {'message': str(e)}, 400 return query_util.fix_ids(annotation)
def get(self): """ Endpoint called by category viewer client """ args = page_data.parse_args() limit = args['limit'] page = args['page'] categories = current_user.categories.filter(deleted=False) pagination = Pagination(categories.count(), limit, page) categories = query_util.fix_ids(categories[pagination.start:pagination.end]) for category in categories: category['numberAnnotations'] = AnnotationModel.objects(deleted=False, category_id=category.get('id')).count() return { "pagination": pagination.export(), "page": page, "categories": categories }
def create_annotation_from(self, annotation_data, image_id): collect_annotation_data = {} self.append_events_ant_times_to(collect_annotation_data, annotation_data) self.append_papers_object_to(collect_annotation_data, annotation_data, image_id) self.append_other_data_to(collect_annotation_data, annotation_data, image_id) return AnnotationModel( image_id=image_id, category_id=annotation_data['category_id'], events=collect_annotation_data['events'], milliseconds=collect_annotation_data['milliseconds'], paper_object=collect_annotation_data['paper_object'], segmentation=collect_annotation_data['segmentation'], area=collect_annotation_data['area'], bbox=collect_annotation_data['bbox'], isbbox=collect_annotation_data['isbbox'], keypoints=collect_annotation_data['keypoints'], metadata=collect_annotation_data['metadata'], color=collect_annotation_data['color'], )
def get(self, image_id): """ Called when loading from the annotator client """ image = ImageModel.objects(id=image_id)\ .exclude('events').first() if image is None: return {'success': False, 'message': 'Could not load image'}, 400 dataset = current_user.datasets.filter(id=image.dataset_id).first() if dataset is None: return { 'success': False, 'message': 'Could not find associated dataset' }, 400 categories = CategoryModel.objects(deleted=False)\ .in_bulk(dataset.categories).items() # Generate data about the image to return to client data = {'categories': []} for category in categories: category = query_util.fix_ids(category[1]) category_id = category.get('id') annotations = AnnotationModel.objects(image_id=image_id, category_id=category_id, deleted=False)\ .exclude('events').all() category['show'] = True category['visualize'] = False category[ 'annotations'] = [] if annotations is None else query_util.fix_ids( annotations) data.get('categories').append(category) return data
def get(self, dataset_id): """ All users in the dataset """ args = dataset_generate.parse_args() dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() if dataset is None: return {"message": "Invalid dataset id"}, 400 images = ImageModel.objects(dataset_id=dataset.id, deleted=False) annotated_images = images.filter(annotated=True) annotations = AnnotationModel.objects(dataset_id=dataset_id, deleted=False) stats = { 'total': { 'Users': dataset.get_users().count(), 'Images': images.count(), 'Annotated Images': annotated_images.count(), 'Annotations': annotations.count(), 'Categories': len(dataset.categories), 'Time Annotating (s)': (images.sum('milliseconds') or 0) / 1000 }, 'average': { 'Image Size (px)': images.average('width'), 'Image Height (px)': images.average('height'), 'Annotation Area (px)': annotations.average('area'), 'Time (ms) per Image': images.average('milliseconds') or 0, 'Time (ms) per Annotation': annotations.average('milliseconds') or 0 } } return stats
def find_all_annotations(): return AnnotationModel.objects()
def find_annotations_by(image_id): return AnnotationModel.objects(image_id=image_id)
def find_annotation_list_by_image_id(image_id): return AnnotationModel.objects(image_id=image_id)
def find_annotations_by_category_id(category_id): return AnnotationModel.objects(category_id=category_id)
def import_annotations(task_id, dataset_id, coco_json): task = TaskModel.objects.get(id=task_id) dataset = DatasetModel.objects.get(id=dataset_id) task.update(status="PROGRESS") socket = create_socket() task.info("Beginning Import") images = ImageModel.objects(dataset_id=dataset.id) categories = CategoryModel.objects coco_images = coco_json.get('images', []) coco_annotations = coco_json.get('annotations', []) coco_categories = coco_json.get('categories', []) task.info(f"Importing {len(coco_categories)} categories, " f"{len(coco_images)} images, and " f"{len(coco_annotations)} annotations") total_items = sum( [len(coco_categories), len(coco_annotations), len(coco_images)]) progress = 0 task.info("===== Importing Categories =====") # category id mapping ( file : database ) categories_id = {} # Create any missing categories for category in coco_categories: category_name = category.get('name') category_id = category.get('id') category_model = categories.filter(name__iexact=category_name).first() if category_model is None: task.warning( f"{category_name} category not found (creating a new one)") new_category = CategoryModel( name=category_name, keypoint_edges=category.get('skeleton', []), keypoint_labels=category.get('keypoints', [])) new_category.save() category_model = new_category dataset.categories.append(new_category.id) task.info(f"{category_name} category found") # map category ids categories_id[category_id] = category_model.id # update progress progress += 1 task.set_progress((progress / total_items) * 100, socket=socket) dataset.update(set__categories=dataset.categories) task.info("===== Loading Images =====") # image id mapping ( file: database ) images_id = {} categories_by_image = {} # Find all images for image in coco_images: image_id = image.get('id') image_filename = image.get('file_name') # update progress progress += 1 task.set_progress((progress / total_items) * 100, socket=socket) image_model = images.filter(file_name__exact=image_filename).all() if len(image_model) == 0: task.warning(f"Could not find image {image_filename}") continue if len(image_model) > 1: task.error( f"Too many images found with the same file name: {image_filename}" ) continue task.info(f"Image {image_filename} found") image_model = image_model[0] images_id[image_id] = image_model categories_by_image[image_id] = list() task.info("===== Import Annotations =====") for annotation in coco_annotations: image_id = annotation.get('image_id') category_id = annotation.get('category_id') segmentation = annotation.get('segmentation', []) keypoints = annotation.get('keypoints', []) # is_crowd = annotation.get('iscrowed', False) area = annotation.get('area', 0) bbox = annotation.get('bbox', [0, 0, 0, 0]) isbbox = annotation.get('isbbox', False) progress += 1 task.set_progress((progress / total_items) * 100, socket=socket) has_segmentation = len(segmentation) > 0 has_keypoints = len(keypoints) > 0 if not has_segmentation and not has_keypoints: task.warning( f"Annotation {annotation.get('id')} has no segmentation or keypoints" ) continue try: image_model = images_id[image_id] category_model_id = categories_id[category_id] image_categories = categories_by_image[image_id] except KeyError: task.warning( f"Could not find image assoicated with annotation {annotation.get('id')}" ) continue annotation_model = AnnotationModel.objects( image_id=image_model.id, category_id=category_model_id, segmentation=segmentation, keypoints=keypoints).first() if annotation_model is None: task.info(f"Creating annotation data ({image_id}, {category_id})") annotation_model = AnnotationModel(image_id=image_model.id) annotation_model.category_id = category_model_id annotation_model.color = annotation.get('color') annotation_model.metadata = annotation.get('metadata', {}) if has_segmentation: annotation_model.segmentation = segmentation annotation_model.area = area annotation_model.bbox = bbox if has_keypoints: annotation_model.keypoints = keypoints annotation_model.isbbox = isbbox annotation_model.save() image_categories.append(category_id) else: annotation_model.update(deleted=False, isbbox=isbbox) task.info( f"Annotation already exists (i:{image_id}, c:{category_id})") for image_id in images_id: image_model = images_id[image_id] category_ids = categories_by_image[image_id] all_category_ids = list(image_model.category_ids) all_category_ids += category_ids num_annotations = AnnotationModel.objects( Q(image_id=image_id) & Q(deleted=False) & (Q(area__gt=0) | Q(keypoints__size__gt=0))).count() image_model.update(set__annotated=True, set__category_ids=list(set(all_category_ids)), set__num_annotations=num_annotations) task.set_progress(100, socket=socket)
def get(self, image_id): """ Called when loading from the annotator client """ data = folder_data.parse_args() folder = data.get('folder') order = data.get('order') image = ImageModel.objects(id=image_id)\ .exclude('events').first() if image is None: return {'success': False, 'message': 'Could not load image'}, 400 dataset = current_user.datasets.filter(id=image.dataset_id).first() if dataset is None: return { 'success': False, 'message': 'Could not find associated dataset' }, 400 categories = CategoryModel.objects(deleted=False)\ .in_bulk(dataset.categories).items() if len(folder) > 0: folder = folder[0].strip('/') + folder[1:] if folder[-1] != '/': folder = folder + '/' else: folder = '' # Get directory directory = os.path.join(dataset.directory, folder) if not os.path.exists(directory): return {'message': 'Directory does not exist.'}, 400 # Get next and previous image # images = ImageModel.objects(dataset_id=dataset.id, deleted=False) # pre = images.filter(file_name__lt=image.file_name).order_by('-file_name').first() # nex = images.filter(file_name__gt=image.file_name).order_by('file_name').first() images = ImageModel.objects(dataset_id=dataset.id, deleted=False, path__startswith=directory) pre = images.filter( file_name__lt=image.file_name).order_by('-' + order).first() nex = images.filter( file_name__gt=image.file_name).order_by(order).first() preferences = {} if not Config.LOGIN_DISABLED: preferences = current_user.preferences # Generate data about the image to return to client data = { 'image': query_util.fix_ids(image), 'categories': [], 'dataset': query_util.fix_ids(dataset), 'preferences': preferences, 'permissions': { 'dataset': dataset.permissions(current_user), 'image': image.permissions(current_user) } } data['image']['previous'] = pre.id if pre else None data['image']['next'] = nex.id if nex else None for category in categories: category = query_util.fix_ids(category[1]) category_id = category.get('id') annotations = AnnotationModel.objects(image_id=image_id, category_id=category_id, deleted=False)\ .exclude('events').all() category['show'] = True category['visualize'] = False category[ 'annotations'] = [] if annotations is None else query_util.fix_ids( annotations) data.get('categories').append(category) return data
def export_annotations(task_id, dataset_id, categories, with_empty_images=False): task = TaskModel.objects.get(id=task_id) dataset = DatasetModel.objects.get(id=dataset_id) task.update(status="PROGRESS") socket = create_socket() task.info("Beginning Export (COCO Format)") db_categories = CategoryModel.objects(id__in=categories, deleted=False) \ .only(*CategoryModel.COCO_PROPERTIES) db_images = ImageModel.objects( deleted=False, dataset_id=dataset.id).only(*ImageModel.COCO_PROPERTIES) db_annotations = AnnotationModel.objects(deleted=False, category_id__in=categories) total_items = db_categories.count() coco = {'images': [], 'categories': [], 'annotations': []} total_items += db_images.count() progress = 0 # iterate though all categoires and upsert category_names = [] for category in fix_ids(db_categories): if len(category.get('keypoint_labels', [])) > 0: category['keypoints'] = category.pop('keypoint_labels', []) category['skeleton'] = category.pop('keypoint_edges', []) else: if 'keypoint_edges' in category: del category['keypoint_edges'] if 'keypoint_labels' in category: del category['keypoint_labels'] task.info(f"Adding category: {category.get('name')}") coco.get('categories').append(category) category_names.append(category.get('name')) progress += 1 task.set_progress((progress / total_items) * 100, socket=socket) total_annotations = db_annotations.count() total_images = db_images.count() for image in db_images: image = fix_ids(image) progress += 1 task.set_progress((progress / total_items) * 100, socket=socket) annotations = db_annotations.filter(image_id=image.get('id'))\ .only(*AnnotationModel.COCO_PROPERTIES) annotations = fix_ids(annotations) if len(annotations) == 0: if with_empty_images: coco.get('images').append(image) continue num_annotations = 0 for annotation in annotations: has_keypoints = len(annotation.get('keypoints', [])) > 0 has_segmentation = len(annotation.get('segmentation', [])) > 0 if has_keypoints or has_segmentation: if not has_keypoints: if 'keypoints' in annotation: del annotation['keypoints'] else: arr = np.array(annotation.get('keypoints', [])) arr = arr[2::3] annotation['num_keypoints'] = len(arr[arr > 0]) num_annotations += 1 coco.get('annotations').append(annotation) task.info( f"Exporting {num_annotations} annotations for image {image.get('id')}" ) coco.get('images').append(image) task.info( f"Done export {total_annotations} annotations and {total_images} images from {dataset.name}" ) timestamp = time.time() directory = f"{dataset.directory}.exports/" file_path = f"{directory}coco-{timestamp}.json" if not os.path.exists(directory): os.makedirs(directory) task.info(f"Writing export to file {file_path}") with open(file_path, 'w') as fp: json.dump(coco, fp) task.info("Creating export object") export = ExportModel(dataset_id=dataset.id, path=file_path, tags=["COCO", *category_names]) export.save() task.set_progress(100, socket=socket)
def post(self): """ Called when saving data from the annotator client """ data = request.get_json(force=True) image = data.get('image') dataset = data.get('dataset') image_id = image.get('id') image_model = ImageModel.objects(id=image_id).first() if image_model is None: return {'success': False, 'message': 'Image does not exist'}, 400 # Check if current user can access dataset db_dataset = current_user.datasets.filter( id=image_model.dataset_id).first() if dataset is None: return { 'success': False, 'message': 'Could not find associated dataset' } db_dataset.update(annotate_url=dataset.get('annotate_url', '')) categories = CategoryModel.objects.all() annotations = AnnotationModel.objects(image_id=image_id) current_user.update(preferences=data.get('user', {})) annotated = False # Iterate every category passed in the data for category in data.get('categories', []): category_id = category.get('id') # Find corresponding category object in the database db_category = categories.filter(id=category_id).first() if db_category is None: continue category_update = {'color': category.get('color')} if current_user.can_edit(db_category): category_update['keypoint_edges'] = category.get( 'keypoint_edges', []) category_update['keypoint_labels'] = category.get( 'keypoint_labels', []) db_category.update(**category_update) # Iterate every annotation from the data annotations for annotation in category.get('annotations', []): # Find corresponding annotation object in database annotation_id = annotation.get('id') db_annotation = annotations.filter(id=annotation_id).first() if db_annotation is None: continue # Paperjs objects are complex, so they will not always be passed. Therefor we update # the annotation twice, checking if the paperjs exists. # Update annotation in database sessions = [] total_time = 0 for session in annotation.get('sessions', []): date = datetime.datetime.fromtimestamp( int(session.get('start')) / 1e3) model = SessionEvent( user=current_user.username, created_at=date, milliseconds=session.get('milliseconds'), tools_used=session.get('tools')) total_time += session.get('milliseconds') sessions.append(model) db_annotation.update(add_to_set__events=sessions, inc__milliseconds=total_time, set__keypoints=annotation.get( 'keypoints', []), set__metadata=annotation.get('metadata'), set__color=annotation.get('color')) paperjs_object = annotation.get('compoundPath', []) # Update paperjs if it exists if len(paperjs_object) == 2: width = db_annotation.width height = db_annotation.height # Generate coco formatted segmentation data segmentation, area, bbox = coco_util.\ paperjs_to_coco(width, height, paperjs_object) db_annotation.update( set__segmentation=segmentation, set__area=area, set__bbox=bbox, set__paper_object=paperjs_object, ) if area > 0: annotated = True image_model.update(set__metadata=image.get('metadata', {}), set__annotated=annotated, set__category_ids=image.get('category_ids', []), set__regenerate_thumbnail=annotated) return {"success": True}
def get_dataset_coco(dataset): """ Generates coco for all images in dataset :param dataset: DatasetModel :return: Coco in dictionary format """ categories = CategoryModel.objects(deleted=False) \ .exclude('deleted_date').in_bulk(dataset.categories).items() dataset = fix_ids(dataset) images = ImageModel.objects(deleted=False, dataset_id=dataset.get('id')).exclude('deleted_date') all_annotations = AnnotationModel.objects(deleted=False).exclude('deleted_date', 'paper_object') coco = { 'images': [], 'categories': [], 'annotations': [] } for category in categories: category = fix_ids(category[1]) del category['deleted'] if len(category.get('keypoint_labels', [])) > 0: category['keypoints'] = category.pop('keypoint_labels') category['skeleton'] = category.pop('keypoint_edges') else: del category['keypoint_edges'] del category['keypoint_labels'] coco.get('categories').append(category) for image in images: annotations = all_annotations.filter(image_id=image.id) if annotations.count() == 0: continue annotations = fix_ids(annotations.all()) for annotation in annotations: has_keypoints = len(annotation.get('keypoints', [])) > 0 has_segmentation = len(annotation.get('segmentation', [])) > 0 if has_keypoints or has_segmentation: del annotation['deleted'] if not has_keypoints: del annotation['keypoints'] else: arr = np.array(annotation.get('keypoints', [])) arr = arr[2::3] annotation['num_keypoints'] = len(arr[arr > 0]) coco.get('annotations').append(annotation) image = fix_ids(image) del image['deleted'] coco.get('images').append(image) return coco