Пример #1
0
def increase_itemsize_of_dtype(dtype, factor):
    dtype = normalize_dtype(dtype)

    assert ia.is_single_integer(factor), (
        "Expected 'factor' to be an integer, got type %s instead." %
        (type(factor), ))
    # int8 -> int64 = factor 8
    # uint8 -> uint64 = factor 8
    # float16 -> float128 = factor 8
    assert factor in [
        1, 2, 4, 8
    ], ("The itemsize may only be increased any of the following factors: "
        "1, 2, 4 or 8. Got factor %d." % (factor, ))
    assert dtype.kind != "b", "Cannot increase the itemsize of boolean."

    dt_high_name = "%s%d" % (dtype.kind, dtype.itemsize * factor)

    try:
        dt_high = np.dtype(dt_high_name)
        return dt_high
    except TypeError:
        raise TypeError(
            "Unable to create a numpy dtype matching the name '%s'. "
            "This error was caused when trying to find a dtype "
            "that increases the itemsize of dtype '%s' by a factor of %d."
            "This error can be avoided by choosing arrays with lower "
            "resolution dtypes as inputs, e.g. by reducing "
            "float32 to float16." % (dt_high_name, dtype.name, factor))
Пример #2
0
def clip_to_dtype_value_range_(array,
                               dtype,
                               validate=True,
                               validate_values=None):
    dtype = normalize_dtype(dtype)
    min_value, _, max_value = get_value_range_of_dtype(dtype)
    if validate:
        array_val = array
        if ia.is_single_integer(validate):
            assert validate >= 1, (
                "If 'validate' is an integer, it must have a value >=1, "
                "got %d instead." % (validate, ))
            assert validate_values is None, (
                "If 'validate' is an integer, 'validate_values' must be "
                "None. Got type %s instead." % (type(validate_values), ))
            array_val = array.flat[0:validate]
        if validate_values is not None:
            min_value_found, max_value_found = validate_values
        else:
            min_value_found = np.min(array_val)
            max_value_found = np.max(array_val)
        assert min_value <= min_value_found <= max_value, (
            "Minimum value of array is outside of allowed value range (%.4f "
            "vs %.4f to %.4f)." % (min_value_found, min_value, max_value))
        assert min_value <= max_value_found <= max_value, (
            "Maximum value of array is outside of allowed value range (%.4f "
            "vs %.4f to %.4f)." % (max_value_found, min_value, max_value))

    return clip_(array, min_value, max_value)
Пример #3
0
    def __init__(self, a, b):
        StochasticParameter.__init__(self)

        # for two ints the samples will be from range a <= x <= b
        assert isinstance(a, (int, StochasticParameter)), "Expected a to be int or StochasticParameter, got %s" % (type(a),)
        assert isinstance(b, (int, StochasticParameter)), "Expected b to be int or StochasticParameter, got %s" % (type(b),)

        if ia.is_single_integer(a):
            self.a = Deterministic(a)
        else:
            self.a = a

        if ia.is_single_integer(b):
            self.b = Deterministic(b)
        else:
            self.b = b
Пример #4
0
def clip_to_dtype_value_range_(array,
                               dtype,
                               validate=True,
                               validate_values=None):
    dtype = normalize_dtype(dtype)
    min_value, _, max_value = get_value_range_of_dtype(dtype)
    if validate:
        array_val = array
        if ia.is_single_integer(validate):
            assert validate >= 1
            assert validate_values is None
            array_val = array.flat[0:validate]
        if validate_values is not None:
            min_value_found, max_value_found = validate_values
        else:
            min_value_found = np.min(array_val)
            max_value_found = np.max(array_val)
        assert min_value <= min_value_found <= max_value, (
            "Minimum value of array is outside of allowed value range (%.4f "
            "vs %.4f to %.4f)." % (min_value_found, min_value, max_value))
        assert min_value <= max_value_found <= max_value, (
            "Maximum value of array is outside of allowed value range (%.4f "
            "vs %.4f to %.4f)." % (max_value_found, min_value, max_value))

    return clip_(array, min_value, max_value)
