Converting RGB to RGBW

c#, color-management, color-theory, colors, rgb

Solution

I've finally figured out how to convert RGB to RGBW, turns out my previous method was completely wrong:

//Get the maximum between R, G, and B
float tM = Math.Max(Ri, Math.Max(Gi, Bi));

//If the maximum value is 0, immediately return pure black.
if(tM == 0)
   { return new rgbwcolor() { r = 0, g = 0, b = 0, w = 0 }; }

//This section serves to figure out what the color with 100% hue is
float multiplier = 255.0f / tM;
float hR = Ri * multiplier;
float hG = Gi * multiplier;
float hB = Bi * multiplier;  

//This calculates the Whiteness (not strictly speaking Luminance) of the color
float M = Math.Max(hR, Math.Max(hG, hB));
float m = Math.Min(hR, Math.Min(hG, hB));
float Luminance = ((M + m) / 2.0f - 127.5f) * (255.0f/127.5f) / multiplier;

//Calculate the output values
int Wo = Convert.ToInt32(Luminance);
int Bo = Convert.ToInt32(Bi - Luminance);
int Ro = Convert.ToInt32(Ri - Luminance);
int Go = Convert.ToInt32(Gi - Luminance);

//Trim them so that they are all between 0 and 255
if (Wo < 0) Wo = 0;
if (Bo < 0) Bo = 0;
if (Ro < 0) Ro = 0;
if (Go < 0) Go = 0;
if (Wo > 255) Wo = 255;
if (Bo > 255) Bo = 255;
if (Ro > 255) Ro = 255;
if (Go > 255) Go = 255;
return new rgbwcolor() { r = Ro, g = Go, b = Bo, w = Wo };

Any optimization ideas are more than welcome :)

Problem

I know this has already been asked, but the anwser given there doesn't work. I've spent over an hour looking for a formula or algorithm, but have found nothing. As a result, I've started writing my own algorithm to convert RGB to RGBW in the most efficient way possible. This is what I've currently got: ``` //'Ri', 'Gi', and 'Bi' correspond to the Red, Green, and Blue inputs. var M = Math.Max(Ri, Math.Max(Gi, Bi)); //The maximum value between R,G, and B. int Wo =0; //White output int Ro=0; //Red output int Go=0; //Green output int Bo=0; //Blue output int av = 0; //Average between the two minimum values int hR = 0; //Red with 100% hue int hG = 0; //Green with 100% hue int hB = 0; //Blue with 100% hue //These 4 lines serve to figure out what the input color is with 100% hue. float multiplier = 255.0f / M; hR = Convert.ToInt32(Ri * multiplier); hG = Convert.ToInt32(Gi * multiplier); hB = Convert.ToInt32(Bi * multiplier); //Depending on the maximum value, get an average of the least used colors, weighted for their importance in the overall hue. //This is the problematic part if (M == Ri) av = (Bi*hB + Gi*hG) / (hB+hG); else if (M == Gi) av = (Ri*hR + Bi*hB) / (hR+hB); else if (M == Bi) av = (Gi*hG + Ri*hR) / (hG+hR); //Set the rgbw colors Wo = av; Bo = Bi - av; Ro = Ri - av; Go = Gi - av; if (Wo < 1) Wo = 0; if (Bo < 1) Bo = 0; if (Ro < 1) Ro = 0; if (Go < 1) Go = 0; if (Wo > 255) Wo = 255; if (Bo > 255) Bo = 255; if (Ro > 255) Ro = 255; if (Go > 255) Go = 255; ``` It works fine if the color I'm dealing with is a primary color, but not in any other case. What would make it work everywhere? Am I even on the right track? EDIT: Here's a .gif of the issue I'm running into. the RGBW values are all the way at the bottom

Original source

Related problems