Skip to content

Yolo fixes with examples #99

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,23 @@ Sample of annotated image along with its mask and settings is show below.
}

```
YOLO Format
### YOLO Format

YOLO format is also supported by A.Lab. Below is an example of annotated ripe and unripe tomatoes. In this example, `0` represents ripe tomatoes and `1` represents unripe ones.

![yolo_annotation_example](./sample_images/yolo_annotation_example.png)

The label of the above image are as follows:
```
Orange 0.0015012463401089847 0.0018903253731438908 0.0016967868433852144 0.0026982117835804955
0 0.213673 0.474717 0.310212 0.498856
0 0.554777 0.540507 0.306350 0.433638
1 0.378432 0.681239 0.223970 0.268879
```

Applying the generated labels we get following results.

![yolo_with_generated_labels](./sample_images/yolo_applied_annotation.jpg)

## Troubleshooting [[documentation page]](https://annotate-docs.dwaste.live/troubleshooting)

- Ensure that both the client and server are running.
Expand Down
Binary file added sample_images/yolo_annotation_example.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 sample_images/yolo_applied_annotation.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 16 additions & 17 deletions server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,47 +564,46 @@ def create_yolo_annotations(image_names, color_map=None):

# Convert points to normalized YOLO format
if points:
xmin = min(point[0] for point in points) / width
ymin = min(point[1] for point in points) / height
xmax = max(point[0] for point in points) / width
ymax = max(point[1] for point in points) / height
xmin = min(point[0] for point in points)
ymin = min(point[1] for point in points)
xmax = max(point[0] for point in points)
ymax = max(point[1] for point in points)

# YOLO format: class_index x_center y_center width height (all normalized)
annotations.append(f"{class_name} {(xmin + xmax) / 2} {(ymin + ymax) / 2} {xmax - xmin} {ymax - ymin}")
annotations.append(f"{class_name} {(xmin + xmax) / 2:.6f} {(ymin + ymax) / 2:.6f} {xmax - xmin:.6f} {ymax - ymin:.6f}")

# Process box regions
if boxRegions is not None:
for index, region in boxRegions.iterrows():
class_name = region.get('class', 'unknown')
try:
x = float(region['x'][1:-1]) * width if isinstance(region['x'], str) else float(region['x'][0]) * width
y = float(region['y'][1:-1]) * height if isinstance(region['y'], str) else float(region['y'][0]) * height
w = float(region['w'][1:-1]) * width if isinstance(region['w'], str) else float(region['w'][0]) * width
h = float(region['h'][1:-1]) * height if isinstance(region['h'], str) else float(region['h'][0]) * height
x = float(region['x'][1:-1]) if isinstance(region['x'], str) else float(region['x'][0])
y = float(region['y'][1:-1]) if isinstance(region['y'], str) else float(region['y'][0])
w = float(region['w'][1:-1]) if isinstance(region['w'], str) else float(region['w'][0])
h = float(region['h'][1:-1]) if isinstance(region['h'], str) else float(region['h'][0])
except (ValueError, TypeError) as e:
raise ValueError(f"Invalid format in region dimensions: {region}, Error: {e}")

# YOLO format: class_index x_center y_center width height (all normalized)
annotations.append(f"{class_name} {x + w / 2} {y + h / 2} {w} {h}")
annotations.append(f"{class_name} {x + w / 2:.6f} {y + h / 2:.6f} {w:.6f} {h:.6f}")

# Process circle/ellipse regions
if circleRegions is not None:
for index, region in circleRegions.iterrows():
class_name = region.get('class', 'unknown')
try:
rx = float(region['rx'][1:-1]) * width if isinstance(region['rx'], str) else float(region['rx'][0]) * width
ry = float(region['ry'][1:-1]) * height if isinstance(region['ry'], str) else float(region['ry'][0]) * height
rw = float(region['rw'][1:-1]) * width if isinstance(region['rw'], str) else float(region['rw'][0]) * width
rh = float(region['rh'][1:-1]) * height if isinstance(region['rh'], str) else float(region['rh'][0]) * height
rx = float(region['rx'][1:-1]) * width if isinstance(region['rx'], str) else float(region['rx'][0])
ry = float(region['ry'][1:-1]) * height if isinstance(region['ry'], str) else float(region['ry'][0])
rw = float(region['rw'][1:-1]) * width if isinstance(region['rw'], str) else float(region['rw'][0])
rh = float(region['rh'][1:-1]) * height if isinstance(region['rh'], str) else float(region['rh'][0])
except (ValueError, TypeError) as e:
raise ValueError(f"Invalid format in region dimensions: {region}, Error: {e}")

# For YOLO, if width and height are equal, it represents a circle
if rw == rh:
annotations.append(f"{class_name} {rx} {ry} {rw} {rw}") # Treat as circle
annotations.append(f"{class_name} {rx:.6f} {ry:.6f} {rw:.6f} {rw:.6f}") # Treat as circle
else:
# Treat as ellipse (YOLO does not directly support ellipse, so treat as box)
annotations.append(f"{class_name} {rx + rw / 2} {ry + rh / 2} {rw} {rh}")
annotations.append(f"{class_name} {rx + rw / 2:.6f} {ry + rh / 2:.6f} {rw:.6f} {rh:.6f}")

# Append annotations for current image to all_annotations list
all_annotations.extend(annotations)
Expand Down
51 changes: 51 additions & 0 deletions server/examples/check_label.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import cv2
import os

# Function to draw bounding boxes
def draw_bboxes(image_path, label_path, output_path):
# Define colors for different classes
colors = [(0, 0, 255), (0, 255, 0)] # Example colors for two classes: green and red for unripe and riped

# Read the image
image = cv2.imread(image_path)
height, width, _ = image.shape

# Read the label file
with open(label_path, 'r') as f:
labels = f.readlines()

for label in labels:
label_data = label.strip().split()
class_id = int(label_data[0])
x_center, y_center, bbox_width, bbox_height = map(float, label_data[1:])

# Convert normalized coordinates to pixel coordinates
x_center *= width
y_center *= height
bbox_width *= width
bbox_height *= height

# Calculate top-left and bottom-right coordinates
x1 = int(x_center - bbox_width / 2)
y1 = int(y_center - bbox_height / 2)
x2 = int(x_center + bbox_width / 2)
y2 = int(y_center + bbox_height / 2)

# Draw the bounding box with a color based on class ID
color = colors[class_id]
cv2.rectangle(image, (x1, y1), (x2, y2), color, 2)
cv2.putText(image, str(class_id), (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

# Save the output image
cv2.imwrite(output_path, image)


# Paths to the image, label, and output
image_path = './tomato_example.jpeg'
label_path = './tomato_example.txt'
output_path = './output_tomato_example.jpg'

# Draw bounding boxes on the image
draw_bboxes(image_path, label_path, output_path)

print(f"Output image saved to {output_path}")
Binary file added server/examples/output_tomato_example.jpg
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 server/examples/tomato_example.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions server/examples/tomato_example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
0 0.213673 0.474717 0.310212 0.498856
0 0.554777 0.540507 0.306350 0.433638
1 0.378432 0.681239 0.223970 0.268879
2 changes: 1 addition & 1 deletion server/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
flask
opencv-python
flask-cors
pandas
pillow
Expand Down
Loading