Пример #5
0
    def __init__(self, a, b):
        StochasticParameter.__init__(self)

        # for two ints the samples will be from range a <= x <= b
        assert isinstance(
            a, (int, StochasticParameter)
        ), "Expected a to be int or StochasticParameter, got %s" % (type(a), )
        assert isinstance(
            b, (int, StochasticParameter)
        ), "Expected b to be int or StochasticParameter, got %s" % (type(b), )

        if ia.is_single_integer(a):
            self.a = Deterministic(a)
        else:
            self.a = a

        if ia.is_single_integer(b):
            self.b = Deterministic(b)
        else:
            self.b = b
Пример #6
0
def increase_array_resolutions_(arrays, factor):
    assert ia.is_single_integer(factor)
    assert factor in [1, 2, 4, 8]
    if factor == 1:
        return arrays

    for i, array in enumerate(arrays):
        dtype = array.dtype
        dtype_target = np.dtype("%s%d" % (dtype.kind, dtype.itemsize * factor))
        arrays[i] = array.astype(dtype_target, copy=False)

    return arrays
Пример #7
0
    def __init__(self, k=1, name=None, deterministic=False, random_state=None):
        super(MedianBlur, self).__init__(name=name, deterministic=deterministic, random_state=random_state)

        # TODO replace this by iap.handle_discrete_kernel_size()
        self.k = iap.handle_discrete_param(k, "k", value_range=(1, None), tuple_to_uniform=True, list_to_choice=True,
                                           allow_floats=False)
        if ia.is_single_integer(k):
            ia.do_assert(k % 2 != 0, "Expected k to be odd, got %d. Add or subtract 1." % (int(k),))
        elif ia.is_iterable(k):
            ia.do_assert(all([ki % 2 != 0 for ki in k]),
                         "Expected all values in iterable k to be odd, but at least one was not. "
                         + "Add or subtract 1 to/from that value.")
Пример #8
0
def increase_array_resolutions_(arrays, factor):
    assert ia.is_single_integer(factor)
    assert factor in [1, 2, 4, 8]
    if factor == 1:
        return arrays

    for i, array in enumerate(arrays):
        dtype = array.dtype
        dtype_target = np.dtype("%s%d" % (dtype.kind, dtype.itemsize * factor))
        arrays[i] = array.astype(dtype_target, copy=False)

    return arrays
Пример #9
0
    def __init__(self, k=1, name=None, deterministic=False, random_state=None):
        super(MedianBlur, self).__init__(name=name, deterministic=deterministic, random_state=random_state)

        # TODO replace this by iap.handle_discrete_kernel_size()
        self.k = iap.handle_discrete_param(k, "k", value_range=(1, None), tuple_to_uniform=True, list_to_choice=True,
                                           allow_floats=False)
        if ia.is_single_integer(k):
            ia.do_assert(k % 2 != 0, "Expected k to be odd, got %d. Add or subtract 1." % (int(k),))
        elif ia.is_iterable(k):
            ia.do_assert(all([ki % 2 != 0 for ki in k]),
                         "Expected all values in iterable k to be odd, but at least one was not. "
                         + "Add or subtract 1 to/from that value.")
Пример #10
0
 def handle(val):
     if ia.is_single_integer(val):
         do_assert(val > 0)
         return (val, val)
     elif ia.is_single_float(val):
         do_assert(val > 0)
         return (val, val)
     elif isinstance(val, tuple):
         do_assert(len(val) == 2)
         do_assert(val[0] > 0 and val[1] > 0)
         return val
     else:
         raise Exception(
             "Expected size to be int, float or tuple, got %s." %
             type(size))
Пример #11
0
    def __init__(self, k=1, seed=None, name=None, **old_kwargs):
        super(MedianBlur, self).__init__(
            seed=seed, name=name, **old_kwargs)

        # TODO replace this by iap.handle_discrete_kernel_size()
        self.k = iap.handle_discrete_param(
            k, "k", value_range=(1, None), tuple_to_uniform=True,
            list_to_choice=True, allow_floats=False)
        if ia.is_single_integer(k):
            assert k % 2 != 0, (
                "Expected k to be odd, got %d. Add or subtract 1." % (
                    int(k),))
        elif ia.is_iterable(k):
            assert all([ki % 2 != 0 for ki in k]), (
                "Expected all values in iterable k to be odd, but at least "
                "one was not. Add or subtract 1 to/from that value.")
