You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

image_ops.py 6.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. # Copyright 2020 Huawei Technologies Co., Ltd
  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. """image_ops"""
  16. from ..._checkparam import Validator as validator
  17. from ..._checkparam import Rel
  18. from ...common import dtype as mstype
  19. from ..primitive import PrimitiveWithInfer, prim_attr_register
  20. class CropAndResize(PrimitiveWithInfer):
  21. """
  22. Extracts crops from the input image tensor and resizes them.
  23. Note:
  24. In case that the output shape depends on crop_size, the crop_size should be constant.
  25. Args:
  26. method (str): An optional string specifying the sampling method for resizing.
  27. It can be either "bilinear" or "nearest" and default to "bilinear"
  28. extrapolation_value (float): An optional float defaults to 0. Value used for extrapolation, when applicable.
  29. Inputs:
  30. - **x** (Tensor) - The input image must be a 4-D tensor of shape [batch, image_height, image_width, depth].
  31. Types allowed: int8, int16, int32, int64, float16, float32, float64, uint8, uint16.
  32. - **boxes** (Tensor) - A 2-D tensor of shape [num_boxes, 4].
  33. The i-th row of the tensor specifies the coordinates of a box in the box_ind[i] image
  34. and is specified in normalized coordinates [y1, x1, y2, x2]. A normalized coordinate value of y is mapped to
  35. the image coordinate at y * (image_height - 1), so as the [0, 1] interval of normalized image height is
  36. mapped to [0, image_height - 1] in image height coordinates. We do allow y1 > y2, in which case the sampled
  37. crop is an up-down flipped version of the original image. The width dimension is treated similarly.
  38. Normalized coordinates outside the [0, 1] range are allowed, in which case we use extrapolation_value to
  39. extrapolate the input image values. Types allowd: float32.
  40. - **box_index** (Tensor) - A 1-D tensor of shape [num_boxes] with int32 values in [0, batch).
  41. The value of box_ind[i] specifies the image that the i-th box refers to. Types allowd: int32.
  42. - **crop_size** (Tensor) - Only constant value is allowd. Types allowed: int32.
  43. A 1-D tensor of 2 elements, size = [crop_height, crop_width].
  44. All cropped image patches are resized to this size. The aspect ratio of the image content is not preserved.
  45. Both crop_height and crop_width need to be positive.
  46. Outputs:
  47. A 4-D tensor of shape [num_boxes, crop_height, crop_width, depth] with type: float32.
  48. Examples:
  49. >>> class CropAndResizeNet(nn.Cell):
  50. >>> def __init__(self, crop_size):
  51. >>> super(CropAndResizeNet, self).__init__()
  52. >>> self.crop_and_resize = P.CropAndResize()
  53. >>> self.crop_size = crop_size
  54. >>> @ms_function
  55. >>> def construct(self, x, boxes, box_index):
  56. >>> return self.crop_and_resize(x, boxes, box_index, self.crop_size)
  57. >>>
  58. >>> BATCH_SIZE = 1
  59. >>> NUM_BOXES = 5
  60. >>> IMAGE_HEIGHT = 256
  61. >>> IMAGE_WIDTH = 256
  62. >>> CHANNELS = 3
  63. >>> image = np.random.normal(size=[BATCH_SIZE, IMAGE_HEIGHT, IMAGE_WIDTH, CHANNELS]).astype(np.float32)
  64. >>> boxes = np.random.uniform(shape=[NUM_BOXES, 4]).astype(np.float32)
  65. >>> box_index = np.random.uniform(shape=[NUM_BOXES], low=0, high=BATCH_SIZE).astype(np.int32)
  66. >>> crop_size = np.array([24, 24]).astype(np.int32)
  67. >>> crop_and_resize = CropAndResizeNet(crop_size=Tensor(crop_size))
  68. >>> output = crop_and_resize(Tensor(image), Tensor(boxes), Tensor(box_index))
  69. >>> print(output.asnumpy())
  70. """
  71. @prim_attr_register
  72. def __init__(self, method="bilinear", extrapolation_value=0.0):
  73. """init CropAndResize"""
  74. self.init_prim_io_names(inputs=['x', 'boxes', 'box_index', 'crop_size'], outputs=['y'])
  75. validator.check_value_type("method", method, [str], self.name)
  76. validator.check_string("method", method, ["bilinear", "nearest"], self.name)
  77. self.method = method
  78. validator.check_value_type("extrapolation_value", extrapolation_value, [float], self.name)
  79. self.extrapolation_value = extrapolation_value
  80. def __infer__(self, x, boxes, box_index, crop_size):
  81. # get shape
  82. x_shape = list(x['shape'])
  83. boxes_shape = list(boxes['shape'])
  84. box_index_shape = list(box_index['shape'])
  85. crop_size_shape = list(crop_size['shape'])
  86. # get value
  87. if crop_size['value'] is None:
  88. raise ValueError(f"For {self.name}, crop_size must be const.")
  89. crop_size_value = crop_size['value'].asnumpy()
  90. # get dtype
  91. x_dtype = x['dtype']
  92. boxes_dtype = boxes['dtype']
  93. box_index_dtype = box_index['dtype']
  94. crop_size_dtype = crop_size['dtype']
  95. # check dytpe
  96. validator.check_tensor_type_same({"x": x_dtype},
  97. [mstype.int8, mstype.int16, mstype.int32, mstype.int64, mstype.float16,
  98. mstype.float32, mstype.float64, mstype.uint8, mstype.uint16], self.name)
  99. validator.check_tensor_type_same({"boxes": boxes_dtype}, [mstype.float32], self.name)
  100. validator.check_tensor_type_same({"box_index": box_index_dtype}, [mstype.int32], self.name)
  101. validator.check_tensor_type_same({"crop_size": crop_size_dtype}, [mstype.int32], self.name)
  102. # check input shape rank
  103. validator.check("x rank", len(x_shape), "expected", 4, Rel.EQ, self.name)
  104. validator.check("boxes rank", len(boxes_shape), "expected", 2, Rel.EQ, self.name)
  105. validator.check("box_index rank", len(box_index_shape), "expected", 1, Rel.EQ, self.name)
  106. validator.check("crop_size rank", len(crop_size_shape), "expected", 1, Rel.EQ, self.name)
  107. validator.check("boxes dim_0", boxes_shape[0], "box_index dim_0", box_index_shape[0], Rel.EQ, self.name)
  108. validator.check("boxes dim_1", boxes_shape[1], "expected", 4, Rel.EQ, self.name)
  109. num_boxes = boxes_shape[0]
  110. crop_height = crop_size_value[0]
  111. crop_width = crop_size_value[1]
  112. depth = x_shape[3]
  113. return {'shape': (num_boxes, crop_height, crop_width, depth),
  114. 'dtype': mstype.float32,
  115. 'value': None}