Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Color spaces, gamma and image enhancement

Color space. Well, everybody knows about RGB: three values normalized in the range [0.0,1.0], which have the meaning of the intensity of the color components Red Green Blue; this intensity is meant as linear, isn't?

Gamma. As far I can understand, gamma is a function which maps RGB color components to another value. Googling on this, I've seen linear functions and non linear functions... Linear functions seems to scale RGB components, so it seems to tune image brightness; non linear functions seems to "decompress" darker/lighter components.

Now, I'm starting to implement an image viewer, which shall display different image formats as texture. I'd like to modify the gamma of these images, so I should build up a fragment shader and run over the textured quad. Fine, but how do I determine the right gamma correction?

OpenGL works using linear RGB color space, using floating point components. Indeed, I could compute gamma-corrected values starting from those values (with special floating point precision), so they are displayed after having clamped the gamma-corrected value.

First, I shall determine the gamma ramp. How could I determine it? (analitically or using lookup tables)

Then, I came up to investigate on the OpenGL extension EXT_framebuffer_sRGB, which seems very related with the extension EXT_texture_sRGB.

EXT_texture_sRGB introduce a new texture format which is used to linearize textel values into RGB linear space. (footnote 1) In this way, I'm aware of sRGB color space and use it as linear RGB color space.

Instead, EXT_framebuffer_sRGB extension allows me to encode linear RGB values onto the sRGB framebuffer, without worrying about it.

...

Wait, all this information for what? If I can use sRGB framebuffer and load sRGB textures, process that textures without sRGB conversions... why should I correct gamma?

Maybe can I correct gamma all the same, even on a sRGB buffer? Or I better not? And brightness and contrast: shall they applied before or after gamma correction?

That's a lot of information, I'm getting confused now. Hope that someone of you can explain me more all these concepts! Thank you.

...

There's another question. In the case the device gamma is different from the "standard" 2.2, how do I "accumulate" different gamma corrections? I don't know if it is clear: in the case image RGB values are already corrected for a monitor with a gamma value of 2.2, but the monitor has a gamma of value 2.8, how to I correct gamma?


(1) Here is some extract to highlight what I mean:

The sRGB color space is based on typical (non-linear) monitor characteristics expected in a dimly lit office. It has been standardized by the International Electrotechnical Commission (IEC) as IEC 61966-2-1. The sRGB color space roughly corresponds to 2.2 gamma correction.


Does this extension provide any sort of sRGB framebuffer formats or guarantee images rendered with sRGB textures will "look good" when output to a device supporting an sRGB color space?

   RESOLVED:  No.

  Whether the displayed framebuffer is displayed to a monitor that
    faithfully reproduces the sRGB color space is beyond the scope
    of this extension.  This involves the gamma correction and color
    calibration of the physical display device.

    With this extension, artists can author content in an sRGB color
    space and provide that sRGB content for use as texture imagery
    that can be properly converted to linear RGB and filtered as part
    of texturing in a way that preserves the sRGB distribution of
    precision, but that does NOT mean sRGB pixels are output
    to the framebuffer.  Indeed, this extension provides texture
    formats that convert sRGB to linear RGB as part of filtering.

    With programmable shading, an application could perform a
    linear RGB to sRGB conversion just prior to emitting color
    values from the shader.  Even so, OpenGL blending (other than
    simple modulation) will perform linear math operations on values
    stored in a non-linear space which is technically incorrect for
    sRGB-encoded colors.

    One way to think about these sRGB texture formats is that they
    simply provide color components with a distribution of values
    distributed to favor precision towards 0 rather than evenly
    distributing the precision with conventional non-sRGB formats
    such as GL_RGB8.
like image 748
Luca Avatar asked Jun 18 '11 17:06

Luca


People also ask

What is color space and gamma?

Avideo color space defines RGB chromaticities that together determine a color gamut, a color component transfer function (often referred to using a confusing and unhelpful but common term “gamma”) and the chromaticity of a white point.

What does gamma do to an image?

Gamma correction can be used to control the overall brightness of an image. It can be used with images that are found to be either bleached out or too dark [12]. Expansion and compression of pixel intensity values are desired for darker and faded images [51].