Пример #12
0
    def __init__(self,
                 size,
                 name=None,
                 deterministic=False,
                 random_state=None):
        super(FiveCrop, self).__init__(name=name,
                                       deterministic=deterministic,
                                       random_state=random_state)
        if ia.is_single_integer(size):
            self.size = (size, size)
        elif isinstance(size, (list, tuple)) and len(size) == 2 and isinstance(
                size[0], (int, long)) and isinstance(size[1], (int, long)):
            self.size = size
        else:
            raise ValueError('Invalid size parameter: %s' % str(size))

        self.choice = ia.parameters.DiscreteUniform(0, 4)
Пример #13
0
def clip_to_dtype_value_range_(array, dtype, validate=True, validate_values=None):
    # for some reason, using 'out' did not work for uint64 (would clip max value to 0)
    # but removing out then results in float64 array instead of uint64
    assert array.dtype.name not in ["uint64", "uint128"]

    dtype = np.dtype(dtype)
    min_value, _, max_value = get_value_range_of_dtype(dtype)
    if validate:
        array_val = array
        if ia.is_single_integer(validate):
            assert validate_values is None
            array_val = array.flat[0:validate]
        if validate_values is not None:
            min_value_found, max_value_found = validate_values
        else:
            min_value_found = np.min(array_val)
            max_value_found = np.max(array_val)
        assert min_value <= min_value_found <= max_value
        assert min_value <= max_value_found <= max_value

    return clip_(array, min_value, max_value)
Пример #14
0
def clip_to_dtype_value_range_(array,
                               dtype,
                               validate=True,
                               validate_values=None):
    # for some reason, using 'out' did not work for uint64 (would clip max value to 0)
    # but removing out then results in float64 array instead of uint64
    assert array.dtype.name not in ["uint64", "uint128"]

    dtype = np.dtype(dtype)
    min_value, _, max_value = get_value_range_of_dtype(dtype)
    if validate:
        array_val = array
        if ia.is_single_integer(validate):
            assert validate_values is None
            array_val = array.flat[0:validate]
        if validate_values is not None:
            min_value_found, max_value_found = validate_values
        else:
            min_value_found = np.min(array_val)
            max_value_found = np.max(array_val)
        assert min_value <= min_value_found <= max_value
        assert min_value <= max_value_found <= max_value
    array = np.clip(array, min_value, max_value, out=array)
    return array
