Fastest formula to get Hue from RGB - colors

If you are given red, green, and blue values that range from 0-255, what would be the fastest computation to get just the hue value? This formula will be used on every pixel of a 640x480 image at 30fps (9.2 million times a second) so every little bit of speed optimization helps.
I've seen other formulas but I'm not happy with how many steps they involve. I'm looking for an actual formula, not a built in library function.

Convert the RGB values to the range 0-1, this can be done by dividing the value by 255 for 8-bit color depth (r,g,b - are given values):
R = r / 255 = 0.09
G = g / 255 = 0.38
B = b / 255 = 0.46
Find the minimum and maximum values of R, G and B.
Depending on what RGB color channel is the max value. The three different formulas are:
If Red is max, then Hue = (G-B)/(max-min)
If Green is max, then Hue = 2.0 + (B-R)/(max-min)
If Blue is max, then Hue = 4.0 + (R-G)/(max-min)
The Hue value you get needs to be multiplied by 60 to convert it to degrees on the color circle. If Hue becomes negative you need to add 360 to, because a circle has 360 degrees.
Here is the full article.

In addition to Umriyaev's answer:
If only the hue is needed, it is not required to divide the 0-255 ranged colours with 255.
The result of e.x. (green - blue) / (max - min) will be the same for any range (as long as the colours are in the same range of course).
Here is the java example to get the Hue:
public int getHue(int red, int green, int blue) {
float min = Math.min(Math.min(red, green), blue);
float max = Math.max(Math.max(red, green), blue);
if (min == max) {
return 0;
}
float hue = 0f;
if (max == red) {
hue = (green - blue) / (max - min);
} else if (max == green) {
hue = 2f + (blue - red) / (max - min);
} else {
hue = 4f + (red - green) / (max - min);
}
hue = hue * 60;
if (hue < 0) hue = hue + 360;
return Math.round(hue);
}
Edit: added check if min and max are the same, since the rest of the calculation is not needed in this case, and to avoid division by 0 (see comments)
Edit: fixed java error

Probably not the fastest but this is a JavaScript function that you can try directly in the browser by clicking the "Run code snippet" button below
function rgbToHue(r, g, b) {
// convert rgb values to the range of 0-1
var h;
r /= 255, g /= 255, b /= 255;
// find min and max values out of r,g,b components
var max = Math.max(r, g, b), min = Math.min(r, g, b);
// all greyscale colors have hue of 0deg
if(max-min == 0){
return 0;
}
if(max == r){
// if red is the predominent color
h = (g-b)/(max-min);
}
else if(max == g){
// if green is the predominent color
h = 2 +(b-r)/(max-min);
}
else if(max == b){
// if blue is the predominent color
h = 4 + (r-g)/(max-min);
}
h = h*60; // find the sector of 60 degrees to which the color belongs
// https://www.pathofexile.com/forum/view-thread/1246208/page/45 - hsl color wheel
// make sure h is a positive angle on the color wheel between 0 and 360
h %= 360;
if(h < 0){
h += 360;
}
return Math.round(h);
}
let gethue = document.getElementById('gethue');
let r = document.getElementById('r');
let g = document.getElementById('g');
let b = document.getElementById('b');
r.value = Math.floor(Math.random() * 256);
g.value = Math.floor(Math.random() * 256);
b.value = Math.floor(Math.random() * 256);
gethue.addEventListener('click', function(event) {
let R = parseInt(r.value)
let G = parseInt(g.value)
let B = parseInt(b.value)
let hue = rgbToHue(R, G, B)
console.log(`Hue(${R}, ${G}, ${B}) = ${hue}`);
});
<table>
<tr><td>R = </td><td><input id="r"></td></tr>
<tr><td>G = </td><td><input id="g"></td></tr>
<tr><td>B = </td><td><input id="b"></td></tr>
<tr><td colspan="2"><input id="gethue" type="button" value="Get Hue"></td></tr>
</table>

The web page Math behind colorspace conversions, RGB-HSL covers this however it contains what I believe is an error. It states for hue calculation to divide by max-min however if you divide by this fractional amount the value increases and easily exceeds the full expected range of -1 to 5. I found multiplying by max-min to work as expected.
Instead of this:
If Red is max, then Hue = (G-B)/(max-min)
If Green is max, then Hue = 2.0 + (B-R)/(max-min)
If Blue is max, then Hue = 4.0 + (R-G)/(max-min)
I suggest this:
If Red is max, then Hue = (G-B)*(max-min)
If Green is max, then Hue = 2.0 + (B-R)*(max-min)
If Blue is max, then Hue = 4.0 + (R-G)*(max-min)

