*extremely* weird—all rgb to hsl converters always return 1.0

I should say I have had this same result with many different lua RGB to HSB converters.

I am trying to find just the saturation value of an rgb color.

No matter what formula I find online, or that I get out of ChatGPT, I always always always get back an s value of 1.0.

Here is just one example. For any Rgb value I put in here, I get 1.0 back:

  function saturationFromColor(c)
            local r, g, b = c.r / 255, c.g / 255, c.b / 255
            local max = math.max(r, g, b)
            local min = math.min(r, g, b)
            local c = max - min
            local h, s, b = 0, 0, 0
            
            if c == 0 then
                h = 0
            elseif max == r then
                h = ((g - b) / c) % 6
            elseif max == g then
                h = ((b - r) / c) + 2
            else
                h = ((r - g) / c) + 4
            end
            
            h = h * 60
            
            if max == 0 then
                s = 0
            else
                s = c / max
            end
            
            b = max
            
            return s
end

ChatGPT was going crazy because no matter what code it gave me I kept telling it “this doesn’t work”. Does anybody else have the same result?

@UberGoober I get values other than 1 for s. If I use r,g,b as 255,128,64 then I get

h = 40.20942408377
s = 0.74901960784314
b= 1.0

Anytime either r,g,b is 0, you’ll get s = 1. Since s= (max - min) / max, you’ll get (max - 0) / max. That will always be 1.

Edit: I also noticed that your using local r,g,b and local h,s,b. You’re setting h,s,b to 0’s which will 0 out the b for r,g,b.

1 Like

@UberGoober See the RGB to HSV conversion program I just put on WebRepo.

1 Like

You could use this:

 local RGBToHSB = function(vals) -- converts: RGB to HSB (Hue,Saturation,Brightness) 
     local r,g,b = vals.r/255, vals.g/255, vals.b/255 -- normalized properties
     local max,min = math.max(r,g,b),math.min(r,g,b)
     local chroma = (r == 0 or g == 0 or b == 0) and max or max - min
     local hue = chroma == 0 and 0 or max == r and 60 * (((g - b)/chroma) % 6) or
      max == g and 60 * (((b - r)/chroma) + 2) or max == b and 60 * (((r - g)/chroma) + 4)
     local b,s = max; s = chroma == 0 and 0 or chroma/b 
   return {h = hue, s = s, b = b} end -- returns: (table) HSB Values {h = ?, s = ?, b = ?}

You could also check this out Colors.lua. I created this a few years ago for converting between color spaces. You could get the correct values by doing something like

color(255,128,244):toHSB()

Thanks guys! Looks good.

That’s a condensed way of doing it. I find it very hard to figure out what’s really happening though. I understand the and/or/xor etc tables but that doesn’t help much. It’s like I have to take each group and determine true/false then determine and/or of what else it’s doing. You also have to determine how the values of the variables affect everything, true if not 0, otherwise false. I would never attempt to code anything like that, but I guess if you do code like that, it gets easier. I just wouldn’t want to debug someone’s code that had a lot of that in it.

This is the equivalent code with the if / elseif / else syntax. I just find that the code is more condensed too using the and / or syntax as you don’t have to assign variables multiple times.

local RGBToHSB = function(vals) -- converts: RGB to HSB (Hue,Saturation,Brightness) 
    local r,g,b = vals.r/255, vals.g/255, vals.b/255 -- normalized properties
    local max,min = math.max(r,g,b),math.min(r,g,b)
    
    local chroma 
    if r == 0 or g == 0 or b == 0 then
       chroma = max
    else 
       chroma = max - min 
    end
    
    local hue
    if chroma == 0 then
        hue = 0
    elseif max == r then 
        hue = 60 * (((g - b)/chroma) % 6)
    elseif max == g then
        hue = 60 * (((b - r)/chroma) + 2)
    elseif max == b then
        hue = 60 * (((r - g)/chroma) + 4)
    end
    
    local b = max
    
    local s
    if chroma == 0 then 
        s = 0
    else
        s = chroma / b
    end

    return {h = hue, s = s, b = b}  -- returns: (table) HSB Values {h = ?, s = ?, b = ?}

end

@Beckett2000 I don’t know if you’re using WebRepo yet, but I have an RGB to HSV program there. If you don’t, here is the program.

-- Convert RGB to HSV

viewer.mode=FULLSCREEN

function setup()
    rectMode(CENTER)
    boxR=input(WIDTH/2-100,HEIGHT-200,90,30,1,"R")  
    boxG=input(WIDTH/2-100,HEIGHT-275,90,30,1,"G")
    boxB=input(WIDTH/2-100,HEIGHT-350,90,30,1,"B")     
    boxH=input(WIDTH/2,HEIGHT-200,90,30,2,"H")  
    boxS=input(WIDTH/2,HEIGHT-275,90,30,2,"S") 
    boxV=input(WIDTH/2,HEIGHT-350,90,30,2,"V") 
    boxC=input(WIDTH/2+100,HEIGHT-200,90,30,2,"RGB Color") 
    boxX=input(WIDTH/2+100,HEIGHT-275,90,30,2,"RGB Hex") 
    
    boxTab={boxR,boxG,boxB,boxH,boxS,boxV,boxC,boxX}
end

function draw()
    background(32, 59, 83)         -- screen color
    headings()
    for nbr,box in pairs(boxTab) do             -- loop thru table  
        box:draw()                            -- draw each box
    end
end

function headings()
    pushStyle()
    fontSize(36)
    fill(255,0,0)
    text("RGB to HSV Converter",WIDTH/2,HEIGHT-50)   -- draw text
    fontSize(20)
    fill(224, 149, 127, 255)            -- set color
    text("( Tap each R, G, B box to input a value )",WIDTH/2,HEIGHT-100)
    popStyle()
end

function touched(t)                     -- check which box is selected
    for nbr,box in pairs(boxTab) do     -- loop thru table
        if box:touched(t) then          -- box touched
            return                      -- exit function
        end
    end  
end

function keyboard(k)
    for nbr,box in pairs(boxTab) do -- loop thru table
        box:keyboard(k)             -- get input from box
    end  
end

input=class()

input.msg=""
input.str=""

function input:init(x,y,w,h,type,txt)
    self.x=x            -- x position
    self.y=y            -- y position
    self.w=w            -- width
    self.h=h            -- height
    self.type=type      -- 1=input box  2=output box
    self.txt=txt        -- text to show above box
    self.val="0"        -- data keyed in box
    self.sel=false      -- box selected true/false
end

function input:draw()
    pushStyle()
    fill(0)                         -- set background for box
    if self.txt=="RGB Color" then
        self.val=""
        fill(boxR.val,boxG.val,boxB.val)
    end
    if self.txt=="RGB Hex" then
        self.val=string.format("%02X%02X%02X",boxR.val,boxG.val,boxB.val)
    end
    if self.sel then                    -- set selected color for box
        fill(105, 101, 31, 255)
        if input.msg~="" then
            fill(0,255,0)
            text(input.msg,WIDTH/2,HEIGHT-140)
        end
    end
    stroke(255)                     -- box outline color
    strokeWidth(2)                      -- outline size
    rect(self.x,self.y,self.w,self.h)   -- draw box
    fill(255)                       -- set text color
    text(self.txt,self.x,self.y+self.h) -- box name
    text(self.val,self.x+4,self.y)      -- box text
    popStyle()
end

function input:keyboard(k)
    if self.sel then
        if input.msg~="" then
            input.msg=""
            self.val="0"
            input.str="0"
        end
        if k==BACKSPACE then            -- backspace key pressed
            input.str=string.sub(input.str,1,#input.str-1) -- remove last digit
            if #input.str==0 then
                input.str="0"
            end
        elseif k>="0" and k<="9" then           -- only digits 1 thru 9
            if string.sub(input.str,1,1) =="0" then
                input.str=""                    -- clear leading 0
            end
            input.str=input.str..k              -- update keyed value
        end
        self.val=input.str                      -- save keyed value
        if math.tointeger(self.val)>255 then    -- check valid range
            input.str=""
            input.msg="ERROR:  Must be 0-255"
        end
        input:convert()
    end
end

function input:touched(t)
    if t.state==BEGAN then
        input.msg=""
        if not isKeyboardShowing() then
            showKeyboard()      -- show keyboard if its not displayed
        end 
        input.str="0"           -- set to 0
        for z=1,#boxTab do      -- clear selected flag for all boxes
            boxTab[z].sel=false
        end
        -- check which box was selected
        if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
        t.y>self.y-self.h/2 and t.y<self.y+self.h/2 and self.type==1 then
            self.val="0"        -- reset val
            self.sel=true       -- set selected flag
            return true         -- box selected
        end
    end 
    return false                -- no box selected
end

function input:convert()        -- convert RGB to HSV
    local r=math.tointeger(boxR.val)/255
    local g=math.tointeger(boxG.val)/255
    local b=math.tointeger(boxB.val)/255
    local max,min=math.max(r,g,b),math.min(r,g,b)
    local diff=max-min h,s,v=0,0,0
    if diff==0 then
        h=0
    else
        if max==r then
            h=(((g-b)/diff)%6)*60
        end
        if max==g then
            h=(((b-r)/diff)+2)*60
        end
        if max==b then
            h=(((r-g)/diff)+4)*60
        end
    end 
    if max==0 then
        s=0
    else
        s=(diff/max)
    end 
    boxH.val=string.format("%d°",h//1)  
    boxS.val=string.format("%2.1f%%",s*100)
    boxV.val=string.format("%2.1f%%",max*100)
end

@dave1707 I ran your program code and it looks pretty good. It’s useful to have an example which shows the values and resulting color. The only differences I saw in your conversion were that you scale your values to 100. I originally did this in colors.lua, but didn’t here to make the values match those gotten by UberGoober. I don’t know how to use WebRepo though. If you could let me know I would appreciate it.

@Steppers Can you help out here. I don’t know where the latest zip is.

@dave1707 1.0.3 Should be on WebRepo now.
Sourced from here: https://codeawebrepo.co.uk/RGB-HSV/1.0.3/project.zip

WebRepo download: https://codeawebrepo.co.uk/webrepo_latest.zip

@Beckett2000 Just tap on the zip file and that should load WebRepo.

@dave1707 @WebRepo-Automation Thank you for sharing. This is really cool. I used to be active on the Codea forum back in 2014 and I don’t think this existed.

1 Like