imgproc_utils.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import numpy as np
  2. import cv2
  3. import random
  4. def hex2bgr(hex):
  5. gmask = 254 << 8
  6. rmask = 254
  7. b = hex >> 16
  8. g = (hex & gmask) >> 8
  9. r = hex & rmask
  10. return np.stack([b, g, r]).transpose()
  11. def union_area(bboxa, bboxb):
  12. x1 = max(bboxa[0], bboxb[0])
  13. y1 = max(bboxa[1], bboxb[1])
  14. x2 = min(bboxa[2], bboxb[2])
  15. y2 = min(bboxa[3], bboxb[3])
  16. if y2 < y1 or x2 < x1:
  17. return -1
  18. return (y2 - y1) * (x2 - x1)
  19. def get_yololabel_strings(clslist, labellist):
  20. content = ''
  21. for cls, xywh in zip(clslist, labellist):
  22. content += str(int(cls)) + ' ' + ' '.join([str(e) for e in xywh]) + '\n'
  23. if len(content) != 0:
  24. content = content[:-1]
  25. return content
  26. # 4 points bbox to 8 points polygon
  27. def xywh2xyxypoly(xywh, to_int=True):
  28. xyxypoly = np.tile(xywh[:, [0, 1]], 4)
  29. xyxypoly[:, [2, 4]] += xywh[:, [2]]
  30. xyxypoly[:, [5, 7]] += xywh[:, [3]]
  31. if to_int:
  32. xyxypoly = xyxypoly.astype(np.int64)
  33. return xyxypoly
  34. def xyxy2yolo(xyxy, w: int, h: int):
  35. if xyxy == [] or len(xyxy) == 0:
  36. return None
  37. if isinstance(xyxy, list):
  38. xyxy = np.array(xyxy)
  39. if len(xyxy.shape) == 1:
  40. xyxy = np.array([xyxy])
  41. yolo = np.copy(xyxy).astype(np.float64)
  42. yolo[:, [0, 2]] = yolo[:, [0, 2]] / w
  43. yolo[:, [1, 3]] = yolo[:, [1, 3]] / h
  44. yolo[:, [2, 3]] -= yolo[:, [0, 1]]
  45. yolo[:, [0, 1]] += yolo[:, [2, 3]] / 2
  46. return yolo
  47. def yolo_xywh2xyxy(xywh: np.array, w: int, h: int, to_int=True):
  48. if xywh is None:
  49. return None
  50. if len(xywh) == 0:
  51. return None
  52. if len(xywh.shape) == 1:
  53. xywh = np.array([xywh])
  54. xywh[:, [0, 2]] *= w
  55. xywh[:, [1, 3]] *= h
  56. xywh[:, [0, 1]] -= xywh[:, [2, 3]] / 2
  57. xywh[:, [2, 3]] += xywh[:, [0, 1]]
  58. if to_int:
  59. xywh = xywh.astype(np.int64)
  60. return xywh
  61. def rotate_polygons(center, polygons, rotation, new_center=None, to_int=True):
  62. if new_center is None:
  63. new_center = center
  64. rotation = np.deg2rad(rotation)
  65. s, c = np.sin(rotation), np.cos(rotation)
  66. polygons = polygons.astype(np.float32)
  67. polygons[:, 1::2] -= center[1]
  68. polygons[:, ::2] -= center[0]
  69. rotated = np.copy(polygons)
  70. rotated[:, 1::2] = polygons[:, 1::2] * c - polygons[:, ::2] * s
  71. rotated[:, ::2] = polygons[:, 1::2] * s + polygons[:, ::2] * c
  72. rotated[:, 1::2] += new_center[1]
  73. rotated[:, ::2] += new_center[0]
  74. if to_int:
  75. return rotated.astype(np.int64)
  76. return rotated
  77. def letterbox(im, new_shape=(640, 640), color=(0, 0, 0), auto=False, scaleFill=False, scaleup=True, stride=128):
  78. # Resize and pad image while meeting stride-multiple constraints
  79. shape = im.shape[:2] # current shape [height, width]
  80. if not isinstance(new_shape, tuple):
  81. new_shape = (new_shape, new_shape)
  82. # Scale ratio (new / old)
  83. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  84. if not scaleup: # only scale down, do not scale up (for better val mAP)
  85. r = min(r, 1.0)
  86. # Compute padding
  87. ratio = r, r # width, height ratios
  88. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
  89. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding
  90. if auto: # minimum rectangle
  91. dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding
  92. elif scaleFill: # stretch
  93. dw, dh = 0.0, 0.0
  94. new_unpad = (new_shape[1], new_shape[0])
  95. ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios
  96. # dw /= 2 # divide padding into 2 sides
  97. # dh /= 2
  98. dh, dw = int(dh), int(dw)
  99. if shape[::-1] != new_unpad: # resize
  100. im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)
  101. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
  102. left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
  103. im = cv2.copyMakeBorder(im, 0, dh, 0, dw, cv2.BORDER_CONSTANT, value=color) # add border
  104. return im, ratio, (dw, dh)
  105. def resize_keepasp(im, new_shape=640, scaleup=True, interpolation=cv2.INTER_LINEAR, stride=None):
  106. shape = im.shape[:2] # current shape [height, width]
  107. if new_shape is not None:
  108. if not isinstance(new_shape, tuple):
  109. new_shape = (new_shape, new_shape)
  110. else:
  111. new_shape = shape
  112. # Scale ratio (new / old)
  113. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  114. if not scaleup: # only scale down, do not scale up (for better val mAP)
  115. r = min(r, 1.0)
  116. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
  117. if stride is not None:
  118. h, w = new_unpad
  119. if new_shape[0] % stride != 0 :
  120. new_h = (stride - (new_shape[0] % stride)) + h
  121. else :
  122. new_h = h
  123. if w % stride != 0 :
  124. new_w = (stride - (w % stride)) + w
  125. else :
  126. new_w = w
  127. new_unpad = (new_h, new_w)
  128. if shape[::-1] != new_unpad: # resize
  129. im = cv2.resize(im, new_unpad, interpolation=interpolation)
  130. return im
  131. def expand_textwindow(img_size, xyxy, expand_r=8, shrink=False):
  132. im_h, im_w = img_size[:2]
  133. x1, y1 , x2, y2 = xyxy
  134. w = x2 - x1
  135. h = y2 - y1
  136. paddings = int(round((max(h, w) * 0.25 + min(h, w) * 0.75) / expand_r))
  137. if shrink:
  138. paddings *= -1
  139. x1, y1 = max(0, x1 - paddings), max(0, y1 - paddings)
  140. x2, y2 = min(im_w-1, x2+paddings), min(im_h-1, y2+paddings)
  141. return [x1, y1, x2, y2]
  142. def draw_connected_labels(num_labels, labels, stats, centroids, names="draw_connected_labels", skip_background=True):
  143. labdraw = np.zeros((labels.shape[0], labels.shape[1], 3), dtype=np.uint8)
  144. max_ind = 0
  145. if isinstance(num_labels, int):
  146. num_labels = range(num_labels)
  147. # for ind, lab in enumerate((range(num_labels))):
  148. for lab in num_labels:
  149. if skip_background and lab == 0:
  150. continue
  151. randcolor = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
  152. labdraw[np.where(labels==lab)] = randcolor
  153. maxr, minr = 0.5, 0.001
  154. maxw, maxh = stats[max_ind][2] * maxr, stats[max_ind][3] * maxr
  155. minarea = labdraw.shape[0] * labdraw.shape[1] * minr
  156. stat = stats[lab]
  157. bboxarea = stat[2] * stat[3]
  158. if stat[2] < maxw and stat[3] < maxh and bboxarea > minarea:
  159. pix = np.zeros((labels.shape[0], labels.shape[1]), dtype=np.uint8)
  160. pix[np.where(labels==lab)] = 255
  161. rect = cv2.minAreaRect(cv2.findNonZero(pix))
  162. box = np.int0(cv2.boxPoints(rect))
  163. labdraw = cv2.drawContours(labdraw, [box], 0, randcolor, 2)
  164. labdraw = cv2.circle(labdraw, (int(centroids[lab][0]),int(centroids[lab][1])), radius=5, color=(random.randint(0,255), random.randint(0,255), random.randint(0,255)), thickness=-1)
  165. cv2.imshow(names, labdraw)
  166. return labdraw