Пример #15
0
def blur_gaussian_(image, sigma, ksize=None, backend="auto", eps=1e-3):
    """Blur an image using gaussian blurring in-place.

    This operation *may* change the input image in-place.

    dtype support::

        if (backend="auto")::

            * ``uint8``: yes; fully tested (1)
            * ``uint16``: yes; tested (1)
            * ``uint32``: yes; tested (2)
            * ``uint64``: yes; tested (2)
            * ``int8``: yes; tested (1)
            * ``int16``: yes; tested (1)
            * ``int32``: yes; tested (1)
            * ``int64``: yes; tested (2)
            * ``float16``: yes; tested (1)
            * ``float32``: yes; tested (1)
            * ``float64``: yes; tested (1)
            * ``float128``: no
            * ``bool``: yes; tested (1)

            - (1) Handled by ``cv2``. See ``backend="cv2"``.
            - (2) Handled by ``scipy``. See ``backend="scipy"``.

        if (backend="cv2")::

            * ``uint8``: yes; fully tested
            * ``uint16``: yes; tested
            * ``uint32``: no (2)
            * ``uint64``: no (3)
            * ``int8``: yes; tested (4)
            * ``int16``: yes; tested
            * ``int32``: yes; tested (5)
            * ``int64``: no (6)
            * ``float16``: yes; tested (7)
            * ``float32``: yes; tested
            * ``float64``: yes; tested
            * ``float128``: no (8)
            * ``bool``: yes; tested (1)

            - (1) Mapped internally to ``float32``. Otherwise causes
                  ``TypeError: src data type = 0 is not supported``.
            - (2) Causes ``TypeError: src data type = 6 is not supported``.
            - (3) Causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957:
                  error: (-213:The function/feature is not implemented)
                  Unsupported combination of source format (=4), and buffer
                  format (=5) in function 'getLinearRowFilter'``.
            - (4) Mapped internally to ``int16``. Otherwise causes
                  ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957: error:
                  (-213:The function/feature is not implemented) Unsupported
                  combination of source format (=1), and buffer format (=5)
                  in function 'getLinearRowFilter'``.
            - (5) Mapped internally to ``float64``. Otherwise causes
                  ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957: error:
                  (-213:The function/feature is not implemented) Unsupported
                  combination of source format (=4), and buffer format (=5)
                  in function 'getLinearRowFilter'``.
            - (6) Causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957:
                  error: (-213:The function/feature is not implemented)
                  Unsupported combination of source format (=4), and buffer
                  format (=5) in function 'getLinearRowFilter'``.
            - (7) Mapped internally to ``float32``. Otherwise causes
                  ``TypeError: src data type = 23 is not supported``.
            - (8) Causes ``TypeError: src data type = 13 is not supported``.

        if (backend="scipy")::

            * ``uint8``: yes; fully tested
            * ``uint16``: yes; tested
            * ``uint32``: yes; tested
            * ``uint64``: yes; tested
            * ``int8``: yes; tested
            * ``int16``: yes; tested
            * ``int32``: yes; tested
            * ``int64``: yes; tested
            * ``float16``: yes; tested (1)
            * ``float32``: yes; tested
            * ``float64``: yes; tested
            * ``float128``: no (2)
            * ``bool``: yes; tested (3)

            - (1) Mapped internally to ``float32``. Otherwise causes
                  ``RuntimeError: array type dtype('float16') not supported``.
            - (2) Causes ``RuntimeError: array type dtype('float128') not
                  supported``.
            - (3) Mapped internally to ``float32``. Otherwise too inaccurate.

    Parameters
    ----------
    image : numpy.ndarray
        The image to blur. Expected to be of shape ``(H, W)`` or ``(H, W, C)``.

    sigma : number
        Standard deviation of the gaussian blur. Larger numbers result in
        more large-scale blurring, which is overall slower than small-scale
        blurring.

    ksize : None or int, optional
        Size in height/width of the gaussian kernel. This argument is only
        understood by the ``cv2`` backend. If it is set to ``None``, an
        appropriate value for `ksize` will automatically be derived from
        `sigma`. The value is chosen tighter for larger sigmas to avoid as
        much as possible very large kernel sizes and therey improve
        performance.

    backend : {'auto', 'cv2', 'scipy'}, optional
        Backend library to use. If ``auto``, then the likely best library
        will be automatically picked per image. That is usually equivalent
        to ``cv2`` (OpenCV) and it will fall back to ``scipy`` for datatypes
        not supported by OpenCV.

    eps : number, optional
        A threshold used to decide whether `sigma` can be considered zero.

    Returns
    -------
    numpy.ndarray
        The blurred image. Same shape and dtype as the input.
        (Input image *might* have been altered in-place.)

    """
    has_zero_sized_axes = (image.size == 0)
    if sigma > 0 + eps and not has_zero_sized_axes:
        dtype = image.dtype

        iadt.gate_dtypes(image,
                         allowed=[
                             "bool", "uint8", "uint16", "uint32", "int8",
                             "int16", "int32", "int64", "uint64", "float16",
                             "float32", "float64"
                         ],
                         disallowed=[
                             "uint128", "uint256", "int128", "int256",
                             "float96", "float128", "float256"
                         ],
                         augmenter=None)

        dts_not_supported_by_cv2 = ["uint32", "uint64", "int64", "float128"]
        backend_to_use = backend
        if backend == "auto":
            backend_to_use = ("cv2" if image.dtype.name
                              not in dts_not_supported_by_cv2 else "scipy")
        elif backend == "cv2":
            assert image.dtype.name not in dts_not_supported_by_cv2, (
                "Requested 'cv2' backend, but provided %s input image, which "
                "cannot be handled by that backend. Choose a different "
                "backend or set backend to 'auto' or use a different "
                "datatype." % (image.dtype.name, ))
        elif backend == "scipy":
            # can handle all dtypes that were allowed in gate_dtypes()
            pass

        if backend_to_use == "scipy":
            if dtype.name == "bool":
                # We convert bool to float32 here, because gaussian_filter()
                # seems to only return True when the underlying value is
                # approximately 1.0, not when it is above 0.5. So we do that
                # here manually. cv2 does not support bool for gaussian blur.
                image = image.astype(np.float32, copy=False)
            elif dtype.name == "float16":
                image = image.astype(np.float32, copy=False)

            # gaussian_filter() has no ksize argument
            # TODO it does have a truncate argument that truncates at x
            #      standard deviations -- maybe can be used similarly to ksize
            if ksize is not None:
                ia.warn(
                    "Requested 'scipy' backend or picked it automatically by "
                    "backend='auto' n blur_gaussian_(), but also provided "
                    "'ksize' argument, which is not understood by that "
                    "backend and will be ignored.")

            # Note that while gaussian_filter can be applied to all channels
            # at the same time, that should not be done here, because then
            # the blurring would also happen across channels (e.g. red values
            # might be mixed with blue values in RGB)
            if image.ndim == 2:
                image[:, :] = ndimage.gaussian_filter(image[:, :],
                                                      sigma,
                                                      mode="mirror")
            else:
                nb_channels = image.shape[2]
                for channel in sm.xrange(nb_channels):
                    image[:, :,
                          channel] = ndimage.gaussian_filter(image[:, :,
                                                                   channel],
                                                             sigma,
                                                             mode="mirror")
        else:
            if dtype.name == "bool":
                image = image.astype(np.float32, copy=False)
            elif dtype.name == "float16":
                image = image.astype(np.float32, copy=False)
            elif dtype.name == "int8":
                image = image.astype(np.int16, copy=False)
            elif dtype.name == "int32":
                image = image.astype(np.float64, copy=False)

            # ksize here is derived from the equation to compute sigma based
            # on ksize, see
            # https://docs.opencv.org/3.1.0/d4/d86/group__imgproc__filter.html
            # -> cv::getGaussianKernel()
            # example values:
            #   sig = 0.1 -> ksize = -1.666
            #   sig = 0.5 -> ksize = 0.9999
            #   sig = 1.0 -> ksize = 1.0
            #   sig = 2.0 -> ksize = 11.0
            #   sig = 3.0 -> ksize = 17.666
            # ksize = ((sig - 0.8)/0.3 + 1)/0.5 + 1

            if ksize is None:
                ksize = _compute_gaussian_blur_ksize(sigma)
            else:
                assert ia.is_single_integer(ksize), (
                    "Expected 'ksize' argument to be a number, "
                    "got %s." % (type(ksize), ))

            ksize = ksize + 1 if ksize % 2 == 0 else ksize

            if ksize > 0:
                image_warped = cv2.GaussianBlur(
                    _normalize_cv2_input_arr_(image), (ksize, ksize),
                    sigmaX=sigma,
                    sigmaY=sigma,
                    borderType=cv2.BORDER_REFLECT_101)

                # re-add channel axis removed by cv2 if input was (H, W, 1)
                image = (image_warped[..., np.newaxis] if image.ndim == 3
                         and image_warped.ndim == 2 else image_warped)

        if dtype.name == "bool":
            image = image > 0.5
        elif dtype.name != image.dtype.name:
            image = iadt.restore_dtypes_(image, dtype)

    return image
