convert RGB to grayscale in C

user2000255 picture user2000255 · Mar 28, 2013 · Viewed 15k times · Source

I used many formulas to convert from RGB to grayscale, but didn't get good results compared to GIMP.

I already tested the following formulas:

gray = (int)(0.299 * r + 0.587 * g + 0.144 * b);

gray = (int)(0.299 * r + 0.587 * g + 0.114 * b);

gray = (int)(0.2126 * r + 0.7152 * g + 0.0722 * b);

gray = (int) (0.35*r + 0.50*g + 0.15*b);

gray = ((r * 61) + (g * 174) + (b * 21)) / 256;

gray = (int)((4897 * r + 9617 * g + 1868 * b) >> 14);

gray = r; if(g > gray) gray = g; if(b > gray) gray = b;

Answer

digitalvision picture digitalvision · Mar 28, 2013

In order to correctly convert RGB to grayscale, you should transform the gamma corrected R,G and B values into the linear color space, apply the conversion in the linear space, and then apply a gamma correction to the result.

The sRGB colorspace has a transform that only approximates a gamma curve. See the Wikipedia article for the particulars. Wikipedia also has a specific section on the subject of sRGB to grayscale.

Basically, to convert a sRGB component to linear format:

double sRGB_to_linear(double x) {
    if (x < 0.04045) return x/12.92;
    return pow((x+0.055)/1.055, 2.4);
}

Then, to convert sRGB to linear grayscale:

double R_linear = sRGB_to_linear(R/255.0);
double G_linear = sRGB_to_linear(G/255.0);
double B_linear = sRGB_to_linear(B/255.0);
double gray_linear = 0.2126 * R_linear + 0.7152 * G_linear + 0.0722 * B_linear;

Then, apply the sRGB gamma correction again:

double linear_to_sRGB(double y) {
    if (y <= 0.0031308) return 12.92 * y;
    return 1.055 * pow(y, 1/2.4) - 0.055;
}

I.e.

double gray_color = round(linear_to_sRGB(gray_linear) * 255);