Reputation: 157
I have around 1000 float values in the range(0.0, 100.0) and I want to map these values into a color(RGB). What I did so far is to create a colormap with 1000 color(RGB) values, use the float values to index the colormap and get an RGB value.
But the problem is, I'm loosing precision since I cast float values into int before using them as indices to my colormap. What is the best way to do this float to rgb conversion?
EDIT:
color color_list[100];
float float_values[1000]
for(i = 0 to 999)
{
int colormap_idx = float_values[i]; // Note that the float is converted into an int
color current_color = color_list[colormap_idx];
}
Upvotes: 3
Views: 5076
Reputation: 399
The total number of RGB values you can have is 256^3. It would be nice if you could utilize all of them, but sometimes it can be hard to come up with a nice intuitive mapping. Since there are a total possible of 256^4 floats (more than possible RGB values) you will lose precision no matter what you do, but you can still do much, much better than what you currently.
I don't know exactly what you are doing with the pre-defined color map, but consider defining only a few intermediate colors that correspond to a few intermediate floating values and interpolating each input floating point value. In the code below, fsample and csample are your corresponding points. For example:
fsample[0] = 0.0 -> csample[0] = (0, 0, 0)
fsample[1] = 0.25 -> csample[1] = (0, 0, 100)
fsample[2] = 0.5 -> csample[2] = (0, 170, 170)
fsample[3] = 0.75 -> csample[3] = (170, 170, 0)
fsample[4] = 1.0 -> csample[4] = (255, 255, 255)
This will allow you to cover a lot more ground in RGB space with floats, allowing a higher precision conversion, while still giving you some power to flexibly define intermediate colors. This is a fairly common method to convert grayscale to color.
There are a few optimizations and error checks you can apply to this code, but I left it unoptimized for the sake of clarity:
int N = float_values.size();
color colormap[N];
for(i = 0 to N)
{
colormap[i] = RGBFromFloat(float_values[i], fsample, csample, num_samples);
}
color RGBFromFloat(float in, float fsample[], float csample[], num_samples)
{
color out;
// find the interval that the input 'in' lies in
// this is a simple search on an ordered array...
// consider replacing with a better algorithm for a large number of samples
for(i = 0 to num_samples-1)
{
if(fsample[i] =< in && in < fsample[i+1])
{
out = interpolate(fsample[i], fsample[i+1], csample[i], csample[i+1], in);
break;
}
}
return color;
}
color interpolate(float flow, float fhigh, color clow, color chigh, float in)
{
float t = (in-flow)/(fhigh-flow);
return clow*(1 - t) + chigh*t
}
Upvotes: 3
Reputation: 6985
I don't know if this is the best method (since you gave us no optimality criteria), but if by "I'm losing precision" you mean that once converted to int, you only have a maximum of 100 different color combinations, then you can do this:
// this code is C99
#define MAX_FLOAT_VAL 100.0
#define N_COLORS 2000
#define N_FLOAT_SAMPLES 1000
color color_list[N_COLORS];
float float_values[N_FLOAT_SAMPLES];
// the following loop must be placed in some function
for( int i = 0; i < N_FLOAT_SAMPLES; i++ )
{
// the following assignment will map
// linearly a float in the range [0 ... MAX_FLOAT_VAL]
// into an int in the range [0 ... (N_COLORS-1)]
int colormap_idx = (float_values[i] / MAX_FLOAT_VAL) * (N_COLORS - 1);
color current_color = color_list[colormap_idx];
// ... do something with current_color ...
}
Of course you still have to generate the entries in color_list
with a suitable algorithm (I advice against doing that by hand :-). This is a whole different problem, since it involves more "degrees of freedom", since you try to map a 1-D space (the values of colormap_idx
) to a 3-D space (the set of all the possible RGB triples).
P.S: the requirements you seem to have remind me of the computations needed to colorize a fractal like the graphic representation of the Mandelbrot's set.
Hope this helps.
Upvotes: 1