|
17 | 17 | import torch
|
18 | 18 | from PIL import Image, ImageDraw, ImageFont
|
19 | 19 |
|
20 |
| -from utils.general import is_ascii, is_chinese, user_config_dir, xywh2xyxy, xyxy2xywh |
| 20 | +from utils.general import clip_coords, increment_path, is_ascii, is_chinese, user_config_dir, xywh2xyxy, xyxy2xywh |
21 | 21 | from utils.metrics import fitness
|
22 | 22 |
|
23 | 23 | # Settings
|
@@ -117,6 +117,33 @@ def result(self):
|
117 | 117 | return np.asarray(self.im)
|
118 | 118 |
|
119 | 119 |
|
| 120 | +def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detect/exp')): |
| 121 | + """ |
| 122 | + x: Features to be visualized |
| 123 | + module_type: Module type |
| 124 | + stage: Module stage within model |
| 125 | + n: Maximum number of feature maps to plot |
| 126 | + save_dir: Directory to save results |
| 127 | + """ |
| 128 | + if 'Detect' not in module_type: |
| 129 | + batch, channels, height, width = x.shape # batch, channels, height, width |
| 130 | + if height > 1 and width > 1: |
| 131 | + f = f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename |
| 132 | + |
| 133 | + blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels |
| 134 | + n = min(n, channels) # number of plots |
| 135 | + fig, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols |
| 136 | + ax = ax.ravel() |
| 137 | + plt.subplots_adjust(wspace=0.05, hspace=0.05) |
| 138 | + for i in range(n): |
| 139 | + ax[i].imshow(blocks[i].squeeze()) # cmap='gray' |
| 140 | + ax[i].axis('off') |
| 141 | + |
| 142 | + print(f'Saving {save_dir / f}... ({n}/{channels})') |
| 143 | + plt.savefig(save_dir / f, dpi=300, bbox_inches='tight') |
| 144 | + plt.close() |
| 145 | + |
| 146 | + |
120 | 147 | def hist2d(x, y, n=100):
|
121 | 148 | # 2d histogram used in labels.png and evolve.png
|
122 | 149 | xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n)
|
@@ -337,37 +364,6 @@ def plot_labels(labels, names=(), save_dir=Path('')):
|
337 | 364 | plt.close()
|
338 | 365 |
|
339 | 366 |
|
340 |
| -def profile_idetection(start=0, stop=0, labels=(), save_dir=''): |
341 |
| - # Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection() |
342 |
| - ax = plt.subplots(2, 4, figsize=(12, 6), tight_layout=True)[1].ravel() |
343 |
| - s = ['Images', 'Free Storage (GB)', 'RAM Usage (GB)', 'Battery', 'dt_raw (ms)', 'dt_smooth (ms)', 'real-world FPS'] |
344 |
| - files = list(Path(save_dir).glob('frames*.txt')) |
345 |
| - for fi, f in enumerate(files): |
346 |
| - try: |
347 |
| - results = np.loadtxt(f, ndmin=2).T[:, 90:-30] # clip first and last rows |
348 |
| - n = results.shape[1] # number of rows |
349 |
| - x = np.arange(start, min(stop, n) if stop else n) |
350 |
| - results = results[:, x] |
351 |
| - t = (results[0] - results[0].min()) # set t0=0s |
352 |
| - results[0] = x |
353 |
| - for i, a in enumerate(ax): |
354 |
| - if i < len(results): |
355 |
| - label = labels[fi] if len(labels) else f.stem.replace('frames_', '') |
356 |
| - a.plot(t, results[i], marker='.', label=label, linewidth=1, markersize=5) |
357 |
| - a.set_title(s[i]) |
358 |
| - a.set_xlabel('time (s)') |
359 |
| - # if fi == len(files) - 1: |
360 |
| - # a.set_ylim(bottom=0) |
361 |
| - for side in ['top', 'right']: |
362 |
| - a.spines[side].set_visible(False) |
363 |
| - else: |
364 |
| - a.remove() |
365 |
| - except Exception as e: |
366 |
| - print(f'Warning: Plotting error for {f}; {e}') |
367 |
| - ax[1].legend() |
368 |
| - plt.savefig(Path(save_dir) / 'idetection_profile.png', dpi=200) |
369 |
| - |
370 |
| - |
371 | 367 | def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *; plot_evolve()
|
372 | 368 | # Plot evolve.csv hyp evolution results
|
373 | 369 | evolve_csv = Path(evolve_csv)
|
@@ -420,28 +416,48 @@ def plot_results(file='path/to/results.csv', dir=''):
|
420 | 416 | plt.close()
|
421 | 417 |
|
422 | 418 |
|
423 |
| -def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detect/exp')): |
424 |
| - """ |
425 |
| - x: Features to be visualized |
426 |
| - module_type: Module type |
427 |
| - stage: Module stage within model |
428 |
| - n: Maximum number of feature maps to plot |
429 |
| - save_dir: Directory to save results |
430 |
| - """ |
431 |
| - if 'Detect' not in module_type: |
432 |
| - batch, channels, height, width = x.shape # batch, channels, height, width |
433 |
| - if height > 1 and width > 1: |
434 |
| - f = f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename |
| 419 | +def profile_idetection(start=0, stop=0, labels=(), save_dir=''): |
| 420 | + # Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection() |
| 421 | + ax = plt.subplots(2, 4, figsize=(12, 6), tight_layout=True)[1].ravel() |
| 422 | + s = ['Images', 'Free Storage (GB)', 'RAM Usage (GB)', 'Battery', 'dt_raw (ms)', 'dt_smooth (ms)', 'real-world FPS'] |
| 423 | + files = list(Path(save_dir).glob('frames*.txt')) |
| 424 | + for fi, f in enumerate(files): |
| 425 | + try: |
| 426 | + results = np.loadtxt(f, ndmin=2).T[:, 90:-30] # clip first and last rows |
| 427 | + n = results.shape[1] # number of rows |
| 428 | + x = np.arange(start, min(stop, n) if stop else n) |
| 429 | + results = results[:, x] |
| 430 | + t = (results[0] - results[0].min()) # set t0=0s |
| 431 | + results[0] = x |
| 432 | + for i, a in enumerate(ax): |
| 433 | + if i < len(results): |
| 434 | + label = labels[fi] if len(labels) else f.stem.replace('frames_', '') |
| 435 | + a.plot(t, results[i], marker='.', label=label, linewidth=1, markersize=5) |
| 436 | + a.set_title(s[i]) |
| 437 | + a.set_xlabel('time (s)') |
| 438 | + # if fi == len(files) - 1: |
| 439 | + # a.set_ylim(bottom=0) |
| 440 | + for side in ['top', 'right']: |
| 441 | + a.spines[side].set_visible(False) |
| 442 | + else: |
| 443 | + a.remove() |
| 444 | + except Exception as e: |
| 445 | + print(f'Warning: Plotting error for {f}; {e}') |
| 446 | + ax[1].legend() |
| 447 | + plt.savefig(Path(save_dir) / 'idetection_profile.png', dpi=200) |
435 | 448 |
|
436 |
| - blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels |
437 |
| - n = min(n, channels) # number of plots |
438 |
| - fig, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols |
439 |
| - ax = ax.ravel() |
440 |
| - plt.subplots_adjust(wspace=0.05, hspace=0.05) |
441 |
| - for i in range(n): |
442 |
| - ax[i].imshow(blocks[i].squeeze()) # cmap='gray' |
443 |
| - ax[i].axis('off') |
444 | 449 |
|
445 |
| - print(f'Saving {save_dir / f}... ({n}/{channels})') |
446 |
| - plt.savefig(save_dir / f, dpi=300, bbox_inches='tight') |
447 |
| - plt.close() |
| 450 | +def save_one_box(xyxy, im, file='image.jpg', gain=1.02, pad=10, square=False, BGR=False, save=True): |
| 451 | + # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop |
| 452 | + xyxy = torch.tensor(xyxy).view(-1, 4) |
| 453 | + b = xyxy2xywh(xyxy) # boxes |
| 454 | + if square: |
| 455 | + b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square |
| 456 | + b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad |
| 457 | + xyxy = xywh2xyxy(b).long() |
| 458 | + clip_coords(xyxy, im.shape) |
| 459 | + crop = im[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(1 if BGR else -1)] |
| 460 | + if save: |
| 461 | + file.parent.mkdir(parents=True, exist_ok=True) # make directory |
| 462 | + cv2.imwrite(str(increment_path(file).with_suffix('.jpg')), crop) |
| 463 | + return crop |
0 commit comments