Пример #16
0
def blur_gaussian_(image, sigma, ksize=None, backend="auto", eps=1e-3):
    """
    Blur an image using gaussian blurring.

    This operation might change the input image in-place.

    dtype support::

        if (backend="auto")::

            * ``uint8``: yes; fully tested (1)
            * ``uint16``: yes; tested (1)
            * ``uint32``: yes; tested (2)
            * ``uint64``: yes; tested (2)
            * ``int8``: yes; tested (1)
            * ``int16``: yes; tested (1)
            * ``int32``: yes; tested (1)
            * ``int64``: yes; tested (2)
            * ``float16``: yes; tested (1)
            * ``float32``: yes; tested (1)
            * ``float64``: yes; tested (1)
            * ``float128``: no
            * ``bool``: yes; tested (1)

            - (1) Handled by ``cv2``. See ``backend="cv2"``.
            - (2) Handled by ``scipy``. See ``backend="scipy"``.

        if (backend="cv2")::

            * ``uint8``: yes; fully tested
            * ``uint16``: yes; tested
            * ``uint32``: no (2)
            * ``uint64``: no (3)
            * ``int8``: yes; tested (4)
            * ``int16``: yes; tested
            * ``int32``: yes; tested (5)
            * ``int64``: no (6)
            * ``float16``: yes; tested (7)
            * ``float32``: yes; tested
            * ``float64``: yes; tested
            * ``float128``: no (8)
            * ``bool``: yes; tested (1)

            - (1) Mapped internally to ``float32``. Otherwise causes ``TypeError: src data type = 0 is not supported``.
            - (2) Causes ``TypeError: src data type = 6 is not supported``.
            - (3) Causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957: error: (-213:The function/feature is not
                  implemented) Unsupported combination of source format (=4), and buffer format (=5) in function
                  'getLinearRowFilter'``.
            - (4) Mapped internally to ``int16``. Otherwise causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957:
                  error: (-213:The function/feature is not implemented) Unsupported combination of source format (=1),
                  and buffer format (=5) in function 'getLinearRowFilter'``.
            - (5) Mapped internally to ``float64``. Otherwise causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957:
                  error: (-213:The function/feature is not implemented) Unsupported combination of source format (=4),
                  and buffer format (=5) in function 'getLinearRowFilter'``.
            - (6) Causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957: error: (-213:The function/feature is not
                  implemented) Unsupported combination of source format (=4), and buffer format (=5) in function
                  'getLinearRowFilter'``.
            - (7) Mapped internally to ``float32``. Otherwise causes ``TypeError: src data type = 23 is not supported``.
            - (8) Causes ``TypeError: src data type = 13 is not supported``.


        if (backend="scipy")::

            * ``uint8``: yes; fully tested
            * ``uint16``: yes; tested
            * ``uint32``: yes; tested
            * ``uint64``: yes; tested
            * ``int8``: yes; tested
            * ``int16``: yes; tested
            * ``int32``: yes; tested
            * ``int64``: yes; tested
            * ``float16``: yes; tested (1)
            * ``float32``: yes; tested
            * ``float64``: yes; tested
            * ``float128``: no (2)
            * ``bool``: yes; tested (3)

            - (1) Mapped internally to ``float32``. Otherwise causes ``RuntimeError: array type dtype('float16')
                  not supported``.
            - (2) Causes ``RuntimeError: array type dtype('float128') not supported``.
            - (3) Mapped internally to ``float32``. Otherwise too inaccurate.

    Parameters
    ----------
    image : numpy.ndarray
        The image to blur. Expected to be of shape ``(H, W)`` or ``(H, W, C)``.

    sigma : number
        Standard deviation of the gaussian blur. Larger numbers result in more large-scale blurring, which is overall
        slower than small-scale blurring.

    ksize : None or int, optional
        Size in height/width of the gaussian kernel. This argument is only understood by the ``cv2`` backend.
        If it is set to None, an appropriate value for `ksize` will automatically be derived from `sigma`.
        The value is chosen tighter for larger sigmas to avoid as much as possible very large kernel sizes
        and therey improve performance.

    backend : {'auto', 'cv2', 'scipy'}, optional
        Backend library to use. If ``auto``, then the likely best library will be automatically picked per image. That
        is usually equivalent to ``cv2`` (OpenCV) and it will fall back to ``scipy`` for datatypes not supported by
        OpenCV.

    eps : number, optional
        A threshold used to decide whether `sigma` can be considered zero.

    Returns
    -------
    image : numpy.ndarray
        The blurred image. Same shape and dtype as the input.

    """
    if sigma > 0 + eps:
        dtype = image.dtype

        iadt.gate_dtypes(image,
                         allowed=["bool",
                                  "uint8", "uint16", "uint32",
                                  "int8", "int16", "int32", "int64", "uint64",
                                  "float16", "float32", "float64"],
                         disallowed=["uint128", "uint256",
                                     "int128", "int256",
                                     "float96", "float128", "float256"],
                         augmenter=None)

        dts_not_supported_by_cv2 = ["uint32", "uint64", "int64", "float128"]
        backend_to_use = backend
        if backend == "auto":
            backend_to_use = "cv2" if image.dtype.name not in dts_not_supported_by_cv2 else "scipy"
        elif backend == "cv2":
            assert image.dtype.name not in dts_not_supported_by_cv2,\
                ("Requested 'cv2' backend, but provided %s input image, which "
                 + "cannot be handled by that backend. Choose a different backend or "
                 + "set backend to 'auto' or use a different datatype.") % (image.dtype.name,)
        elif backend == "scipy":
            # can handle all dtypes that were allowed in gate_dtypes()
            pass

        if backend_to_use == "scipy":
            if dtype.name == "bool":
                # We convert bool to float32 here, because gaussian_filter() seems to only return True when
                # the underlying value is approximately 1.0, not when it is above 0.5. So we do that here manually.
                # cv2 does not support bool for gaussian blur
                image = image.astype(np.float32, copy=False)
            elif dtype.name == "float16":
                image = image.astype(np.float32, copy=False)

            # gaussian_filter() has no ksize argument
            # TODO it does have a truncate argument that truncates at x standard deviations -- maybe can be used
            #      similarly to ksize
            if ksize is not None:
                warnings.warn("Requested 'scipy' backend or picked it automatically by backend='auto' "
                              "in blur_gaussian_(), but also provided 'ksize' argument, which is not understood by "
                              "that backend and will be ignored.")

            # Note that while gaussian_filter can be applied to all channels at the same time, that should not
            # be done here, because then the blurring would also happen across channels (e.g. red values might
            # be mixed with blue values in RGB)
            if image.ndim == 2:
                image[:, :] = ndimage.gaussian_filter(image[:, :], sigma, mode="mirror")
            else:
                nb_channels = image.shape[2]
                for channel in sm.xrange(nb_channels):
                    image[:, :, channel] = ndimage.gaussian_filter(image[:, :, channel], sigma, mode="mirror")
        else:
            if dtype.name == "bool":
                image = image.astype(np.float32, copy=False)
            elif dtype.name == "float16":
                image = image.astype(np.float32, copy=False)
            elif dtype.name == "int8":
                image = image.astype(np.int16, copy=False)
            elif dtype.name == "int32":
                image = image.astype(np.float64, copy=False)

            # ksize here is derived from the equation to compute sigma based on ksize,
            # see https://docs.opencv.org/3.1.0/d4/d86/group__imgproc__filter.html -> cv::getGaussianKernel()
            # example values:
            #   sig = 0.1 -> ksize = -1.666
            #   sig = 0.5 -> ksize = 0.9999
            #   sig = 1.0 -> ksize = 1.0
            #   sig = 2.0 -> ksize = 11.0
            #   sig = 3.0 -> ksize = 17.666
            # ksize = ((sig - 0.8)/0.3 + 1)/0.5 + 1

            if ksize is None:
                if sigma < 3.0:
                    ksize = 3.3 * sigma  # 99% of weight
                elif sigma < 5.0:
                    ksize = 2.9 * sigma  # 97% of weight
                else:
                    ksize = 2.6 * sigma  # 95% of weight

                # we use 5x5 here as the minimum size as that simplifies comparisons with gaussian_filter() in the tests
                # TODO reduce this to 3x3
                ksize = int(max(ksize, 5))
            else:
                assert ia.is_single_integer(ksize), "Expected 'ksize' argument to be a number, got %s." % (type(ksize),)

            ksize = ksize + 1 if ksize % 2 == 0 else ksize

            if ksize > 0:
                image_warped = cv2.GaussianBlur(image, (ksize, ksize), sigmaX=sigma, sigmaY=sigma,
                                                borderType=cv2.BORDER_REFLECT_101)

                # re-add channel axis removed by cv2 if input was (H, W, 1)
                image = image_warped[..., np.newaxis] if image.ndim == 3 and image_warped.ndim == 2 else image_warped

        if dtype.name == "bool":
            image = image > 0.5
        elif dtype.name != image.dtype.name:
            image = iadt.restore_dtypes_(image, dtype)

    return image