glenn-jocher pre-commit-ci[bot] commited on
Commit
c3e599c
1 Parent(s): cb40c9a

Update val_batch*.jpg for Chinese fonts (#6526)

Browse files

* Update plots for Chinese fonts

* make is_chinese() non-str safe

* Add global FONT

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update general.py

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

Files changed (2) hide show
  1. utils/general.py +42 -29
  2. utils/plots.py +10 -13
utils/general.py CHANGED
@@ -37,6 +37,7 @@ FILE = Path(__file__).resolve()
37
  ROOT = FILE.parents[1] # YOLOv5 root directory
38
  NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLOv5 multiprocessing threads
39
  VERBOSE = str(os.getenv('YOLOv5_VERBOSE', True)).lower() == 'true' # global verbose mode
 
40
 
41
  torch.set_printoptions(linewidth=320, precision=5, profile='long')
42
  np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5
@@ -55,6 +56,21 @@ def is_kaggle():
55
  return False
56
 
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  def set_logging(name=None, verbose=VERBOSE):
59
  # Sets level and returns logger
60
  if is_kaggle():
@@ -68,6 +84,22 @@ def set_logging(name=None, verbose=VERBOSE):
68
  LOGGER = set_logging('yolov5') # define globally (used in train.py, val.py, detect.py, etc.)
69
 
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  class Profile(contextlib.ContextDecorator):
72
  # Usage: @Profile() decorator or 'with Profile():' context manager
73
  def __enter__(self):
@@ -152,34 +184,6 @@ def get_latest_run(search_dir='.'):
152
  return max(last_list, key=os.path.getctime) if last_list else ''
153
 
154
 
155
- def user_config_dir(dir='Ultralytics', env_var='YOLOV5_CONFIG_DIR'):
156
- # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required.
157
- env = os.getenv(env_var)
158
- if env:
159
- path = Path(env) # use environment variable
160
- else:
161
- cfg = {'Windows': 'AppData/Roaming', 'Linux': '.config', 'Darwin': 'Library/Application Support'} # 3 OS dirs
162
- path = Path.home() / cfg.get(platform.system(), '') # OS-specific config dir
163
- path = (path if is_writeable(path) else Path('/tmp')) / dir # GCP and AWS lambda fix, only /tmp is writeable
164
- path.mkdir(exist_ok=True) # make if required
165
- return path
166
-
167
-
168
- def is_writeable(dir, test=False):
169
- # Return True if directory has write permissions, test opening a file with write permissions if test=True
170
- if test: # method 1
171
- file = Path(dir) / 'tmp.txt'
172
- try:
173
- with open(file, 'w'): # open file with write permissions
174
- pass
175
- file.unlink() # remove file
176
- return True
177
- except OSError:
178
- return False
179
- else: # method 2
180
- return os.access(dir, os.R_OK) # possible issues on Windows
181
-
182
-
183
  def is_docker():
184
  # Is environment a Docker container?
185
  return Path('/workspace').exists() # or Path('/.dockerenv').exists()
@@ -207,7 +211,7 @@ def is_ascii(s=''):
207
 
208
  def is_chinese(s='人工智能'):
209
  # Is string composed of any Chinese characters?
210
- return re.search('[\u4e00-\u9fff]', s)
211
 
212
 
213
  def emojis(str=''):
@@ -378,6 +382,15 @@ def check_file(file, suffix=''):
378
  return files[0] # return file
379
 
380
 
 
 
 
 
 
 
 
 
 
381
  def check_dataset(data, autodownload=True):
382
  # Download and/or unzip dataset if not found locally
383
  # Usage: https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128_with_yaml.zip
 
37
  ROOT = FILE.parents[1] # YOLOv5 root directory
38
  NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLOv5 multiprocessing threads
39
  VERBOSE = str(os.getenv('YOLOv5_VERBOSE', True)).lower() == 'true' # global verbose mode
40
+ FONT = 'Arial.ttf' # https://ultralytics.com/assets/Arial.ttf
41
 
42
  torch.set_printoptions(linewidth=320, precision=5, profile='long')
43
  np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5
 
56
  return False
57
 
58
 
59
+ def is_writeable(dir, test=False):
60
+ # Return True if directory has write permissions, test opening a file with write permissions if test=True
61
+ if test: # method 1
62
+ file = Path(dir) / 'tmp.txt'
63
+ try:
64
+ with open(file, 'w'): # open file with write permissions
65
+ pass
66
+ file.unlink() # remove file
67
+ return True
68
+ except OSError:
69
+ return False
70
+ else: # method 2
71
+ return os.access(dir, os.R_OK) # possible issues on Windows
72
+
73
+
74
  def set_logging(name=None, verbose=VERBOSE):
75
  # Sets level and returns logger
76
  if is_kaggle():
 
84
  LOGGER = set_logging('yolov5') # define globally (used in train.py, val.py, detect.py, etc.)
85
 
86
 
87
+ def user_config_dir(dir='Ultralytics', env_var='YOLOV5_CONFIG_DIR'):
88
+ # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required.
89
+ env = os.getenv(env_var)
90
+ if env:
91
+ path = Path(env) # use environment variable
92
+ else:
93
+ cfg = {'Windows': 'AppData/Roaming', 'Linux': '.config', 'Darwin': 'Library/Application Support'} # 3 OS dirs
94
+ path = Path.home() / cfg.get(platform.system(), '') # OS-specific config dir
95
+ path = (path if is_writeable(path) else Path('/tmp')) / dir # GCP and AWS lambda fix, only /tmp is writeable
96
+ path.mkdir(exist_ok=True) # make if required
97
+ return path
98
+
99
+
100
+ CONFIG_DIR = user_config_dir() # Ultralytics settings dir
101
+
102
+
103
  class Profile(contextlib.ContextDecorator):
104
  # Usage: @Profile() decorator or 'with Profile():' context manager
105
  def __enter__(self):
 
184
  return max(last_list, key=os.path.getctime) if last_list else ''
185
 
186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  def is_docker():
188
  # Is environment a Docker container?
189
  return Path('/workspace').exists() # or Path('/.dockerenv').exists()
 
211
 
212
  def is_chinese(s='人工智能'):
213
  # Is string composed of any Chinese characters?
214
+ return True if re.search('[\u4e00-\u9fff]', str(s)) else False
215
 
216
 
217
  def emojis(str=''):
 
382
  return files[0] # return file
383
 
384
 
385
+ def check_font(font=FONT):
386
+ # Download font to CONFIG_DIR if necessary
387
+ font = Path(font)
388
+ if not font.exists() and not (CONFIG_DIR / font.name).exists():
389
+ url = "https://ultralytics.com/assets/" + font.name
390
+ LOGGER.info(f'Downloading {url} to {CONFIG_DIR / font.name}...')
391
+ torch.hub.download_url_to_file(url, str(font), progress=False)
392
+
393
+
394
  def check_dataset(data, autodownload=True):
395
  # Download and/or unzip dataset if not found locally
396
  # Usage: https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128_with_yaml.zip
utils/plots.py CHANGED
@@ -17,12 +17,11 @@ import seaborn as sn
17
  import torch
18
  from PIL import Image, ImageDraw, ImageFont
19
 
20
- from utils.general import (LOGGER, Timeout, check_requirements, clip_coords, increment_path, is_ascii, is_chinese,
21
- try_except, user_config_dir, xywh2xyxy, xyxy2xywh)
22
  from utils.metrics import fitness
23
 
24
  # Settings
25
- CONFIG_DIR = user_config_dir() # Ultralytics settings dir
26
  RANK = int(os.getenv('RANK', -1))
27
  matplotlib.rc('font', **{'size': 11})
28
  matplotlib.use('Agg') # for writing to files only
@@ -49,16 +48,14 @@ class Colors:
49
  colors = Colors() # create instance for 'from utils.plots import colors'
50
 
51
 
52
- def check_font(font='Arial.ttf', size=10):
53
  # Return a PIL TrueType Font, downloading to CONFIG_DIR if necessary
54
  font = Path(font)
55
  font = font if font.exists() else (CONFIG_DIR / font.name)
56
  try:
57
  return ImageFont.truetype(str(font) if font.exists() else font.name, size)
58
  except Exception as e: # download if missing
59
- url = "https://ultralytics.com/assets/" + font.name
60
- LOGGER.info(f'Downloading {url} to {font}...')
61
- torch.hub.download_url_to_file(url, str(font), progress=False)
62
  try:
63
  return ImageFont.truetype(str(font), size)
64
  except TypeError:
@@ -67,7 +64,7 @@ def check_font(font='Arial.ttf', size=10):
67
 
68
  class Annotator:
69
  if RANK in (-1, 0):
70
- check_font() # download TTF if necessary
71
 
72
  # YOLOv5 Annotator for train/val mosaics and jpgs and detect/hub inference annotations
73
  def __init__(self, im, line_width=None, font_size=None, font='Arial.ttf', pil=False, example='abc'):
@@ -76,8 +73,8 @@ class Annotator:
76
  if self.pil: # use PIL
77
  self.im = im if isinstance(im, Image.Image) else Image.fromarray(im)
78
  self.draw = ImageDraw.Draw(self.im)
79
- self.font = check_font(font='Arial.Unicode.ttf' if is_chinese(example) else font,
80
- size=font_size or max(round(sum(self.im.size) / 2 * 0.035), 12))
81
  else: # use cv2
82
  self.im = im
83
  self.lw = line_width or max(round(sum(im.shape) / 2 * 0.003), 2) # line width
@@ -89,10 +86,10 @@ class Annotator:
89
  if label:
90
  w, h = self.font.getsize(label) # text width, height
91
  outside = box[1] - h >= 0 # label fits outside box
92
- self.draw.rectangle([box[0],
93
  box[1] - h if outside else box[1],
94
  box[0] + w + 1,
95
- box[1] + 1 if outside else box[1] + h + 1], fill=color)
96
  # self.draw.text((box[0], box[1]), label, fill=txt_color, font=self.font, anchor='ls') # for PIL>8.0
97
  self.draw.text((box[0], box[1] - h if outside else box[1]), label, fill=txt_color, font=self.font)
98
  else: # cv2
@@ -210,7 +207,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max
210
 
211
  # Annotate
212
  fs = int((h + w) * ns * 0.01) # font size
213
- annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True)
214
  for i in range(i + 1):
