Beispiel #1
0
def convert_image_dtype(
    image,
    dtype,
    saturate=False,
    name=None,
):

    image = ops.convert_to_tensor(image, name='image')
    if dtype == image.dtype:
        return array_ops.identity(image, name=name)

    with ops.name_scope(name, 'convert_image', [image]) as name:
        if image.dtype.is_integer and dtype.is_integer:
            scale_in = image.dtype.max
            scale_out = dtype.max
            if scale_in > scale_out:
                scale = (scale_in + 1) // (scale_out + 1)
                scaled = math_ops.div(image, scale)
                if saturate:
                    return math_ops.saturate_cast(scaled, dtype, name=name)
                else:
                    return math_ops.cast(scaled, dtype, name=name)
            else:
                if saturate:
                    cast = math_ops.saturate_cast(image, dtype)
                else:
                    cast = math_ops.cast(image, dtype)
                scale = (scale_out + 1) // (scale_in + 1)
                return math_ops.multiply(cast, scale, name=name)
        elif image.dtype.is_floating and dtype.is_floating:
            return math_ops.cast(image, dtype, name=name)
        else:
            if image.dtype.is_integer:
                cast = math_ops.cast(image, dtype)
                scale = 1. / image.dtype.max
                return math_ops.multiply(cast, scale, name=name)
            else:
                scale = dtype.max + 0.5  # avoid rounding problems in the cast
                scaled = math_ops.multiply(image, scale)
                if saturate:
                    return math_ops.saturate_cast(scaled, dtype, name=name)
                else:
                    return math_ops.cast(scaled, dtype, name=name)
