Converting an RGBW color to a standard RGB/HSB representation

13.2k views Asked by At

I am building an interface for light management in a home automation system. I managed to control standard on/off and dimmable light for various providers with little problem, but now I am stuck with a problem related to RGB light.

The light I am currently using is an RGBW led strip - specifically, I am working with a low-cost RGBW light: the light is composed by four led and every led can be controlled individually.

To be more clear - I am working on some c# code that should retrieve the currently selected color and display it in the UI, and enable the user to specify a new color for the light. For setting the color and retrieving it I must use a command provider that enables me to send and receive commands via a web service.

The provider works with RGBW colors - the four component for Red, Green, Blue and White are used. To represent the current light color on my interface I would like to translate the RGBW color returned by the service to a more standard RGB/HSB scheme.

Searching the web, the only reference for color conversion that I found (excluding a c++ sample for rgb to rgbw conversion that, based on my understanding, must have some severe bug) is this article that shows a conversion from HSI to RGBW, which is the inverse of what I needed: link here

I am searching for some insight about how I can achieve this conversion (or a simple explanation of why it isn't possible). As far as I get the conversion from RGB to an RGBW is arbitrary - a single RGB value can be represented as multiple RGBW values, but the opposite conversion should be univocal. Also note that while I am using c#, feel free to refer to algorithms in other language too - language isn't the problem, the problem is that I don't know the math to do the color conversion.

4

There are 4 answers

0
cobra18t On BEST ANSWER

I have been reviewing the answer suggested by Roberto but the colors seemed dimmer and undersaturated in many cases. Taking the example of RGB = (255,255,2) leads to RGBW = (128,128,1,2).

Digging further, it seems that the paper by Chul Lee has an error in its equation for K. The equation, which comes from a paper by Lili Wang ("Trade-off between luminance and color in RGBW displays for mobile-phone usage") is actually:

K = (Wo + M)/M

Note that it is a capital M, not a lowercase m. Given this change, you also do not need Q since it scales properly by nature. Using the new K on the same RGB = (255,255,2) example leads to a much more reasonable RGBW = (255,255,0,2).

Putting it all together:

M = max(Ri,Gi,Bi)
m = min(Ri,Gi,Bi)

Wo = if (m/M < 0.5) use ( (m*M) / (M-m) ) else M 
K = (Wo + M) / M
Ro = floor[ ( K * Ri ) - Wo ]
Go = floor[ ( K * Gi ) - Wo ]
Bo = floor[ ( K * Bi ) - Wo ]
1
Oliver On

I know this is a fairly old question, but I'm looking at the RGB->RGBW algorithm and found this article which - whilst not the answer - may help?

http://web.archive.org/web/20101008153429/http://www.nouvoyance.com:80/files/pdf/Adding-a-White.pdf

In this, they suggest one conversion for RGB->RGBW is simply to create the W from min(R, G, B).

  • R -> R
  • G -> G
  • B -> B
  • W -> min(R, G, B)

The reverse of this (for your scenario) would simply be to throw away the W.

  • R -> R
  • G -> G
  • B -> B
  • W -> null
0
iamh2o On

A little late, but this still amazingly seems to be a tough thing to find tooling for.

This repo can do the job for you: https://github.com/iamh2o/rgbw_colorspace_converter/

I wrote this module with a friend in such a way that 'color' objects could be instantiated via several color systems, and the object could spit out translations to all the other colorsystems it supports- which after a LOT of research (a key piece being https://www.neltnerlabs.com/saikoled/how-to-convert-from-hsi-to-rgb-white ), we finally nailed the [HSI/HSL/HSV/RGB/HEX] -> RGBW conversion.

There are a ton of packages that have the general colorspace problem solved, but it seems the RGBW case is pretty specific to physical lighting/leds, and not applicable to digital displays, RGBW was not included in any modules I'd looked at.

And the killer feature of this module is that the color objects you instantiate can be manipulated in several color systems depending on your needs (different ones that you created it in), and it will keep all of the translations to the other spaces up to date- and it's super fast, we've not yet had it be a frame rate limiting component.

So something like this would be a loop through the fully bright, fully saturated rainbow (note how the RGB vs the HSV codes are far less amenable to programatic manipulation):

from rgbw_colorspace_converter.colors.converters import RGB

color = RGB(255,0,0)

ctr = 0

while ctr < 10:
     color.hsv_h += .1
     print(f"HSV:{color.hsv}  RGB:{color.rgb}  HSI:{color.hsi} HEX:{color.hex}")
     ctr += 1

# "H" in hsv is actually expressed in 360 degrees, and it is cylindrical. We've normalized it to being between 0-1 (so H=0=H=1 - both are red)
HSV:(0.0, 1.0, 1.0)  RGB:(255, 0, 0)  HSI:(0.0, 1.0, 0.33333) HEX:#ff0000
HSV:(0.1, 1.0, 1.0)  RGB:(255, 153, 0)  HSI:(36.0, 1.0, 0.533328) HEX:#ff9900
HSV:(0.2, 1.0, 1.0)  RGB:(203, 255, 0)  HSI:(72.23529411764707, 1.0, 0.5986868235294117) HEX:#cbff00
HSV:(0.3, 1.0, 1.0)  RGB:(51, 255, 0)  HSI:(108.0, 1.0, 0.399996) HEX:#33ff00
HSV:(0.4, 1.0, 1.0)  RGB:(0, 255, 102)  HSI:(144.0, 1.0, 0.46666199999999997) HEX:#00ff66
HSV:(0.5, 1.0, 1.0)  RGB:(0, 255, 255)  HSI:(180.0, 1.0, 0.66666) HEX:#00ffff
HSV:(0.6, 1.0, 1.0)  RGB:(0, 102, 255)  HSI:(216.0, 1.0, 0.46666199999999997) HEX:#0066ff
HSV:(0.7, 1.0, 1.0)  RGB:(50, 0, 255)  HSI:(251.76470588235296, 1.0, 0.39868882352941176) HEX:#3200ff
HSV:(0.8, 1.0, 1.0)  RGB:(204, 0, 255)  HSI:(288.0, 1.0, 0.599994) HEX:#cc00ff
HSV:(0.9, 1.0, 1.0)  RGB:(255, 0, 152)  HSI:(324.2352941176471, 1.0, 0.5320208235294118) HEX:#ff0098
HSV:(1.0, 1.0, 1.0)  RGB:(255, 0, 0)  HSI:(0.0, 1.0, 0.33333) HEX:#ff0000

3
Roberto Cantanhede On

How to convert RGB to RGBW is described in item 2.1 of the following paper

http://www.mirlab.org/conference_papers/International_Conference/ICASSP%202014/papers/p1214-lee.pdf

Think of your leds as a huge pixel. Oliver's answer uses Wo = min(Ri,Gi,Bi), what is computationaly cheap and just works. This paper explains other alternatives to minimize power consumption, what is good for a home automation project. I'm also on a home automation project with OpenHAB, Arduino and RGBW leds and on the one hand paper proposed alternative would be good, on the other hand a huge LUT would just not work and convert all values on arduino eighter. I would suggest you to try correcting RGB values using not so energy eficient technics as cited in the paper:

Assuming Ri, Gi, Bi are color inputs, integers from 0 to 255, so Q = 255 and that your outputs are Wo, Ro, Go and Bo with values from 0 to 255:

M = max(Ri,Gi,Bi)
m = min(Ri,Gi,Bi)

Wo = if (m/M < 0.5) use ( (m*M) / (M-m) ) else M 
Q = 255
K = (Wo + M) / m
Ro = floor( [ ( K * Ri ) - Wo ] / Q )
Go = floor( [ ( K * Gi ) - Wo ] / Q )
Bo = floor( [ ( K * Bi ) - Wo ] / Q )

Exercise it in a spreadsheet before implementing, experiment on Wo = m, m^2 and -m^3+m^2+m, correct Wo value with the right Qw and you will be surprised that the simple solution without correction is not what one would expect and that other answers do not vary that much. Check the paper for color distortion results, I suppose that if you do not correct RGB values you will end up with some washed out colors.