def to_coco(image_filenames, inference_output, class_names):
    """
    Convert output from `inference()` to a COCO dataset.

    Args:
        image_filenames (List[str]): list of image filenames corresponding to
            each element of `inference_output`.
        inference_output (list): List of (bbox_xywh, class_prob, class_idx)
            tuples for each image processed by `inference()`.
        class_names (List[str]): List of class names.

    Returns:
        Dict representing a COCO object detection dataset.
    """
    categories = []
    for i, class_name in enumerate(class_names):
        categories.append(
            {
                "id": i,
                "name": class_name
            }
        )

    dataset = {
        "info": [],
        "licenses": [],
        "categories": categories,
        "images": [],
        "annotations": []
    }

    num_annotations = 0
    for i, image_output in enumerate(inference_output):
        bbox_tlbr, class_prob, class_idx = image_output

        # Assign an arbitrary id to the image.
        image = {
            "file_name": image_filenames[i],
            "id": i,
        }
        dataset["images"].append(image)

        for j, (tl_x, tl_y, br_x, br_y) in enumerate(bbox_tlbr):
            tl_x = int(tl_x)
            tl_y = int(tl_y)
            br_x = int(br_x)
            br_y = int(br_y)
            w = br_x - tl_x
            h = br_y - tl_y

            ann = {
                "image_id": i,
                "bbox": [tl_x, tl_y, w, h],
                "category_id": class_idx[j],
                "id": num_annotations,
                "score": float(class_prob[j]),
                "area": w * h,
            }
            dataset["annotations"].append(ann)
            num_annotations += 1

    return dataset