215
  x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin
216
  annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders
 
17
  import torch
18
  from PIL import Image, ImageDraw, ImageFont
19
 
20
+ from utils.general import (CONFIG_DIR, FONT, LOGGER, Timeout, check_font, check_requirements, clip_coords,
21
+ increment_path, is_ascii, is_chinese, try_except, xywh2xyxy, xyxy2xywh)
22
  from utils.metrics import fitness
23
 
24
  # Settings
 
25
  RANK = int(os.getenv('RANK', -1))
26
  matplotlib.rc('font', **{'size': 11})
27
  matplotlib.use('Agg') # for writing to files only
 
48
  colors = Colors() # create instance for 'from utils.plots import colors'
49
 
50
 
51
+ def check_pil_font(font=FONT, size=10):
52
  # Return a PIL TrueType Font, downloading to CONFIG_DIR if necessary
53
  font = Path(font)
54
  font = font if font.exists() else (CONFIG_DIR / font.name)
55
  try:
56
  return ImageFont.truetype(str(font) if font.exists() else font.name, size)
57
  except Exception as e: # download if missing
58
+ check_font(font)
 
 
59
  try:
60
  return ImageFont.truetype(str(font), size)
61
  except TypeError:
 
64
 
65
  class Annotator:
66
  if RANK in (-1, 0):
