色彩空间、伽玛和图像增强
色彩空间。嗯,大家都知道 RGB:在 [0.0,1.0] 范围内归一化的三个值,它们具有颜色分量红、绿、蓝的强度的含义;这个强度是线性的,不是吗?
伽玛。据我所知,gamma 是将 RGB 颜色分量映射到另一个值的函数。谷歌搜索,我看到了线性函数和非线性函数...... 线性函数似乎可以缩放 RGB 分量,因此似乎可以调整图像亮度;非线性函数似乎可以“解压”较暗/较亮的成分。
现在,我开始实现一个图像查看器,它将显示不同的图像格式作为纹理。我想修改这些图像的伽马值,因此我应该构建一个片段着色器并在纹理四边形上运行。很好,但是如何确定正确的伽玛校正呢?
OpenGL 使用线性 RGB 颜色空间和浮点组件工作。事实上,我可以从这些值(具有特殊的浮点精度)开始计算伽马校正值,因此它们在钳位伽马校正值后显示。
首先,我将确定伽玛斜坡。我怎样才能确定呢? (分析或使用查找表)
然后,我开始研究 OpenGL 扩展 EXT_framebuffer_sRGB,它似乎与扩展 EXT_texture_sRGB。
EXT_texture_sRGB 引入了一种新的纹理格式,用于将 textel 值线性化到 RGB 线性空间。 (脚注1)通过这种方式,我知道了sRGB颜色空间并将其用作线性RGB颜色空间。
相反,EXT_framebuffer_sRGB 扩展允许我将线性 RGB 值编码到 sRGB 帧缓冲区上,而无需担心它。
...
等等,所有这些信息是为了什么?如果我可以使用 sRGB 帧缓冲区并加载 sRGB 纹理,无需 sRGB 转换即可处理该纹理...为什么我应该校正伽玛?
也许我可以同样校正伽玛,即使是在 sRGB 缓冲区上?或者我最好不要?亮度和对比度:它们应该在伽玛校正之前还是之后应用?
信息量太大了,我现在有点困惑了。希望你们中的一些人可以向我解释更多所有这些概念!谢谢。
……
还有一个问题。如果设备伽玛与“标准”2.2不同,如何“累积”不同的伽玛校正?我不知道是否清楚:如果图像 RGB 值已经针对伽玛值为 2.2 的显示器进行了校正,但显示器的伽玛值为 2.8,如何校正伽玛?
(1) 以下是一些摘录,以强调我的意思:
sRGB 色彩空间基于典型(非线性)显示器 光线昏暗的办公室应具有的特征。它一直 由国际电工委员会 (IEC) 标准化 如 IEC 61966-2-1。 sRGB色彩空间大致对应2.2 伽马校正。
此扩展是否提供任何类型的 sRGB 帧缓冲区格式 或保证使用 sRGB 纹理渲染的图像“看起来不错” 当输出到支持 sRGB 色彩空间的设备时?
<前><代码>已解决:否。 显示的帧缓冲区是否显示到显示器上 忠实再现 sRGB 色彩空间超出了范围 这个扩展。这涉及伽马校正和颜色 物理显示设备的校准。 通过此扩展,艺术家可以使用 sRGB 颜色创作内容 空间并提供 sRGB 内容用作纹理图像 可以正确转换为线性 RGB 并作为一部分进行过滤 以保留 sRGB 分布的方式进行纹理处理 精度,但这并不意味着输出 sRGB 像素 到帧缓冲区。事实上,这个扩展提供了纹理 作为过滤的一部分,将 sRGB 转换为线性 RGB 的格式。 通过可编程着色,应用程序可以执行 在发射颜色之前进行线性 RGB 到 sRGB 转换 来自着色器的值。即便如此,OpenGL 混合(除了 简单调制)将对值执行线性数学运算 存储在非线性空间中,这在技术上是不正确的 sRGB 编码颜色。 思考这些 sRGB 纹理格式的一种方法是: 只需提供具有值分布的颜色分量 分布有利于精度接近 0 而不是均匀分布 使用传统的非 sRGB 格式分配精度 例如GL_RGB8。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不幸的是,OpenGL 本身并没有定义色彩空间。它只是定义传递给OpenGL的RGB值形成一个线性向量空间。然后,渲染的帧缓冲区的值将按原样发送到显示设备。 OpenGL 只是传递该值。
伽玛有两个用途:
伽玛校正用于补偿这两个目的。
变换只是“线性值 V 到某个幂 Gamma”,即 y(v) = v^gamma
色彩空间变换涉及从输入值到发送到显示器的完整链,因此这包括伽玛校正。这也意味着您不应该自己操纵伽玛斜坡。
很长一段时间以来,典型的 Gamma 值一直是 2.2。然而,这会导致一些不良的低值量化,因此 Adobe 引入了一种新的色彩空间,称为 sRGB,它具有用于低值的线性部分和用于较高值的指数 ~2.3 的幂函数。如今大多数显示设备都使用 sRGB。而且现在大多数图像文件都是 sRGB 格式。
因此,如果您有 sRGB 图像,并在 sRGB 显示设备上按原样显示它,并在设备上配置了线性伽玛斜坡(即视频驱动程序 gamma=1),那么只需使用 sRGB 纹理和帧缓冲区而不是执行以下操作就可以了还要别的吗。
因评论而编辑 总结
一下:
使用 ARB_framebuffer_sRGB 帧缓冲区,以便线性 OpenGL 处理的结果由驱动程序正确进行颜色转换http://www.opengl.org/registry/specs/ARB/framebuffer_sRGB.txt
线性化 OpenGL 的所有颜色输入
sRGB 颜色空间中的纹理应通过 EXT_texture_sRGB 传递 http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt
不对输出值进行伽玛校正(sRGB 格式帧缓冲区将处理此问题) )
如果您的系统不支持 sRGB 帧缓冲区:
在显示设备上设置线性颜色渐变。
创建(线性)帧缓冲区对象,以在帧缓冲区对象中进行线性渲染。 FBO 的用途是正确地进行混合,该混合仅适用于线性颜色空间。
使用片段着色器将最终渲染结果从 FBO 绘制到窗口,该片段着色器应用所需的颜色(伽玛和其他)校正。
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:
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.
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.
一般来说,你不会。 sRGB 纹理和帧缓冲区的目的是让您不必手动进行伽玛校正。从 sRGB 纹理读取的数据将转换为线性色彩空间,而写入 sRGB 帧缓冲区的数据则采用线性 RGB 值并将其转换为 sRGB 值。这都是自动的,而且更重要的是免费,从性能角度来看。
您唯一需要进行伽玛校正的情况是显示器的伽玛与 2.2 伽玛的 sRGB 伽玛近似值不匹配。做到这一点的显示器很少见。
您的纹理不必位于 sRGB 色彩空间中。然而,大多数图像创建应用程序都会以 sRGB 格式保存图像并使用 sRGB 格式的颜色,因此无论您是否愿意,您的大多数纹理已经都是 sRGB 格式。 sRGB 纹理功能仅允许您实际获取正确颜色值,而不是您迄今为止所获取的颜色值。
不知道你说的亮度和对比度是什么意思。这应该由监视器而不是您的应用程序设置。但实际上,您想要对图像数据执行的所有数学运算都应该在线性色彩空间中完成。因此,如果给定 sRGB 色彩空间中的图像,则需要先对其进行线性化,然后才能对其进行任何数学运算。 sRGB 纹理功能使这一过程变得免费,而不必进行复杂的着色器数学运算。
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.
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.
RGB
不。RGB 值是毫无意义的数字,除非定义了它们与特定空间/编码的相关性。它们可能是线性的、伽马编码的或对数编码的,或者使用复合传输曲线,如 Rec709 和 sRGB 规范。
此外,它们与色彩空间中定义的原色和白点相关,因此例如,sRGB 中的#00FF00 与 DCI-P3 中的#00FF00 是不同的颜色。
要定义 RGB 像素值的显示方式,您不仅需要 RGB 三元组,还需要知道其预期的色彩空间,其中需要包括主坐标、白点和传输曲线。
sRGB 是用于 Web 和通用计算的默认“标准”RGB 色彩空间。它与 HDTV 标准色彩空间 Rec709 相关。
GAMMA 又名传输曲线
图像伽玛利用人类感知的非线性,充分利用每通道图像 8 位的有限数据大小。人眼对较暗颜色的变化更敏感,因此使用更多位来定义伽玛编码图像中的较暗颜色。
在数字化之前,伽玛也被用于 NTSC 广播系统中,它抑制信号中的明显噪声,其方式类似于图像伽玛如何防止每通道 8 位图像出现“带状”伪影。
伽玛曲线。 sRGB 伽马曲线很容易访问。这是从 sRGB 到线性的维基百科链接。您还可以使用“简化”方法,该方法仅使用 2.2 指数曲线:
linearVideo = sRGBvideo^2.2
和简化的逆函数,返回到 sRGB:sRGBvideo = LinearVideo^0.4545
代码>使用简化版本会引入一些轻微的伽马误差,建议在关键操作或图像将多次“往返”的情况下使用“正确”曲线。
2.8 ???那是什么显示器?朋友?这是不寻常的——虽然 PAL 规范这么说,但 2.8 并不“实用”。显示器通常在 2.3 到 2.5 左右,具体取决于它们的设置方式。当您调整黑电平和对比度(白电平)时,您实质上是在调整感知的伽玛值以匹配观看环境(房间照明)。
仅供参考,虽然 sRGB“信号”的编码伽玛值为 1/2.2,但显示器通常会增加约 1.1 的指数。
对于 Rec709,编码信号的有效伽玛值为约 1/1.9,但显示器在参考视图中环境约为 2.4
在这两种情况下,都有有意的系统伽玛增益。
如果您想使用 2.8 显示器的伽玛值对图像进行编码,并且不需要系统伽玛增益,则指数为 1/2.8
常用的“最高”伽玛值用于数字影院(以及 Rec2020),为 2.6你们中那些认为 PAL 和 PAL 的人2.8,我鼓励您阅读有关该主题的 Poynton:
强烈推荐阅读
Charles Poynton 的 Gamma FAQ 是一个简单的文章阅读并完整描述这些问题以及它们在图像管道中的重要性。另请在同一链接阅读他的颜色常见问题解答。
关于线性与 sRGB 的几句话
在线性工作空间中处理图像通常是理想的,因为它不仅简化了数学,而且模拟了现实世界中的光。世界中的光以线性方式工作(相加)。但如果以线性方式工作,则需要足够的位深度,而 8 位是不够的。
人类的感知是非线性的。图像伽玛编码利用非线性来充分利用 8 位图像容器。当您转换为线性时,您需要更多位。每个通道 12 位被认为是最低限度,但 16 位浮点是线性工作空间的最低“推荐最佳实践”。
如果在线性渲染环境中使用纹理,则需要将这些纹理转换为线性空间(通常是更深的位深度)。虽然添加的位增加了数据带宽,但简化的数学通常可以实现更快的计算。
sRGB 是一个显示参考空间,它旨在用于显示目的,并用于以紧凑的“显示就绪”状态存储图像。黑色为 0,白色为 255,传输曲线接近 1/2.2
sRGB 基于 Rec709 (HDTV),并使用相同的原色和白点。但传输曲线和数据编码不同。 Rec709 旨在在黑暗的客厅中在更高伽玛监视器上显示,并以 16 编码黑色,以 235 编码白色。
RGB
No. RGB values are meaningless numbers unless their relevance to a particular space/encoding is defined. They may be linear, gamma encoded, or log encoded, or use a compound transfer curve like the Rec709 and sRGB specs.
Also, they are relative to their primaries and whitepoint as defined in the colorspace, so for instance, #00FF00 in sRGB is a different color than #00FF00 in DCI-P3.
To define how an RGB pixel value should be displayed, you need not only the RGB triplet, but you need to know the colorspace it is intended for, which needs to include the primary coordinates, whitepoint, and transfer curve.
sRGB is the default "standard" RGB colorspace for the Web and general purpose computing. It is related to Rec709, the standard colorspace for HDTV.
GAMMA aka TRANSFER CURVE
Image gamma takes advantage of the non-linearity of human perception to make the best use of the limited data size of 8 bit per channel images. The human eye is more sensitive to changes in darker colors, so more bits ae used to define the darker colors in a gamma encoded image.
Before digital, gamma was also used in the NTSC broadcast system which suppressed the apparent noise in the signal, in a way similar to how image gamma prevents an 8-bit per channel image from having "banding" artifacts.
Gamma CURVE. The sRGB gamma curve is easily accessed. Here is the Wikipedia link for go from sRGB to linear. You can also use the "simplified" method which simply uses a 2.2 exponent curve:
linearVideo = sRGBvideo^2.2
and the simplified inverse, to go back to sRGB:sRGBvideo = linearVideo^0.4545
Using the simplified version will introduce some minor gamma errors, it is advised to use the "correct" curve for critical operations or where an image will be "round tripped" multiple times.
2.8 ??? What monitor is that? PAL? This is unusual — While the PAL spec says that, 2.8 isn't "practical". Monitors are typically around 2.3 to 2.5 depending on how they are setup. When you adjust black level and contrast (white level) you are in essence adjusting the perceived gamma to match the viewing environment (room lighting).
Just FYI, while the sRGB "signal" has an encoded gamma of 1/2.2, the monitor normally adds an exponent of about 1.1
For Rec709, the encoded signal has an effective gamma of about 1/1.9 ish but the monitor in the reference viewing environment is about 2.4
In both cases there is an intentional system gamma gain.
If you wanted to encode an image with a gamma for a 2.8 display and you wanted no system gamma gain, then the exponent is 1/2.8
The "highest" gamma in common use is for digital cinema (and also Rec2020), at 2.6 For those of you thinking PAL & 2.8, I encourage you to read Poynton on that subject:
HIGHLY RECOMMENDED READING
Charles Poynton's Gamma FAQ is an easy read and completely describes these issues and why they are important in an image pipeline. Also read his Color FAQ at the same link.
A FEW WORDS ON LINEAR vs sRGB
Working on images in a linear workspace is typically ideal, as it not only simplifies the math, but emulates light in the real world. Light in the world works in a linear manner (additive). But if working in linear, you need adequate bit depth, and 8 bits is not enough.
Human perception is NON linear. Image gamma encoding takes advantage of the non linearity to make the most use of 8 bit image containers. When you convert to linear YOU NEED MORE BITS. 12 bit per chan is considered a minimum, but 16bit float is the minimum "recommend best practice" for linear workspaces.
If using textures in a linear rendering environment, those textures need to be transformed to a linear space (and often a deeper bit depth). While the added bits increase data bandwidth, the simplified math often allows faster computation.
sRGB is a DISPLAY REFERRED space, it is intended for DISPLAY PURPOSES, and for storing images in a compact "display ready" state. Black is 0 and white is 255, and the transfer curve is close to 1/2.2
sRGB is based on Rec709 (HDTV), and uses identical primaries and whitepoint. But the transfer curve and data encoding are different. Rec709 is intended for display on a higher gamma monitor in a darkened livingroom, and encodes black at 16 and white at 235.