Значения диапазона для псевдоколор

У меня есть определенный массив с плавающей точкой (в Python), который может варьироваться от 0 до 100. Я хочу создать псевдоцветное изображение, чтобы цвета варьировались от зеленого (соответствует 0) до красного (100). Это похоже на pcolor из matplotlib. Однако я не хочу использовать pcolor.

Есть ли такая функция, как pseudocolorForValue(val,(minval,maxval)) которая возвращает тройку RGB, соответствующую pseudocolorForValue(val,(minval,maxval)) для val? Кроме того, есть ли гибкость в этой функции, чтобы выбрать, отображать ли цвета от зеленого к красному или от красного к зеленому?

Спасибо ник

Ответы

Ответ 1

Вы могли бы написать свою собственную функцию, которая преобразовывала бы значения 0… 100 → 0… 120 градусов, а затем использовала это значение как Н (или угол) цвета в цветовом пространстве HSV (или HLS). Затем его можно преобразовать в цвет RGB для отображения. Линейно интерпретируемый цвет часто выглядит лучше, когда он рассчитывается в этом цветовом пространстве. Вот как выглядит цветовое пространство HSV:

hsv colorspace diagram

Обновить:

Хорошая новость, я был приятно удивлен, обнаружив, что в Python есть встроенные процедуры преобразования цветового пространства во встроенном модуле colorsys (они действительно означают "батареи включены"). Что приятно, так это то, что это делает создание функции, которая делает то, что я описал, довольно просто, как показано ниже:

from colorsys import hsv_to_rgb

def pseudocolor(val, minval, maxval):
    """ Convert val in range minval..maxval to the range 0..120 degrees which
        correspond to the colors Red and Green in the HSV colorspace.
    """
    h = (float(val-minval) / (maxval-minval)) * 120

    # Convert hsv color (h,1,1) to its rgb equivalent.
    # Note: hsv_to_rgb() function expects h to be in the range 0..1 not 0..360
    r, g, b = hsv_to_rgb(h/360, 1., 1.)
    return r, g, b

if __name__ == '__main__':
    steps = 10

    print('val       R      G      B')
    for val in range(0, 100+steps, steps):
        print('{:3d} -> ({:.3f}, {:.3f}, {:.3f})'.format(
                                                val, *pseudocolor(val, 0, 100)))

Выход:

val       R      G      B
  0 -> (1.000, 0.000, 0.000)
 10 -> (1.000, 0.200, 0.000)
 20 -> (1.000, 0.400, 0.000)
 30 -> (1.000, 0.600, 0.000)
 40 -> (1.000, 0.800, 0.000)
 50 -> (1.000, 1.000, 0.000)
 60 -> (0.800, 1.000, 0.000)
 70 -> (0.600, 1.000, 0.000)
 80 -> (0.400, 1.000, 0.000)
 90 -> (0.200, 1.000, 0.000)
100 -> (0.000, 1.000, 0.000)

Вот пример, показывающий, как выглядит его вывод:

sample showing color interpolation in HSV colorspace

Я думаю, что вы можете найти цвета получше, чем в моем другом ответе.

Обобщая:

Можно изменить эту функцию, чтобы она была немного более общей в том смысле, что она будет работать с цветами, отличными от только красного и зеленого, которые в настоящее время жестко закодированы в нее.

Вот как это сделать:

def pseudocolor(val, minval, maxval, start_hue, stop_hue):
    """ Convert val in range minval..maxval to the range start_hue..stop_hue
        degrees in the HSV colorspace.
    """
    h = (float(val-minval) / (maxval-minval)) * (stop_hue-start_hue) + start_hue

    # Convert hsv color (h,1,1) to its rgb equivalent.
    # Note: hsv_to_rgb() function expects h to be in the range 0..1 not 0..360
    r, g, b = hsv_to_rgb(h/360, 1., 1.)
    return r, g, b

if __name__ == '__main__':
    # angles of common colors in hsv colorspace
    RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA = range(0, 360, 60)
    steps = 10

    print('val       R      G      B')
    for val in range(0, 100+steps, steps):
        print('{:3d} -> ({:.3f}, {:.3f}, {:.3f})'.format(
                val, *pseudocolor(val, 0, 100, YELLOW, BLUE)))

