weecology / DeepForest

Python Package for Airborne RGB machine learning
https://deepforest.readthedocs.io/
MIT License
464 stars 169 forks source link

Integrate visualizations from roboflows supervision annotator package #697

Open bw4sz opened 1 week ago

bw4sz commented 1 week ago

One of the core beliefs of DeepForest has been to be minimal, and not reproduce code made by others. I am seeing alot of nice work on viz by Roboflow's supervision package

https://supervision.roboflow.com/latest/detection/annotators/#__tabbed_1_1

image

Roadmap

import supervision as sv
from deepforest import main
from deepforest import get_data
import cv2

m = main.deepforest()
m.use_release()
img_path = get_data("OSBS_029.tif")

image = cv2.imread(img_path)
result = m.predict_image(img_path)

# Some kind of converter to a format that supervision knows about, this does not yet exist.
sv_format = convert_to_sv_format(result)

detections = sv.Detections(sv_format)

bounding_box_annotator = sv.BoundingBoxAnnotator()
annotated_frame = bounding_box_annotator.annotate(
    scene=image.copy(),
    detections=detections
)

@Mu-Magdy do you want to have a look at this portion and see if you can play with this idea. The issue itself is large, but the connector function is a good first step.

Mu-Magdy commented 6 days ago

Hi @bw4sz

I made this function to do so

def convert_to_sv_format(df):

    """
    Convert DeepForest prediction results to a supervision Detections object.

    Args:
        df (pd.DataFrame): The results from `predict_image` or `predict_tile`.
                           Expected columns: ['xmin', 'ymin', 'xmax', 'ymax', 'label', 'score', 'image_path'].

    Returns:
        sv.Detections: A supervision Detections object containing bounding boxes, class IDs,
                       confidence scores, and class names object mapping classes ids to corresponding
                       class names inside of data dictionary.

    Example:
        detections = convert_to_sv_format(result)
    """
    # Extract bounding boxes as a 2D numpy array with shape (_, 4)
    boxes = df[['xmin', 'ymin', 'xmax', 'ymax']].values.astype(np.float32)

    label_mapping = {label: idx for idx, label in enumerate(df['label'].unique())}

    # Extract labels as a numpy array
    labels = df['label'].map(label_mapping).values.astype(int)

    # Extract scores as a numpy array
    scores = np.array(df['score'].tolist())
    # Create a reverse mapping from integer to string labels
    class_name = {v: k for k, v in label_mapping.items()}

    return sv.Detections(
        xyxy=boxes,
        class_id=labels,
        confidence=scores,
        data={"class_name": [class_name[class_id] for class_id in labels]}

    )

# an example

sample_image_path = get_data("OSBS_029.png")
results = model.predict_image(path=sample_image_path, return_plot=False)

# make sv detections object
detections = convert_to_sv_format(results)

# Read the image using OpenCV
image = cv2.imread(sample_image_path)

# Convert the image from BGR to RGB color space
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# initialize the bounding box annotator 
bounding_box_annotator = sv.BoundingBoxAnnotator()
annotated_frame = bounding_box_annotator.annotate(
    scene=image.copy(),
    detections=detections
)

label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER)
annotated_frame = label_annotator.annotate(
    scene=annotated_frame, # to add labels and bounding boxes
    # scene=iamge, # to add just the labels to original image
    detections=detections,
    labels=detections['class_name']
)

# Display the image using Matplotlib
plt.imshow(annotated_frame)
plt.axis('off')  # Hide axes for a cleaner look
plt.show()

should i write it in the utilities.py file?

bw4sz commented 5 days ago

Thanks! Add it to deepforest.visualize

https://github.com/weecology/DeepForest/blob/main/deepforest/visualize.py

Then add a new visualization page to docs (update doc/index.rst) https://github.com/weecology/DeepForest/blob/cce441c1a126920e9f5ab88346dc3c16e604cb22/docs/index.rst?plain=1#L50 and show a couple different functionalities from sv package