Skip to content

Commit c38b17a

Browse files
glenn-jocherfeiccccccccpre-commit-ci[bot]Laughing-q
authored
ultralytics 8.0.70 minor fixes and improvements (ultralytics#1892)
Co-authored-by: feicccccccc <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Laughing-q <[email protected]>
1 parent c2cd3fd commit c38b17a

File tree

17 files changed

+71
-90
lines changed

17 files changed

+71
-90
lines changed

docs/modes/predict.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -216,19 +216,19 @@ masks, classification logits, etc.) found in the results object
216216
res_plotted = res[0].plot()
217217
cv2.imshow("result", res_plotted)
218218
```
219-
| Argument | Description |
220-
| ----------- | ------------- |
221-
| `conf (bool)` | Whether to plot the detection confidence score. |
222-
| `line_width (float, optional)` | The line width of the bounding boxes. If None, it is scaled to the image size. |
223-
| `font_size (float, optional)` | The font size of the text. If None, it is scaled to the image size. |
224-
| `font (str)` | The font to use for the text. |
225-
| `pil (bool)` | Whether to return the image as a PIL Image. |
226-
| `example (str)` | An example string to display. Useful for indicating the expected format of the output. |
227-
| `img (numpy.ndarray)` | Plot to another image. if not, plot to original image. |
228-
| `labels (bool)` | Whether to plot the label of bounding boxes. |
229-
| `boxes (bool)` | Whether to plot the bounding boxes. |
230-
| `masks (bool)` | Whether to plot the masks. |
231-
| `probs (bool)` | Whether to plot classification probability. |
219+
| Argument | Description |
220+
|--------------------------------|----------------------------------------------------------------------------------------|
221+
| `conf (bool)` | Whether to plot the detection confidence score. |
222+
| `line_width (float, optional)` | The line width of the bounding boxes. If None, it is scaled to the image size. |
223+
| `font_size (float, optional)` | The font size of the text. If None, it is scaled to the image size. |
224+
| `font (str)` | The font to use for the text. |
225+
| `pil (bool)` | Whether to use PIL for image plotting. |
226+
| `example (str)` | An example string to display. Useful for indicating the expected format of the output. |
227+
| `img (numpy.ndarray)` | Plot to another image. if not, plot to original image. |
228+
| `labels (bool)` | Whether to plot the label of bounding boxes. |
229+
| `boxes (bool)` | Whether to plot the bounding boxes. |
230+
| `masks (bool)` | Whether to plot the masks. |
231+
| `probs (bool)` | Whether to plot classification probability. |
232232

233233

234234
## Streaming Source `for`-loop

docs/tasks/pose.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,19 @@ Train a YOLOv8-pose model on the COCO128-pose dataset.
5656
model = YOLO('yolov8n-pose.yaml').load('yolov8n-pose.pt') # build from YAML and transfer weights
5757
5858
# Train the model
59-
model.train(data='coco128-pose.yaml', epochs=100, imgsz=640)
59+
model.train(data='coco8-pose.yaml', epochs=100, imgsz=640)
6060
```
6161
=== "CLI"
6262

6363
```bash
6464
# Build a new model from YAML and start training from scratch
65-
yolo pose train data=coco128-pose.yaml model=yolov8n-pose.yaml epochs=100 imgsz=640
65+
yolo pose train data=coco8-pose.yaml model=yolov8n-pose.yaml epochs=100 imgsz=640
6666

6767
# Start training from a pretrained *.pt model
68-
yolo pose train data=coco128-pose.yaml model=yolov8n-pose.pt epochs=100 imgsz=640
68+
yolo pose train data=coco8-pose.yaml model=yolov8n-pose.pt epochs=100 imgsz=640
6969

7070
# Build a new model from YAML, transfer pretrained weights to it and start training
71-
yolo pose train data=coco128-pose.yaml model=yolov8n-pose.yaml pretrained=yolov8n-pose.pt epochs=100 imgsz=640
71+
yolo pose train data=coco8-pose.yaml model=yolov8n-pose.yaml pretrained=yolov8n-pose.pt epochs=100 imgsz=640
7272
```
7373

7474
## Val

ultralytics/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Ultralytics YOLO 🚀, GPL-3.0 license
22

3-
__version__ = '8.0.69'
3+
__version__ = '8.0.70'
44

55
from ultralytics.hub import start
66
from ultralytics.yolo.engine.model import YOLO

