det_transforms.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
  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. """
  15. function:
  16. transforms for detection in PaddleX<2.0
  17. """
  18. import numpy as np
  19. from .operators import Transform, Compose, ResizeByShort, Resize, RandomHorizontalFlip, Normalize
  20. from .operators import RandomExpand as dy_RandomExpand
  21. from .operators import RandomCrop as dy_RandomCrop
  22. from .functions import is_poly, expand_poly, expand_rle
  23. class Padding(Transform):
  24. """1.将图像的长和宽padding至coarsest_stride的倍数。如输入图像为[300, 640],
  25. `coarest_stride`为32,则由于300不为32的倍数,因此在图像最右和最下使用0值
  26. 进行padding,最终输出图像为[320, 640]。
  27. 2.或者,将图像的长和宽padding到target_size指定的shape,如输入的图像为[300,640],
  28. a. `target_size` = 960,在图像最右和最下使用0值进行padding,最终输出
  29. 图像为[960, 960]。
  30. b. `target_size` = [640, 960],在图像最右和最下使用0值进行padding,最终
  31. 输出图像为[640, 960]。
  32. 1. 如果coarsest_stride为1,target_size为None则直接返回。
  33. 2. 获取图像的高H、宽W。
  34. 3. 计算填充后图像的高H_new、宽W_new。
  35. 4. 构建大小为(H_new, W_new, 3)像素值为0的np.ndarray,
  36. 并将原图的np.ndarray粘贴于左上角。
  37. Args:
  38. coarsest_stride (int): 填充后的图像长、宽为该参数的倍数,默认为1。
  39. target_size (int|list|tuple): 填充后的图像长、宽,默认为None,coarset_stride优先级更高。
  40. Raises:
  41. TypeError: 形参`target_size`数据类型不满足需求。
  42. ValueError: 形参`target_size`为(list|tuple)时,长度不满足需求。
  43. """
  44. def __init__(self, coarsest_stride=1, target_size=None):
  45. if target_size is not None:
  46. if not isinstance(target_size, int):
  47. if not isinstance(target_size, tuple) and not isinstance(
  48. target_size, list):
  49. raise TypeError(
  50. "Padding: Type of target_size must in (int|list|tuple)."
  51. )
  52. elif len(target_size) != 2:
  53. raise ValueError(
  54. "Padding: Length of target_size must equal 2.")
  55. super(Padding, self).__init__()
  56. self.coarsest_stride = coarsest_stride
  57. self.target_size = target_size
  58. def apply_im(self, image, padding_im_h, padding_im_w):
  59. im_h, im_w, im_c = image.shape
  60. padding_im = np.zeros(
  61. (padding_im_h, padding_im_w, im_c), dtype=np.float32)
  62. padding_im[:im_h, :im_w, :] = image
  63. return padding_im
  64. def apply_bbox(self, bbox):
  65. return bbox
  66. def apply_segm(self, segms, im_h, im_w, padding_im_h, padding_im_w):
  67. expanded_segms = []
  68. for segm in segms:
  69. if is_poly(segm):
  70. # Polygon format
  71. expanded_segms.append(
  72. [expand_poly(poly, 0, 0) for poly in segm])
  73. else:
  74. # RLE format
  75. expanded_segms.append(
  76. expand_rle(segm, 0, 0, im_h, im_w, padding_im_h,
  77. padding_im_w))
  78. return expanded_segms
  79. def apply(self, sample):
  80. im_h, im_w, im_c = sample['image'].shape[:]
  81. if isinstance(self.target_size, int):
  82. padding_im_h = self.target_size
  83. padding_im_w = self.target_size
  84. elif isinstance(self.target_size, list) or isinstance(self.target_size,
  85. tuple):
  86. padding_im_w = self.target_size[0]
  87. padding_im_h = self.target_size[1]
  88. elif self.coarsest_stride > 0:
  89. padding_im_h = int(
  90. np.ceil(im_h / self.coarsest_stride) * self.coarsest_stride)
  91. padding_im_w = int(
  92. np.ceil(im_w / self.coarsest_stride) * self.coarsest_stride)
  93. else:
  94. raise ValueError(
  95. "coarsest_stridei(>1) or target_size(list|int) need setting in Padding transform"
  96. )
  97. pad_height = padding_im_h - im_h
  98. pad_width = padding_im_w - im_w
  99. if pad_height < 0 or pad_width < 0:
  100. raise ValueError(
  101. 'the size of image should be less than target_size, but the size of image ({}, {}), is larger than target_size ({}, {})'
  102. .format(im_w, im_h, padding_im_w, padding_im_h))
  103. sample['image'] = self.apply_im(sample['image'], padding_im_h,
  104. padding_im_w)
  105. if 'gt_bbox' in sample and len(sample['gt_bbox']) > 0:
  106. sample['gt_bbox'] = self.apply_bbox(sample['gt_bbox'])
  107. if 'gt_poly' in sample and len(sample['gt_poly']) > 0:
  108. sample['gt_poly'] = self.apply_segm(sample['gt_poly'], im_h, im_w,
  109. padding_im_h, padding_im_w)
  110. return sample
  111. class RandomExpand(dy_RandomExpand):
  112. def __init__(self,
  113. ratio=4.,
  114. prob=0.5,
  115. fill_value=[123.675, 116.28, 103.53]):
  116. super(RandomExpand, self).__init__(
  117. upper_ratio=ratio, prob=prob, im_padding_value=fill_value)
  118. class RandomCrop(dy_RandomCrop):
  119. def __init__(self,
  120. aspect_ratio=[.5, 2.],
  121. thresholds=[.0, .1, .3, .5, .7, .9],
  122. scaling=[.3, 1.],
  123. num_attempts=50,
  124. allow_no_crop=True,
  125. cover_all_box=False):
  126. super(RandomCrop, self).__init__(
  127. crop_size=None,
  128. aspect_ratio=aspect_ratio,
  129. thresholds=thresholds,
  130. scaling=scaling,
  131. num_attempts=num_attempts,
  132. allow_no_crop=allow_no_crop,
  133. cover_all_box=cover_all_box)