def blend_alpha(image_fg, image_bg, alpha, eps=<NUM_LIT>):
assert image_fg.shape == image_bg.shape<EOL>assert image_fg.dtype.kind == image_bg.dtype.kind<EOL>assert image_fg.dtype.name not in ["<STR_LIT>"]<EOL>assert image_bg.dtype.name not in ["<STR_LIT>"]<EOL>input_was_2d = (len(image_fg.shape) == <NUM_LIT:2>)<EOL>if input_was_2d:<EOL><INDENT>image_fg = np.atleast_3d(image_fg)<EOL>image_bg = np.atleast_3d(image_bg)<EOL><DEDENT>input_was_bool = False<EOL>if image_fg.dtype.kind == "<STR_LIT:b>":<EOL><INDENT>input_was_bool = True<EOL>image_fg = image_fg.astype(np.float32)<EOL>image_bg = image_bg.astype(np.float32)<EOL><DEDENT>alpha = np.array(alpha, dtype=np.float64)<EOL>if alpha.size == <NUM_LIT:1>:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>if alpha.ndim == <NUM_LIT:2>:<EOL><INDENT>assert alpha.shape == image_fg.shape[<NUM_LIT:0>:<NUM_LIT:2>]<EOL>alpha = alpha.reshape((alpha.shape[<NUM_LIT:0>], alpha.shape[<NUM_LIT:1>], <NUM_LIT:1>))<EOL><DEDENT>elif alpha.ndim == <NUM_LIT:3>:<EOL><INDENT>assert alpha.shape == image_fg.shape or alpha.shape == image_fg.shape[<NUM_LIT:0>:<NUM_LIT:2>] + (<NUM_LIT:1>,)<EOL><DEDENT>else:<EOL><INDENT>alpha = alpha.reshape((<NUM_LIT:1>, <NUM_LIT:1>, -<NUM_LIT:1>))<EOL><DEDENT>if alpha.shape[<NUM_LIT:2>] != image_fg.shape[<NUM_LIT:2>]:<EOL><INDENT>alpha = np.tile(alpha, (<NUM_LIT:1>, <NUM_LIT:1>, image_fg.shape[<NUM_LIT:2>]))<EOL><DEDENT><DEDENT>if not input_was_bool:<EOL><INDENT>if np.all(alpha >= <NUM_LIT:1.0> - eps):<EOL><INDENT>return np.copy(image_fg)<EOL><DEDENT>elif np.all(alpha <= eps):<EOL><INDENT>return np.copy(image_bg)<EOL><DEDENT><DEDENT>assert <NUM_LIT:0> <= alpha.item(<NUM_LIT:0>) <= <NUM_LIT:1.0><EOL>dt_images = iadt.get_minimal_dtype([image_fg, image_bg])<EOL>isize = dt_images.itemsize * <NUM_LIT:2><EOL>isize = max(isize, <NUM_LIT:4>)  <EOL>dt_blend = np.dtype("<STR_LIT>" % (isize,))<EOL>if alpha.dtype != dt_blend:<EOL><INDENT>alpha = alpha.astype(dt_blend)<EOL><DEDENT>if image_fg.dtype != dt_blend:<EOL><INDENT>image_fg = image_fg.astype(dt_blend)<EOL><DEDENT>if image_bg.dtype != dt_blend:<EOL><INDENT>image_bg = image_bg.astype(dt_blend)<EOL><DEDENT>image_blend = image_bg + alpha * (image_fg - image_bg)<EOL>if input_was_bool:<EOL><INDENT>image_blend = image_blend > <NUM_LIT:0.5><EOL><DEDENT>else:<EOL><INDENT>image_blend = iadt.restore_dtypes_(image_blend, dt_images, clip=False, round=True)<EOL><DEDENT>if input_was_2d:<EOL><INDENT>return image_blend[:, :, <NUM_LIT:0>]<EOL><DEDENT>return image_blend<EOL>
Blend two images using an alpha blending.

In an alpha blending, the two images are naively mixed. Let ``A`` be the foreground image
and ``B`` the background image and ``a`` is the alpha value. Each pixel intensity is then
computed as ``a * A_ij + (1-a) * B_ij``.

dtype support::

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

    - (1) Tests show that these dtypes work, but a conversion to float128 happens, which only
          has 96 bits of size instead of true 128 bits and hence not twice as much resolution.
          It is possible that these dtypes result in inaccuracies, though the tests did not
          indicate that.
    - (2) Not available due to the input dtype having to be increased to an equivalent float
          dtype with two times the input resolution.
    - (3) Mapped internally to ``float16``.

Parameters
----------
image_fg : (H,W,[C]) ndarray
    Foreground image. Shape and dtype kind must match the one of the
    background image.

image_bg : (H,W,[C]) ndarray
    Background image. Shape and dtype kind must match the one of the
    foreground image.

alpha : number or iterable of number or ndarray
    The blending factor, between 0.0 and 1.0. Can be interpreted as the opacity of the
    foreground image. Values around 1.0 result in only the foreground image being visible.
    Values around 0.0 result in only the background image being visible.
    Multiple alphas may be provided. In these cases, there must be exactly one alpha per
    channel in the foreground/background image. Alternatively, for ``(H,W,C)`` images,
    either one ``(H,W)`` array or an ``(H,W,C)`` array of alphas may be provided,
    denoting the elementwise alpha value.

eps : number, optional
    Controls when an alpha is to be interpreted as exactly 1.0 or exactly 0.0, resulting
    in only the foreground/background being visible and skipping the actual computation.

Returns
-------
image_blend : (H,W,C) ndarray
    Blend of foreground and background image.