Skip to content

Commit

Permalink
Export preds to coco annotations (#1132)
Browse files Browse the repository at this point in the history
* Add a function to export preds to COCO annotations

* Downsample example images to save space; add optional metadata parameter

* Separate 'info' field from the rest of 'addl_info' as a parameter

* Fix unsightly notebook outputs

* Fix slightly errant docstring. TODO: Add type hints

* Black formatting
  • Loading branch information
boscacci authored Aug 24, 2022
1 parent 72d30c9 commit bebdd93
Show file tree
Hide file tree
Showing 7 changed files with 3,509 additions and 1,227 deletions.
127 changes: 127 additions & 0 deletions icevision/data/convert_records_to_coco_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,140 @@
"coco_api_from_records",
"coco_api_from_preds",
"create_coco_eval",
"export_batch_inferences_as_coco_annotations",
]

from icevision.imports import *
from icevision.utils import *
from icevision.core import *
from pycocotools.coco import COCO
from pycocotools.cocoeval import COCOeval
from icevision.models.inference import *
import json
import numpy as np
import PIL


class NpEncoder(json.JSONEncoder):
"""
Smooths out datatype conversions for IceVision preds to JSON export
"""

def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
if isinstance(obj, np.floating):
return float(obj)
if isinstance(obj, np.ndarray):
return obj.tolist()
return json.JSONEncoder.default(self, obj)


def export_batch_inferences_as_coco_annotations(
preds,
img_files,
transforms,
class_map,
output_filepath="inference_results_as_coco_annotations.json",
info=None,
licenses=None,
):
"""
For converting object detection predictions to COCO annotation format.
Useful for e.g. leveraging partly-trained models to help annotate
unlabeled data and make round trips back into annotation programs.
Parameters
----------
preds : List[Prediction]
The result of predict_from_dl()
img_files : fastcore.foundation.L (i.e. 'Paths')
References to the original image filepaths in array-like form.
transforms : Albumentations Adapter
Transforms that were applied to the original images (to be reversed)
class_map : icevision.core.class_map.ClassMap
The map of classes your model is familiar with
output_filepath : str, optional
The filepath (including filename) where you want the json results
to be serialized, by default
"new_pseudo_labels_for_further_training.json"
info: dict, optional
Option to manually create the info dict containing annotation metadata
including year, version, description, contributor, url, and date created
For example:
"info": {
"year": "2022",
"version": "1",
"description": "Exported from IceVision",
"contributor": "Awesome contributor",
"url": "https://lazyannotator.fun",
"date_created": "2022-08-05T20:13:09+00:00"
}
licenses: List[dict], optional
Option to manually create the license metadata for the annotations, e.g.
licenses = [
{
"name": "Creative Commons Attribution 4.0",
"id": 0,
"url": "https://creativecommons.org/licenses/by/4.0/legalcode",
}
]
Returns
-------
None
This just spits out a serialized .json file and returns nothing.
"""
object_category_list = [
{"id": v, "name": k, "supercategory": ""}
for k, v in class_map._class2id.items()
]

if info is None:
# Then automatically generate COCO annotation metadata:
info = {
"contributor": "",
"date_created": "",
"description": "",
"url": "",
"version": "",
"year": "",
}

if licenses is None:
licenses = [
{
"name": "",
"id": 0,
"url": "",
}
]

addl_info = {
"licenses": licenses,
"info": info,
"categories": object_category_list,
}

# Each entry needs a filepath
[pred.add_component(FilepathRecordComponent()) for pred in preds]
[preds[_].set_filepath(img_files[_]) for _ in range(len(preds))]

# process_bbox_predictions happens inplace, thus no new variable
for p in preds:
process_bbox_predictions(
p, PIL.Image.open(Path(p.pred.filepath)), transforms.tfms_list
)

coco_style_preds = convert_preds_to_coco_style(preds)
finalized_pseudo_labels = {**addl_info, **coco_style_preds}

# Serialize
with open(output_filepath, "w") as jfile:
json.dump(finalized_pseudo_labels, jfile, cls=NpEncoder)

# Print confirmation message
print(f"New COCO annotation file saved to {output_filepath}")


def create_coco_api(coco_records) -> COCO:
Expand Down
Binary file added notebooks/images/boy_skating.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added notebooks/images/clock_shop.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added notebooks/images/donuts.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added notebooks/images/toothbrushes.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added notebooks/images/umbrellas.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit bebdd93

Please sign in to comment.