diff options
| -rw-r--r-- | fg21sim/utils/draw.py | 63 | 
1 files changed, 62 insertions, 1 deletions
| diff --git a/fg21sim/utils/draw.py b/fg21sim/utils/draw.py index 25d83c9..47c9c08 100644 --- a/fg21sim/utils/draw.py +++ b/fg21sim/utils/draw.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Weitian LI <liweitianux@live.com> +# Copyright (c) 2016-2017 Weitian LI <weitian@aaronly.me>  # MIT license @@ -6,9 +6,70 @@  Generic drawers (a.k.a. painters) that draw some commonly used shapes.  """ +import logging  import numpy as np  import numba as nb +from scipy import interpolate + + +logger = logging.getLogger(__name__) + + +def circle(radius=None, rprofile=None, fill_value=0.0): +    """ +    Draw a (filled) circle at the center of the output grid. +    If ``rprofile`` is supplied, then it is used as the radial values +    for the circle. + +    Parameters +    ---------- +    radius : int +        The radius of the circle to draw +    rprofile : 1D `~numpy.ndarray`, optional +        The radial values for the circle, and ``radius`` will be ignored +        if specified. +        If not provided, then fill the circle with ones. +    fill_value : float, optional +        Value to be filled to the empty pixels, default 0.0 + +    Returns +    ------- +    img : 2D `~numpy.ndarray` +        Image of size ``(2*radius+1, 2*radius+1)`` with the circle drawn +        at the center. + +    NOTE +    ---- +    Using a rotational formulation to create the 2D window/image from the +    1D window/profile gives more circular contours, than using the +    "outer product." + +    Credit +    ------ +    [1] MATLAB - creating 2D convolution filters +        https://cn.mathworks.com/matlabcentral/newsreader/view_thread/23588 +    """ +    if rprofile is not None: +        if radius is not None: +            logger.warning("circle(): Ignored parameter radius.") +        rprofile = np.asarray(rprofile) +        radius = len(rprofile) - 1 + +    xsize = 2 * radius + 1 +    x = np.arange(xsize) - radius +    xg, yg = np.meshgrid(x, x) +    r = np.sqrt(xg**2 + yg**2) +    ridx = (r <= radius) +    img = np.zeros(shape=(xsize, xsize)) +    img.fill(fill_value) +    if rprofile is None: +        img[ridx] = 1.0 +    else: +        finterp = interpolate.interp1d(x=np.arange(len(rprofile)), +                                       y=rprofile, kind="linear") +        img[ridx] = finterp(r[ridx]) +    return img  @nb.jit(nb.types.UniTuple(nb.int64[:], 2)(nb.types.UniTuple(nb.int64, 2), | 