Beispiel #2
0
 def testSaturate(self):
     in_types = dtypes.float32,
     out_types = dtypes.int8, dtypes.uint8, dtypes.int16, dtypes.float32
     for in_type in in_types:
         for out_type in out_types:
             lo, hi = in_type.min, in_type.max
             x = constant_op.constant(
                 [lo, lo + 1, lo // 2, hi // 2, hi - 1, hi], dtype=in_type)
             y = math_ops.saturate_cast(x, dtype=out_type)
             self.assertEqual(y.dtype, out_type)
             x, y = self.evaluate([x, y])
             correct = np.maximum(out_type.min, np.minimum(out_type.max, x))
             self.assertAllEqual(correct, y)
Beispiel #3
0
 def testSaturate(self):
   in_types = dtypes.float32,
   out_types = dtypes.int8, dtypes.uint8, dtypes.int16, dtypes.float32
   with self.cached_session() as sess:
     for in_type in in_types:
       for out_type in out_types:
         lo, hi = in_type.min, in_type.max
         x = constant_op.constant(
             [lo, lo + 1, lo // 2, hi // 2, hi - 1, hi], dtype=in_type)
         y = math_ops.saturate_cast(x, dtype=out_type)
         self.assertEqual(y.dtype, out_type)
         x, y = sess.run([x, y])
         correct = np.maximum(out_type.min, np.minimum(out_type.max, x))
         self.assertAllEqual(correct, y)
Beispiel #4
0
def convert_image_dtype(image, dtype, saturate=False, name=None):
  """Convert `image` to `dtype`, scaling its values if needed.

  Images that are represented using floating point values are expected to have
  values in the range [0,1). Image data stored in integer data types are
  expected to have values in the range `[0,MAX]`, where `MAX` is the largest
  positive representable number for the data type.

  This op converts between data types, scaling the values appropriately before
  casting.

  Note that converting from floating point inputs to integer types may lead to
  over/underflow problems. Set saturate to `True` to avoid such problem in
  problematic conversions. If enabled, saturation will clip the output into the
  allowed range before performing a potentially dangerous cast (and only before
  performing such a cast, i.e., when casting from a floating point to an integer
  type, and when casting from a signed to an unsigned type; `saturate` has no
  effect on casts between floats, or on casts that increase the type's range).

  Args:
    image: An image.
    dtype: A `DType` to convert `image` to.
    saturate: If `True`, clip the input before casting (if necessary).
    name: A name for this operation (optional).

  Returns:
    `image`, converted to `dtype`.
  """
  image = ops.convert_to_tensor(image, name='image')
  if dtype == image.dtype:
    return array_ops.identity(image, name=name)

  with ops.op_scope([image], name, 'convert_image') as name:
    # Both integer: use integer multiplication in the larger range
    if image.dtype.is_integer and dtype.is_integer:
      scale_in = image.dtype.max
      scale_out = dtype.max
      if scale_in > scale_out:
        # Scaling down, scale first, then cast. The scaling factor will
        # cause in.max to be mapped to above out.max but below out.max+1,
        # so that the output is safely in the supported range.
        scale = (scale_in + 1) // (scale_out + 1)
        scaled = math_ops.div(image, scale)

        if saturate:
          return math_ops.saturate_cast(scaled, dtype, name=name)
        else:
          return math_ops.cast(scaled, dtype, name=name)
      else:
        # Scaling up, cast first, then scale. The scale will not map in.max to
        # out.max, but converting back and forth should result in no change.
        if saturate:
          cast = math_ops.saturate_cast(scaled, dtype)
        else:
          cast = math_ops.cast(image, dtype)
        scale = (scale_out + 1) // (scale_in + 1)
        return math_ops.mul(cast, scale, name=name)
    elif image.dtype.is_floating and dtype.is_floating:
      # Both float: Just cast, no possible overflows in the allowed ranges.
      # Note: We're ignoreing float overflows. If your image dynamic range
      # exceeds float range you're on your own.
      return math_ops.cast(image, dtype, name=name)
    else:
      if image.dtype.is_integer:
        # Converting to float: first cast, then scale. No saturation possible.
        cast = math_ops.cast(image, dtype)
        scale = 1. / image.dtype.max
        return math_ops.mul(cast, scale, name=name)
      else:
        # Converting from float: first scale, then cast
        scale = dtype.max + 0.5  # avoid rounding problems in the cast
        scaled = math_ops.mul(image, scale)
        if saturate:
          return math_ops.saturate_cast(scaled, dtype, name=name)
        else:
          return math_ops.cast(scaled, dtype, name=name)
Beispiel #5
0
def convert_image_dtype(image, dtype, saturate=False, name=None):
    """Convert `image` to `dtype`, scaling its values if needed.

  Images that are represented using floating point values are expected to have
  values in the range [0,1). Image data stored in integer data types are
  expected to have values in the range `[0,MAX]`, where `MAX` is the largest
  positive representable number for the data type.

  This op converts between data types, scaling the values appropriately before
  casting.

  Note that converting from floating point inputs to integer types may lead to
  over/underflow problems. Set saturate to `True` to avoid such problem in
  problematic conversions. If enabled, saturation will clip the output into the
  allowed range before performing a potentially dangerous cast (and only before
  performing such a cast, i.e., when casting from a floating point to an integer
  type, and when casting from a signed to an unsigned type; `saturate` has no
  effect on casts between floats, or on casts that increase the type's range).

  Args:
    image: An image.
    dtype: A `DType` to convert `image` to.
    saturate: If `True`, clip the input before casting (if necessary).
    name: A name for this operation (optional).

  Returns:
    `image`, converted to `dtype`.
  """
    image = ops.convert_to_tensor(image, name='image')
    if dtype == image.dtype:
        return array_ops.identity(image, name=name)

    with ops.op_scope([image], name, 'convert_image') as name:
        # Both integer: use integer multiplication in the larger range
        if image.dtype.is_integer and dtype.is_integer:
            scale_in = image.dtype.max
            scale_out = dtype.max
            if scale_in > scale_out:
                # Scaling down, scale first, then cast. The scaling factor will
                # cause in.max to be mapped to above out.max but below out.max+1,
                # so that the output is safely in the supported range.
                scale = (scale_in + 1) // (scale_out + 1)
                scaled = math_ops.div(image, scale)

                if saturate:
                    return math_ops.saturate_cast(scaled, dtype, name=name)
                else:
                    return math_ops.cast(scaled, dtype, name=name)
            else:
                # Scaling up, cast first, then scale. The scale will not map in.max to
                # out.max, but converting back and forth should result in no change.
                if saturate:
                    cast = math_ops.saturate_cast(scaled, dtype)
                else:
                    cast = math_ops.cast(image, dtype)
                scale = (scale_out + 1) // (scale_in + 1)
                return math_ops.mul(cast, scale, name=name)
        elif image.dtype.is_floating and dtype.is_floating:
            # Both float: Just cast, no possible overflows in the allowed ranges.
            # Note: We're ignoreing float overflows. If your image dynamic range
            # exceeds float range you're on your own.
            return math_ops.cast(image, dtype, name=name)
        else:
            if image.dtype.is_integer:
                # Converting to float: first cast, then scale. No saturation possible.
                cast = math_ops.cast(image, dtype)
                scale = 1. / image.dtype.max
                return math_ops.mul(cast, scale, name=name)
            else:
                # Converting from float: first scale, then cast
                scale = dtype.max + 0.5  # avoid rounding problems in the cast
                scaled = math_ops.mul(image, scale)
                if saturate:
                    return math_ops.saturate_cast(scaled, dtype, name=name)
                else:
                    return math_ops.cast(scaled, dtype, name=name)