What is color space in image?

A color space is a range of colors on a spectrum that can be interpreted and displayed on a visual plane. Many of these displays are interpreted through a RGB (Red, Green, Blue) chromaticity diagram, then processed and displayed on digital/analog images.

What is gamma in color?

Definition of Gamma Gamma can be described as how smoothly black transitions to white on a digital display. It is often associated with a number like 2.2 or 2.4. This number represents the extent of the curve from black to white, or from white to black.


2 Answers

Unfortunately OpenGL by itself doesn't define a colour space. It's just defined that the RGB values passed to OpenGL form a linear vector space. The values of the rendered framebuffer are then sent to the display device as they are. OpenGL just passes through the value.

Gamma services two purposes:

  • Sensory perception is nonlinear
  • In the old days, display devices had a nonlinear response

The gamma correction is used to compensate for both.

The transformation is just "linear value V to some power Gamma", i.e. y(v) = v^gamma

Colorspace transformations involve the complete chain from input values to whats sent to the display, so this includes the gamma correction. This also implies that you should not manipulate the gamma ramp youself.

For a long time the typical Gamma value used to be 2.2. However this caused some undesireable quantisation of low values, so Adobe introduced a new colour space, called sRGB which has a linear part for low values and a powerfunction with exponential ~2.3 for the higher values. Most display devices these days use sRGB. Also most image files these days are in sRGB.

So if you have a sRGB image, and display it as-is on a sRGB display device with a linear gamma ramp configured on the device (i.e. video driver gamma=1) you're good by simply using sRGB texturing and framebuffer and not doing anything else.

EDIT due to comments

Just to summarize:

  • Use a ARB_framebuffer_sRGB framebuffer, so that the results of the linear OpenGL processing are properly color transformed by the driver http://www.opengl.org/registry/specs/ARB/framebuffer_sRGB.txt

  • Linearize all colour inputs to OpenGL

  • Textures in sRGB colour space should be passed through EXT_texture_sRGB http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt

  • Don't gamma correct the output values (the sRGB format framebuffer will take care of this)

If your system does not support sRGB framebuffers:

  • Set a linear colour ramp on your display device.

    • Windows http://msdn.microsoft.com/en-us/library/ms536529(v=vs.85).aspx
    • X11 can be done though xgamma http://www.xfree86.org/current/xgamma.1.html
  • create (linear) framebuffer objects, to linear rendering in the framebuffer object. The use of a FBO is, to properly to blending, which only works in linear colour space.

  • draw the final render result from the FBO to the window using a fragment shader that applies the desired colour (gamma and other) corrections.

like image 101
datenwolf Avatar answered Oct 11 '22 23:10

datenwolf


Wait, all this information for what? If I can use sRGB framebuffer and load sRGB textures, process that textures without sRGB conversions... why should I correct gamma?

Generally, you don't. The purpose of the sRGB texturing and framebuffers is so that you don't have to manually do gamma correction. Reads from sRGB textures are converted to a linear colorspace, and writes to sRGB framebuffers take linear RGB values and convert them to sRGB values. This is all automatic, and more to the point free, performance-wise.

The only time you will need to do gamma correction is if the monitor's gamma does not match the sRGB gamma approximation of 2.2 gamma. Rare is the monitor that does this.

Your textures do not have to be in sRGB colorspace. However, most image creation applications will save images in sRGB and works with colors in sRGB, so odds are most of your textures are already in sRGB whether you want them to be or not. The sRGB texture feature simply allows you to actually get the correct color values, rather than the color values you've been getting up until now.

And brightness and contrast: shall they applied before or after gamma correction?

I don't know what you mean by brightness and contrast. That's something that should be set by the monitor, not your application. But virtually all math operations you will want to do on image data should be done in a linear colorspace. Therefore, if you are given an image in the sRGB colorspace, you need to linearize it before you can do any math on it. The sRGB texture feature makes this free, rather than having to do complex shader math.

like image 28
Nicol Bolas Avatar answered Oct 11 '22 21:10

Nicol Bolas