ultralytics/hub/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def login(api_key=''):
1818
from ultralytics import hub
1919
hub.login('API_KEY')
2020
"""
21-
Auth(api_key)
21+
Auth(api_key, verbose=True)
2222

2323

2424
def logout():
@@ -82,7 +82,7 @@ def export_model(model_id='', format='torchscript'):
8282

8383
def get_export(model_id='', format='torchscript'):
8484
# Get an exported model dictionary with download URL
85-
assert format in export_fmts_hub, f"Unsupported export format '{format}', valid formats are {export_fmts_hub}"
85+
assert format in export_fmts_hub(), f"Unsupported export format '{format}', valid formats are {export_fmts_hub()}"
8686
r = requests.post('https://api.ultralytics.com/get-export',
8787
json={
8888
'apiKey': Auth().api_key,

ultralytics/hub/auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
class Auth:
1212
id_token = api_key = model_key = False
1313

14-
def __init__(self, api_key='', verbose=True):
14+
def __init__(self, api_key='', verbose=False):
1515
"""
1616
Initialize the Auth class with an optional API key.
1717

ultralytics/hub/session.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(self, url):
5858
raise ValueError(f'Invalid HUBTrainingSession input: {url}')
5959

6060
# Authorize
61-
auth = Auth(key, verbose=False)
61+
auth = Auth(key)
6262
self.agent_id = None # identifies which instance is communicating with server
6363
self.model_id = model_id
6464
self.model_url = f'https://hub.ultralytics.com/models/{model_id}'

ultralytics/yolo/cfg/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
'detect': 'coco128.yaml',
2020
'segment': 'coco128-seg.yaml',
2121
'classify': 'imagenet100',
22-
'pose': 'coco128-pose.yaml'}
22+
'pose': 'coco8-pose.yaml'}
2323
TASK2MODEL = {
2424
'detect': 'yolov8n.pt',
2525
'segment': 'yolov8n-seg.pt',

ultralytics/yolo/engine/predictor.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
9999
self.device = None
100100
self.dataset = None
101101
self.vid_path, self.vid_writer = None, None
102-
self.annotator = None
102+
self.plotted_img = None
103103
self.data_path = None
104104
self.source_type = None
105105
self.batch = None
@@ -109,9 +109,6 @@ def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
109109
def preprocess(self, img):
110110
pass
111111

112-
def get_annotator(self, img):
113-
raise NotImplementedError('get_annotator function needs to be implemented')
114-
115112
def write_results(self, results, batch, print_string):
116113
raise NotImplementedError('print_results function needs to be implemented')
117114

@@ -208,10 +205,10 @@ def stream_inference(self, source=None, model=None):
208205
if self.args.verbose or self.args.save or self.args.save_txt or self.args.show:
209206
s += self.write_results(i, self.results, (p, im, im0))
210207

211-
if self.args.show:
208+
if self.args.show and self.plotted_img is not None:
212209
self.show(p)
213210

214-
if self.args.save:
211+
if self.args.save and self.plotted_img is not None:
215212
self.save_preds(vid_cap, i, str(self.save_dir / p.name))
216213
self.run_callbacks('on_predict_batch_end')
217214
yield from self.results
@@ -251,7 +248,7 @@ def setup_model(self, model, verbose=True):
251248
self.model.eval()
252249

253250
def show(self, p):
254-
im0 = self.annotator.result()
251+
im0 = self.plotted_img
255252
if platform.system() == 'Linux' and p not in self.windows:
256253
self.windows.append(p)
257254
cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux)
@@ -260,7 +257,7 @@ def show(self, p):
260257
cv2.waitKey(500 if self.batch[4].startswith('image') else 1) # 1 millisecond
261258

262259
def save_preds(self, vid_cap, idx, save_path):
263-
im0 = self.annotator.result()
260+
im0 = self.plotted_img
264261
# save imgs
265262
if self.dataset.mode == 'image':
266263
cv2.imwrite(save_path, im0)

ultralytics/yolo/engine/results.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@
1010

1111
import numpy as np
1212
import torch
13-
import torchvision.transforms.functional as F
1413

14+
from ultralytics.yolo.data.augment import LetterBox
1515
from ultralytics.yolo.utils import LOGGER, SimpleClass, deprecation_warn, ops
1616
from ultralytics.yolo.utils.plotting import Annotator, colors
17-
from ultralytics.yolo.utils.torch_utils import TORCHVISION_0_10
1817

1918

