#effect #image #dither #conversion #error-handling

image-effects

使用image库可以应用于图像的各种效果。

1 个不稳定版本

0.1.0 2023年8月18日

#685 in 图像

MPL-2.0 许可证

3.5MB
1K SLoC

图像效果

该项目实际上是一个应用于图像的库。它大量使用了imagecrate,因为它是Rust的主要图像处理库,以及palette库,用于辅助颜色转换等——尽管该项目最初使用了一个定制的颜色库。

目前有两个主要类别的效果,抖动,它适用于图像并支持< strong>有序和< strong>错误传播方法,以及< strong>过滤器,如亮度、对比度、饱和度等,这些过滤器适用于单个像素(因此也适用于图像)。

以下展示了哪些效果适用于哪些类型。

dither filter
pixel no yes
image yes yes
gif yes yes
  • pixel = [u8; 3] / [u8; 4]
  • image = Vec<Vec<{pixel}>> / (image) DynamicImage / (image) ImageBuffer<Rgb(a)<u8>, Vec<u8>>
  • gif = (image) Frame

(image): 来自 image crate。

抖动

方法

由于每次都需要指定黑色和白色调色板,所以将< strong>1位抖动单独列出是为了方便。内部实际上只是调用了带有< strong>1位调色板的常规错误传播函数。

拜耳和< strong>基本由于工作方式不同,在实现上与其他分开。 拜耳,也称为< em>有序抖动,不传播任何错误,只是使用矩阵在原地操纵每个像素。 基本是一个< em>天真的实现,只是将错误传播到右边。

所有其他算法都是通过使用不同的参数来对 误差传播 进行变体。因此,实现是通过创建一个通用的误差传播函数来工作的,该函数接受

  • 一个 list 的传播偏移量,即错误发送的位置和 增加的量。例如,如果一个矩阵提供 30 个分割,(1, 0, 5) 将指向 下一个 像素 (x+1, y) 并发送 5/30 的错误。
  • 分割的数量。大多数算法将错误完全分割,但一些,如 Atkison,只传播 一些

在此之后,每个算法都通过宏有效地生成。

存在两种类型的抖动:误差传播有序/Bayer。它们之间的唯一相似之处在于它们都会逐像素进行操作,将像素转换成调色板中的最接近匹配。测量哪个颜色是最接近的匹配是在不同的模块 colour 中完成的 - 更多详情 这里

误差传播

对于这些算法,我要感谢 Tanner HellandEfron Licht 提供的资源。Tanner 写了一篇关于误差传播的文章,包括多种帮助理解这个过程的方法,而 Efron 编写了 dither crate,这为这个项目提供了灵感。

所以,对于 误差传播 算法,在它们找到最接近的匹配后,将计算 误差 - 这实际上是所选颜色和实际颜色之间的 RGB 差异。然后,根据所谓的 传播矩阵部分量 将此错误传播到附近的像素。

传播矩阵 更像是一个坐标列表,除了要传播多少误差外,还以 (dx, dy, portion) 的形式。例如,(1, 0, 5) 将 $\frac{5}{N}$ 的错误发送到下一个右边的像素,其中 $N$ 是 部分量。请注意,错误 不需要 准确分布 - 例如 Atkinson 使用 8 个部分,但只传播 6 个。技术上你也可以 过度传播,但这只是给像素添加额外的错误。

有序 / Bayer

这个算法工作方式非常不同,开始更深入地探讨数学。例如,以下是整个算法的一部分

$$ c' = \textrm{nearest_palette_color}(c + r \times (M(x \textrm{ mod } y, y \textrm{ mod } n) - 1/2)) $$

在这里,$c'$ 是新的颜色,$M$ 是 阈值映射,而 $r$ 是颜色空间中的扩散量。我使用 $r = \frac{255}{3}$ - 但是在代码中它是 $\frac{1}{3}$,因为 rgb 值在 0.01.0 之间使用。如果诚实地说,我不完全记得我从哪里得到了这个 $r$ 值,但它似乎效果相当不错。

至于 阈值映射,可以预先计算 - 因为那里唯一的变量是矩阵大小,它通常是2的幂。更多关于这一点,请查看 有序抖动的维基百科页面。它们可以预先计算,但这个库支持 任何任意大小

算法

目前支持以下抖动算法

名称 1位 RGB(Web安全) RGB(8位)
Floyd-Steinberg
Jarvis-Judice-Ninke
Stucki
Atkinson
Burkes
Sierra
SierraTwoRow
SierraLite
Bayer 2x2
Bayer 4x4
Bayer 8x8
Bayer 16x16

过滤器

方法

对于颜色,某些过滤器,如 亮度、饱和度、色调旋转,首先将每个 RGB 像素映射到 HSL 或 LCH。最初,由于计算简单,使用了 HSL。然而,LCH 在表示其各个组成部分方面更为准确。

然而,RGB -> LCH 的计算比 RGB -> HSL 更多。目前代码需要您更改它以使用正确的像素,但可能值得考虑允许用户使用 HSL 以获得最大速度。

算法

目前支持以下效果

名称 图像
增加亮度 +0.2
降低亮度 -0.2
增加饱和度 +0.2
降低饱和度 -0.2
对比度 0.5
对比度 1.5
渐变映射
旋转色调 180
量化色调

参数的尺度如下

  • 增加亮度:取 -1.01.0。正数增强亮度,1.0 将其设置为最大亮度 - 反之亦然。
  • 增加饱和度:与 增加亮度 相同 - 假设最大色度为 128 以便于缩放。(与 palette 的文档匹配)
  • 对比度:接受任何浮点数。
    • x > 1.0 增加对比度。
    • x > 0.0 且 x < 1.0 降低对比度。
    • 负对比度 遵循相似的尺度,其中 -1.01.0 相同 - 但每个颜色通道都被反转。
    • 可能 很有趣尝试在其它空间中进行对比度计算... 这是我需要考虑的事情。

其他任何东西都有特定的类型(量化色调渐变映射),或者按预期工作(旋转色调

颜色

曾经有一段时间,我开始手动实现所有颜色空间及其之间的转换。为此还专门编写了一个子库,但后来我发现有人比我先做了这件事,而且做得更好好多了,于是我就把所有的代码都扔掉了。

如果我不是一个收藏家,我就会这么说。

所有这些代码现在都在colour-exercise-rs上——从RGBHSL,再到LABOKLCH,还有更多——从技术上讲,作为一个库并不是很有用,因为直接使用palette会更好,但如果你对颜色感兴趣,并且认为看到别人在学习过程中摸索可能会有所帮助,那么欢迎你来看看!

不过,那段代码的一个残余部分仍然存在。即colour/comparisons.rs实现了多个距离函数。

colour/comparisons.rs

方法

目前使用的颜色距离函数是加权欧几里得,其公式如下:

$$ f(R, G, B) = \begin{cases} \sqrt{2\Delta R^2 + 4\Delta G^2 + 3\Delta B^2} & \overline{R} < 128, \ \sqrt{3\Delta R^2 + 4\Delta G^2 + 2\Delta B^2} & \textrm{otherwise}, \end{cases} $$

这个库还有其他距离函数,例如cie76cie94ciede2000。之所以使用加权欧几里得,主要是因为效率更高,并且被认为足够好。不过,代码应该很容易修改以使用其他函数,所以使用的函数可能会改变或变成一个选项。

特别是ciede2000非常复杂,可能慢一个数量级。它可能变得更高效,但就目前而言,它有点不切实际。

依赖项

~16MB
~132K SLoC