0

我正在使用 libvips 在后端转换图像,并在前端使用 css/svg 预览来节省资源。

我正在努力实现对比度 css/svg 过滤器功能。

该规范将对比度显示为以下形式的线性变换:

out = slope * in + intercept

intercept应该在哪里:

intercept = - (0.5 * slope) + 0.5

这样,我可以contrast(1.25)在图像修改的 css 预览中使用。

但是,通过JS库sharp在libvips中实现这个线性函数:

sharp.linear(contrast, - (0.5 * contrast) + 0.5)

深入研究图像的对比度变化,预期结果是高点更高,低点更低。这看起来像是与规范的矛盾,因为规范应用了线性变换,所以它应该总是乘法和相加,使高点更高,但也让低点更高一点。

使用线性锐化(在 libvips 中也是如此)来改变对比度,输出实际上看起来像一个亮度过滤器,在 css/svg 过滤器的规范中它是形式线性变换而不加

out = slope * in

在我看来,我可能误解了拦截在 svg 线性函数中的作用。此外,比较 svg 和 css 显示出差异。contrast(2)在 css中使用应该模仿slope = 2intercept = -(0.5 * 2) + 0.5 = -0.5在 svg 中使用,这不是这个小提琴的情况:

.svg {
  filter: url(#contrast);
}

.css {
  filter: contrast(2);
}
<img src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="svg" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="css" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">

<svg>
  <filter id="contrast">
    <feComponentTransfer>
      <feFuncR type="linear" slope="2" intercept="-0.5"/>
      <feFuncG type="linear" slope="2" intercept="-0.5"/>
      <feFuncB type="linear" slope="2" intercept="-0.5"/>
    </feComponentTransfer>
  </filter>
</svg>

您可以清楚地看到使用 svg 过滤器的第二张图像与使用 css 过滤器的第三张图像看起来不同。

我对过滤器的理解完全错误吗?我希望在某个地方应该有一些阈值来将乘法转换为除法以获得低点。

如何在不同的环境中将 css 对比度实现为具有相同结果的线性函数?

4

2 回答 2

1

您的直觉不正确:) 对于小于 0.5 的输入值 - 公式会降低亮度 - 为什么?让我们取对比度值 2 和输入值 0.4

输出 = 2*0.4 - (0.5 *2) + 0.5

输出 = 0.8 - 1 + 0.5

输出 = 0.3

如您所见,当输入低于 0.5 时,输出将始终小于输入,因为斜率分量和截距的第一个(负)分量之和将等于对比度乘以差异在输入和 0.5 之间

这是单位化值的公式结果(以 0/1 为下限和上限)。

在此处输入图像描述

CSS 过滤器也默认使用 sRGB 颜色空间。SVG 过滤器使用线性RGB。您需要通过向您的 svg 元素添加属性:color-interpolation-filters="sRGB" 将 SVG 过滤器颜色空间设置为 sRGB。当你这样做时——你的图像看起来是一样的。

.svg {
  filter: url(#contrast);
}

.css {
  filter: contrast(2);
}
<img src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="svg" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="css" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">

<svg color-interpolation-filters="sRGB">
  <filter id="contrast">
    <feComponentTransfer>
      <feFuncR type="linear" slope="2" intercept="-0.5"/>
      <feFuncG type="linear" slope="2" intercept="-0.5"/>
      <feFuncB type="linear" slope="2" intercept="-0.5"/>
    </feComponentTransfer>
  </filter>
</svg>

于 2019-03-26T05:40:39.747 回答
0

https://github.com/lovell/sharp/issues/1958

在这里,您有一个来自 css 的工作公式:

filter: `contrast(${contrast})`

尖锐:

brightness = 1;
image.linear(brightness * constrast, brightness * (-(128 * contrast) + 128));

虽然,我还没有弄清楚如何brightness融入这个

于 2021-05-02T07:46:42.593 回答