【问题标题】:Match colors in feColorMatrix filter在 feColorMatrix 过滤器中匹配颜色
【发布时间】:2014-03-25 12:50:46
【问题描述】:

我有一张灰度图像。我想过滤它,使white -> color1black -> color2。两种颜色都采用十六进制 CSS 语法。我需要做哪些数学运算才能获得这种效果?

我正在使用这种语法:

<!-- just an example -->
<filter id="colorMeMatrix">
  <feColorMatrix in="SourceGraphic"
    type="matrix"
    values="0 0 0 0 0
            1 1 1 1 0
            0 0 0 0 0
            0 0 0 1 0" />

【问题讨论】:

标签: css svg svg-filters


【解决方案1】:

要了解您需要的矩阵,您必须清楚地定义开始的内容、最终的结果以及 colour matrix filter 的工作原理。

矩阵有五列四行。每行代表一个输出数字:R、G、B、A。这些列代表您的输入 RGBA 和一个常数 1。您可以通过将行中的每个值相加乘以相应的输入值来计算每一行的输出值。

输入和输出数字都标准化为 0-1 范围,因此您不必担心将所有内容都乘以 256。

所以对于您示例中的矩阵:

      /*R G B A 1 */
        0 0 0 0 0 // R = 0*R + 0*G + 0*B + 0*A + 0
        1 1 1 1 0 // G = 1*R + 1*G + 1*B + 1*A + 0
        0 0 0 0 0 // B = 0*R + 0*G + 0*B + 0*A + 0
        0 0 0 1 0 // A = 0*R + 0*G + 0*B + 1*A + 0

它采用输入颜色,将所有四个通道 (RGBA) 相加,然后将结果设为绿色通道。红色和蓝色通道为零,Alpha 通道没有改变。因此,您的图片最终的黑色区域仍然是黑色,但所有彩色/灰色/白色/透明区域都会转换为绿色阴影。

这当然不是你想要的。您希望黑色区域为一种颜色,白色区域为另一种颜色,所有灰色区域介于两者之间。

要使黑色区域具有某种颜色,您必须设置矩阵的常数因子参数。黑色的输入 RGB 值将为零,因此此时它们不考虑在内。

如果您的 colour2(您想在单色图像中用于黑色的值)是 (r2, g2, b2),那么这就是您的常数因子必须是:

      /*R G B A 1  */
        ? ? ? 0 r2 // R = ?*0 + ?*0 + ?*0 + 0*0 + r2 = r2
        ? ? ? 0 g2 // G = ?*0 + ?*0 + ?*0 + 0*0 + g2 = g2
        ? ? ? 0 b2 // B = ?*0 + ?*0 + ?*0 + 0*0 + b2 = b2
        0 0 0 1 0  // A = 1*A 

当然,上述矩阵会将 任何 输入颜色转换为该输出颜色,因为它不考虑输入 RGBA 值中的任何内容。要获得您想要的渐变,您需要白色区域——R、G 和 B 的输入值为 1 的区域,最终得到您的 colour1,我将其写为 (r1, g1, b1)。

现在,为了让事情更容易一些,请记住,对于灰度图像,任何点的 R、G 和 B 值都是相等的。所以我们可以只使用其中任何一个值作为输入,而忽略其他值。因此,如果我们只是为每个通道设置 R 因子,当输入值为白色时,输入 R 等于 1,方程为

      /*R G B A 1  */
        ? 0 0 0 r2 // R = ?*1 + r2 = r1
        ? 0 0 0 g2 // G = ?*1 + g2 = g1
        ? 0 0 0 b2 // B = ?*1 + b2 = b1
        0 0 0 1 0  // A = 1*A 

简单代数告诉你,为了使这些方程有效,你需要用 colour1 和 colour2 值之间的差异来替换问号:

      /*   R    G B A 1  */
        (r1-r2) 0 0 0 r2 // R = (r1-r2)*1 + r2 = r1
        (g1-g2) 0 0 0 g2 // G = (g1-g2)*1 + g2 = g1
        (b1-b2) 0 0 0 b2 // B = (b1-b2)*1 + b2 = b1
           0    0 0 1 0  // A = 1*A 

例如,如果您希望输入图像的白色区域映射为青色 (r=0,g=1,b=1),而您的黑色输入区域映射为深紫色 (r=0.1, g= 0, b=0.2),你会使用像

这样的矩阵
        /*R  G B A  1  */
        -0.1 0 0 0 0.1 // R = (-0.1)*R + 0.1
          1  0 0 0  0  // G = 1*R + 0
         0.8 0 0 0 0.2 // B = 0.8*R + 0.2
          0  0 0 1  0  // A = 1*A 

Using that matrix in a filter 应用于this original image

请注意,这实际上与我在评论中链接的示例完全不同;在那个过滤器中,我试图将白色保持为白色,将黑色保持为黑色,但将灰色更改为彩色。为此,我使用了伽马校正滤镜,而不是颜色矩阵。

【讨论】:

  • 解释得很好!!
  • 您可能希望为您的过滤器添加一个 color-interpolation-filters="sRGB" 属性 - 它为图像提供更自然的颜色插值(经过伽马校正)
  • @MichaelMullany 我没有玩过——它确实有很大的不同,虽然我不知道 sRGB 版本一定更好。您只需要知道您想要什么,并确保您在正确的色彩空间中计算颜色的 RGB 值。我更新了linked example 进行比较。
  • 好吧,如果您从灰度开始,则起始颜色配置文件不相关。但是,如果您要尝试匹配另一张图像中的颜色,那肯定会。如果 sRGB 规范的定义更明确且跨浏览器一致,那将是对其有利的一大论据。
  • @MichaelMullany 推荐添加color-interpolation-filters="sRGB" 达到了我想要的效果。基本上我有一个想要的目标颜色(#002A78),下面的过滤器现在正确地将整个源映射到所述目标:&lt;feColorMatrix result="matrixOut" in="source" type="matrix" color-interpolation-filters="sRGB" values="0 0 0 0 0 0 0 0 0 0.17 0 0 0 0 0.47 0 0 0 1 0" /&gt;
猜你喜欢
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-29
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多