utils.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import os
  2. from functools import reduce
  3. import cv2
  4. import numpy as np
  5. from PIL import Image, ImageFont, ImageDraw
  6. import sys
  7. sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../")
  8. def pil_resize(image_np, height, width):
  9. image_pil = Image.fromarray(cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB))
  10. image_pil = image_pil.resize((int(width), int(height)), Image.BICUBIC)
  11. image_np = cv2.cvtColor(np.asarray(image_pil), cv2.COLOR_RGB2BGR)
  12. return image_np
  13. def get_best_predict_size(image_np, times=8, min_size=128, max_size=400):
  14. sizes = []
  15. for i in range(int(min_size/times), 100):
  16. if i*times <= max_size:
  17. sizes.append(i*times)
  18. sizes.sort(key=lambda x: x, reverse=True)
  19. min_len = 10000
  20. best_height = sizes[0]
  21. for height in sizes:
  22. if abs(image_np.shape[0] - height) < min_len:
  23. min_len = abs(image_np.shape[0] - height)
  24. best_height = height
  25. min_len = 10000
  26. best_width = sizes[0]
  27. for width in sizes:
  28. if abs(image_np.shape[1] - width) < min_len:
  29. min_len = abs(image_np.shape[1] - width)
  30. best_width = width
  31. if best_height > best_width:
  32. best_width = best_height
  33. else:
  34. best_height = best_width
  35. return best_height, best_width
  36. def letterbox_image(image, size):
  37. """resize image with unchanged aspect ratio using padding"""
  38. iw, ih = image.size
  39. w, h = size
  40. scale = min(w/iw, h/ih)
  41. nw = int(iw*scale)
  42. nh = int(ih*scale)
  43. image = image.resize((nw,nh), Image.BICUBIC)
  44. new_image = Image.new('RGB', size, (128,128,128))
  45. new_image.paste(image, ((w-nw)//2, (h-nh)//2))
  46. return new_image
  47. def compose(*funcs):
  48. """Compose arbitrarily many functions, evaluated left to right.
  49. Reference: https://mathieularose.com/function-composition-in-python/
  50. """
  51. if funcs:
  52. return reduce(lambda f, g: lambda *a, **kw: g(f(*a, **kw)), funcs)
  53. else:
  54. raise ValueError('Composition of empty sequence not supported.')
  55. def draw_boxes(image, out_boxes, out_classes, out_scores, class_names, colors):
  56. font = ImageFont.truetype(font=os.path.abspath(os.path.dirname(__file__))+'/font/FiraMono-Medium.otf',
  57. size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
  58. thickness = (image.size[0] + image.size[1]) // 300
  59. box_list = []
  60. for i, c in reversed(list(enumerate(out_classes))):
  61. predicted_class = class_names[c]
  62. box = out_boxes[i]
  63. score = out_scores[i]
  64. label = '{} {:.2f}'.format(predicted_class, score)
  65. draw = ImageDraw.Draw(image)
  66. label_size = draw.textsize(label, font)
  67. top, left, bottom, right = box
  68. top = max(0, np.floor(top + 0.5).astype('int32'))
  69. left = max(0, np.floor(left + 0.5).astype('int32'))
  70. bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
  71. right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
  72. # print(label, (left, top), (right, bottom))
  73. box_list.append([(left, top), (right, bottom)])
  74. if top - label_size[1] >= 0:
  75. text_origin = np.array([left, top - label_size[1]])
  76. else:
  77. text_origin = np.array([left, top + 1])
  78. # My kingdom for a good redistributable image drawing library.
  79. for i in range(thickness):
  80. draw.rectangle(
  81. [left + i, top + i, right - i, bottom - i],
  82. outline=colors[c])
  83. draw.rectangle(
  84. [tuple(text_origin), tuple(text_origin + label_size)],
  85. fill=colors[c])
  86. draw.text(text_origin, label, fill=(0, 0, 0), font=font)
  87. del draw
  88. return image
  89. def adjust_boxes(image, boxes, threshold=10):
  90. new_boxes = []
  91. for box in boxes:
  92. w, h = image.size
  93. top, left, bottom, right = box
  94. top = max(0, np.floor(top + 0.5).astype('int32'))
  95. left = max(0, np.floor(left + 0.5).astype('int32'))
  96. bottom = min(h, np.floor(bottom + 0.5).astype('int32'))
  97. right = min(w, np.floor(right + 0.5).astype('int32'))
  98. # 把框加大,有时候圈不全
  99. top = 0 if top - threshold < 0 else top - threshold
  100. bottom = h if bottom + threshold > h else bottom + threshold
  101. left = 0 if left - threshold < 0 else left - threshold
  102. right = w if right + threshold > w else right + threshold
  103. new_boxes.append([(left, top), (right, bottom)])
  104. return new_boxes