elegant-scipy / elegant-scipy-submissions

Submissions of code snippets for the book Elegant SciPy
13 stars 2 forks source link

Reservoir sampling over a collection of images #9

Open starcalibre opened 9 years ago

starcalibre commented 9 years ago

Code by @jni Submitted by @starcalibre

Reservoir sampling over a collection of images for purposes of image illumination correction.

def _reservoir_sampled_image(ims_iter, random_state=None):
    """Return an image where each pixel is sampled from a list of images.
    The idea is to get a sample of image intensity throughout a collection
    of images, to know what the "standard range" is for this type of image.
    The implementation uses a "reservoir" image to sample while remaining
    space-efficient, and only needs to hold about four images at one time
    (the reservoir, the current sample, a random image for sampling, and
    a thresholded version of the random image).
    Parameters
    ----------
    ims_iter : iterable of arrays
        An iterable over numpy arrays (representing images).
    random_state : None, int, or numpy RandomState instance, optional
        An optional random number generator or seed from which to draw
        samples.
    Returns
    -------
    sampled : array, same shape as input
        The sampled "image".
    Examples
    --------
    >>> ims = iter(np.arange(27).reshape((3, 3, 3)))
    >>> _reservoir_sampled_image(ims, 0)
    array([[ 0,  1,  2],
           [ 3, 13, 23],
           [24, 25,  8]])
    """
    random = normalise_random_state(random_state)
    ims_iter = iter(ims_iter)  # ensure iterator and not e.g. list
    sampled = next(ims_iter)
    for k, im in enumerate(ims_iter, start=2):
        to_replace = random.rand(*im.shape) < (1 / k)
        sampled[to_replace] = im[to_replace]
    return sampled