iOS Metal,为什么简单地更改colorPixelFormat会产生更明亮的图像?

des4xlb0  于 2023-08-08  发布在  iOS
关注(0)|答案(2)|浏览(125)

在iOS上的Metal中,默认的colorPixelFormat是bgra8Unorm。当我将格式更改为rgba16Float时,所有图像都会变亮。为什么?为什么?
一个例子:
艺术品


的数据
MTKView,格式为bgra8Unorm。纹理贴图四边形。使用SRGB=false创建的纹理。



MTKView,格式为rgba16Float。纹理贴图四边形。使用SRGB=false创建的纹理。



为什么rgba16Float一切都更亮。我的理解是,SRGB=false意味着导入图稿时不进行gamma校正。假设艺术品未应用伽马
这是怎么回事

pjngdqdw

pjngdqdw1#

如果您的图稿具有Gamma(它是根据您上传的第一张图像),如果您想在线性空间中使用它,则必须将其转换为线性Gamma。
这里发生的是,您在线性工作空间中显示图像的伽马编码值,而不使用颜色管理或变换来转换这些 * 值 *。
但是:阅读你的一些评论,纹理不是一个图像,而是一个.svg??您是否将颜色值转换为线性空间?

**事情是这样的:RGB值是无意义的数字,除非您定义这些RGB值与给定空间的关系。

例如,sRGB中的#00FF00与Adobe 98中的#00FF00颜色不同。在你的情况下,你是线性的,但什么是初级呢?还在使用sRGB原色?P3初级?我没有看到真实的的色调偏移,所以我假设你在第二个例子中使用了sRGB原色和线性转移曲线。
也就是说,中间最高的孩子绿色衬衫的RGB值是#8DB54F,归一化为0-1,即0.553 0.710 0.310。这些数字 * 本身 * 不知道它们是否是伽马编码的。

sRGB、Y和Light之间的关系:

  • 为了讨论的目的,我们将假设SIMPLE sRGB gamma为1/2.2,而不是分段版本。

在sRGB中,#8DB54F,当在sRGB监视器上显示时,亮度(Y)为39
这可以通过以下方式找到
第一个月
0.057 + 0.33 + 0.0061 = 0.39 and 0.39 * 100 = 39 (Y)
但是,如果颜色管理被告知值是线性的,则伽马校正被丢弃,并且(或多或少):
0.553*0.2126 + 0.710*0.7152 + 0.310*0.0722
0.1175 + 0.5078 + 0.0223 = 0.65 and 0.65 * 100 = 65 (Y)

  • (假设使用相同的系数)*

亮度(Y)是线性的,就像光一样。但人类的感知不是,sRGB值也不是。
Y是CIEXYZ的线性亮度,虽然它是基于眼睛对不同波长的响应进行光谱加权的,但它在亮度方面是不均匀的。在0-100的范围内,18.4被认为是中间的。
L* 是来自CIELAB的感知亮度(L* a* b*),它是(的简化曲线):
L* = Y^0.42在0-100的范围内,L* 50是“感知中间”值。所以,Y 39的绿色衬衫在解释和显示为sRGB时是L* 69,Y 65大约是L* 84(这些数字是基于数学,这里是我MacBook上每个颜色选择器的值):
100d 1xx 1c 1d 1x的字符串
sRGB是伽马编码信号,用于最好地利用每通道8位的有限位深度。有效伽马曲线类似于人类感知,使得更多的位用于定义较暗区域,因为人类感知对暗区域中的亮度变化更敏感。如上所述,它是以下的简化曲线:
sRGB_Video = Linear_Video^0.455(需要注意的是,MONITOR增加了大约1.1的指数)
因此,如果0%是黑色,100%是白色,那么中间灰色,大多数人会说在0%和100%之间的点是:
Y 18.4%. = L* 50% = sRGB 46.7%
也就是说,sRGB十六进制值#777777将显示18.4Y的亮度,并且相当于50 L* 的感知亮度。中灰。
但等等,还有更多
那么,发生了什么,你正在告诉MTKView,你正在向它发送引用 * 线性 * 值的图像数据。但你实际上是发送 sRGB 值,由于应用了伽马校正,这些值更亮。然后颜色管理是取它认为是线性值,并将它们转换为输出显示所需的值。
色彩管理需要知道值 * 意味着什么,它们与什么颜色空间相关。当你设置SRGB=false时,你告诉它你发送的是线性值,而不是伽玛编码值。
但是,您显然是在将伽马编码的值发送到线性空间中,而没有将值转换/解码为线性。除非隐式地这样做,否则线性化不会发生。

解决方案

线性化图像数据或设置标志SRGB=true

如果您还有其他问题,请告诉我。但是,您可能希望看到Poynton Gamma FAQ或颜色常见问题解答以澄清。

**此外,对于灰色:**线性值0.216相当于sRGB(0-1)值0.500

niknxzdl

niknxzdl2#

我最近不得不与这个问题作斗争,我终于弄明白了为什么将像素格式从bgra8Unorm更改为rgba16Float会改变视觉外观,即使它应该只是我们如何存储像素数据的实现细节。
缺少的部分是当未指定colorspace时核心动画如何合成CAMetalLayer。如果像素格式为bgra8Unorm,则Core Animation假定像素数据位于非线性sRGB空间中。如果像素格式为rgba16Float,则Core Animation假定像素数据在线性空间中。这就是为什么你所有的颜色看起来更明亮。颜色看起来太亮和褪色是sRGB颜色被解释为线性空间中的颜色的典型症状。
解决办法其实很简单。只需将CAMetalLayercolorspace设置为与内容的色彩空间(通常为sRGB)相匹配:

layer.colorspace = CGColorSpace(name: CGColorSpace.sRGB)!

字符串
并且无论像素格式如何,您的内容看起来都应该相同。

相关问题