处理RGB到CIEL*a*b*到RGB转换中的“Out-of-Gamut”颜色

3
我有一些函数(c++),可以将游戏图像(SDL2 SDL_Surface)从RGB转换为CIEXYZ,再到CIEL*a*b*,以便在色调、亮度和饱和度的调整中比在HSV空间更自然。这个方法有效,但是有一些像素在这个过程中会超出RGB色域,需要将其调整回色域内。虽然强制将值限制在色域内也不难,方法如下:
- 将每个子像素值分别裁剪至0以下或255以上; - 通过除以(max-min)和减去min/(max-min)来压缩并移动整个像素或整个图像到0-255范围内。
但是,这些选项在对同一图像进行多次操作时会导致严重的伪影。我正在寻找用代码最少破坏的处理超出颜色范围的子像素的方法。在谷歌搜索了许多页面后,发现大部分结果都是有关Photoshop的链接,还有一些与设计有关的链接,以及一些有关LittleCMS等CMS的参考资料。
我需要一个算法解决方案,可以放入c++代码里。
注:做了一些基本实验后,使用线性压缩整个图像会导致亮度的大量损失,在运算时,这种指数形式的压缩的更多信息是非常欢迎的。

将数据存储在足够大的空间中表示怎么样?RGB 888像素的色调、饱和度和亮度变化无法在该空间中根本表示。 - Yakk - Adam Nevraumont
这正是问题所在。我需要回到RGBA8888,因为这些“图像”实际上是“精灵”,或者你想怎么称呼它们,将它们传递给SDL2进行转换为SDL_Texture,然后渲染到屏幕上。我试图将Lab操作的照片真实性应用于游戏中。 - justinzane
1
保留显示精灵和具有更好色域的真实图像数据。或者保留原始精灵,对其进行转换并保留当前结果。当应用新变换时,请将其与现有变换组合,并从原始状态开始重新执行。 - Yakk - Adam Nevraumont
1
也许考虑使用类Sigmoid的压缩函数将超出色域范围的值映射到0-255之间?即使它在20-235之间大部分是线性的,而将色域的其余部分映射到顶部和底部的最后20个位置中? - Joe Z
@Yakk,保留浮点副本的想法确实可行,但由于目标是使其在大多数SDL2平台上运行--包括平板电脑和手机等ARM设备--我希望通过找到一个良好的色域管理算法来避免不必要的RAM消耗。 - justinzane
显示剩余5条评论
1个回答

3
您面临的根本问题是在不同颜色空间之间进行多次转换。如果转换不是无损的,那么您将会获得累积的伪影。
更好的解决方案是将所有的图片都保持在一个颜色空间中,并在该颜色空间内进行所有的操作。把颜色空间的转换看做是单向的,将副本转换为RGB以进行显示,而不是来回转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接