Пиксели и геометрические фигуры - Python / PIL - PullRequest
2 голосов
/ 16 февраля 2011

Я пытаюсь построить базовую тепловую карту на основе точек.Каждая точка имеет тепловой радиус и поэтому представлена ​​кругом.

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

Мне сложно найти оптимальное решение по многим пунктам. Сейчас у меня есть что-то похожее на это:

for pixels in pixels:
    if (pixel.x - circle.x)**2 + (pixel.y - circle.y)**2 <= circle.radius:
        pixel.set_color(circle.color)

Редактировать:

Данные, которые у меня есть:

  • пиксель в центре круга
  • радиус круга (целое число)

Любые подсказки?

Ответы [ 4 ]

3 голосов
/ 16 февраля 2011

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

Обведите количество желаемых цветовых шагов (скажем, radius / 2) и используйте 255 / number_of_steps * current_step в качестве альфа-значения для цвета заливки.

1 голос
/ 17 февраля 2011

Если вы сами обрабатываете свои пиксели, и ваша цель - повысить производительность, вы можете просто сфокусироваться на квадрате [x - radius; x + radius] * [y - radius; y + radius], поскольку точки вашего круга живут здесь.Это избавит вас от множества бесполезных итераций, если, конечно, вы МОЖЕТЕ сфокусироваться на этой области (т.е. ваши пиксели - это не просто массив без индекса на строку и столбец).

Вы даже можете быть уверены, что пикселив квадрате [x - radius*sqrt(2)/2; x + radius*sqrt(2)/2] * [y - radius*sqrt(2)/2; y + radius*sqrt(2)/2] должен быть цветным, с базовой тригонометрией (максимальный квадрат внутри круга).

Так что вы можете сделать:

import math
half_sqrt = math.sqrt(2) / 2
x_max = x + half_sqrt
y_max = y + half_sqrt
for (i in range(x, x + radius + 1):
    for (j in range(y, y + radius + 1):
        if (x <= x_max and y <= y_max):
            colorize_4_parts(i, j)
        else:
            pixel = get_pixel(i, j)
            if (pixel.x - circle.x)**2 + (pixel.y - circle.y)**2 <= circle.radius:
                # Apply same colors as above, could be a function
                colorize_4_parts(i, j)

def colorize_4_parts(i, j):
    # Hoping you have access to such a function get_pixel !
    pixel_top_right = get_pixel(i, j)
    pixel_top_right.set_color(circle.color)
    pixel_top_left = get_pixel(2 * x - i, j)
    pixel_top_leftt.set_color(circle.color)
    pixel_bot_right = get_pixel(i, 2 * y - j)
    pixel_bot_right.set_color(circle.color)
    pixel_bot_left = get_pixel(2 * x - i,  2 * y - j)
    pixel_bot_leftt.set_color(circle.color)

Это оптимизировано для сокращения дорогостоящих вычислений доминимум.

РЕДАКТИРОВАТЬ: функция обновлена, чтобы быть более эффективной снова: я забыл, что у нас была двойная симметрия горизонтальная и вертикальная, поэтому мы можем вычислять только для верхнего правого угла!

1 голос
/ 16 февраля 2011

Для построения графика обычно рекомендуется использовать библиотеку matplotlib (например, используя imshow для тепловых карт). Конечно, Matplotlib также поддерживает цветовых градиентов .

Однако я не совсем понимаю, чего вы пытаетесь достичь. Если вы просто хотите нарисовать кучу цветных кругов, тогда подойдет любая графическая библиотека (например, с помощью функции ellipse в PIL).

Звучит так, будто вы хотите покрасить пиксель в соответствии с его расстоянием от центра, но ваш собственный пример кода предполагает, что цвет постоянен?

0 голосов
/ 18 февраля 2011

Это очень распространенная операция, и вот как люди это делают ...

сводка: представьте плотность точек на сетке , сгладьте ее, используя 2D свертку , если необходимо (это дает ваши точки кружкам), и постройте ее как тепловая карта с использованием matplotlib .

Более подробно: сначала создайте двумерную сетку для своей тепловой карты и добавьте свои точки данных в сетку, увеличивая их на 1, когда точка данных попадает в ячейку. Во-вторых, создайте другую сетку, чтобы представить форму, которую вы хотите придать каждой точке (обычно люди используют цилиндр или гауссиан или что-то вроде этого). В-третьих, сведи эти два вместе, используя, скажем, scipy.signal.convolve2d . Наконец, используйте функцию imshow в matplotlib для построения свертки, и это будет ваша тепловая карта.

Если вы не можете использовать инструменты, предлагаемые в стандартном подходе, то вы можете найти обходные пути, но у него есть свои преимущества. Например, свертка хорошо справится со случаями, когда круги перекрываются.

...