def blockproc_inplace(image, block_shape, fun, *fun_args, **fun_kwargs):
    """
    Processes image IN PLACE block by block. Result of each block is a block of the same size.
    Intended for local enhancement/thresholding operations
    :param image: Grayscale fingerprint image
    :param block_shape: size of sub-block/sliding window to be processed
    :param fun: Function to be applied to a block
    :param fun_args: positional args to the function
    :param fun_kwargs: optional args to the function
    :return: processed image of same size as input
    """
    img_h, img_w = image.shape
    block_h, block_w = block_shape

    for i, r in enumerate(range(0, img_h, block_h)):
        for j, c in enumerate(range(0, img_w, block_w)):
            image[r:min(r + block_w, img_h), c:min(c + block_w, img_w)] = fun(image[r:min(r + block_w, img_h), c:min(c + block_w, img_w)], *fun_args, **fun_kwargs)
    return image