Результаты:

sample showing color interpolation in HSV colorspace between yellow and blue

Ответ 2

Хотя это, возможно, и не так красиво, как интерполяция H в цветовом пространстве HLS или HSV, гораздо проще реализовать подход, заключающийся в том, чтобы написать функцию, отображающую одно значение в три компонента, соответствующих линейно-интерполированному цвету между полностью red (1,0,0) и полностью зеленый (0,1,0) в цветовом пространстве RGB.

Вот что я имею в виду:

def pseudocolor(val, minval, maxval):
    """ Convert value in the range minval...maxval to a color between red
        and green.
    """
    f = float(val-minval) / (maxval-minval)
    r, g, b = 1-f, f, 0.
    return r, g, b

if __name__ == '__main__':
    steps = 10
    print('val       R      G      B')
    for val in xrange(0, 100+steps, steps):
        print('{:3d} -> ({:.3f}, {:.3f}, {:.3f})'.format(
                    val, *pseudocolor(val, 0, 100)))

Выход:

val       R      G      B
  0 -> (1.000, 0.000, 0.000)
 10 -> (0.900, 0.100, 0.000)
 20 -> (0.800, 0.200, 0.000)
 30 -> (0.700, 0.300, 0.000)
 40 -> (0.600, 0.400, 0.000)
 50 -> (0.500, 0.500, 0.000)
 60 -> (0.400, 0.600, 0.000)
 70 -> (0.300, 0.700, 0.000)
 80 -> (0.200, 0.800, 0.000)
 90 -> (0.100, 0.900, 0.000)
100 -> (0.000, 1.000, 0.000)

При необходимости вы можете преобразовать компоненты r, g, b с плавающей точкой, например, в целые числа в диапазоне 0..255.

Вот пример, показывающий, как выглядит его вывод:

image showing interpolation in RGB colorspace

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

Вот как это можно сделать:

def pseudocolor(val, minval, maxval, startcolor, stopcolor):
    """ Convert value in the range minval...maxval to a color in the range
        startcolor to stopcolor. The colors passed and the the one returned are
        composed of a sequence of N component values.
    """
    f = float(val-minval) / (maxval-minval)
    return tuple(f*(b-a)+a for (a, b) in zip(startcolor, stopcolor))

if __name__ == '__main__':
    YELLOW, BLUE = (1, 1, 0), (0, 0, 1)
    steps = 10

    print('val       R      G      B')
    for val in range(0, 100+steps, steps):
        print('{:3d} -> ({:.3f}, {:.3f}, {:.3f})'.format(
                    val, *pseudocolor(val, 0, 100, YELLOW, BLUE)))

Пример вывода с использованием предоставленных цветов:

image showing interpolation in RGB colorspace with different colors

Ответ 3

Вы можете напрямую получить matplolib встроенные цветовые коды, которые именно они используют для определения своей цветокоррекции. Каждая карта принимает поплавок в диапазоне [0, 1] и возвращает 4-элементный набор поплавков в диапазоне [0, 1] с компонентами (R, G, B, A). Ниже приведен пример функции, которая возвращает кортеж RGBA с использованием стандартного jet colormap:

from matplotlib import cm

def pseudocolor(val, minval, maxmal):
    # Scale val to be in the range [0, 1]
    val = (val - minval) / (maxval - minval)
    # Return RGBA tuple from jet colormap
    return cm.jet(val)

pseudocolor(20, 0, 100)
# Returns: (0.0, 0.3, 1.0, 1.0)

pseudocolor(80, 0, 100)
# Returns: (1.0, 0.4074, 0.0, 1.0)

Это отобразится в цветовой диапазон, показанный на изображении ниже.

введите описание изображения здесь

Одной из удобных функций этого метода является то, что вы можете легко переключиться на любой из matplotlib colormaps, изменив cm.jet на cm.rainbow, cm.nipy_spectral, cm.Accent и т.д.