HSV and RGB

Difference between version 18 and 19 - Previous - Next
[HSV] and [RGB] defines color spaces. [HSV] stands for Hue, Saturation, Value, while [RGB] stands for Red, Green, Blue. This page provides way(s) to convert values between these two color formats.

[Googie] 11.07.2007 - The code below uses only [math] package from [tcllib], so it's fully portable. It implements routines described on [http://en.wikipedia.org/wiki/HSV_color_space%|%Wikipedia].

----
[KPV] These routines appear in several other places in this wiki but it's
good to have them in one place (see [Harmonic color wheel],
[Selecting visually different RGB colors], and
[Image Processing with HSV]).

I added ''hls2rgb'' from one of the above pages, and I removed
the [math] package requirement (it only used functions min and max, now in 8.5).
Note the rgbToHsv / hsvToRgb pair encodes saturation and value from 0-255, not the usual 0-100%. Edit the code below, replace 255 with 100 to make them work in the normal ranges [PS] 24.2.2020.

----
======
 proc rgbToHsv {r g b} {
    set temp  [expr {min($r, $g, $b)}]
    set value [expr {max($r, $g, $b)}]
    set range [expr {$value-$temp}]
    if {$range == 0} {
        set hue 0
    } else {
        if {$value == $r} {
            set top [expr {$g-$b}]
            if {$g >= $b} {
                set angle 0
            } else {
                set angle 360
            }
        } elseif {$value == $g} {
            set top [expr {$b-$r}]
            set angle 120
        } elseif {$value == $b} {
            set top [expr {$r-$g}]
            set angle 240
        }
        set hue [expr { round( double($top) / $range * 60 + $angle ) }]
    }

    if {$value == 0} {
        set saturation 0
    } else {
        set saturation [expr { round( 255 - double($temp) / $value * 255 ) }]
    }
    return [list $hue $saturation $value]
 }

 proc hsvToRgb {h s v} {
    set Hi [expr { int( double($h) / 60 ) % 6 }]
    set f [expr { double($h) / 60 - $Hi }]
    set s [expr { double($s)/255 }]
    set v [expr { double($v)/255 }]
    set p [expr { double($v) * (1 - $s) }]
    set q [expr { double($v) * (1 - $f * $s) }]
    set t [expr { double($v) * (1 - (1 - $f) * $s) }]
    switch -- $Hi {
        0 {
            set r $v
            set g $t
            set b $p
        }
        1 {
            set r $q
            set g $v
            set b $p
        }
        2 {
            set r $p
            set g $v
            set b $t
        }
        3 {
            set r $p
            set g $q
            set b $v
        }
        4 {
            set r $t
            set g $p
            set b $v
        }
        5 {
            set r $v
            set g $p
            set b $q
        }
        default {
            error "Wrong Hi value in hsvToRgb procedure! This should never happen!"
        }
    }
    set r [expr {round($r*255)}]
    set g [expr {round($g*255)}]
    set b [expr {round($b*255)}]
    return [list $r $g $b]
 }


 proc hls2rgb {h l s} {
    # h, l and s are floats between 0.0 and 1.0, ditto for r, g and b
    # h = 0   => red
    # h = 1/3 => green
    # h = 2/3 => blue

    set h6 [expr {($h-floor($h)) * 6}]
    set r [expr {($h6 <= 3) ? (2-$h6) : ($h6-4)}]
    set g [expr {($h6 <= 2) ? ($h6) :
                 ($h6 <= 5) ? (4-$h6) : ($h6-6)}]
    set b [expr {($h6 <= 1) ? (-$h6) :
                 ($h6 <= 4) ? ($h6-2) : (6-$h6)}]
    set r [expr {max(0.0, min(1.0, double($r)))}]
    set g [expr {max(0.0, min(1.0, double($g)))}]
    set b [expr {max(0.0, min(1.0, double($b)))}]

    set r [expr {(($r-1) * $s + 1) * $l}]
    set g [expr {(($g-1) * $s + 1) * $l}]
    set b [expr {(($b-1) * $s + 1) * $l}]
    return [list $r $g $b]
 }

 # Demo
 set r 100
 set g 200
 set b 150
 foreach {h s v} [rgbToHsv $r $g $b] {}
 puts "rgb: $r $g $b -> hsv: $h $s $v"
 puts "back to hsv: [hsvToRgb $h $s $v]"
======
----
**See also**
   * [Color validation]
   * [Picking a range of colors]

<<categories>> GUI