Skip to content

Commit 3456fe6

Browse files
thepycoderpre-commit-ci[bot]glenn-jocher
authored
Fix torchvision dependency for ClearML logging (#8993)
* Replace torchvision annotator with native local Annotator * Add colored bounding boxes and rewrite for efficiency * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix pep8 issue * Update clearml_utils.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update clearml_utils.py * Reduced conf_threshold to 0.25 to match defaults The 0.25 default conf threshold value is used a default throughout YOLOv5 (i.e. in detect.py) and also in other tools like CoreML Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher <[email protected]>
1 parent fd004f5 commit 3456fe6

File tree

1 file changed

+19
-13
lines changed

1 file changed

+19
-13
lines changed

utils/loggers/clearml/clearml_utils.py

+19-13
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@
33
import re
44
from pathlib import Path
55

6+
import numpy as np
67
import yaml
7-
from torchvision.transforms import ToPILImage
8+
9+
from utils.plots import Annotator, colors
810

911
try:
1012
import clearml
1113
from clearml import Dataset, Task
12-
from torchvision.utils import draw_bounding_boxes # WARNING: requires torchvision>=0.9.0
13-
1414
assert hasattr(clearml, '__version__') # verify package import not local dir
1515
except (ImportError, AssertionError):
1616
clearml = None
1717

1818

1919
def construct_dataset(clearml_info_string):
20+
"""Load in a clearml dataset and fill the internal data_dict with its contents.
21+
"""
2022
dataset_id = clearml_info_string.replace('clearml://', '')
2123
dataset = Dataset.get(dataset_id=dataset_id)
2224
dataset_root_path = Path(dataset.get_local_copy())
@@ -120,9 +122,9 @@ def log_debug_samples(self, files, title='Debug Samples'):
120122
local_path=str(f),
121123
iteration=iteration)
122124

123-
def log_image_with_boxes(self, image_path, boxes, class_names, image):
125+
def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_threshold=0.25):
124126
"""
125-
Draw the bounding boxes on a single image and report the result as a ClearML debug sample
127+
Draw the bounding boxes on a single image and report the result as a ClearML debug sample.
126128
127129
arguments:
128130
image_path (PosixPath) the path the original image file
@@ -133,16 +135,20 @@ def log_image_with_boxes(self, image_path, boxes, class_names, image):
133135
if len(self.current_epoch_logged_images) < self.max_imgs_to_log_per_epoch and self.current_epoch >= 0:
134136
# Log every bbox_interval times and deduplicate for any intermittend extra eval runs
135137
if self.current_epoch % self.bbox_interval == 0 and image_path not in self.current_epoch_logged_images:
136-
converter = ToPILImage()
137-
labels = []
138-
for conf, class_nr in zip(boxes[:, 4], boxes[:, 5]):
138+
im = np.ascontiguousarray(np.moveaxis(image.mul(255).clamp(0, 255).byte().cpu().numpy(), 0, 2))
139+
annotator = Annotator(im=im, pil=True)
140+
for i, (conf, class_nr, box) in enumerate(zip(boxes[:, 4], boxes[:, 5], boxes[:, :4])):
141+
color = colors(i)
142+
139143
class_name = class_names[int(class_nr)]
140144
confidence = round(float(conf) * 100, 2)
141-
labels.append(f"{class_name}: {confidence}%")
142-
annotated_image = converter(
143-
draw_bounding_boxes(image=image.mul(255).clamp(0, 255).byte().cpu(),
144-
boxes=boxes[:, :4],
145-
labels=labels))
145+
label = f"{class_name}: {confidence}%"
146+
147+
if confidence > conf_threshold:
148+
annotator.rectangle(box.cpu().numpy(), outline=color)
149+
annotator.box_label(box.cpu().numpy(), label=label, color=color)
150+
151+
annotated_image = annotator.result()
146152
self.task.get_logger().report_image(title='Bounding Boxes',
147153
series=image_path.name,
148154
iteration=self.current_epoch,

0 commit comments

Comments
 (0)