2019
class BaseTensor(SimpleClass):
@@ -160,6 +159,7 @@ def plot(
160159
pil=False,
161160
example='abc',
162161
img=None,
162+
img_gpu=None,
163163
kpt_line=True,
164164
labels=True,
165165
boxes=True,
@@ -178,14 +178,15 @@ def plot(
178178
pil (bool): Whether to return the image as a PIL Image.
179179
example (str): An example string to display. Useful for indicating the expected format of the output.
180180
img (numpy.ndarray): Plot to another image. if not, plot to original image.
181+
img_gpu (torch.Tensor): Normalized image in gpu with shape (1, 3, 640, 640), for faster mask plotting.
181182
kpt_line (bool): Whether to draw lines connecting keypoints.
182183
labels (bool): Whether to plot the label of bounding boxes.
183184
boxes (bool): Whether to plot the bounding boxes.
184185
masks (bool): Whether to plot the masks.
185186
probs (bool): Whether to plot classification probability
186187
187188
Returns:
188-
(None) or (PIL.Image): If `pil` is True, a PIL Image is returned. Otherwise, nothing is returned.
189+
(numpy.ndarray): A numpy array of the annotated image.
189190
"""
190191
# Deprecation warn TODO: remove in 8.2
191192
if 'show_conf' in kwargs:
@@ -200,22 +201,20 @@ def plot(
200201
pred_probs, show_probs = self.probs, probs
201202
names = self.names
202203
keypoints = self.keypoints
204+
if pred_masks and show_masks:
205+
if img_gpu is None:
206+
img = LetterBox(pred_masks.shape[1:])(image=annotator.im)
207+
img_gpu = torch.as_tensor(img, dtype=torch.float16, device=pred_masks.masks.device).permute(
208+
2, 0, 1).flip(0).contiguous() / 255
209+
annotator.masks(pred_masks.data, colors=[colors(x, True) for x in pred_boxes.cls], im_gpu=img_gpu)
210+
203211
if pred_boxes and show_boxes:
204212
for d in reversed(pred_boxes):
205213
c, conf, id = int(d.cls), float(d.conf) if conf else None, None if d.id is None else int(d.id.item())
206214
name = ('' if id is None else f'id:{id} ') + names[c]
207215
label = (f'{name} {conf:.2f}' if conf else name) if labels else None
208216
annotator.box_label(d.xyxy.squeeze(), label, color=colors(c, True))
209217

210-
if pred_masks and show_masks:
211-
im = torch.as_tensor(annotator.im, dtype=torch.float16, device=pred_masks.data.device).permute(2, 0,
212-
1).flip(0)
213-
if TORCHVISION_0_10:
214-
im = F.resize(im.contiguous(), pred_masks.data.shape[1:], antialias=True) / 255
215-
else:
216-
im = F.resize(im.contiguous(), pred_masks.data.shape[1:]) / 255
217-
annotator.masks(pred_masks.data, colors=[colors(x, True) for x in pred_boxes.cls], im_gpu=im)
218-
219218
if pred_probs is not None and show_probs:
220219
n5 = min(len(names), 5)
221220
top5i = pred_probs.argsort(0, descending=True)[:n5].tolist() # top 5 indices
@@ -226,7 +225,7 @@ def plot(
226225
for k in reversed(keypoints):
227226
annotator.kpts(k, self.orig_shape, kpt_line=kpt_line)
228227

229-
return np.asarray(annotator.im) if annotator.pil else annotator.im
228+
return annotator.result()
230229

231230

232231
class Boxes(BaseTensor):

ultralytics/yolo/utils/ops.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,24 +300,27 @@ def clip_coords(coords, shape):
300300
coords[..., 1] = coords[..., 1].clip(0, shape[0]) # y
301301

302302

303-
def scale_image(im1_shape, masks, im0_shape, ratio_pad=None):
303+
def scale_image(masks, im0_shape, ratio_pad=None):
304304
"""
305305
Takes a mask, and resizes it to the original image size
306306
307307
Args:
308-
im1_shape (tuple): model input shape, [h, w]
309-
masks (torch.Tensor): [h, w, num]
308+
masks (torch.Tensor): resized and padded masks/images, [h, w, num]/[h, w, 3].
310309
im0_shape (tuple): the original image shape
311310
ratio_pad (tuple): the ratio of the padding to the original image.
312311
313312
Returns:
314313
masks (torch.Tensor): The masks that are being returned.
315314
"""
316315
# Rescale coordinates (xyxy) from im1_shape to im0_shape
316+
im1_shape = masks.shape
317+
if im1_shape[:2] == im0_shape[:2]:
318+
return masks
317319
if ratio_pad is None: # calculate from im0_shape
318320
gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1]) # gain = old / new
319321
pad = (im1_shape[1] - im0_shape[1] * gain) / 2, (im1_shape[0] - im0_shape[0] * gain) / 2 # wh padding
320322
else:
323+
gain = ratio_pad[0][0]
321324
pad = ratio_pad[1]
322325
top, left = int(pad[1]), int(pad[0]) # y, x
323326
bottom, right = int(im1_shape[0] - pad[1]), int(im1_shape[1] - pad[0])
@@ -329,9 +332,9 @@ def scale_image(im1_shape, masks, im0_shape, ratio_pad=None):
329332
# masks = F.interpolate(masks[None], im0_shape[:2], mode='bilinear', align_corners=False)[0]
330333
# masks = masks.permute(1, 2, 0).contiguous()
331334
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]))
332-
333335
if len(masks.shape) == 2:
334336
masks = masks[:, :, None]
337+
335338
return masks
336339

337340

0 commit comments

Comments
 (0)