You must specify which language and platform you're using because C#, Java and C are very different languages and the performance also varies among them and among the platforms. The question is currently too broad!!!
640×480 is not very large compared to current common resolutions, but "fastest" is subjective and you need to do careful benchmarking to choose which is best for your usecase. An algorithm that looks longer with many more steps isn't necessarily slower than a shorter one because instruction cycles are not fixed and there are many other factors that affect performance such as cache coherency and branch (mis)predictions.
For the algorithm Umriyaev mentioned above, you can replace the division by 255 with a multiplication by 1.0/255, that'll improve performance with a tiny acceptable error.
But the best way will involve vectorization and parallelization in some way because modern CPUs have multiple cores and also SIMD units to accelerate math and multimedia operations like this. For example x86 has SSE/AVX/AVX-512... which can do things on 8/16/32 channels at once. Combining with multithreading, hardware acceleration, GPU compute.... it'll be far better than any answers in this question.
In C# and Java there weren't many vectorization options in the past so with older .NET and JVM versions you need to run unsafe code in C#. In Java you can run native code through JNI. But nowadays all of them also had vectorized math support. Java had a new Vector API in JEP-338. In Mono you can use the vector type in the Mono.Simd namespace. In RyuJIT there's Microsoft.Bcl.Simd. In .NET 1.6+ there's System.Numerics which includes Vector and other
... SIMD-enabled vector types, which include Vector2, Vector3, Vector4, Matrix3x2, Matrix4x4, Plane, and Quaternion.
How to use the Intel AVX in Java?
Parallelism on a Single Core - SIMD with C#
SIMD in Depth - Performance and Cost in C# and C++
Will .NET ever do intelligent SIMD?
Using System.Numerics.Vector for Graphics Programming
System.Numerics.Vectors 'Vector<T>': is it basically just System.UInt128?
Performance Gains with Data Parallelism: Using SIMD Instructions from C#

You could use one of the mathematical techniques suggested here, but instead of doing it on every pixel, do it on a random sample of ~10% of the pixels. This is still very likely to have high accuracy and will be 10x as fast.

Related

Convert 24-bit color to 4-bit RGBI

I need to convert 24-bit colors to 4-bit RGBI (1 bit for Red, Green, Blue + Intensity).
Converting to 3-bit RGB is rather simple: set color bit if greater than 127, clear otherwise. However, there's only one intensity bit for all three channels, so what's the correct way to set it (if any)?
First I thought about dividing 8-bit channel to three parts like below:
if 0 <= color <= 85, then clear rgbi-color bit
if 86 <= color <= 170, then set rgbi-color bit
if 171 <= color <= 255, then set rgbi-color bit and intensity
But then I thought that probably the correct way would be to set intensity bit only if two of three channels are greater than 127. But in that case pure R, G, or B will not have intensity ever set (for example, in case of rbg(0,0,200)
Any advice is highly appreciated
A simple way to find the closest 4-bit RGBI approximation of a color is to consider the two possibilities for the intensity bit separately. That is to say, first find the closest RGB0 and RGB1 approximations for the color (which is easy to do, just by dividing each color axis at the appropriate point), and the determine which of these approximations is better.
Here's a simple C-ish pseudocode description of this algorithm:
// find the closest RGBx approximation of a 24-bit RGB color, for x = 0 or 1
function rgbx_approx(red, green, blue, x) {
threshold = (x + 1) * 255 / 3;
r = (red > threshold ? 1 : 0);
g = (green > threshold ? 1 : 0);
b = (blue > threshold ? 1 : 0);
return (r, g, b);
}
// convert a 4-bit RGBI color back to 24-bit RGB
function rgbi_to_rgb24(r, g, b, i) {
red = (2*r + i) * 255 / 3;
green = (2*g + i) * 255 / 3;
blue = (2*b + i) * 255 / 3;
return (red, green, blue);
}
// return the (squared) Euclidean distance between two RGB colors
function color_distance(red_a, green_a, blue_a, red_b, green_b, blue_b) {
d_red = red_a - red_b;
d_green = green_a - green_b;
d_blue = blue_a - blue_b;
return (d_red * d_red) + (d_green * d_green) + (d_blue * d_blue);
}
// find the closest 4-bit RGBI approximation (by Euclidean distance) to a 24-bit RGB color
function rgbi_approx(red, green, blue) {
// find best RGB0 and RGB1 approximations:
(r0, g0, b0) = rgbx_approx(red, green, blue, 0);
(r1, g1, b1) = rgbx_approx(red, green, blue, 1);
// convert them back to 24-bit RGB:
(red0, green0, blue0) = rgbi_to_rgb24(r0, g0, b0, 0);
(red1, green1, blue1) = rgbi_to_rgb24(r1, g1, b1, 1);
// return the color closer to the original:
d0 = color_distance(red, green, blue, red0, green0, blue0);
d1 = color_distance(red, green, blue, red1, green1, blue1);
if (d0 <= d1) return (r0, g0, b0, 0);
else return (r1, g1, b1, 1);
}
Alternatively, you could simply use any generic fixed-palette color quantization algorithm. This may yield better results if your actual color palette is not a pure evenly spaced RGBI palette like the code above assumes, but rather something like e.g. the CGA tweaked RGBI palette.

Scrolling through colors effect in RGB

I want to create a colour scroller effect. I have a function that I give it RGB values (eg. setColor(189,234,45)) and I want to change the colour rapidly but I don't want to get many repeats to create an effect of scrolling through the colours.
I have tried tried the following but it doesn't quite generate the effect that I am looking for.
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
for (int k = 0; k < 256; k++) {
setColor(i, j, k);
}
}
}
I wanted to know if anyone knows how the colour scroller's colours are arranged next to each other. The arrangement I am looking for looks like the scroll on the right.
The colors you are working with are represented as R,G,B (red green blue) values. However, another
way to think about color is hue, saturation, value. In the scroll image you are trying to emulate,
it is the hue that is changing - the saturation and value (brightness) are unaffected.
Here is a function that happens to make a hue-cycle gradient like the one in the image you linked to:
int n = 256; // number of steps
float TWO_PI = 3.14159*2;
for (int i = 0; i < n; ++i) {
int red = 128 + sin(i*TWO_PI/n + 0) + 127;
int grn = 128 + sin(i*TWO_PI/n + TWO_PI/3) + 127;
int blu = 128 + sin(i*TWO_PI/n + 2*TWO_PI/3) + 127;
setColor(red, grn, blu);
}
To understand how that function works, I recommend that you read my color tutorial that GreenAsJade linked to.
However, that kind of gradient function isn't quite what you need, because you want to start from a particular color you are passing in, and then go to the next color in the sequence. It's much easier to do this kind of thing if you represent your colors as HSV triplets (or HSB triplets), instead of RGB triplets. Then you can manipulate just the hue component, and get those kind of rainbow effects. In helps to have a set of function that can convert from RGB to HSV and back again.
This site contains a bunch of color conversion source code, including the ones you need for those conversions. Using the two conversion functions supplied on that page, your code might look like:
void cycleMyColor(int *r, int *g, int *b) {
float h,s,v, fr,fg,fb;
RGBtoHSV(*r/255.0,*g/255.0,*b/255.0,&h,&s,&v);
h += 1/256.0; // increment the hue here
h -= (int) h; // and cycle around if necessary
HSVtoRGB(&fr,&fg,&fb,h,s,v);
*r = fr*255; *g = fg*255; *b = fb*255;
setColor(*r,*g,*b);
}
This code is a little more complicated than it needs to be because the color conversions on that site use floating point color components that go from 0-1, instead of integers that go from 0-255, as you were using, so I'm spending a few lines converting between those two representations. You may find it simpler to just keep your color in HSB space, and then convert to RGB when you want to display it.
As you mentioned in your edit, you don't like the sequence of colours, because you start from black an end at white, instead of starting at one end of the rainbow and going to the other.
So you are going to need to work out a sequence of RGB that goes from blue through green and yellow to red. That means you need to start with (0,0,255) and end at (255, 0, 0), and don't pass through (255,255,255) or (0,0,0) - in a nutshell, that's how its done.
There are many ways you could do this and get a pleasing effect - beyond the scope of an answer here. This article explores it in depth:
http://krazydad.com/tutorials/makecolors.php

Converting images into a linear color palette with JS, losing colors

The project in question: https://github.com/matutter/Pixel2 is a personal project to replace some out of date software at work. What it should do is, the user adds an image and it generates a color palette of the image. The color palette should have no duplicate colors. (thats the only important stuff)
My question is: why do larger or hi-res or complex images not work as well? (loss of color data)
Using dropzone.js I have the user put a picture on the page. The picture is a thumbnail. Next I use jquery to find the src out of a <img src="...">. I pass that src to a function that does this
function generate(imgdata) {
var imageObj = new Image();
imageObj.src = imgdata;
convert(imageObj); //the function that traverses the image data pulling out RGB
}
the "convert" function pulls out the data fairly simply by
for(var i=0, n=data.length; i<n; i+=4, pixel++ ) {
r = data[i];
g = data[i+1];
b = data[i+2];
color = r + g + b; // format is a string of **r, g, b**
}
finally, the last part of the main algorithme filters out duplicate colors, I only want just 1 occurrence of each... here's the last part
color = monoFilter(color); // the call
function monoFilter(s) {
var unique = [];
$.each(s, function(i, el){
if($.inArray(el, unique) === -1) unique.push(el);
});
unique.splice(0,1); //remove undefine
unique.unshift("0, 0, 0"); //make sure i have black
unique.push("255, 255, 255"); //and white
return unique;
}
I'm hoping someone can help me identify why there is such a loss of color data in big files.
If anyone is actually interesting enough to look at the github, the relivent files are js/pixel2.js, js/dropzone.js, and ../index.html
This is probably the cause of the problem:
color = r + g + b; // format is a string of **r, g, b**
This simply adds the numbers together and the more pixels you have the higher risk you run to get the same number. For example, these colors generate the same result:
R G B
color = 90 + 0 + 0 = 90;
color = 0 + 90 + 0 = 90;
color = 0 + 0 + 90 = 90;
even though they are completely different colors.
To avoid this you can do it like this if you want a string:
color = [r,g,b].join();
or you can create an integer value of them (which is faster to compare with than a string):
color = (b << 16) + (g << 8) + r; /// LSB byte-order
Even an Euclidean vector would be better:
color = r*r + g*g + b*b;
but with the latter you risk eventually the same scenario as the initial one (but useful for nearest color scenarios).
Anyways, hope this helps.
"The problem was that I wasn't accounting for alpha. So a palette from an image that uses alpha would have accidental duplicate records."
I figured this out after finding this Convert RGBA color to RGB

Why doesn't hue rotation by +180deg and -180deg yield the original color?

By reading HSL/HSV color theory, I get the impression that hue component is a cyclical attribute that repeats every 360 degrees and can be changed independently of saturation and lightness/value. Correct me if I am wrong, but these statements logically follow the previous definition:
Rotating hue by 360 degrees yields the same color
Rotating hue by 180 degrees twice yields the original color
Rotating hue by 180 degrees followed by -180 degrees yields the original color
However, only the option 1 is correct. Rotating hue 4 times by +90 degrees yields a color that isn't even remotely similar to the original.
Furthermore, using -webkit-filter and SVG's
<filter><feColorMatrix in="SourceGraphic" type="hueRotate" values="..." /></filter>
don't produce the same result for the same rotation. On the other hand, colors produced by SVG filters are consistent across browsers.
Is there any "hidden" property of hue rotation that makes the operation not associative?
Examples of both webkit filters and SVGs can be found here: http://jsfiddle.net/maros_urbanec/ARsjb/5/
In both CSS and SVG filters, there is no conversion into HSV or HSL - the hueRotation shorthands are using a linear matrix approximation in RGB space to perform the hue rotation. This doesn't conserve saturation or brightness very well for small rotations and highly saturated colors - as you're seeing.
A true hue rotation, would first convert the input RGB color to HSL, adjust the H and then convert back to RGB. Filters don't do this. And this conversion can't be accurately approximated with a linear matrix, so while the hue is accurately changed(mostly), the saturation and brightness goes all over the place. These effects are non-linear, so adding smaller ops together results in different colors vs. doing one big operation.
(The difference between huerotation in SVG and CSS filters could be due to using different color spaces (sRGB vs. linearRGB) - these should be the same.)
Update: I got interested enough to go and do a manual comparison. As you can see, filters do a terrible job of hue rotating pure colors in the 0 to 180 degree range. This image compares a manual hue rotation done by plugging in hsl colors manually (outer ring) vs. a filter hue rotation on the base color (inner ring)
But, they do a better job at less pure colors like hsl(0,50%,75%) as you can see.
codepen link in case you want to play: http://codepen.io/mullany/pen/fwHrd
Michael's answer is awesome, and I wish I had seen it before; but since I need to not only understand they're damn wierd but also in which way (I want to work around their logic so I need the maths), I've coded a hue-rotate implementation in Javascript (which was mostly taken from reading Firefox's source code), which emulates the hue-rotate that Webkit/Blink/Gecko use.
Again, the whole point here is just to understand what results it produces.
function calculate() {
// Get the RGB and angle to work with.
var color = document.getElementById('color').value;
if (! /^[0-9A-F]{6}$/i.test(color)) return alert('Bad color!');
var angle = document.getElementById('angle').value;
if (! /^-?[0-9]+$/i.test(angle)) return alert('Bad angle!');
var r = parseInt(color.substr(0, 2), 16);
var g = parseInt(color.substr(2, 2), 16);
var b = parseInt(color.substr(4, 2), 16);
var angle = (parseInt(angle) % 360 + 360) % 360;
// Hold your breath because what follows isn't flowers.
var matrix = [ // Just remember this is the identity matrix for
1, 0, 0, // Reds
0, 1, 0, // Greens
0, 0, 1 // Blues
];
// Luminance coefficients.
var lumR = 0.2126;
var lumG = 0.7152;
var lumB = 0.0722;
// Hue rotate coefficients.
var hueRotateR = 0.143;
var hueRotateG = 0.140;
var hueRotateB = 0.283;
var cos = Math.cos(angle * Math.PI / 180);
var sin = Math.sin(angle * Math.PI / 180);
matrix[0] = lumR + (1 - lumR) * cos - lumR * sin;
matrix[1] = lumG - lumG * cos - lumG * sin;
matrix[2] = lumB - lumB * cos + (1 - lumB) * sin;
matrix[3] = lumR - lumR * cos + hueRotateR * sin;
matrix[4] = lumG + (1 - lumG) * cos + hueRotateG * sin;
matrix[5] = lumB - lumB * cos - hueRotateB * sin;
matrix[6] = lumR - lumR * cos - (1 - lumR) * sin;
matrix[7] = lumG - lumG * cos + lumG * sin;
matrix[8] = lumB + (1 - lumB) * cos + lumB * sin;
function clamp(num) {
return Math.round(Math.max(0, Math.min(255, num)));
}
var R = clamp(matrix[0] * r + matrix[1] * g + matrix[2] * b);
var G = clamp(matrix[3] * r + matrix[4] * g + matrix[5] * b);
var B = clamp(matrix[6] * r + matrix[7] * g + matrix[8] * b);
// Output the result
var result = 'The original color, rgb(' + [r,g,b] + '), '
+ 'when rotated by ' + angle + ' degrees '
+ 'by the devil\'s logic, gives you '
+ 'rgb(' + [R,G,B] + '). If I got it right.';
document.getElementById('result').innerText = result;
}
// Listen for Enter key press.
['color', 'angle'].forEach(function(i) {
document.getElementById(i).onkeypress = function(event) {
var e = event || window.event, c = e.which || e.keyCode;
if (c == '13') return calculate();
}
});
body {
font: 14px sans-serif;
padding: 6px 8px;
}
input {
width: 64px;
}
<p>
This algorithm emulates the wierd, nonsensical and completely
idiotic <code>hue-rotate</code> CSS filter. I wanted to know
how it worked, because it is out of touch with any definition
of "hue" I've ever seen; the results it produces are stupid
and I believe it was coded under extreme influence of meth,
alcohol and caffeine, by a scientologist listening to Death Metal.
</p>
<span>#</span>
<input type="text" id="color" placeholder="RRGGBB">
<input type="text" id="angle" placeholder="degrees">
<button onclick="calculate()">Calculate</button>
<p id="result"></p>
The snippet was taken from this answer.
tl;dr Error from converting colors from floats (inside the filter) to bytes (everywhere else).
So it's a bit more complicated than that, the spec provides a good formula for hue rotation matrices, for instance the one for 180 degrees is (excluding alpha and shifts):
-0.5747 1.4304 0.1444
0.4252 0.4304 0.1444
0.4252 1.4304 -0.8556
Note, if you multiply that by itself you get (to four decimal places):
0.9999 0.0001 0.0000
0.0000 1.0 0.0
0.0000 0.0000 1.0
which is very close to the identity matrix, or a null transformation.
That would be perfect, except that the browser is converting back to RGB between each filter. Look what happens when we hue-rotate bright red:
-0.5747 1.4304 0.1444 1 -0.5747
0.4252 0.4304 0.1444 * 0 = 0.4252
0.4252 1.4304 -0.8556 0 0.4252
We get a color that's impossible to represent in RGB with values from 0 to 255. So it gets bound and rounded to 0 0.4235 0.4235 during the RGB conversion, and when it's rotated again we end up with a dark desaturated red, 0.6667 0.2431 0.2431 instead of the bright pure red we started with.

