Визуализация круга или эллипса с помощью сглаживания - PullRequest
1 голос
/ 02 марта 2020

Предположим, у меня есть квадратный растр заданного размера, и я хочу "нарисовать" (сделать) круг (или эллипс) заданного радиуса (или больших / малых осей) и центра.

В одну сторону Выполнение этого в Python с NumPy:

import numpy as np


def ellipse(box_size, semisizes, position=0.5, n_dim=2):
    shape = (box_size,) * n_dim
    if isinstance(semisizes, (int, float)):
        semisizes = (semisizes,) * n_dim
    position = ((box_size - 1) * position,) * n_dim
    grid = [slice(-x0, dim - x0) for x0, dim in zip(position, shape)]
    position = np.ogrid[grid]
    arr = np.zeros(shape, dtype=float)
    for x_i, semisize in zip(position, semisizes):
        arr += (np.abs(x_i / semisize) ** 2)
    return arr <= 1.0

print(ellipse(5, 2).astype(float))
# [[0. 0. 1. 0. 0.]
#  [0. 1. 1. 1. 0.]
#  [1. 1. 1. 1. 1.]
#  [0. 1. 1. 1. 0.]
#  [0. 0. 1. 0. 0.]]

, что приводит к растеризации без сглаживания . В частности, пиксели, которые только частично включены в круг, получают значение 0 (аналогично пикселям, исключенным из круга), тогда как пиксели, полностью включенные в круг, получают значение 1 .

При использовании сглаживания пиксели , частично включенные в круг, получат значение в диапазоне от 0 до 1 в зависимости от того, какая их площадь включена в круг.


Как я могу изменить код сверху, чтобы (возможно, дешево) включить сглаживание? Я изо всех сил пытаюсь понять, как (если?) Я мог бы использовать значения arr.

Методы, основанные на суперсэмплинге, здесь не обсуждаются.

В конце концов, результат должен выглядеть что-то вроде:

# [[0.0 0.2 1.0 0.2 0.0]
#  [0.2 1.0 1.0 1.0 0.2]
#  [1.0 1.0 1.0 1.0 1.0]
#  [0.2 1.0 1.0 1.0 0.2]
#  [0.0 0.2 1.0 0.2 0.0]]

(где 0.2 должно быть значением между 0.0 и 1.0, представляющим, сколько области этого указанного c пикселя покрыто кружком).


EDIT

Теперь я вижу очевидный способ адаптации кода из Эффективное создание круговой маски с сглаживанием , хотя, очевидно, np.clip() должно быть частью решения .

1 Ответ

0 голосов
/ 02 марта 2020

Один быстрый, но не обязательно математически правильный способ сделать это (в основном на основе кода из Эффективное создание круговой маски с сглаживанием ):

import numpy as np


def prod(items, start=1):
    for item in items:
        start *= item
    return start


def ellipse(box_size, semisizes, position=0.5, n_dim=2, smoothing=1.0):
    shape = (box_size,) * n_dim
    if isinstance(semisizes, (int, float)):
        semisizes = (semisizes,) * n_dim
    position = ((box_size - 1) * position,) * n_dim
    grid = [slice(-x0, dim - x0) for x0, dim in zip(position, shape)]
    position = np.ogrid[grid]
    arr = np.zeros(shape, dtype=float)
    for x_i, semisize in zip(position, semisizes):
        arr += (np.abs(x_i / semisize) ** 2)
    if smoothing:
        k = prod(semisizes) ** (0.5 / n_dim / smoothing)
        return 1.0 - np.clip(arr - 1.0, 0.0, 1.0 / k) * k
    elif isinstance(smoothing, float):
        return (arr <= 1.0).astype(float)
    else:
        return arr <= 1.0


n = 1
print(np.round(ellipse(5 * n, 2 * n, smoothing=0.0), 2))
# [[0. 0. 1. 0. 0.]
#  [0. 1. 1. 1. 0.]
#  [1. 1. 1. 1. 1.]
#  [0. 1. 1. 1. 0.]
#  [0. 0. 1. 0. 0.]]

n = 1
print(np.round(ellipse(5 * n, 2 * n, smoothing=1.0), 2))
# [[0.   0.65 1.   0.65 0.  ]
#  [0.65 1.   1.   1.   0.65]
#  [1.   1.   1.   1.   1.  ]
#  [0.65 1.   1.   1.   0.65]
#  [0.   0.65 1.   0.65 0.  ]]
...