Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

258 rindas
11KB

  1. import cv2
  2. import numpy as np
  3. from PIL import Image, ImageDraw, ImageFont
  4. import unicodedata
  5. FONT_PATH = "../AIlib2/conf/platech.ttf"
  6. zhFont = ImageFont.truetype(FONT_PATH, 20, encoding="utf-8")
  7. def get_label_array(color=None, label=None, font=None, fontSize=40, unify=False):
  8. if unify:
  9. x, y, width, height = font.getbbox("标") # 统一数组大小
  10. else:
  11. x, y, width, height = font.getbbox(label)
  12. text_image = np.zeros((height, width, 3), dtype=np.uint8)
  13. text_image = Image.fromarray(text_image)
  14. draw = ImageDraw.Draw(text_image)
  15. draw.rectangle((0, 0, width, height), fill=tuple(color))
  16. draw.text((0, -1), label, fill=(255, 255, 255), font=font)
  17. im_array = np.asarray(text_image)
  18. # scale = fontSize / height
  19. # im_array = cv2.resize(im_array, (0, 0), fx=scale, fy=scale)
  20. scale = height / fontSize
  21. im_array = cv2.resize(im_array, (0, 0), fx=scale, fy=scale)
  22. return im_array
  23. def get_label_arrays(labelNames, colors, fontSize=40, fontPath="platech.ttf"):
  24. font = ImageFont.truetype(fontPath, fontSize, encoding='utf-8')
  25. label_arraylist = [get_label_array(colors[i % 20], label_name, font, fontSize) for i, label_name in
  26. enumerate(labelNames)]
  27. return label_arraylist
  28. def get_label_array_dict(colors, fontSize=40, fontPath="platech.ttf"):
  29. font = ImageFont.truetype(fontPath, fontSize, encoding='utf-8')
  30. all_chinese_characters = []
  31. for char in range(0x4E00, 0x9FFF + 1): # 中文
  32. chinese_character = chr(char)
  33. if unicodedata.category(chinese_character) == 'Lo':
  34. all_chinese_characters.append(chinese_character)
  35. for char in range(0x0041, 0x005B): # 大写字母
  36. all_chinese_characters.append(chr(char))
  37. for char in range(0x0061, 0x007B): # 小写字母
  38. all_chinese_characters.append(chr(char))
  39. for char in range(0x0030, 0x003A): # 数字
  40. all_chinese_characters.append(chr(char))
  41. zh_dict = {}
  42. for code in all_chinese_characters:
  43. arr = get_label_array(colors[2], code, font, fontSize, unify=True)
  44. zh_dict[code] = arr
  45. return zh_dict
  46. def xywh2xyxy(box):
  47. if not isinstance(box[0], (list, tuple, np.ndarray)):
  48. xc, yc, w, h = int(box[0]), int(box[1]), int(box[2]), int(box[3])
  49. bw, bh = int(w / 2), int(h / 2)
  50. lt, yt, rt, yr = xc - bw, yc - bh, xc + bw, yc + bh
  51. box = [(lt, yt), (rt, yt), (rt, yr), (lt, yr)]
  52. return box
  53. def xywh2xyxy2(param):
  54. if not isinstance(param[0], (list, tuple, np.ndarray)):
  55. xc, yc, x2, y2 = int(param[0]), int(param[1]), int(param[2]), int(param[3])
  56. return [(xc, yc), (x2, yc), (x2, y2), (xc, y2)], float(param[4]), int(param[5])
  57. # bw, bh = int(w / 2), int(h / 2)
  58. # lt, yt, rt, yr = xc - bw, yc - bh, xc + bw, yc + bh
  59. # return [(lt, yt), (rt, yt), (rt, yr), (lt, yr)]
  60. return np.asarray(param[0][0:4], np.int32), float(param[1]), int(param[2])
  61. def draw_painting_joint(box, img, label_array, score=0.5, color=None, config=None, isNew=False):
  62. # 识别问题描述图片的高、宽
  63. lh, lw = label_array.shape[0:2]
  64. # 图片的长度和宽度
  65. imh, imw = img.shape[0:2]
  66. box = xywh2xyxy(box)
  67. # 框框左上的位置
  68. x0, y1 = box[0][0], box[0][1]
  69. # if score_location == 'leftTop':
  70. # x0, y1 = box[0][0], box[0][1]
  71. # # 框框左下的位置
  72. # elif score_location == 'leftBottom':
  73. # x0, y1 = box[3][0], box[3][1]
  74. # else:
  75. # x0, y1 = box[0][0], box[0][1]
  76. # x1 框框左上x位置 + 描述的宽
  77. # y0 框框左上y位置 - 描述的高
  78. x1, y0 = x0 + lw, y1 - lh
  79. # 如果y0小于0, 说明超过上边框
  80. if y0 < 0:
  81. y0 = 0
  82. # y1等于文字高度
  83. y1 = y0 + lh
  84. # 如果y1框框的高大于图片高度
  85. if y1 > imh:
  86. # y1等于图片高度
  87. y1 = imh
  88. # y0等于y1减去文字高度
  89. y0 = y1 - lh
  90. # 如果x0小于0
  91. if x0 < 0:
  92. x0 = 0
  93. x1 = x0 + lw
  94. if x1 > imw:
  95. x1 = imw
  96. x0 = x1 - lw
  97. # box_tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1
  98. '''
  99. 1. img(array) 为ndarray类型(可以为cv.imread)直接读取的数据
  100. 2. box(array):为所画多边形的顶点坐标
  101. 3. 所画四边形是否闭合,通常为True
  102. 4. color(tuple):BGR三个通道的值
  103. 5. thickness(int):画线的粗细
  104. 6. shift:顶点坐标中小数的位数
  105. '''
  106. tl = config[0]
  107. box1 = np.asarray(box, np.int32)
  108. cv2.polylines(img, [box1], True, color, tl)
  109. img[y0:y1, x0:x1, :] = label_array
  110. pts_cls = [(x0, y0), (x1, y1)]
  111. # 把英文字符score画到类别旁边
  112. # tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1
  113. label = ' %.2f' % score
  114. # tf = max(tl, 1)
  115. # fontScale = float(format(imw / 1920 * 1.1, '.2f')) or tl * 0.33
  116. # fontScale = tl * 0.33
  117. '''
  118. 1. text:要计算大小的文本内容,类型为字符串。
  119. 2. fontFace:字体类型,例如cv2.FONT_HERSHEY_SIMPLEX等。
  120. 3. fontScale:字体大小的缩放因子,例如1.2表示字体大小增加20%。
  121. 4. thickness:文本线条的粗细,以像素为单位。
  122. 5. (text_width, text_height):给定文本在指定字体、字体大小、线条粗细下所占用的像素宽度和高度。
  123. '''
  124. # t_size = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0]
  125. t_size = (config[1], config[2])
  126. # if socre_location=='leftTop':
  127. p1, p2 = (pts_cls[1][0], pts_cls[0][1]), (pts_cls[1][0] + t_size[0], pts_cls[1][1])
  128. '''
  129. 1. img:要绘制矩形的图像
  130. 2. pt1:矩形框的左上角坐标,可以是一个包含两个整数的元组或列表,例如(x1, y1)或[x1, y1]。
  131. 3. pt2:矩形框的右下角坐标,可以是一个包含两个整数的元组或列表,例如(x2, y2)或[x2, y2]。
  132. 4. color:矩形框的颜色,可以是一个包含三个整数的元组或列表,例如(255, 0, 0)表示蓝色,或一个标量值,例如255表示白色。颜色顺序为BGR。
  133. 5. thickness:线条的粗细,以像素为单位。如果为负值,则表示要绘制填充矩形。默认值为1。
  134. 6. lineType:线条的类型,可以是cv2.LINE_AA表示抗锯齿线条,或cv2.LINE_4表示4连通线条,或cv2.LINE_8表示8连通线条。默认值为cv2.LINE_8。
  135. 7. shift:坐标点小数点位数。默认值为0。
  136. '''
  137. cv2.rectangle(img, p1, p2, color, -1, cv2.LINE_AA)
  138. p3 = pts_cls[1][0], pts_cls[1][1] - (lh - t_size[1]) // 2
  139. '''
  140. 1. img:要在其上绘制文本的图像
  141. 2. text:要绘制的文本内容,类型为字符串
  142. 3. org:文本起始位置的坐标,可以是一个包含两个整数的元组或列表,例如(x, y)或[x, y]。
  143. 4. fontFace:字体类型,例如cv2.FONT_HERSHEY_SIMPLEX等。
  144. 5. fontScale:字体大小的缩放因子,例如1.2表示字体大小增加20%。
  145. 6. color:文本的颜色,可以是一个包含三个整数的元组或列表,例如(255, 0, 0)表示蓝色,或一个标量值,例如255表示白色。颜色顺序为BGR。
  146. 7. thickness:文本线条的粗细,以像素为单位。默认值为1。
  147. 8. lineType:线条的类型,可以是cv2.LINE_AA表示抗锯齿线条,或cv2.LINE_4表示4连通线条,或cv2.LINE_8表示8连通线条。默认值为cv2.LINE_8。
  148. 9. bottomLeftOrigin:文本起始位置是否为左下角。如果为True,则文本起始位置为左下角,否则为左上角。默认值为False。
  149. '''
  150. if isNew:
  151. cv2.putText(img, label, p3, 0, config[3], [0, 0, 0], thickness=config[4], lineType=cv2.LINE_AA)
  152. else:
  153. cv2.putText(img, label, p3, 0, config[3], [225, 255, 255], thickness=config[4], lineType=cv2.LINE_AA)
  154. return img, box
  155. # 动态标签
  156. def draw_name_joint(box, img, label_array_dict, score=0.5, color=None, config=None, name=""):
  157. label_array = None
  158. for zh in name:
  159. if zh in label_array_dict:
  160. if label_array is None:
  161. label_array = label_array_dict[zh]
  162. else:
  163. label_array = np.concatenate((label_array,label_array_dict[zh]), axis= 1)
  164. # 识别问题描述图片的高、宽
  165. if label_array is None:
  166. lh, lw = 0, 0
  167. else:
  168. lh, lw = label_array.shape[0:2]
  169. # 图片的长度和宽度
  170. imh, imw = img.shape[0:2]
  171. box = xywh2xyxy(box)
  172. # 框框左上的位置
  173. x0, y1 = box[0][0], box[0][1]
  174. x1, y0 = x0 + lw, y1 - lh
  175. # 如果y0小于0, 说明超过上边框
  176. if y0 < 0:
  177. y0 = 0
  178. # y1等于文字高度
  179. y1 = y0 + lh
  180. # 如果y1框框的高大于图片高度
  181. if y1 > imh:
  182. # y1等于图片高度
  183. y1 = imh
  184. # y0等于y1减去文字高度
  185. y0 = y1 - lh
  186. # 如果x0小于0
  187. if x0 < 0:
  188. x0 = 0
  189. x1 = x0 + lw
  190. if x1 > imw:
  191. x1 = imw
  192. x0 = x1 - lw
  193. tl = config[0]
  194. box1 = np.asarray(box, np.int32)
  195. cv2.polylines(img, [box1], True, color, tl)
  196. if label_array is not None:
  197. img[y0:y1, x0:x1, :] = label_array
  198. pts_cls = [(x0, y0), (x1, y1)]
  199. # 把英文字符score画到类别旁边
  200. # tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1
  201. label = ' %.2f' % score
  202. t_size = (config[1], config[2])
  203. # if socre_location=='leftTop':
  204. p1, p2 = (pts_cls[1][0], pts_cls[0][1]), (pts_cls[1][0] + t_size[0], pts_cls[1][1])
  205. cv2.rectangle(img, p1, p2, color, -1, cv2.LINE_AA)
  206. p3 = pts_cls[1][0], pts_cls[1][1] - (lh - t_size[1]) // 2
  207. cv2.putText(img, label, p3, 0, config[3], [225, 255, 255], thickness=config[4], lineType=cv2.LINE_AA)
  208. return img, box
  209. def filterBox(det0, det1, pix_dis):
  210. # det0为 (m1, 11) 矩阵
  211. # det1为 (m2, 12) 矩阵
  212. if len(det0.shape) == 1:
  213. det0 = det0[np.newaxis,...]
  214. if len(det1.shape) == 1:
  215. det1 = det1[np.newaxis,...]
  216. det1 = det1[...,0:11].copy()
  217. m, n = det0.size, det1.size
  218. if not m:
  219. return det0
  220. # 在det0的列方向加一个元素flag代表该目标框中心点是否在之前目标框内(0代表不在,其他代表在)
  221. flag = np.zeros([len(det0), 1])
  222. det0 = np.concatenate([det0, flag], axis=1)
  223. det0_copy = det0.copy()
  224. # det1_copy = det1.copy()
  225. if not n:
  226. return det0
  227. # det0转成 (m1, m2, 12) 的矩阵
  228. # det1转成 (m1, m2, 12) 的矩阵
  229. # det0与det1在第3维方向上拼接(6 + 7 = 13)
  230. det0 = det0[:, np.newaxis, :].repeat(det1.shape[0], 1)
  231. det1 = det1[np.newaxis, ...].repeat(det0.shape[0], 0)
  232. joint_det = np.concatenate((det1, det0), axis=2)
  233. # 分别求det0和det1的x1, y1, x2, y2(水平框的左上右下角点)
  234. x1, y1, x2, y2 = joint_det[..., 0], joint_det[..., 1], joint_det[..., 4], joint_det[..., 5]
  235. x3, y3, x4, y4 = joint_det[..., 11], joint_det[..., 12], joint_det[..., 15], joint_det[..., 16]
  236. x2_c, y2_c = (x1+x2)//2, (y1+y2)//2
  237. x_c, y_c = (x3+x4)//2, (y3+y4)//2
  238. dis = (x2_c - x_c)**2 + (y2_c - y_c)**2
  239. mask = (joint_det[..., 9] == joint_det[..., 20]) & (dis <= pix_dis**2)
  240. # 类别相同 & 中心点在上一帧的框内 判断为True
  241. res = np.sum(mask, axis=1)
  242. det0_copy[..., -1] = res
  243. return det0_copy