Преобразование цветов HSV в RGB

Есть ли способ преобразовать цветовые аргументы HSV в цветовые аргументы типа RGB, используя модули pygame в python? Я попробовал следующий код, но он возвращает смешные значения.

import colorsys
test_color = colorsys.hsv_to_rgb(359, 100, 100)
print(test_color)

и этот код возвращает следующую ерунду

(100, -9900.0, -9900.0)

Это явно не RGB. Что я делаю неправильно?

10 ответов

Решение

Эта функция ожидает десятичного числа для s (насыщенность) и v (значение), а не проценты. Разделите на 100.

>>> import colorsys

# Using percent, incorrect
>>> test_color = colorsys.hsv_to_rgb(359,100,100)
>>> test_color
(100, -9900.0, -9900.0)

# Using decimal, correct
>>> test_color = colorsys.hsv_to_rgb(1,1,1)
>>> test_color
(1, 0.0, 0.0)

Если вы хотите ненормализованный кортеж RGB, вот функция для переноса colorsys функция.

def hsv2rgb(h,s,v):
    return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h,s,v))

Пример функциональности

>>> hsv2rgb(0.5,0.5,0.5)
(64, 128, 128)

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

Вот точный код из colorsys, слегка модифицированный, чтобы сделать байт-код немного быстрее:

    def hsv_to_rgb(h, s, v):
        if s == 0.0: return (v, v, v)
        i = int(h*6.) # XXX assume int() truncates!
        f = (h*6.)-i; p,q,t = v*(1.-s), v*(1.-s*f), v*(1.-s*(1.-f)); i%=6
        if i == 0: return (v, t, p)
        if i == 1: return (q, v, p)
        if i == 2: return (p, v, t)
        if i == 3: return (p, q, v)
        if i == 4: return (t, p, v)
        if i == 5: return (v, p, q)

выход:

>>> hsv_to_rgb(359,1,1)
[1, 0.0, 0.0]

Использование if-цепочки, как описано выше, на самом деле быстрее, чем использование elif.

Использование оболочки, как в ответе Кибера, требует от переводчика нескольких дополнительных шагов.
Чтобы добавить, цикл for в примере Cyber ​​является реальным убийцей производительности при таком использовании

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

    def hsv_to_rgb(h, s, v):
        if s == 0.0: v*=255; return (v, v, v)
        i = int(h*6.) # XXX assume int() truncates!
        f = (h*6.)-i; p,q,t = int(255*(v*(1.-s))), int(255*(v*(1.-s*f))), int(255*(v*(1.-s*(1.-f)))); v*=255; i%=6
        if i == 0: return (v, t, p)
        if i == 1: return (q, v, p)
        if i == 2: return (p, v, t)
        if i == 3: return (p, q, v)
        if i == 4: return (t, p, v)
        if i == 5: return (v, p, q)

^ это гарантирует вывод int() с диапазоном 255 (ввод остается прежним)

>>> hsv_to_rgb(359./360.,1,1)
(255, 0, 0)

СОВЕТ: по возможности держитесь подальше от сторонних, попробуйте прямой подход, если можете.
exculusions: скомпилированные расширения C, такие как PIL или NumPy, или обертки ctypes, такие как PyOpenGL (использует DLL)

Аргумент Хюэ также должен отличаться от 0-1.

import colorsys
test_color = colorsys.hsv_to_rgb(359/360.0, 1, 1)

Если вы работаете с массивами Numpy, то matplotlib.colors.hsv_to_rgb вполне прям:

import numpy as np
from matplotlib.colors import hsv_to_rgb
# This will create a nice image of varying hue and value
hsv = np.zeros((512, 512, 3))
hsv[..., 0] = np.linspace(0, 1, 512)
hsv[..., 1] = 1.
hsv[..., 2] = np.linspace(0, 1, 512)[:, np.newaxis]
rgb = hsv_to_rgb(hsv)

Обратите внимание, что входные и выходные изображения имеют значения в диапазоне [0, 1].

Поскольку вопрос помечен как pygame, я хочу упомянуть, что PyGame позволяет преобразовывать цветовые схемы. В pygame.Color объект может использоваться для преобразования цветовых схем RGB и HSL/HSV.

В hsva свойство:

Получает или задает представление Color в формате HSVA. Компоненты HSVA находятся в диапазонах H = [0, 360], S = [0, 100], V = [0, 100], A = [0, 100].

       hsva = pygame.Color((red, green, blue, alpha)).hsva
       color = pygame.Color(0)
color.hsva = (hue, saturation, value, alpha)
rgba = (color.r, color.g, color.b, color.a)

В hsla свойство:

Получает или задает HSLA-представление Color. Компоненты HSLA находятся в диапазонах H = [0, 360], S = [0, 100], V = [0, 100], A = [0, 100].

       hsla = pygame.Color((red, green, blue, alpha)).hsla
       color = pygame.Color(0)
color.hsla = (hue, saturation, lightness, alpha)
rgba = (color.r, color.g, color.b, color.a)

Минимальный пример:

       import pygame

pygame.init()

window = pygame.display.set_mode((450, 300))
clock = pygame.time.Clock()

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill((255, 255, 255))
    w, h = window.get_size()
    for i in range(6):
        color = pygame.Color(0)
        color.hsla = (i * 60, 100, 50, 100)
        pygame.draw.circle(window, color, 
            (w//6 + w//3 * (i%3), h//4 + h//2 * (i//3)), 
            round(min(window.get_width() * 0.16, window.get_height() * 0.2)))

    pygame.display.flip()

pygame.quit()
exit()

Я подготовил векторизованную версию, она примерно в 10 раз быстрее

def hsv_to_rgb(h, s, v):
    shape = h.shape
    i = int_(h*6.)
    f = h*6.-i

    q = f
    t = 1.-f
    i = ravel(i)
    f = ravel(f)
    i%=6

    t = ravel(t)
    q = ravel(q)

    clist = (1-s*vstack([zeros_like(f),ones_like(f),q,t]))*v

    #0:v 1:p 2:q 3:t
    order = array([[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]])
    rgb = clist[order[i], arange(prod(shape))[:,None]]

    return rgb.reshape(shape+(3,))

Я нашел следующий код для работы с изображениями, представленными в виде numpy ndarrays:

from skimage.io import imread
import matplotlib.colors as mcolors
img = imread( 'my_image.png' )
img_hsv = mcolors.rgb_to_hsv( img )
img_hsv = img_hsv / (1.0, 1.0, 255.0)

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

В opencv используйте любое их преобразование цвета. Обратите внимание, что BGR и RGB перевернуты в cv2 land.

def convertColor(hsv, conversion):
    return tuple(int(i) for i in cv2.cvtColor(np.uint8([[hsv]]), conversion).flatten())

Применение:

hsvColor = (0,255,255) #bright red
bgrColor = convertColor(hsvColor, cv2.COLOR_HSV2BGR)

OpenCV также предлагает такую ​​возможность. Обратите внимание, что каналы R и B инвертированы, то есть BGR. Поэтому использует функцию, которая лучше всего соответствует вашим потребностям:

import cv2

rgbimg = cv2.cvtColor(hsvimg, cv2.COLOR_HSV2RGB)
bgrimg = cv2.cvtColor(hsvimg, cv2.COLOR_HSV2BGR)

Если вам нужно больше контролировать формат цвета при их преобразовании (например, вы хотите, чтобы максимальное значение RGB было равно 255 вместо 1), я бы рекомендовал colorir.

      from colorir import HSV, sRGB
rgb = HSV(359, 100, 100, max_sva=100).rgb()
... your code

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

Другие вопросы по тегам