67
+ check_pil_font() # download TTF if necessary
68
 
69
  # YOLOv5 Annotator for train/val mosaics and jpgs and detect/hub inference annotations
70
  def __init__(self, im, line_width=None, font_size=None, font='Arial.ttf', pil=False, example='abc'):
 
73
  if self.pil: # use PIL
74
  self.im = im if isinstance(im, Image.Image) else Image.fromarray(im)
75
  self.draw = ImageDraw.Draw(self.im)
76
+ self.font = check_pil_font(font='Arial.Unicode.ttf' if is_chinese(example) else font,
77
+ size=font_size or max(round(sum(self.im.size) / 2 * 0.035), 12))
78
  else: # use cv2
79
  self.im = im
80
  self.lw = line_width or max(round(sum(im.shape) / 2 * 0.003), 2) # line width
 
86
  if label:
87
  w, h = self.font.getsize(label) # text width, height
88
  outside = box[1] - h >= 0 # label fits outside box
89
+ self.draw.rectangle((box[0],
90
  box[1] - h if outside else box[1],
91
  box[0] + w + 1,
92
+ box[1] + 1 if outside else box[1] + h + 1), fill=color)
93
  # self.draw.text((box[0], box[1]), label, fill=txt_color, font=self.font, anchor='ls') # for PIL>8.0
94
  self.draw.text((box[0], box[1] - h if outside else box[1]), label, fill=txt_color, font=self.font)
95
  else: # cv2
 
207
 
208
  # Annotate
209
  fs = int((h + w) * ns * 0.01) # font size
210
+ annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True, example=names)
211
  for i in range(i + 1):
212
  x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin
213
  annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders