visualizer.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # -*- coding: UTF-8 -*-
  2. ################################################################################
  3. #
  4. # Copyright (c) 2024 Baidu.com, Inc. All Rights Reserved
  5. #
  6. ################################################################################
  7. """
  8. Author: PaddlePaddle Authors
  9. """
  10. import os
  11. import numpy as np
  12. import json
  13. from pathlib import Path
  14. import PIL
  15. from PIL import Image, ImageDraw, ImageFont
  16. from pycocotools.coco import COCO
  17. from ......utils.fonts import PINGFANG_FONT_FILE_PATH
  18. from ......utils import logging
  19. def colormap(rgb=False):
  20. """
  21. Get colormap
  22. The code of this function is copied from https://github.com/facebookresearch/Detectron/blob/main/detectron/\
  23. utils/colormap.py
  24. """
  25. color_list = np.array([
  26. 0xFF, 0x00, 0x00, 0xCC, 0xFF, 0x00, 0x00, 0xFF, 0x66, 0x00, 0x66, 0xFF,
  27. 0xCC, 0x00, 0xFF, 0xFF, 0x4D, 0x00, 0x80, 0xff, 0x00, 0x00, 0xFF, 0xB2,
  28. 0x00, 0x1A, 0xFF, 0xFF, 0x00, 0xE5, 0xFF, 0x99, 0x00, 0x33, 0xFF, 0x00,
  29. 0x00, 0xFF, 0xFF, 0x33, 0x00, 0xFF, 0xff, 0x00, 0x99, 0xFF, 0xE5, 0x00,
  30. 0x00, 0xFF, 0x1A, 0x00, 0xB2, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0x00, 0x4D
  31. ]).astype(np.float32)
  32. color_list = (color_list.reshape((-1, 3)))
  33. if not rgb:
  34. color_list = color_list[:, ::-1]
  35. return color_list.astype('int32')
  36. def font_colormap(color_index):
  37. """
  38. Get font color according to the index of colormap
  39. """
  40. dark = np.array([0x14, 0x0E, 0x35])
  41. light = np.array([0xFF, 0xFF, 0xFF])
  42. light_indexs = [0, 3, 4, 8, 9, 13, 14, 18, 19]
  43. if color_index in light_indexs:
  44. return light.astype('int32')
  45. else:
  46. return dark.astype('int32')
  47. def draw_bbox(image, coco_info: COCO, img_id):
  48. """
  49. Draw bbox on image
  50. """
  51. try:
  52. image_info = coco_info.loadImgs(img_id)[0]
  53. font_size = int(0.024 * int(image_info['width'])) + 2
  54. except:
  55. font_size = 12
  56. font = ImageFont.truetype(
  57. PINGFANG_FONT_FILE_PATH, font_size, encoding="utf-8")
  58. image = image.convert('RGB')
  59. draw = ImageDraw.Draw(image)
  60. image_size = image.size
  61. width = int(max(image_size) * 0.005)
  62. catid2color = {}
  63. catid2fontcolor = {}
  64. catid_num_dict = {}
  65. color_list = colormap(rgb=True)
  66. annotations = coco_info.loadAnns(coco_info.getAnnIds(imgIds=img_id))
  67. for ann in annotations:
  68. catid = ann['category_id']
  69. catid_num_dict[catid] = catid_num_dict.get(catid, 0) + 1
  70. for i, (catid, _) in enumerate(
  71. sorted(
  72. catid_num_dict.items(), key=lambda x: x[1], reverse=True)):
  73. if catid not in catid2color:
  74. color_index = i % len(color_list)
  75. catid2color[catid] = color_list[color_index]
  76. catid2fontcolor[catid] = font_colormap(color_index)
  77. for ann in annotations:
  78. catid, bbox = ann['category_id'], ann['bbox']
  79. color = tuple(catid2color[catid])
  80. font_color = tuple(catid2fontcolor[catid])
  81. if len(bbox) == 4:
  82. # draw bbox
  83. xmin, ymin, w, h = bbox
  84. xmax = xmin + w
  85. ymax = ymin + h
  86. draw.line(
  87. [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin),
  88. (xmin, ymin)],
  89. width=width,
  90. fill=color)
  91. elif len(bbox) == 8:
  92. x1, y1, x2, y2, x3, y3, x4, y4 = bbox
  93. draw.line(
  94. [(x1, y1), (x2, y2), (x3, y3), (x4, y4), (x1, y1)],
  95. width=width,
  96. fill=color)
  97. xmin = min(x1, x2, x3, x4)
  98. ymin = min(y1, y2, y3, y4)
  99. else:
  100. logging.info('Error: The shape of bbox must be [M, 4] or [M, 8]!')
  101. # draw label
  102. label = coco_info.loadCats(catid)[0]['name']
  103. text = "{}".format(label)
  104. if tuple(map(int, PIL.__version__.split('.'))) <= (10, 0, 0):
  105. tw, th = draw.textsize(text, font=font)
  106. else:
  107. left, top, right, bottom = draw.textbbox((0, 0), text, font)
  108. tw, th = right - left, bottom - top
  109. if ymin < th:
  110. draw.rectangle(
  111. [(xmin, ymin), (xmin + tw + 4, ymin + th + 1)], fill=color)
  112. draw.text((xmin + 2, ymin - 2), text, fill=font_color, font=font)
  113. else:
  114. draw.rectangle(
  115. [(xmin, ymin - th), (xmin + tw + 4, ymin + 1)], fill=color)
  116. draw.text(
  117. (xmin + 2, ymin - th - 2), text, fill=font_color, font=font)
  118. return image