|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Builder function for image resizing operations.""" |
|
import functools |
|
import tensorflow as tf |
|
|
|
from object_detection.core import preprocessor |
|
from object_detection.protos import image_resizer_pb2 |
|
|
|
|
|
def _tf_resize_method(resize_method): |
|
"""Maps image resize method from enumeration type to TensorFlow. |
|
|
|
Args: |
|
resize_method: The resize_method attribute of keep_aspect_ratio_resizer or |
|
fixed_shape_resizer. |
|
|
|
Returns: |
|
method: The corresponding TensorFlow ResizeMethod. |
|
|
|
Raises: |
|
ValueError: if `resize_method` is of unknown type. |
|
""" |
|
dict_method = { |
|
image_resizer_pb2.BILINEAR: |
|
tf.image.ResizeMethod.BILINEAR, |
|
image_resizer_pb2.NEAREST_NEIGHBOR: |
|
tf.image.ResizeMethod.NEAREST_NEIGHBOR, |
|
image_resizer_pb2.BICUBIC: |
|
tf.image.ResizeMethod.BICUBIC, |
|
image_resizer_pb2.AREA: |
|
tf.image.ResizeMethod.AREA |
|
} |
|
if resize_method in dict_method: |
|
return dict_method[resize_method] |
|
else: |
|
raise ValueError('Unknown resize_method') |
|
|
|
|
|
def build(image_resizer_config): |
|
"""Builds callable for image resizing operations. |
|
|
|
Args: |
|
image_resizer_config: image_resizer.proto object containing parameters for |
|
an image resizing operation. |
|
|
|
Returns: |
|
image_resizer_fn: Callable for image resizing. This callable always takes |
|
a rank-3 image tensor (corresponding to a single image) and returns a |
|
rank-3 image tensor, possibly with new spatial dimensions. |
|
|
|
Raises: |
|
ValueError: if `image_resizer_config` is of incorrect type. |
|
ValueError: if `image_resizer_config.image_resizer_oneof` is of expected |
|
type. |
|
ValueError: if min_dimension > max_dimension when keep_aspect_ratio_resizer |
|
is used. |
|
""" |
|
if not isinstance(image_resizer_config, image_resizer_pb2.ImageResizer): |
|
raise ValueError('image_resizer_config not of type ' |
|
'image_resizer_pb2.ImageResizer.') |
|
|
|
image_resizer_oneof = image_resizer_config.WhichOneof('image_resizer_oneof') |
|
if image_resizer_oneof == 'keep_aspect_ratio_resizer': |
|
keep_aspect_ratio_config = image_resizer_config.keep_aspect_ratio_resizer |
|
if not (keep_aspect_ratio_config.min_dimension <= |
|
keep_aspect_ratio_config.max_dimension): |
|
raise ValueError('min_dimension > max_dimension') |
|
method = _tf_resize_method(keep_aspect_ratio_config.resize_method) |
|
per_channel_pad_value = (0, 0, 0) |
|
if keep_aspect_ratio_config.per_channel_pad_value: |
|
per_channel_pad_value = tuple(keep_aspect_ratio_config. |
|
per_channel_pad_value) |
|
image_resizer_fn = functools.partial( |
|
preprocessor.resize_to_range, |
|
min_dimension=keep_aspect_ratio_config.min_dimension, |
|
max_dimension=keep_aspect_ratio_config.max_dimension, |
|
method=method, |
|
pad_to_max_dimension=keep_aspect_ratio_config.pad_to_max_dimension, |
|
per_channel_pad_value=per_channel_pad_value) |
|
if not keep_aspect_ratio_config.convert_to_grayscale: |
|
return image_resizer_fn |
|
elif image_resizer_oneof == 'fixed_shape_resizer': |
|
fixed_shape_resizer_config = image_resizer_config.fixed_shape_resizer |
|
method = _tf_resize_method(fixed_shape_resizer_config.resize_method) |
|
image_resizer_fn = functools.partial( |
|
preprocessor.resize_image, |
|
new_height=fixed_shape_resizer_config.height, |
|
new_width=fixed_shape_resizer_config.width, |
|
method=method) |
|
if not fixed_shape_resizer_config.convert_to_grayscale: |
|
return image_resizer_fn |
|
elif image_resizer_oneof == 'identity_resizer': |
|
def image_resizer_fn(image, masks=None, **kwargs): |
|
del kwargs |
|
if masks is None: |
|
return [image, tf.shape(image)] |
|
else: |
|
return [image, masks, tf.shape(image)] |
|
return image_resizer_fn |
|
else: |
|
raise ValueError( |
|
'Invalid image resizer option: \'%s\'.' % image_resizer_oneof) |
|
|
|
def grayscale_image_resizer(image, masks=None): |
|
"""Convert to grayscale before applying image_resizer_fn. |
|
|
|
Args: |
|
image: A 3D tensor of shape [height, width, 3] |
|
masks: (optional) rank 3 float32 tensor with shape [num_instances, height, |
|
width] containing instance masks. |
|
|
|
Returns: |
|
Note that the position of the resized_image_shape changes based on whether |
|
masks are present. |
|
resized_image: A 3D tensor of shape [new_height, new_width, 1], |
|
where the image has been resized (with bilinear interpolation) so that |
|
min(new_height, new_width) == min_dimension or |
|
max(new_height, new_width) == max_dimension. |
|
resized_masks: If masks is not None, also outputs masks. A 3D tensor of |
|
shape [num_instances, new_height, new_width]. |
|
resized_image_shape: A 1D tensor of shape [3] containing shape of the |
|
resized image. |
|
""" |
|
|
|
|
|
|
|
|
|
retval = image_resizer_fn(image, masks) |
|
resized_image = retval[0] |
|
resized_image_shape = retval[-1] |
|
retval[0] = preprocessor.rgb_to_gray(resized_image) |
|
retval[-1] = tf.concat([resized_image_shape[:-1], [1]], 0) |
|
return retval |
|
|
|
return functools.partial(grayscale_image_resizer) |
|
|