def estimate_foreground_ml_pyopencl(
    input_image,
    input_alpha,
    regularization=1e-5,
    n_small_iterations=10,
    n_big_iterations=2,
    small_size=32,
    return_background=False,
):
    """See the :code:`estimate_foreground` method for documentation."""

    def upload(array):
        hostbuf = array.astype(np.float32).flatten()
        return cl.Buffer(
            context,
            cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR,
            hostbuf=hostbuf,
        )

    def alloc(*shape):
        n = math.prod(shape)
        buffer = cl.Buffer(context, cl.mem_flags.READ_WRITE, n * 4)
        zero = np.uint32(0)
        cl.enqueue_fill_buffer(queue, buffer, zero, 0, n*4)
        return buffer

    def download(device_buf, shape):
        host_buf = np.empty(shape, dtype=np.float32)

        cl.enqueue_copy(queue, host_buf, device_buf)

        return host_buf.reshape(shape)

    h0, w0, depth = input_image.shape

    assert depth == 3

    n = h0 * w0 * depth

    input_image = upload(input_image)
    input_alpha = upload(input_alpha)

    F_prev = alloc(n)
    B_prev = alloc(n)

    F = alloc(n)
    B = alloc(n)

    image_level = alloc(n)
    alpha_level = alloc(h0 * w0)

    n_levels = (max(w0, h0) - 1).bit_length()

    def resize_nearest(dst, src, w_src, h_src, w_dst, h_dst, depth):
        program.resize_nearest(
            queue,
            (w_dst, h_dst),
            None,
            dst,
            src,
            *np.int32([w_src, h_src, w_dst, h_dst, depth])
        )

    w_prev = 1
    h_prev = 1

    resize_nearest(F, input_image, w0, h0, w_prev, h_prev, depth)
    resize_nearest(B, input_image, w0, h0, w_prev, h_prev, depth)

    for i_level in range(n_levels + 1):
        w = round(w0 ** (i_level / n_levels))
        h = round(h0 ** (i_level / n_levels))

        resize_nearest(image_level, input_image, w0, h0, w, h, depth)
        resize_nearest(alpha_level, input_alpha, w0, h0, w, h, 1)

        resize_nearest(F_prev, F, w_prev, h_prev, w, h, depth)
        resize_nearest(B_prev, B, w_prev, h_prev, w, h, depth)

        # Do more iterations for low resolution.
        n_iter = n_big_iterations
        if min(w, h) <= small_size:
            n_iter = n_small_iterations

        for i_iter in range(n_iter):
            program.ml_iteration(
                queue,
                (w, h),
                None,
                F,
                B,
                F_prev,
                B_prev,
                image_level,
                alpha_level,
                np.int32(w),
                np.int32(h),
                np.float32(regularization),
            )

            F_prev, F = F, F_prev
            B_prev, B = B, B_prev

        w_prev = w
        h_prev = h

    F_host = download(F, (h0, w0, depth))
    B_host = download(B, (h0, w0, depth))

    for buf in [
        F,
        B,
        F_prev,
        B_prev,
        input_image,
        input_alpha,
        image_level,
        alpha_level,
    ]:
        buf.release()

    if return_background:
        return F_host, B_host

    return F_host
See the :code:`estimate_foreground` method for documentation.
pymatting/foreground/estimate_foreground_ml_pyopencl.py