visualize.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import os
  15. import os.path as osp
  16. import cv2
  17. from PIL import Image
  18. import numpy as np
  19. import math
  20. from .imgaug_support import execute_imgaug
  21. from .cls_transforms import ClsTransform
  22. from .det_transforms import DetTransform
  23. from .seg_transforms import SegTransform
  24. import paddlex as pdx
  25. from paddlex.cv.models.utils.visualize import get_color_map_list
  26. def _draw_rectangle_and_cname(img, xmin, ymin, xmax, ymax, cname, color):
  27. """ 根据提供的标注信息,给图片描绘框体和类别显示
  28. Args:
  29. img: 图片路径
  30. xmin: 检测框最小的x坐标
  31. ymin: 检测框最小的y坐标
  32. xmax: 检测框最大的x坐标
  33. ymax: 检测框最大的y坐标
  34. cname: 类别信息
  35. color: 类别与颜色的对应信息
  36. """
  37. # 描绘检测框
  38. line_width = math.ceil(2 * max(img.shape[0:2]) / 600)
  39. cv2.rectangle(
  40. img,
  41. pt1=(xmin, ymin),
  42. pt2=(xmax, ymax),
  43. color=color,
  44. thickness=line_width)
  45. return img
  46. def cls_compose(im, label=None, transforms=None, vdl_writer=None, step=0):
  47. """
  48. Args:
  49. im (str/np.ndarray): 图像路径/图像np.ndarray数据。
  50. label (int): 每张图像所对应的类别序号。
  51. vdl_writer (visualdl.LogWriter): VisualDL存储器,日志信息将保存在其中。
  52. 当为None时,不对日志进行保存。默认为None。
  53. step (int): 数据预处理的轮数,当vdl_writer不为None时有效。默认为0。
  54. Returns:
  55. tuple: 根据网络所需字段所组成的tuple;
  56. 字段由transforms中的最后一个数据预处理操作决定。
  57. """
  58. if isinstance(im, np.ndarray):
  59. if len(im.shape) != 3:
  60. raise Exception(
  61. "im should be 3-dimension, but now is {}-dimensions".
  62. format(len(im.shape)))
  63. else:
  64. try:
  65. im = cv2.imread(im).astype('float32')
  66. except:
  67. raise TypeError('Can\'t read The image file {}!'.format(im))
  68. im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
  69. if vdl_writer is not None:
  70. vdl_writer.add_image(tag='0. OriginalImange/' + str(step),
  71. img=im,
  72. step=0)
  73. op_id = 1
  74. for op in transforms:
  75. if isinstance(op, ClsTransform):
  76. if vdl_writer is not None and hasattr(op, 'prob'):
  77. op.prob = 1.0
  78. outputs = op(im, label)
  79. im = outputs[0]
  80. if len(outputs) == 2:
  81. label = outputs[1]
  82. if isinstance(op, pdx.cv.transforms.cls_transforms.Normalize):
  83. continue
  84. else:
  85. import imgaug.augmenters as iaa
  86. if isinstance(op, iaa.Augmenter):
  87. im = execute_imgaug(op, im)
  88. outputs = (im, )
  89. if label is not None:
  90. outputs = (im, label)
  91. if vdl_writer is not None:
  92. tag = str(op_id) + '. ' + op.__class__.__name__ + '/' + str(step)
  93. vdl_writer.add_image(tag=tag,
  94. img=im,
  95. step=0)
  96. op_id += 1
  97. def det_compose(im, im_info=None, label_info=None, transforms=None, vdl_writer=None, step=0,
  98. labels=[], catid2color=None):
  99. def decode_image(im_file, im_info, label_info):
  100. if im_info is None:
  101. im_info = dict()
  102. if isinstance(im_file, np.ndarray):
  103. if len(im_file.shape) != 3:
  104. raise Exception(
  105. "im should be 3-dimensions, but now is {}-dimensions".
  106. format(len(im_file.shape)))
  107. im = im_file
  108. else:
  109. try:
  110. im = cv2.imread(im_file).astype('float32')
  111. except:
  112. raise TypeError('Can\'t read The image file {}!'.format(
  113. im_file))
  114. im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
  115. # make default im_info with [h, w, 1]
  116. im_info['im_resize_info'] = np.array(
  117. [im.shape[0], im.shape[1], 1.], dtype=np.float32)
  118. im_info['image_shape'] = np.array([im.shape[0],
  119. im.shape[1]]).astype('int32')
  120. use_mixup = False
  121. for t in transforms:
  122. if type(t).__name__ == 'MixupImage':
  123. use_mixup = True
  124. if not use_mixup:
  125. if 'mixup' in im_info:
  126. del im_info['mixup']
  127. # decode mixup image
  128. if 'mixup' in im_info:
  129. im_info['mixup'] = \
  130. decode_image(im_info['mixup'][0],
  131. im_info['mixup'][1],
  132. im_info['mixup'][2])
  133. if label_info is None:
  134. return (im, im_info)
  135. else:
  136. return (im, im_info, label_info)
  137. outputs = decode_image(im, im_info, label_info)
  138. im = outputs[0]
  139. im_info = outputs[1]
  140. if len(outputs) == 3:
  141. label_info = outputs[2]
  142. if vdl_writer is not None:
  143. vdl_writer.add_image(tag='0. OriginalImange/' + str(step),
  144. img=im,
  145. step=0)
  146. op_id = 1
  147. bboxes = label_info['gt_bbox']
  148. transforms = [None] + transforms
  149. for op in transforms:
  150. if im is None:
  151. return None
  152. if isinstance(op, DetTransform) or op is None:
  153. if vdl_writer is not None and hasattr(op, 'prob'):
  154. op.prob = 1.0
  155. if op is not None:
  156. outputs = op(im, im_info, label_info)
  157. else:
  158. outputs = (im, im_info, label_info)
  159. im = outputs[0]
  160. vdl_im = im
  161. if vdl_writer is not None:
  162. if isinstance(op, pdx.cv.transforms.det_transforms.ResizeByShort):
  163. scale = outputs[1]['im_resize_info'][2]
  164. bboxes = bboxes * scale
  165. elif isinstance(op, pdx.cv.transforms.det_transforms.Resize):
  166. h = outputs[1]['image_shape'][0]
  167. w = outputs[1]['image_shape'][1]
  168. target_size = op.target_size
  169. if isinstance(target_size, int):
  170. h_scale = float(target_size) / h
  171. w_scale = float(target_size) / w
  172. else:
  173. h_scale = float(target_size[0]) / h
  174. w_scale = float(target_size[1]) / w
  175. bboxes[:,0] = bboxes[:,0] * w_scale
  176. bboxes[:,1] = bboxes[:,1] * h_scale
  177. bboxes[:,2] = bboxes[:,2] * w_scale
  178. bboxes[:,3] = bboxes[:,3] * h_scale
  179. else:
  180. bboxes = outputs[2]['gt_bbox']
  181. if not isinstance(op, pdx.cv.transforms.det_transforms.RandomHorizontalFlip):
  182. for i in range(bboxes.shape[0]):
  183. bbox = bboxes[i]
  184. cname = labels[outputs[2]['gt_class'][i][0]-1]
  185. vdl_im = _draw_rectangle_and_cname(vdl_im,
  186. int(bbox[0]),
  187. int(bbox[1]),
  188. int(bbox[2]),
  189. int(bbox[3]),
  190. cname,
  191. catid2color[outputs[2]['gt_class'][i][0]-1])
  192. if isinstance(op, pdx.cv.transforms.det_transforms.Normalize):
  193. continue
  194. else:
  195. im = execute_imgaug(op, im)
  196. if label_info is not None:
  197. outputs = (im, im_info, label_info)
  198. else:
  199. outputs = (im, im_info)
  200. vdl_im = im
  201. if vdl_writer is not None:
  202. tag = str(op_id) + '. ' + op.__class__.__name__ + '/' + str(step)
  203. if op is None:
  204. tag = str(op_id) + '. OriginalImangeWithGTBox/' + str(step)
  205. vdl_writer.add_image(tag=tag,
  206. img=vdl_im,
  207. step=0)
  208. op_id += 1
  209. def seg_compose(im, im_info=None, label=None, transforms=None, vdl_writer=None, step=0):
  210. if im_info is None:
  211. im_info = list()
  212. if isinstance(im, np.ndarray):
  213. if len(im.shape) != 3:
  214. raise Exception(
  215. "im should be 3-dimensions, but now is {}-dimensions".
  216. format(len(im.shape)))
  217. else:
  218. try:
  219. im = cv2.imread(im).astype('float32')
  220. except:
  221. raise ValueError('Can\'t read The image file {}!'.format(im))
  222. im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
  223. if label is not None:
  224. if not isinstance(label, np.ndarray):
  225. label = np.asarray(Image.open(label))
  226. if vdl_writer is not None:
  227. vdl_writer.add_image(tag='0. OriginalImange' + '/' + str(step),
  228. img=im,
  229. step=0)
  230. op_id = 1
  231. for op in transforms:
  232. if isinstance(op, SegTransform):
  233. outputs = op(im, im_info, label)
  234. im = outputs[0]
  235. if len(outputs) >= 2:
  236. im_info = outputs[1]
  237. if len(outputs) == 3:
  238. label = outputs[2]
  239. if isinstance(op, pdx.cv.transforms.seg_transforms.Normalize):
  240. continue
  241. else:
  242. im = execute_imgaug(op, im)
  243. if label is not None:
  244. outputs = (im, im_info, label)
  245. else:
  246. outputs = (im, im_info)
  247. if vdl_writer is not None:
  248. tag = str(op_id) + '. ' + op.__class__.__name__ + '/' + str(step)
  249. vdl_writer.add_image(tag=tag,
  250. img=im,
  251. step=0)
  252. op_id += 1
  253. def visualize(dataset, img_count=3, save_dir='vdl_output'):
  254. '''对数据预处理/增强中间结果进行可视化。
  255. 可使用VisualDL查看中间结果:
  256. 1. VisualDL启动方式: visualdl --logdir vdl_output --port 8001
  257. 2. 浏览器打开 https://0.0.0.0:8001即可,
  258. 其中0.0.0.0为本机访问,如为远程服务, 改成相应机器IP
  259. Args:
  260. dataset (paddlex.datasets): 数据集读取器。
  261. img_count (int): 需要进行数据预处理/增强的图像数目。默认为3。
  262. save_dir (str): 日志保存的路径。默认为'vdl_output'。
  263. '''
  264. if dataset.num_samples < img_count:
  265. img_count = dataset.num_samples
  266. transforms = dataset.transforms
  267. if not osp.isdir(save_dir):
  268. if osp.exists(save_dir):
  269. os.remove(save_dir)
  270. os.makedirs(save_dir)
  271. from visualdl import LogWriter
  272. vdl_save_dir = osp.join(save_dir, 'image_transforms')
  273. vdl_writer = LogWriter(vdl_save_dir)
  274. for i, data in enumerate(dataset.iterator()):
  275. if i == img_count:
  276. break
  277. data.append(transforms.transforms)
  278. data.append(vdl_writer)
  279. data.append(i)
  280. if isinstance(transforms, ClsTransform):
  281. cls_compose(*data)
  282. elif isinstance(transforms, DetTransform):
  283. labels = dataset.labels
  284. color_map = get_color_map_list(len(labels) + 1)
  285. catid2color = {}
  286. for catid in range(len(labels)):
  287. catid2color[catid] = color_map[catid + 1]
  288. data.append(labels)
  289. data.append(catid2color)
  290. det_compose(*data)
  291. elif isinstance(transforms, SegTransform):
  292. seg_compose(*data)
  293. else:
  294. raise Exception('The transform must the subclass of \
  295. ClsTransform or DetTransform or SegTransform!')