Calculate a color fade

Given two colors and n steps, how can one calculate n colors including the two given colors that create a fade effect?
If possible pseudo-code is preferred but this will probably be implemented in Java.
Thanks!
Divide each colour into its RGB components and then calculate the individual steps required.
oldRed = 120;
newRed = 200;
steps = 10;
redStepAmount = (newRed - oldRed) / steps;
currentRed = oldRed;
for (i = 0; i < steps; i++) {
currentRed += redStepAmount;
}
Obviously extend that for green and blue.
There are two good related questions you should also review:
Generating gradients programatically?
Conditional formatting — percentage to color conversion
Please note that you're often better off doing this in the HSV color space rather than RGB - it generates more pleasing colors to the human eye (lower chance of clashing or negative optical properties).
Good luck!
-Adam
If you want a blend that looks anything like most color picker GUI widgets, you really want to translate to HSL or HSV. From there, you're probably fine with linear interpolation in each dimension.
Trying to do any interpolations directly in RGB colorspace is a bad idea. It's way too nonlinear (and no, gamma correction won't help in this case).
For those looking for something they can copy and paste. Made a quick function for RGB colors. Returns a single color that is the amount of ratio closer to rgbColor2.
function fadeToColor(rgbColor1, rgbColor2, ratio) {
var color1 = rgbColor1.substring(4, rgbColor1.length - 1).split(','),
color2 = rgbColor2.substring(4, rgbColor2.length - 1).split(','),
difference,
newColor = [];
for (var i = 0; i < color1.length; i++) {
difference = color2[i] - color1[i];
newColor.push(Math.floor(parseInt(color1[i], 10) + difference * ratio));
}
return 'rgb(' + newColor + ')';
}
The quesiton is what transformation do you want to occur? If you transpose into the HSV colourspace and given
FF0000 and 00FF00
It will transition from red through yellow to green.
However, if you define "black" or some other shade as being the mid-point of the blend, you have to shade to that colour first ff0000->000000->00ff00 or via white : ff0000 -> ffffff -> 00ff00.
Transforming via HSV however can be fun because you have to use a bit of trig to map the circular map into the vector components.
The easiest thing to do is linear interpolation between the color components (see nickf's response). Just be aware that the eye is highly nonlinear, so it won't necessarily look you're making even steps. Some color spaces attempt to address this (CIE maybe?), so you might want to transform into another color space first, interpolate, then transform back to RGB or whatever you're using.
How about this answer
- (UIColor *)colorFromColor:(UIColor *)fromColor toColor:(UIColor *)toColor percent:(float)percent
{
float dec = percent / 100.f;
CGFloat fRed, fBlue, fGreen, fAlpha;
CGFloat tRed, tBlue, tGreen, tAlpha;
CGFloat red, green, blue, alpha;
if(CGColorGetNumberOfComponents(fromColor.CGColor) == 2) {
[fromColor getWhite:&fRed alpha:&fAlpha];
fGreen = fRed;
fBlue = fRed;
}
else {
[fromColor getRed:&fRed green:&fGreen blue:&fBlue alpha:&fAlpha];
}
if(CGColorGetNumberOfComponents(toColor.CGColor) == 2) {
[toColor getWhite:&tRed alpha:&tAlpha];
tGreen = tRed;
tBlue = tRed;
}
else {
[toColor getRed:&tRed green:&tGreen blue:&tBlue alpha:&tAlpha];
}
red = (dec * (tRed - fRed)) + fRed;
green = (dec * (tGreen - fGreen)) + fGreen;
blue = (dec * (tBlue - fBlue)) + fBlue;
alpha = (dec * (tAlpha - fAlpha)) + fAlpha;
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}

Resources