Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Algorithm to convert any positive integer to an RGB value

Tags:

algorithm

rgb

We have a heatmap we want to display. The numbers that will make up the values being displayed are unknown (except that they will be positive integers). The range of numbers is also unknown (again, except that they will be posiitive integars). The range could be between 0 and 200 or 578 and 1M or whatever. It depends on the data, which is unknown.

We want to take an unknown range of positive integers and turn it into a scaled (compressed) range to be displayed with RGB values in a heatmap. I hope this makes sense. Thanks!

I want to clarify that the min/max values need to be "plugged" into the forumla.

like image 536
Richard Avatar asked Mar 03 '10 21:03

Richard


People also ask

How do you convert numbers to RGB?

Hex to RGB conversionGet the 2 left digits of the hex color code and convert to decimal value to get the red color level. Get the 2 middle digits of the hex color code and convert to decimal value to get the green color level.

How do you calculate RGB int?

RGB color space or RGB color system, constructs all the colors from the combination of the Red, Green and Blue colors. The red, green and blue use 8 bits each, which have integer values from 0 to 255. This makes 256*256*256=16777216 possible colors.

Why are RGB values on a scale of 0 to 255?

In RGB, a color is defined as a mixture of pure red, green, and blue lights of various strengths. Each of the red, green and blue light levels is encoded as a number in the range 0.. 255, with 0 meaning zero light and 255 meaning maximum light.


3 Answers

You need to first find the range of those values to get the min and max. Then you need to create a colour scale like the bar below this image. You can experiment with different functions to map an integer to an RGB. You need 3 functions R(X), G(X), B(X). Looking at the image below it loks like B(X) peaks in the middle, R(X) peaks at the end and green is somewhere else. As long as you make sure that you never get two (RGBs) for some value of X then you've got your conversion.

alt text
(source: globalwarmingart.com)

EDIT: Come to think of it you could sample some unit circle around YUV space. alt text http://www.biocrawler.com/w/images/e/ec/Yuv.png

Or even just download a high-res colour bar and sample that.

EDIT 2: I was just faced with color bar generation and remembered the MATLAB/Octave colorbar code. I plotted their data and got the following image. alt text

like image 105
Chris H Avatar answered Sep 22 '22 13:09

Chris H


You want to convert your data values to a frequency of light:

  • lower wavelength = cooler colors = blueish
  • higher wavelength = warmer colors = redder

The frequencies of visible light go from about 350nm (violet) to 650nm (red):

alt text
(source: gamonline.com)

The following function converts numbers in your specified range to the the range of visible light, then gets the rgb:

function DataPointToColor(Value, MinValue, MaxValue: Real): TColor; var    r, g, b: Byte;    WaveLength: Real; begin    WaveLength := GetWaveLengthFromDataPoint(Value, MinValue, MaxValue);    WavelengthToRGB(Wavelength, r, g, b);    Result := RGB(r, g, b); end; 

With the function i wrote off the top of my head:

function GetWaveLengthFromDataPoint(Value: Real; MinValues, MaxValues: Real): Real; const    MinVisibleWaveLength = 350.0;    MaxVisibleWaveLength = 650.0; begin    //Convert data value in the range of MinValues..MaxValues to the     //range 350..650     Result := (Value - MinValue) / (MaxValues-MinValues) *          (MaxVisibleWavelength - MinVisibleWavelength) +          MinVisibleWaveLength; end; 

And a function i found on the internets, that converts a wavelength into RGB:

PROCEDURE WavelengthToRGB(CONST Wavelength:  Nanometers;                           VAR R,G,B:  BYTE);   CONST     Gamma        =   0.80;     IntensityMax = 255;   VAR     Blue   :  DOUBLE;     factor :  DOUBLE;     Green  :  DOUBLE;     Red    :  DOUBLE;   FUNCTION Adjust(CONST Color, Factor:  DOUBLE):  INTEGER;   BEGIN     IF   Color = 0.0     THEN RESULT := 0     // Don't want 0^x = 1 for x <> 0     ELSE RESULT := ROUND(IntensityMax * Power(Color * Factor, Gamma))   END {Adjust}; BEGIN   CASE TRUNC(Wavelength) OF     380..439:       BEGIN         Red   := -(Wavelength - 440) / (440 - 380);         Green := 0.0;         Blue  := 1.0       END;     440..489:       BEGIN         Red   := 0.0;         Green := (Wavelength - 440) / (490 - 440);         Blue  := 1.0       END;     490..509:       BEGIN         Red   := 0.0;         Green := 1.0;         Blue  := -(Wavelength - 510) / (510 - 490)       END;     510..579:       BEGIN         Red   := (Wavelength - 510) / (580 - 510);         Green := 1.0;         Blue  := 0.0       END;     580..644:       BEGIN         Red   := 1.0;         Green := -(Wavelength - 645) / (645 - 580);         Blue  := 0.0       END;     645..780:       BEGIN         Red   := 1.0;         Green := 0.0;         Blue  := 0.0       END;     ELSE       Red   := 0.0;       Green := 0.0;       Blue  := 0.0   END;   // Let the intensity fall off near the vision limits   CASE TRUNC(Wavelength) OF     380..419:  factor := 0.3 + 0.7*(Wavelength - 380) / (420 - 380);     420..700:  factor := 1.0;     701..780:  factor := 0.3 + 0.7*(780 - Wavelength) / (780 - 700)     ELSE       factor := 0.0   END;   R := Adjust(Red,   Factor);   G := Adjust(Green, Factor);   B := Adjust(Blue,  Factor) END {WavelengthToRGB};  

Sample use:

Data set in the range of 10..65,000,000. And this particular data point has a value of 638,328:

color = DataPointToColor(638328, 10, 65000000); 
like image 25
Ian Boyd Avatar answered Sep 23 '22 13:09

Ian Boyd


Function for colorbar

// value between 0 and 1 (percent)   
function color(value) {
    var RGB = {R:0,G:0,B:0};

    // y = mx + b
    // m = 4
    // x = value
    // y = RGB._
    if (0 <= value && value <= 1/8) {
        RGB.R = 0;
        RGB.G = 0;
        RGB.B = 4*value + .5; // .5 - 1 // b = 1/2
    } else if (1/8 < value && value <= 3/8) {
        RGB.R = 0;
        RGB.G = 4*value - .5; // 0 - 1 // b = - 1/2
        RGB.B = 1; // small fix
    } else if (3/8 < value && value <= 5/8) {
        RGB.R = 4*value - 1.5; // 0 - 1 // b = - 3/2
        RGB.G = 1;
        RGB.B = -4*value + 2.5; // 1 - 0 // b = 5/2
    } else if (5/8 < value && value <= 7/8) {
        RGB.R = 1;
        RGB.G = -4*value + 3.5; // 1 - 0 // b = 7/2
        RGB.B = 0;
    } else if (7/8 < value && value <= 1) {
        RGB.R = -4*value + 4.5; // 1 - .5 // b = 9/2
        RGB.G = 0;
        RGB.B = 0;
    } else {    // should never happen - value > 1
        RGB.R = .5;
        RGB.G = 0;
        RGB.B = 0;
    }

    // scale for hex conversion
    RGB.R *= 15;
    RGB.G *= 15;
    RGB.B *= 15;

    return Math.round(RGB.R).toString(16)+''+Math.round(RGB.G).toString(16)+''+Math.round(RGB.B).toString(16);
}
like image 21
will Farrell Avatar answered Sep 25 '22 13:09

will Farrell