web-dev-qa-db-fra.com

Calculer la valeur RVB pour une plage de valeurs pour créer une carte thermique

J'essaie de créer une carte de chaleur avec python. Pour cela, je dois attribuer une valeur RVB à chaque valeur dans la plage de valeurs possibles. J'ai pensé à changer la couleur du bleu (valeur minimale) sur le vert au rouge (valeur maximale).

L'exemple d'image ci-dessous explique comment j'ai pensé à la composition des couleurs: nous avons une plage de 1 (bleu pur) à 3 (rouge pur), 2 entre les deux ressemble au vert.

color composition RGB in range(1-3)

J'ai lu sur l'interpolation linéaire et écrit une fonction qui (plus ou moins) gère le calcul pour une certaine valeur dans la plage entre un minimum et un maximum et renvoie un tuple RVB. Il utilise les conditions if et Elif (ce qui ne me satisfait pas complètement):

def convert_to_rgb(minimum, maximum, value):
    minimum, maximum = float(minimum), float(maximum)    
    halfmax = (minimum + maximum) / 2
    if minimum <= value <= halfmax:
        r = 0
        g = int( 255./(halfmax - minimum) * (value - minimum))
        b = int( 255. + -255./(halfmax - minimum)  * (value - minimum))
        return (r,g,b)    
    Elif halfmax < value <= maximum:
        r = int( 255./(maximum - halfmax) * (value - halfmax))
        g = int( 255. + -255./(maximum - halfmax)  * (value - halfmax))
        b = 0
        return (r,g,b)

Cependant, je me demande si on pourrait écrire une fonction pour chaque valeur de couleur sans en utilisant les conditions if. Est-ce que quelqu'un a une idée? Merci beaucoup!

22
aldorado
def rgb(minimum, maximum, value):
    minimum, maximum = float(minimum), float(maximum)
    ratio = 2 * (value-minimum) / (maximum - minimum)
    b = int(max(0, 255*(1 - ratio)))
    r = int(max(0, 255*(ratio - 1)))
    g = 255 - b - r
    return r, g, b
33
John1024

Voici une autre façon de le faire qui, bien qu'elle ne soit pas aussi courte que possible, est beaucoup plus générale car elle n'a pas été codée en dur pour votre jeu de couleurs spécifique. Cela signifie qu'il peut également être utilisé pour interpoler de manière linéaire une plage de valeurs spécifiée sur une palette de couleurs arbitraires de taille variable.

Notez également que les couleurs auraient pu être interpolées dans d'autres espaces chromatiques, ce qui donnerait des résultats plus agréables que dans d'autres. Ceci est illustré par les différents résultats obtenus à partir des deux réponses distinctes que j'ai soumises à une question connexe intitulée Valeurs de plage à pseudocolor .

import sys
EPSILON = sys.float_info.epsilon  # Smallest possible difference.

def convert_to_rgb(minval, maxval, val, colors):
    # "colors" is a series of RGB colors delineating a series of
    # adjacent linear color gradients between each pair.
    # Determine where the given value falls proportionality within
    # the range from minval->maxval and scale that fractional value
    # by the total number in the "colors" pallette.
    i_f = float(val-minval) / float(maxval-minval) * (len(colors)-1)
    # Determine the lower index of the pair of color indices this
    # value corresponds and its fractional distance between the lower
    # and the upper colors.
    i, f = int(i_f // 1), i_f % 1  # Split into whole & fractional parts.
    # Does it fall exactly on one of the color points?
    if f < EPSILON:
        return colors[i]
    else:  # Otherwise return a color within the range between them.
        (r1, g1, b1), (r2, g2, b2) = colors[i], colors[i+1]
        return int(r1 + f*(r2-r1)), int(g1 + f*(g2-g1)), int(b1 + f*(b2-b1))

if __name__ == '__main__':
    minval, maxval = 1, 3
    steps = 10
    delta = float(maxval-minval) / steps
    colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0)]  # [BLUE, GREEN, RED]
    print('  Val       R    G    B')
    for i in range(steps+1):
        val = minval + i*delta
        r, g, b = convert_to_rgb(minval, maxval, val, colors)
        print('{:.3f} -> ({:3d}, {:3d}, {:3d})'.format(val, r, g, b))

Sortie numérique:

  Val       R    G    B
1.000 -> (  0,   0, 255)
1.200 -> (  0,  50, 204)
1.400 -> (  0, 101, 153)
1.600 -> (  0, 153, 101)
1.800 -> (  0, 204,  50)
2.000 -> (  0, 255,   0)
2.200 -> ( 51, 203,   0)
2.400 -> (102, 152,   0)
2.600 -> (153, 101,   0)
2.800 -> (203,  51,   0)
3.000 -> (255,   0,   0)

Voici la sortie visualisée comme un dégradé horizontal:

horizontal gradient generated with function in answer

15
martineau

Vous pouvez souvent éliminer un if avec un index dans un tableau de deux valeurs. Python n'a pas d'opérateur conditionnel ternaire, mais cela fonctionne:

r = [red_curve_1, red_curve_2][value>=halfmax]
g = [green_curve_1, green_curve_2][value>=halfmax]
b = [blue_curve_1, blue_curve_2][value>=halfmax]

Remplacez les expressions *_curve_1 Et *_curve_2 Par les constantes ou les pentes ou les courbes à gauche ou à droite du milieu, respectivement.

Je vous laisse ces substitutions, mais par exemple:

  • red_curve_1 Et blue_curve_2 Sont simplement 0
  • green_curve_1 Est 255*(value-minimum)/(halfmax-minimum)
  • etc.
2
Darren Stone

"Nous sentons l'intensité lumineuse sur une échelle logarithmique - une rampe d'intensité exponentielle sera considérée comme une rampe linéaire" https://courses.cs.washington.edu/courses/cse455/09wi/Lects/lect11.pdf

D'après https://en.wikipedia.org/wiki/RGB_color_model : "une valeur RVB d'intensité d'entrée de (0,5, 0,5, 0,5) ne produit qu'environ 22% de la pleine luminosité (1.0, 1.0, 1.0), au lieu de 50% "

Cela conduit à la tache brunâtre à 2,5 dans l'exemple de @martineau, où elle devrait être jaune et cyan à 1,5 afin d'obtenir un gradient de teinte approprié.

La formule que vous devez utiliser pour obtenir le dégradé n'est donc pas nécessairement celle que vous souhaitez. (désolé de ne pas avoir répondu directement à votre question)

Mais il peut être utile de convertir le modèle d'espace colorimétrique HSV ou HLS, d'utiliser H (pour la teinte) et de l'utiliser comme entrée, puis de le reconvertir en RVB à des fins d'affichage. c'est à dire:

colorsys.hsv_to_rgb(value, 1, 1)

https://docs.python.org/2/library/colorsys.html

1
Maarten Albers