I know this is little bit old, but is worthy if someone is searching for it.
First of all, you can do interpolation in any color space, including RGB, which, in my opinion, is one of the easiest.
Let's assume the variation will be controlled by a fraction value between 0 and 1 (e.g. 0.3), where 0 means full color1 and 1 means full color2.
The theory:
Result = (color2 - color1) * fraction + color1
Applying:
As the RGB has 3 channels (red, green and blue) we have to perform this math for each one of the channels.
Using your example colors:
fraction: 0.3
color1: 151,206,255
color2: 114,127,157
R = (114-151) * fraction + 151
G = (127-206) * fraction + 206
B = (157-255) * fraction + 255
Code example in C/C++:
/**
* interpolate 2 RGB colors
* @param color1 integer containing color as 0x00RRGGBB
* @param color2 integer containing color as 0x00RRGGBB
* @param fraction how much interpolation (0..1)
* - 0: full color 1
* - 1: full color 2
* @return the new color after interpolation
*/
int interpolate(int color1, int color2, float fraction)
{
unsigned char r1 = (color1 >> 16) & 0xff;
unsigned char r2 = (color2 >> 16) & 0xff;
unsigned char g1 = (color1 >> 8) & 0xff;
unsigned char g2 = (color2 >> 8) & 0xff;
unsigned char b1 = color1 & 0xff;
unsigned char b2 = color2 & 0xff;
return (int) ((r2 - r1) * fraction + r1) << 16 |
(int) ((g2 - g1) * fraction + g1) << 8 |
(int) ((b2 - b1) * fraction + b1);
}
/*
* 0x0097ceff == RGB(151,206,255)
* 0x00727f9d == RGB(114,127,157)
*/
int new_color = interpolate(0x0097ceff, 0x00727f9d, 0.3f);
EDIT 1.
As pointed out by flying sheep, the RGB format may introduce some undesired colors during a blend operation. To solve this problem new steps may be added to the process: convert to linear RGB, perform the interpolation and then convert it back. Below a working example in C that also generates a PPM file for visualization.
/* vim: set sw=4 ts=4 nowrap hlsearch: */
#include <stdio.h>
#include <math.h>
#include <inttypes.h>
/**
* convert a single default RGB (a.k.a. sRGB) channel to linear RGB
* @param channel R, G or B channel
* @return channel in linear RGB
*/
float rgb2linear(uint8_t channel)
{
float s = channel / 255.0f;
return s <= 0.04045 ? s / 12.92 : pow((s + 0.055) / 1.055, 2.4);
}
/**
* convert a linear RGB channel to default RGB channel (a.k.a. sRGB)
* @param linear R, G or B channel in linear format
* @return converted channel to default RGB value
*/
uint8_t linear2rgb(float linear)
{
float s = linear <= 0.0031308 ? linear * 12.92 : 1.055 * pow(linear, 1.0/2.4) - 0.055;
return (uint8_t) (s * 255);
}
/**
* interpolate 2 RGB colors
* @param color1 integer containing color as 0x00RRGGBB
* @param color2 integer containing color as 0x00RRGGBB
* @param fraction how much interpolation (0..1)
* - 0: full color 1
* - 1: full color 2
* @return the new color after interpolation
*/
int interpolate(int color1, int color2, float fraction)
{
uint8_t in[3];
for(int x = 0; x < 3; x++) {
float c1 = rgb2linear((color1 >> (16 - x * 8)) & 0xff);
float c2 = rgb2linear((color2 >> (16 - x * 8)) & 0xff);
in[x] = linear2rgb((c2 - c1) * fraction + c1);
}
return in[0] << 16 | in[1] << 8 | in[2];;
}
/**
* example interpolating sRGB colors
* first the colors are converted to linear-RGB,
* interpolated and then converted back to sRGB
*/
int main(int argc, char *argv[])
{
float factor = 0.3f;
int c1 = 0x0097ceff; /* RGB(151,206,255) */
int c2 = 0x00727f9d; /* RGB(114,127,157) */
int nc = interpolate(c1, c2, factor);
printf("interpolate 0x%08x to 0x%08x ==> 0x%08x factor: %.2f\n", c1, c2, nc, factor);
/* create a PPM file to vizualize the interpolation
* gradients in 100 steps - PPM files may be opened
* in Gimp or other image editors */
FILE *f = fopen("interpolate.ppm", "w");
if(f) {
/* PPM file header */
fprintf(f, "P3\n");
fprintf(f, "707 50\n");
fprintf(f, "255\n");
/* iterate over the rows */
for(int x = 0; x < 50; x++) {
/* iterate over the steps */
for(int k = 0; k <= 100; k++) {
factor = k * 0.01f;
nc = interpolate(c1, c2, factor);
/* iterate over the cols */
for(int y = 0; y < 7; y++) {
fprintf(f, "%d %d %d%s", (nc >> 16) & 0xff, (nc >> 8) & 0xff, nc & 0xff, k+1 > 100 && y+1 >= 7 ? "\n" : " ");
}
}
}
fclose(f);
}
return 0;
}
PPM image: