svg中的黑白(非灰度)滤镜,最好是snap.svg

时间:2017-01-07 03:43:18

标签: image-processing svg raphael snap.svg svg-filters

编辑1:重写了问题,以便更清楚地理解。

这个真的让我分心。

我想对图像应用滤镜,使得超过特定阈值的值显示为完全白色,并且所有等于或小于阈值的值都是完全黑色。

这是一张表示3x3像素图像的RGB值的地图:

|(255,255,255)|(220,220,220)|(100,100,100)|  
|(254,254,254)|(12 ,12 ,12 )|(38 ,38 ,38 )|  
|(201,201,201)|(105,105,105)|(60 ,60 ,60 )|

应用我的过滤器后,我希望收到一个图像,其中所有大于200的值都转换为(255,255,255),所有等于或小于200的值都转换为(0,0,0),如:

|(255,255,255)|(255,255,255)|(0  ,0  ,0  )|
|(255,255,255)|(0  ,0  ,0  )|(0  ,0  ,0  )|
|(255,255,255)|(0  ,0  ,0  )|(0  ,0  ,0  )|

我应该从哪里开始的想法?这在svg中甚至可能吗? 我知道我可以在svg的过滤器中创建矩阵乘法,但我不知道如何处理这个问题。

谢谢你!

编辑1: 相关问题我在数学交流中发布: https://math.stackexchange.com/questions/2087482/creating-binary-matrix-for-threshold-as-a-result-of-matrix-multiplcation

编辑2::从Snap.svg代码中提取:此矩阵将彩色图像转换为灰度:

<feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/>

我想修改这里的值以获得黑色和白色,而不是获得灰度。我想选择高于哪个阈值返回白色的阈值,下面返回为黑色

其他信息:根据MSDN,这是乘法发生的方式:

Resulting vector   my coveted matrix     original vector
    | R' |     | a00 a01 a02 a03 a04 |   | R |
    | G' |     | a10 a11 a12 a13 a14 |   | G |
    | B' |  =  | a20 a21 a22 a23 a24 | * | B |
    | A' |     | a30 a31 a32 a33 a34 |   | A |
    | 1  |     |  0   0   0   0   1  |   | 1 |

这又适用于输入图像的每个像素。

3 个答案:

答案 0 :(得分:6)

您可以使用<feComponentTransfer type="discrete">过滤器原语实现阈值处理。

以下是一个例子。

&#13;
&#13;
<svg width="300" height="550" style="background-color: linen">
  <defs>
    <linearGradient id="gradient">
      <stop offset="0" stop-color="white"/>
      <stop offset="1" stop-color="black"/>
    </linearGradient>
    
    <filter id="threshold" color-interpolation-filters="sRGB">
      <feComponentTransfer>
        <feFuncR type="discrete" tableValues="0 1"/>
        <feFuncG type="discrete" tableValues="0 1"/>
        <feFuncB type="discrete" tableValues="0 1"/>
      </feComponentTransfer>
    </filter>
  </defs>

  <rect x="50" y="50" width="200" height="200" fill="url(#gradient)"/>
  <rect x="50" y="300" width="200" height="200" fill="url(#gradient)" filter="url(#threshold)"/>
</svg>
&#13;
&#13;
&#13;

这个原语的工作原理是你为每个颜色组件创建一个乐队表。但是,波段的数量与输入有关,而与输出无关。想想它,因为输入被分成许多相同大小的频段。然后为每个波段分配输出值。因此,如果您希望拆分发生在50%(R,G或B = 0.5(128)),那么您创建两个波段,&#34; 0 1&#34;。第一个带(0 - > 0.5)中的值被赋值为0,第二个带(0.5 - > 1)中的值被赋值为1.

因此,例如,如果您想要达到20%(0.2或51)的阈值,则需要创建五个波段。输出表值为&#34; 0 1 1 1 1&#34;。

&#13;
&#13;
<svg width="300" height="550" style="background-color: linen">
  <defs>
    <linearGradient id="gradient">
      <stop offset="0" stop-color="white"/>
      <stop offset="1" stop-color="black"/>
    </linearGradient>
    
    <filter id="threshold" color-interpolation-filters="sRGB">
      <feComponentTransfer>
        <feFuncR type="discrete" tableValues="0 1 1 1 1"/>
        <feFuncG type="discrete" tableValues="0 1 1 1 1"/>
        <feFuncB type="discrete" tableValues="0 1 1 1 1"/>
      </feComponentTransfer>
    </filter>
  </defs>

  <rect x="50" y="50" width="200" height="200" fill="url(#gradient)"/>
  <rect x="50" y="300" width="200" height="200" fill="url(#gradient)" filter="url(#threshold)"/>
</svg>
&#13;
&#13;
&#13;

这种方法的缺点是它确实意味着如果你想要在任意组件值上设置阈值,你可能需要在表中最多包含256个值。

为了证明这一点,在最后一个例子中,我使用一些javascript来根据范围滑块设置的值更新过滤表。

&#13;
&#13;
var selector = document.getElementById("selector");
var funcR = document.getElementById("funcR");
var funcG = document.getElementById("funcG");
var funcB = document.getElementById("funcB");

function updateFilter() {
  // Input value
  var threshold = selector.value;
  // Create the table
  var table = "0 ".repeat(threshold) + "1 ".repeat(256-threshold);
  // Update the filter components
  funcR.setAttribute("tableValues", table);
  funcG.setAttribute("tableValues", table);
  funcB.setAttribute("tableValues", table);
}

selector.addEventListener('input', updateFilter);

// Call the filter updater once at the start to initialise the filter table
updateFilter();
&#13;
<svg width="300" height="300" style="background-color: linen">
  <defs>
    <filter id="threshold" color-interpolation-filters="sRGB">
      <feComponentTransfer>
        <feFuncR id="funcR" type="discrete" tableValues="0 1 1 1"/>
        <feFuncG id="funcG" type="discrete" tableValues="0 1 1 1"/>
        <feFuncB id="funcB" type="discrete" tableValues="0 1 1 1"/>
      </feComponentTransfer>
    </filter>
  </defs>

  <image xlink:href="https://placekitten.com/g/300/300"
         x="50" y="50"width="200" height="200"
         filter="url(#threshold)"/>
</svg>

<form>
  <input id="selector" type="range" min="0" max="256"/>
</form>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

这是SVG的feComponentTransfer原语用于,类型=“离散”。请参阅webplatform documentation以了解如何使用该元素。

答案 2 :(得分:0)

您所参考的RGB到灰度转换是一个线性过程。它可以通过矩阵乘法来完成。 每个输出值都是R,G和B值的加权和。如果为每个输出通道选择相同的权重,则生成的RGB图像将显示为灰色。

二值化是一种非线性操作。因此,无法修改转换矩阵,因此它将执行黑白而不是灰度。

我不知道是否有一个标志或者你可以添加到svg文件中的东西会使它看起来像黑白但你可以写一个小的程序来适当地替换颜色值。