voxel51 / fiftyone

Refine high-quality datasets and visual AI models
https://fiftyone.ai
Apache License 2.0
8.88k stars 563 forks source link

[HELP] Converting exported YoLov5 annotations to pascal VOC #1426

Closed neel04 closed 3 years ago

neel04 commented 3 years ago

Hi, thanks for this great repo!

I know this is technically not related to FiftyOne, but I am having some trouble converting the Yolov5 annotations generated by FO to pascal VOC style 😫

This exporter here write annotations in the normalized, Yolo format. What I am attempting to do, is convert those annotations generated by a model (specifically Yolo-R) to --> Pascal Voc.

So far, I have been unsuccessful in understanding how FiftyOne accomplishes this - if someone has an idea of how such a function would look like, it would be really great 🤗

This is a sample of how the Yolo annotations generated by my model looks like = [0.436523, 0.535156, 0.587891, 0.484375]. I assume normalization is done by dividing by image_height or image_width perhaps? my image_width == image_height as images are square.

Again, many many thanks in advance Cheers! ❤️

brimoor commented 3 years ago

If I understand correctly, you have a model that generates predictions in YOLO format, and you want to convert these predictions to VOC format. You can do that by:

The links I provided show a variety of syntaxes for each step depending on your exact needs.

neel04 commented 3 years ago

Thanks for such a quick reply 🤗 Indeed, but I would want to use bboxes for further real-time processing, so was looking for a simple distilled function that converts it to VOC so I wouldn't have to modify my pipeline too heavily; converting back and forth between datasets would be pretty complicated :(

brimoor commented 3 years ago

Here I populate a directory of YOLO-formatted labels to work with:

import os

import fiftyone as fo
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset("quickstart")

# The list of classes
classes = dataset.distinct("predictions.detections.label")

# A directory of images
data_path = os.path.dirname(dataset.first().filepath)

# A directory of YOLO predictions
dataset.export(
    labels_path="/tmp/yolo",
    dataset_type=fo.types.YOLOv4Dataset,
    label_field="predictions",
    classes=classes,
)

And here's how to convert to a directory of VOC-formatted labels:

fo.Dataset.from_dir(
    data_path=data_path,
    labels_path="/tmp/yolo",
    dataset_type=fo.types.YOLOv4Dataset,
    classes=classes,
).export(
    labels_path="/tmp/voc",
    dataset_type=fo.types.VOCDetectionDataset,
)

Not too bad :)

neel04 commented 3 years ago

Sorry for the confusion 😓 I think I may have communicated poorly there.

I can't really re-convert b/w datasets since that would require a huge amount of logging, like writing images to files and lots of back and forth conversions. The aim is to write all the boxes to a csv and its a real-time application so that would be very slow whereas a csv would be decent as it can be updated quite fast.

What I meant was a simple function, which provided a bounding box that converts it to a pascal annotation - I don't require the extra baggage of an entire dataset, simply the bounding box :)

Hope that clears things up!

brimoor commented 3 years ago

The code I shared doesn't create copies of the source media; it only reads/writes labels.

It does convert YOLO -> FiftyOne -> VOC and therefore temporarily creates a representation of the labels in our format rather than a direct YOLO -> VOC conversion, but that's the way we do things in this project. Supporting X -> Y direct would require O(n^2) utilities, while X -> FiftyOne -> Y requires only O(2n) utilities to support all possible conversions.

In the case of YOLO -> VOC, since YOLO uses relative coordinates and VOC uses absolute, the conversion also requires retrieving the dimensions of each image, which the code I shared implicitly does for you.

So, if I were you, I wouldn't be too keen on cutting FiftyOne out of the process. Also, I'd recommend storing all your data in FiftyOne format :)

neel04 commented 3 years ago

Alright, I'll try and figure how to integrate everything. Thanks a ton! 🍰